Class: Datadog::DI::Probe Private
- Inherits:
-
Object
- Object
- Datadog::DI::Probe
- Defined in:
- lib/datadog/di/probe.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
Encapsulates probe information (as received via remote config) and state (e.g. whether the probe was installed, or executed).
It is possible that remote configuration will specify an unsupported probe type or attribute, due to new DI functionality being added over time. We want to have predictable behavior in such cases, and since we can't guarantee that there will be enough information in a remote config payload to construct a functional probe, ProbeBuilder and remote config code must be prepared to deal with exceptions raised by Probe constructor in particular. Therefore, Probe constructor will raise an exception if it determines that there is not enough information (or conflicting information) in the arguments to create a functional probe, and upstream code is tasked with not spamming logs with notifications of such errors (and potentially limiting the attempts to construct probe from a given payload).
Note that, while remote configuration provides line numbers as an array, the only supported line number configuration is a single line (this is the case for all languages currently). Therefore Probe only supports one line number, and ProbeBuilder is responsible for extracting that one line number out of the array received from RC.
Note: only some of the parameter/attribute values are currently validated.
Constant Summary collapse
- KNOWN_TYPES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
%i[log].freeze
- EVALUATE_AT_VALUES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
%i[entry exit].freeze
Instance Attribute Summary collapse
- #capture_expressions ⇒ Object readonly private
-
#condition ⇒ Object
readonly
private
The compiled condition for the probe, as a String.
-
#condition_evaluation_failed_rate_limiter ⇒ Object
readonly
private
Rate limiter object for sending snapshots with evaluation errors for when probe condition evaluation fails.
-
#emitting_notified ⇒ Object
writeonly
private
TODO emitting_notified reads and writes should in theory be locked, however since DI is only implemented for MRI in practice the missing locking should not cause issues.
- #evaluate_at ⇒ Object readonly private
- #file ⇒ Object readonly private
- #id ⇒ Object readonly private
-
#instrumentation_module ⇒ Object
private
Instrumentation module for method probes.
-
#instrumentation_trace_point ⇒ Object
private
Line trace point for line probes.
-
#instrumented_path ⇒ Object
private
Actual path to the file instrumented by the probe, for line probes, when code tracking is available and line trace point is targeted.
- #line_no ⇒ Object readonly private
-
#max_capture_attribute_count ⇒ Object
readonly
private
Configured maximum capture attribute count.
- #max_capture_collection_size ⇒ Object readonly private
-
#max_capture_depth ⇒ Object
readonly
private
Configured maximum capture depth.
- #max_capture_string_length ⇒ Object readonly private
- #method_name ⇒ Object readonly private
-
#rate_limit ⇒ Object
readonly
private
Rate limit in effect, in invocations per second.
-
#rate_limiter ⇒ Object
readonly
private
Rate limiter object.
- #template ⇒ Object readonly private
- #template_segments ⇒ Object readonly private
- #type ⇒ Object readonly private
- #type_name ⇒ Object readonly private
Instance Method Summary collapse
- #capture_entry_expressions? ⇒ Boolean private
- #capture_expressions? ⇒ Boolean private
-
#capture_expressions_only? ⇒ Boolean
private
Capture-expression mode: the probe captures expressions but not a full snapshot.
- #capture_snapshot? ⇒ Boolean private
-
#capturing? ⇒ Boolean
private
Whether this probe captures user data, either as a full snapshot or via capture expressions.
- #disable! ⇒ Object private
- #emitting_notified? ⇒ Boolean private
- #enabled? ⇒ Boolean private
- #evaluate_at_entry? ⇒ Boolean private
- #executed_on_line! ⇒ Object private
- #executed_on_line? ⇒ Boolean private
-
#file_matches?(path) ⇒ Boolean
private
Returns whether the provided
pathmatches the user-designated file (of a line probe). -
#initialize(id:, type:, file: nil, line_no: nil, type_name: nil, method_name: nil, template: nil, template_segments: nil, capture_snapshot: false, max_capture_depth: nil, max_capture_attribute_count: nil, max_capture_collection_size: nil, max_capture_string_length: nil, capture_expressions: [], evaluate_at: nil, condition: nil, rate_limit: nil) ⇒ Probe
constructor
private
A new instance of Probe.
-
#line? ⇒ Boolean
private
Returns whether the probe is a line probe.
-
#line_no! ⇒ Object
private
Returns the line number associated with the probe, raising Error::MissingLineNumber if the probe does not have a line number associated with it.
-
#location ⇒ Object
private
Source code location of the probe, for diagnostic reporting.
-
#method? ⇒ Boolean
private
Returns whether the probe is a method probe.
-
#method_name! ⇒ Object
private
Returns the method name associated with the probe, raising Error::MissingMethodName if the probe does not have a method name associated with it.
- #snapshot_serializer_limits(settings) ⇒ Object private
Constructor Details
#initialize(id:, type:, file: nil, line_no: nil, type_name: nil, method_name: nil, template: nil, template_segments: nil, capture_snapshot: false, max_capture_depth: nil, max_capture_attribute_count: nil, max_capture_collection_size: nil, max_capture_string_length: nil, capture_expressions: [], evaluate_at: nil, condition: nil, rate_limit: nil) ⇒ Probe
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of Probe.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/datadog/di/probe.rb', line 39 def initialize(id:, type:, file: nil, line_no: nil, type_name: nil, method_name: nil, template: nil, template_segments: nil, capture_snapshot: false, max_capture_depth: nil, max_capture_attribute_count: nil, max_capture_collection_size: nil, max_capture_string_length: nil, capture_expressions: [], evaluate_at: nil, condition: nil, rate_limit: nil) # Perform some sanity checks here to detect unexpected attribute # combinations, in order to not do them in subsequent code. unless KNOWN_TYPES.include?(type) raise ArgumentError, "Unknown probe type: #{type}" end # Probe should be inferred to be a line probe if the specification # contains a line number. This how Java tracer works and Go tracer # is implementing the same behavior, and Go will have all 3 fields # (file path, line number and method name) for line probes. # Do not raise if line number and method name both exist - instead # treat the probe as a line probe. # # In the future we want to provide type name and method name to line # probes, so that the library can verify that the instrumented line # is in the method that the frontend showed to the user when the # user created the probe. if line_no && !file raise ArgumentError, "Probe contains line number but not file: #{id}" end if type_name && !method_name || method_name && !type_name raise ArgumentError, "Partial method probe definition: #{id}" end if line_no.nil? && method_name.nil? raise ArgumentError, "Unhandled probe type: neither method nor line probe: #{id}" end @id = id @type = type @file = file @line_no = line_no @type_name = type_name @method_name = method_name @template = template @template_segments = template_segments @capture_snapshot = !!capture_snapshot @max_capture_depth = max_capture_depth @max_capture_attribute_count = max_capture_attribute_count @max_capture_collection_size = max_capture_collection_size @max_capture_string_length = max_capture_string_length @capture_expressions = capture_expressions || [] evaluate_at = :exit if evaluate_at.nil? unless EVALUATE_AT_VALUES.include?(evaluate_at) raise ArgumentError, "Unknown evaluate_at value: #{evaluate_at.inspect} (expected one of #{EVALUATE_AT_VALUES.inspect})" end @evaluate_at = evaluate_at @condition = condition @rate_limit = rate_limit || (capturing? ? 1 : 5000) @rate_limiter = Datadog::Core::TokenBucket.new(@rate_limit) # At most one report per second. # We create the rate limiter here even though it may never be used, # to avoid having to synchronize the creation since method probes # can be executed on multiple threads concurrently (even if line # probes are never executed concurrently since those are done in a # trace point). if condition @condition_evaluation_failed_rate_limiter = Datadog::Core::TokenBucket.new(1) end @emitting_notified = false @enabled = true end |
Instance Attribute Details
#capture_expressions ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
141 142 143 |
# File 'lib/datadog/di/probe.rb', line 141 def capture_expressions @capture_expressions end |
#condition ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The compiled condition for the probe, as a String.
127 128 129 |
# File 'lib/datadog/di/probe.rb', line 127 def condition @condition end |
#condition_evaluation_failed_rate_limiter ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Rate limiter object for sending snapshots with evaluation errors for when probe condition evaluation fails. This rate limit is separate from the "base" rate limit for the probe because when the condition evaluation succeeds we want the "base" rate limit applied, not tainted by any evaluation errors (for example, the condition can be highly selective, and when it does not hold the evaluation may fail - we don't want to use up the probe rate limit for the errors).
159 160 161 |
# File 'lib/datadog/di/probe.rb', line 159 def condition_evaluation_failed_rate_limiter @condition_evaluation_failed_rate_limiter end |
#emitting_notified=(value) ⇒ Object (writeonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
TODO emitting_notified reads and writes should in theory be locked, however since DI is only implemented for MRI in practice the missing locking should not cause issues.
284 285 286 |
# File 'lib/datadog/di/probe.rb', line 284 def emitting_notified=(value) @emitting_notified = value end |
#evaluate_at ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
143 144 145 |
# File 'lib/datadog/di/probe.rb', line 143 def evaluate_at @evaluate_at end |
#file ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
119 120 121 |
# File 'lib/datadog/di/probe.rb', line 119 def file @file end |
#id ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
117 118 119 |
# File 'lib/datadog/di/probe.rb', line 117 def id @id end |
#instrumentation_module ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Instrumentation module for method probes.
270 271 272 |
# File 'lib/datadog/di/probe.rb', line 270 def instrumentation_module @instrumentation_module end |
#instrumentation_trace_point ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Line trace point for line probes. Normally this would be a targeted trace point.
274 275 276 |
# File 'lib/datadog/di/probe.rb', line 274 def instrumentation_trace_point @instrumentation_trace_point end |
#instrumented_path ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Actual path to the file instrumented by the probe, for line probes, when code tracking is available and line trace point is targeted. For untargeted line trace points instrumented path will be nil.
279 280 281 |
# File 'lib/datadog/di/probe.rb', line 279 def instrumented_path @instrumented_path end |
#line_no ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
120 121 122 |
# File 'lib/datadog/di/probe.rb', line 120 def line_no @line_no end |
#max_capture_attribute_count ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Configured maximum capture attribute count. Can be nil in which case the global default will be used.
135 136 137 |
# File 'lib/datadog/di/probe.rb', line 135 def max_capture_attribute_count @max_capture_attribute_count end |
#max_capture_collection_size ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
137 138 139 |
# File 'lib/datadog/di/probe.rb', line 137 def max_capture_collection_size @max_capture_collection_size end |
#max_capture_depth ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Configured maximum capture depth. Can be nil in which case the global default will be used.
131 132 133 |
# File 'lib/datadog/di/probe.rb', line 131 def max_capture_depth @max_capture_depth end |
#max_capture_string_length ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
139 140 141 |
# File 'lib/datadog/di/probe.rb', line 139 def max_capture_string_length @max_capture_string_length end |
#method_name ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
122 123 124 |
# File 'lib/datadog/di/probe.rb', line 122 def method_name @method_name end |
#rate_limit ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Rate limit in effect, in invocations per second. Always present.
146 147 148 |
# File 'lib/datadog/di/probe.rb', line 146 def rate_limit @rate_limit end |
#rate_limiter ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Rate limiter object. For internal DI use only.
149 150 151 |
# File 'lib/datadog/di/probe.rb', line 149 def rate_limiter @rate_limiter end |
#template ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
123 124 125 |
# File 'lib/datadog/di/probe.rb', line 123 def template @template end |
#template_segments ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
124 125 126 |
# File 'lib/datadog/di/probe.rb', line 124 def template_segments @template_segments end |
#type ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
118 119 120 |
# File 'lib/datadog/di/probe.rb', line 118 def type @type end |
#type_name ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
121 122 123 |
# File 'lib/datadog/di/probe.rb', line 121 def type_name @type_name end |
Instance Method Details
#capture_entry_expressions? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
188 189 190 |
# File 'lib/datadog/di/probe.rb', line 188 def capture_entry_expressions? capture_expressions_only? && evaluate_at_entry? end |
#capture_expressions? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
165 166 167 |
# File 'lib/datadog/di/probe.rb', line 165 def capture_expressions? !@capture_expressions.empty? end |
#capture_expressions_only? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Capture-expression mode: the probe captures expressions but not a full snapshot. Snapshot capture serializes its own values, so expression capture only runs when a snapshot is not being taken.
184 185 186 |
# File 'lib/datadog/di/probe.rb', line 184 def capture_expressions_only? capture_expressions? && !capture_snapshot? end |
#capture_snapshot? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
161 162 163 |
# File 'lib/datadog/di/probe.rb', line 161 def capture_snapshot? @capture_snapshot end |
#capturing? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Whether this probe captures user data, either as a full snapshot or via capture expressions.
173 174 175 |
# File 'lib/datadog/di/probe.rb', line 173 def capturing? capture_snapshot? || capture_expressions? end |
#disable! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
302 303 304 |
# File 'lib/datadog/di/probe.rb', line 302 def disable! @enabled = false end |
#emitting_notified? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
285 286 287 |
# File 'lib/datadog/di/probe.rb', line 285 def emitting_notified? !!@emitting_notified end |
#enabled? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
298 299 300 |
# File 'lib/datadog/di/probe.rb', line 298 def enabled? @enabled end |
#evaluate_at_entry? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
177 178 179 |
# File 'lib/datadog/di/probe.rb', line 177 def evaluate_at_entry? evaluate_at == :entry end |
#executed_on_line! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
293 294 295 296 |
# File 'lib/datadog/di/probe.rb', line 293 def executed_on_line! # TODO lock? @executed_on_line = true end |
#executed_on_line? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
289 290 291 |
# File 'lib/datadog/di/probe.rb', line 289 def executed_on_line? !!(defined?(@executed_on_line) && @executed_on_line) end |
#file_matches?(path) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns whether the provided path matches the user-designated
file (of a line probe).
Delegates to Utils.path_can_match_spec? which performs fuzzy matching. See the comments in utils.rb for details.
259 260 261 262 263 264 265 266 267 |
# File 'lib/datadog/di/probe.rb', line 259 def file_matches?(path) if path.nil? raise ArgumentError, "Cannot match against a nil path" end unless file raise ArgumentError, "Probe does not have a file to match against" end Utils.path_can_match_spec?(path, file) end |
#line? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns whether the probe is a line probe.
Method probes may still specify a file name (to aid in locating the method or for stack traversal purposes?), therefore we do not check for file name/path presence here and just consider the line number.
201 202 203 204 205 206 |
# File 'lib/datadog/di/probe.rb', line 201 def line? # Constructor checks that file is given if line number is given, # but for safety, check again here since we somehow got a probe with # a line number but no file in the wild. !!(file && line_no) end |
#line_no! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the line number associated with the probe, raising Error::MissingLineNumber if the probe does not have a line number associated with it.
This method is used by instrumentation driver to ensure a line number that is passed into the instrumentation logic is actually a line number and not nil.
220 221 222 223 224 225 |
# File 'lib/datadog/di/probe.rb', line 220 def line_no! if line_no.nil? raise Error::MissingLineNumber, "Probe #{id} does not have a line number associated with it" end line_no end |
#location ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Source code location of the probe, for diagnostic reporting.
242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/datadog/di/probe.rb', line 242 def location if method? "#{type_name}.#{method_name}" elsif line? "#{file}:#{line_no}" else # This case should not be possible because constructor verifies that # the probe is a method or a line probe. raise NotImplementedError end end |
#method? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns whether the probe is a method probe.
209 210 211 |
# File 'lib/datadog/di/probe.rb', line 209 def method? line_no.nil? end |
#method_name! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the method name associated with the probe, raising Error::MissingMethodName if the probe does not have a method name associated with it.
This method is used by instrumentation driver to ensure a method name that is passed into the instrumentation logic is actually a method name and not nil.
234 235 236 237 238 239 |
# File 'lib/datadog/di/probe.rb', line 234 def method_name! if method_name.nil? raise Error::MissingMethodName, "Probe #{id} does not have a method name associated with it" end method_name end |
#snapshot_serializer_limits(settings) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
192 193 194 |
# File 'lib/datadog/di/probe.rb', line 192 def snapshot_serializer_limits(settings) CaptureLimits.resolve(expr_limits: nil, probe: self, settings: settings) end |