Class: Contrast::Agent::Scope

Inherits:
Object
  • Object
show all
Defined in:
lib/contrast/agent/scope.rb

Overview

Scope lets us disable Contrast for certain code calls. We need to do this so that we don’t propagate through our own code.

Think logging: If you have something like “The source was ‘” + source + “’”, and source is tracked, you’ll trigger propagation with the + method. This in turn would cause propagation if you log there “The target ”” + target + “‘ was propagated’” Which would then cause another propagation with the ‘+’ method, forever.

Instead, we should say “If I’m already doing Contrast things, don’t track this”

Constant Summary collapse

SCOPE_LIST =
%i[contrast deserialization].cs__freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeScope

Returns a new instance of Scope.



20
21
22
23
# File 'lib/contrast/agent/scope.rb', line 20

def initialize
  instance_variable_set(:@contrast_scope, 0)
  instance_variable_set(:@deserialization_scope, 0)
end

Class Method Details

.ensure_valid_scope!(scope_sym) ⇒ Object



113
114
115
116
117
118
119
# File 'lib/contrast/agent/scope.rb', line 113

def ensure_valid_scope! scope_sym
  unless valid_scope? scope_sym # rubocop:disable Style/GuardClause
    with_contrast_scope do
      raise NoMethodError, "Scope '#{ scope_sym.inspect }' is not registered as a scope."
    end
  end
end

.valid_scope?(scope_sym) ⇒ Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/contrast/agent/scope.rb', line 109

def valid_scope? scope_sym
  Contrast::Agent::Scope::SCOPE_LIST.include? scope_sym
end

Instance Method Details

#enter_contrast_scope!Object



33
34
35
36
# File 'lib/contrast/agent/scope.rb', line 33

def enter_contrast_scope!
  level = instance_variable_get(:@contrast_scope)
  instance_variable_set(:@contrast_scope, level + 1)
end

#enter_deserialization_scope!Object



38
39
40
41
# File 'lib/contrast/agent/scope.rb', line 38

def enter_deserialization_scope!
  level = instance_variable_get(:@deserialization_scope)
  instance_variable_set(:@deserialization_scope, level + 1)
end

#enter_scope!(name) ⇒ Object



96
97
98
99
100
# File 'lib/contrast/agent/scope.rb', line 96

def enter_scope! name
  cs__class.ensure_valid_scope! name
  call = with_contrast_scope { :"enter_#{ name }_scope!" }
  send(call)
end

#exit_contrast_scope!Object

Scope Exits… by design, can go below zero. every exit/enter pair (regardless of series) should cancel each other out.

so we prefer this sequence:

scope =  0
exit  = -1
enter =  0
enter =  1
exit  =  0
scope =  0

over this sequence:

scope =  0
exit  =  0
enter =  1
enter =  2
exit  =  1
scope =  1


63
64
65
66
# File 'lib/contrast/agent/scope.rb', line 63

def exit_contrast_scope!
  level = instance_variable_get(:@contrast_scope)
  instance_variable_set(:@contrast_scope, level - 1)
end

#exit_deserialization_scope!Object



68
69
70
71
# File 'lib/contrast/agent/scope.rb', line 68

def exit_deserialization_scope!
  level = instance_variable_get(:@deserialization_scope)
  instance_variable_set(:@deserialization_scope, level - 1)
end

#exit_scope!(name) ⇒ Object



102
103
104
105
106
# File 'lib/contrast/agent/scope.rb', line 102

def exit_scope! name
  cs__class.ensure_valid_scope! name
  call = with_contrast_scope { :"exit_#{ name }_scope!" }
  send(call)
end

#in_contrast_scope?Boolean

Returns:

  • (Boolean)


25
26
27
# File 'lib/contrast/agent/scope.rb', line 25

def in_contrast_scope?
  instance_variable_get(:@contrast_scope).positive?
end

#in_deserialization_scope?Boolean

Returns:

  • (Boolean)


29
30
31
# File 'lib/contrast/agent/scope.rb', line 29

def in_deserialization_scope?
  instance_variable_get(:@deserialization_scope).positive?
end

#in_scope?(name) ⇒ Boolean

Dynamic versions of the above. These are equivalent, but they’re slower and riskier. Prefer the static methods if you know what scope you need at the call site.

Returns:

  • (Boolean)


90
91
92
93
94
# File 'lib/contrast/agent/scope.rb', line 90

def in_scope? name
  cs__class.ensure_valid_scope! name
  call = with_contrast_scope { :"in_#{ name }_scope?" }
  send(call)
end

#with_contrast_scopeObject



73
74
75
76
77
78
# File 'lib/contrast/agent/scope.rb', line 73

def with_contrast_scope
  enter_contrast_scope!
  yield
ensure
  exit_contrast_scope!
end

#with_deserialization_scopeObject



80
81
82
83
84
85
# File 'lib/contrast/agent/scope.rb', line 80

def with_deserialization_scope
  enter_deserialization_scope!
  yield
ensure
  exit_deserialization_scope!
end