datadog 2.28.0 → 2.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +87 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +82 -12
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +32 -11
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +3 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +9 -24
- data/ext/datadog_profiling_native_extension/heap_recorder.c +186 -55
- data/ext/datadog_profiling_native_extension/heap_recorder.h +12 -1
- data/ext/datadog_profiling_native_extension/http_transport.c +51 -64
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +0 -13
- data/ext/datadog_profiling_native_extension/profiling.c +3 -1
- data/ext/datadog_profiling_native_extension/setup_signal_handler.c +24 -8
- data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -3
- data/ext/datadog_profiling_native_extension/stack_recorder.c +63 -48
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -1
- data/ext/libdatadog_api/crashtracker.c +5 -0
- data/ext/libdatadog_api/crashtracker_report_exception.c +126 -0
- data/ext/libdatadog_api/extconf.rb +4 -21
- data/ext/libdatadog_extconf_helpers.rb +49 -11
- data/lib/datadog/ai_guard/configuration/settings.rb +3 -0
- data/lib/datadog/appsec/assets/blocked.html +2 -1
- data/lib/datadog/appsec/configuration/settings.rb +14 -0
- data/lib/datadog/appsec/context.rb +44 -9
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +3 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/patcher.rb +2 -0
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +55 -6
- data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/faraday/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +60 -7
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +11 -6
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
- data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +6 -10
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +4 -4
- data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +26 -5
- data/lib/datadog/appsec/contrib/rack/response_body.rb +36 -0
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +2 -0
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +2 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +72 -7
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +5 -3
- data/lib/datadog/appsec/counter_sampler.rb +25 -0
- data/lib/datadog/appsec/event.rb +1 -17
- data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +2 -3
- data/lib/datadog/appsec/instrumentation/gateway.rb +2 -2
- data/lib/datadog/appsec/metrics/telemetry_exporter.rb +18 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/security_engine/engine.rb +23 -2
- data/lib/datadog/appsec/utils/http/body.rb +38 -0
- data/lib/datadog/appsec/utils/http/media_range.rb +2 -1
- data/lib/datadog/appsec/utils/http/media_type.rb +28 -35
- data/lib/datadog/appsec/utils/http/url_encoded.rb +52 -0
- data/lib/datadog/core/configuration/components.rb +29 -4
- data/lib/datadog/core/configuration/option.rb +2 -1
- data/lib/datadog/core/configuration/options.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +27 -3
- data/lib/datadog/core/configuration/supported_configurations.rb +19 -0
- data/lib/datadog/core/configuration.rb +2 -2
- data/lib/datadog/core/crashtracking/component.rb +71 -19
- data/lib/datadog/core/environment/agent_info.rb +65 -1
- data/lib/datadog/core/logger.rb +1 -1
- data/lib/datadog/core/metrics/logging.rb +1 -1
- data/lib/datadog/core/process_discovery.rb +20 -19
- data/lib/datadog/core/rate_limiter.rb +2 -0
- data/lib/datadog/core/remote/component.rb +16 -5
- data/lib/datadog/core/remote/transport/config.rb +5 -11
- data/lib/datadog/core/runtime/metrics.rb +1 -2
- data/lib/datadog/core/telemetry/component.rb +0 -13
- data/lib/datadog/core/telemetry/transport/telemetry.rb +5 -6
- data/lib/datadog/core/transport/ext.rb +1 -0
- data/lib/datadog/core/transport/http/response.rb +4 -0
- data/lib/datadog/core/transport/parcel.rb +61 -9
- data/lib/datadog/core/utils/base64.rb +1 -1
- data/lib/datadog/core/utils/fnv.rb +26 -0
- data/lib/datadog/core/workers/interval_loop.rb +13 -6
- data/lib/datadog/core/workers/queue.rb +0 -4
- data/lib/datadog/core/workers/runtime_metrics.rb +9 -1
- data/lib/datadog/core.rb +6 -1
- data/lib/datadog/data_streams/processor.rb +35 -33
- data/lib/datadog/data_streams/transport/http/stats.rb +6 -0
- data/lib/datadog/data_streams/transport/http.rb +0 -4
- data/lib/datadog/data_streams/transport/stats.rb +5 -12
- data/lib/datadog/di/boot.rb +1 -0
- data/lib/datadog/di/component.rb +17 -5
- data/lib/datadog/di/configuration/settings.rb +9 -0
- data/lib/datadog/di/context.rb +6 -0
- data/lib/datadog/di/instrumenter.rb +183 -134
- data/lib/datadog/di/probe.rb +10 -1
- data/lib/datadog/di/probe_file_loader.rb +2 -2
- data/lib/datadog/di/probe_manager.rb +86 -64
- data/lib/datadog/di/probe_notification_builder.rb +46 -18
- data/lib/datadog/di/probe_notifier_worker.rb +65 -9
- data/lib/datadog/di/probe_repository.rb +198 -0
- data/lib/datadog/di/proc_responder.rb +4 -0
- data/lib/datadog/di/remote.rb +6 -7
- data/lib/datadog/di/serializer.rb +127 -9
- data/lib/datadog/di/transport/diagnostics.rb +5 -7
- data/lib/datadog/di/transport/http/diagnostics.rb +3 -1
- data/lib/datadog/di/transport/http/input.rb +1 -1
- data/lib/datadog/di/transport/http.rb +12 -3
- data/lib/datadog/di/transport/input.rb +51 -14
- data/lib/datadog/kit/tracing/method_tracer.rb +132 -0
- data/lib/datadog/open_feature/configuration.rb +2 -0
- data/lib/datadog/open_feature/transport.rb +8 -11
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +13 -0
- data/lib/datadog/profiling/component.rb +20 -6
- data/lib/datadog/profiling/http_transport.rb +5 -6
- data/lib/datadog/profiling/profiler.rb +15 -8
- data/lib/datadog/tracing/contrib/dalli/integration.rb +4 -1
- data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/ethon/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/excon/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/faraday/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +2 -2
- data/lib/datadog/tracing/contrib/grape/instrumentation.rb +13 -8
- data/lib/datadog/tracing/contrib/grape/patcher.rb +6 -1
- data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/http/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/http/integration.rb +0 -2
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/httpclient/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/httprb/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/karafka/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +6 -0
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +2 -1
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +6 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +2 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +10 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +24 -0
- data/lib/datadog/tracing/contrib/que/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/que/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/rack/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/rack/route_inference.rb +18 -6
- data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/rails/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/registerable.rb +11 -0
- data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +5 -2
- data/lib/datadog/tracing/contrib/rest_client/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/sinatra/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/sneakers/integration.rb +15 -4
- data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +6 -0
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +5 -1
- data/lib/datadog/tracing/contrib/waterdrop/ext.rb +1 -0
- data/lib/datadog/tracing/metadata/ext.rb +4 -0
- data/lib/datadog/tracing/sync_writer.rb +0 -1
- data/lib/datadog/tracing/transport/io/client.rb +5 -8
- data/lib/datadog/tracing/transport/io/traces.rb +28 -34
- data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/transport/traces.rb +4 -10
- data/lib/datadog/tracing/writer.rb +0 -1
- data/lib/datadog/version.rb +1 -1
- metadata +14 -8
- data/lib/datadog/appsec/contrib/rails/ext.rb +0 -13
- data/lib/datadog/tracing/workers/trace_writer.rb +0 -204
|
@@ -112,51 +112,59 @@ module Datadog
|
|
|
112
112
|
end
|
|
113
113
|
rate_limiter = probe.rate_limiter
|
|
114
114
|
settings = self.settings
|
|
115
|
+
instrumenter = self
|
|
115
116
|
|
|
116
117
|
mod = Module.new do
|
|
117
118
|
define_method(method_name) do |*args, **kwargs, &target_block| # steep:ignore NoMethod
|
|
118
119
|
# Steep: Unsure why it cannot detect kwargs in this block. Workaround:
|
|
119
120
|
# @type var kwargs: ::Hash[::Symbol, untyped]
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
121
|
+
di_start_time = Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
|
|
122
|
+
|
|
123
|
+
if continue = probe.enabled?
|
|
124
|
+
if condition = probe.condition
|
|
125
|
+
begin
|
|
126
|
+
# This context will be recreated later, unlike for line probes.
|
|
127
|
+
#
|
|
128
|
+
# We do not need the stack for condition evaluation, therefore
|
|
129
|
+
# stack is not passed to Context here.
|
|
130
|
+
context = Context.new(
|
|
131
|
+
locals: serializer.combine_args(args, kwargs, self),
|
|
132
|
+
target_self: self,
|
|
133
|
+
probe: probe, settings: settings, serializer: serializer,
|
|
134
|
+
)
|
|
135
|
+
continue = condition.satisfied?(context)
|
|
136
|
+
rescue => exc
|
|
137
|
+
# Evaluation error exception can be raised for "expected"
|
|
138
|
+
# errors, we probably need another setting to control whether
|
|
139
|
+
# these exceptions are propagated.
|
|
140
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions &&
|
|
141
|
+
!exc.is_a?(DI::Error::ExpressionEvaluationError)
|
|
142
|
+
|
|
143
|
+
if context
|
|
144
|
+
# We want to report evaluation errors for conditions
|
|
145
|
+
# as probe snapshots. However, if we failed to create
|
|
146
|
+
# the context, we won't be able to report anything as
|
|
147
|
+
# the probe notifier builder requires a context.
|
|
148
|
+
begin
|
|
149
|
+
responder.probe_condition_evaluation_failed_callback(context, exc)
|
|
150
|
+
rescue => nested_exc
|
|
151
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
152
|
+
|
|
153
|
+
instrumenter.logger.debug { "di: error in probe condition evaluation failed callback: #{nested_exc.class}: #{nested_exc}" }
|
|
154
|
+
instrumenter.telemetry&.report(nested_exc, description: "Error in probe condition evaluation failed callback")
|
|
155
|
+
end
|
|
156
|
+
else
|
|
157
|
+
_ = 42 # stop standard from wrecking this code
|
|
158
|
+
|
|
146
159
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
147
160
|
|
|
148
|
-
|
|
161
|
+
instrumenter.logger.debug { "di: error evaluating condition without context (tracer bug?): #{exc.class}: #{exc}" }
|
|
162
|
+
instrumenter.telemetry&.report(exc, description: "Error evaluating condition without context")
|
|
163
|
+
# If execution gets here, there is probably a bug in the tracer.
|
|
149
164
|
end
|
|
150
|
-
else
|
|
151
|
-
_ = 42 # stop standard from wrecking this code
|
|
152
165
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
# TODO log / report via telemetry?
|
|
156
|
-
# If execution gets here, there is probably a bug in the tracer.
|
|
166
|
+
continue = false
|
|
157
167
|
end
|
|
158
|
-
|
|
159
|
-
continue = false
|
|
160
168
|
end
|
|
161
169
|
end
|
|
162
170
|
|
|
@@ -173,6 +181,8 @@ module Datadog
|
|
|
173
181
|
# customer, and DI is not allowed to invoke customer code.
|
|
174
182
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
175
183
|
|
|
184
|
+
di_duration = Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID) - di_start_time
|
|
185
|
+
|
|
176
186
|
rv = nil
|
|
177
187
|
begin
|
|
178
188
|
# Under Ruby 2.6 we cannot just call super(*args, **kwargs)
|
|
@@ -195,7 +205,15 @@ module Datadog
|
|
|
195
205
|
# the instrumentation callback runs.
|
|
196
206
|
end
|
|
197
207
|
|
|
198
|
-
|
|
208
|
+
end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
209
|
+
duration = end_time - start_time
|
|
210
|
+
|
|
211
|
+
# Restart DI timer.
|
|
212
|
+
# The DI execution duration covers time spent in DI code before
|
|
213
|
+
# the customer method is invoked and time spent in DI code
|
|
214
|
+
# after the customer method finishes.
|
|
215
|
+
di_start_time = Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
|
|
216
|
+
|
|
199
217
|
# The method itself is not part of the stack trace because
|
|
200
218
|
# we are getting the stack trace from outside of the method.
|
|
201
219
|
# Add the method in manually as the top frame.
|
|
@@ -222,6 +240,9 @@ module Datadog
|
|
|
222
240
|
return_value: rv, duration: duration, exception: exc,)
|
|
223
241
|
|
|
224
242
|
responder.probe_executed_callback(context)
|
|
243
|
+
|
|
244
|
+
instrumenter.send(:check_and_disable_if_exceeded, probe, responder, di_start_time, di_duration)
|
|
245
|
+
|
|
225
246
|
if exc
|
|
226
247
|
raise exc
|
|
227
248
|
else
|
|
@@ -296,7 +317,6 @@ module Datadog
|
|
|
296
317
|
end
|
|
297
318
|
|
|
298
319
|
line_no = probe.line_no!
|
|
299
|
-
rate_limiter = probe.rate_limiter
|
|
300
320
|
|
|
301
321
|
# Memoize the value to ensure this method always uses the same
|
|
302
322
|
# value for the setting.
|
|
@@ -367,103 +387,7 @@ module Datadog
|
|
|
367
387
|
[:line]
|
|
368
388
|
end
|
|
369
389
|
tp = TracePoint.new(*types) do |tp|
|
|
370
|
-
|
|
371
|
-
# If trace point is not targeted, we must verify that the invocation
|
|
372
|
-
# is the file & line that we want, because untargeted trace points
|
|
373
|
-
# are invoked for *each* line of Ruby executed.
|
|
374
|
-
# TODO find out exactly when the path in trace point is relative.
|
|
375
|
-
# Looks like this is the case when line trace point is not targeted?
|
|
376
|
-
continue = iseq || tp.lineno == probe.line_no && (
|
|
377
|
-
probe.file == tp.path || probe.file_matches?(tp.path)
|
|
378
|
-
)
|
|
379
|
-
|
|
380
|
-
# We set the trace point on :return to be able to instrument
|
|
381
|
-
# 'end' lines. This also causes the trace point to be invoked on
|
|
382
|
-
# non-'end' lines when a line raises an exception, since the
|
|
383
|
-
# exception causes the method to stop executing and stack unwends.
|
|
384
|
-
# We do not want two invocations of the trace point.
|
|
385
|
-
# Therefore, if a trace point is invoked with a :line event,
|
|
386
|
-
# mark it as such and ignore subsequent :return events.
|
|
387
|
-
continue &&= if probe.executed_on_line?
|
|
388
|
-
tp.event == :line
|
|
389
|
-
else
|
|
390
|
-
if tp.event == :line
|
|
391
|
-
probe.executed_on_line!
|
|
392
|
-
end
|
|
393
|
-
true
|
|
394
|
-
end
|
|
395
|
-
|
|
396
|
-
if continue
|
|
397
|
-
if condition = probe.condition
|
|
398
|
-
begin
|
|
399
|
-
context = Context.new(
|
|
400
|
-
locals: Instrumenter.get_local_variables(tp),
|
|
401
|
-
target_self: tp.self,
|
|
402
|
-
probe: probe, settings: settings, serializer: serializer,
|
|
403
|
-
path: tp.path,
|
|
404
|
-
caller_locations: caller_locations,
|
|
405
|
-
)
|
|
406
|
-
continue = condition.satisfied?(context)
|
|
407
|
-
rescue => exc
|
|
408
|
-
# Evaluation error exception can be raised for "expected"
|
|
409
|
-
# errors, we probably need another setting to control whether
|
|
410
|
-
# these exceptions are propagated.
|
|
411
|
-
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions &&
|
|
412
|
-
!exc.is_a?(DI::Error::ExpressionEvaluationError)
|
|
413
|
-
|
|
414
|
-
continue = false
|
|
415
|
-
if context
|
|
416
|
-
# We want to report evaluation errors for conditions
|
|
417
|
-
# as probe snapshots. However, if we failed to create
|
|
418
|
-
# the context, we won't be able to report anything as
|
|
419
|
-
# the probe notifier builder requires a context.
|
|
420
|
-
begin
|
|
421
|
-
responder.probe_condition_evaluation_failed_callback(context, condition, exc)
|
|
422
|
-
rescue
|
|
423
|
-
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
424
|
-
|
|
425
|
-
# TODO log / report via telemetry?
|
|
426
|
-
end
|
|
427
|
-
else
|
|
428
|
-
_ = 42 # stop standard from wrecking this code
|
|
429
|
-
|
|
430
|
-
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
431
|
-
|
|
432
|
-
# TODO log / report via telemetry?
|
|
433
|
-
# If execution gets here, there is probably a bug in the tracer.
|
|
434
|
-
end
|
|
435
|
-
end
|
|
436
|
-
end
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
continue &&= rate_limiter.nil? || rate_limiter.allow? # standard:disable Style/AndOr
|
|
440
|
-
|
|
441
|
-
if continue
|
|
442
|
-
# The context creation is relatively expensive and we don't
|
|
443
|
-
# want to run it if the callback won't be executed due to the
|
|
444
|
-
# rate limit.
|
|
445
|
-
# Thus the copy-paste of the creation call here.
|
|
446
|
-
context ||= Context.new(
|
|
447
|
-
locals: Instrumenter.get_local_variables(tp),
|
|
448
|
-
target_self: tp.self,
|
|
449
|
-
probe: probe, settings: settings, serializer: serializer,
|
|
450
|
-
path: tp.path,
|
|
451
|
-
caller_locations: caller_locations,
|
|
452
|
-
)
|
|
453
|
-
|
|
454
|
-
responder.probe_executed_callback(context)
|
|
455
|
-
end
|
|
456
|
-
rescue => exc
|
|
457
|
-
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
458
|
-
logger.debug { "di: unhandled exception in line trace point: #{exc.class}: #{exc}" }
|
|
459
|
-
telemetry&.report(exc, description: "Unhandled exception in line trace point")
|
|
460
|
-
# TODO test this path
|
|
461
|
-
end
|
|
462
|
-
rescue => exc
|
|
463
|
-
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
464
|
-
logger.debug { "di: unhandled exception in line trace point: #{exc.class}: #{exc}" }
|
|
465
|
-
telemetry&.report(exc, description: "Unhandled exception in line trace point")
|
|
466
|
-
# TODO test this path
|
|
390
|
+
line_trace_point_callback(probe, iseq, responder, tp)
|
|
467
391
|
end
|
|
468
392
|
|
|
469
393
|
# Internal sanity check - untargeted trace points create a huge
|
|
@@ -551,6 +475,131 @@ module Datadog
|
|
|
551
475
|
|
|
552
476
|
attr_reader :lock
|
|
553
477
|
|
|
478
|
+
def line_trace_point_callback(probe, iseq, responder, tp)
|
|
479
|
+
di_start_time = Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
|
|
480
|
+
|
|
481
|
+
# Check if probe is enabled before doing any processing
|
|
482
|
+
return unless probe.enabled?
|
|
483
|
+
|
|
484
|
+
# If trace point is not targeted, we must verify that the invocation
|
|
485
|
+
# is the file & line that we want, because untargeted trace points
|
|
486
|
+
# are invoked for *each* line of Ruby executed.
|
|
487
|
+
# TODO find out exactly when the path in trace point is relative.
|
|
488
|
+
# Looks like this is the case when line trace point is not targeted?
|
|
489
|
+
unless iseq
|
|
490
|
+
return unless tp.lineno == probe.line_no && ( # standard:disable Style/UnlessLogicalOperators
|
|
491
|
+
probe.file == tp.path || probe.file_matches?(tp.path)
|
|
492
|
+
)
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
# We set the trace point on :return to be able to instrument
|
|
496
|
+
# 'end' lines. This also causes the trace point to be invoked on
|
|
497
|
+
# non-'end' lines when a line raises an exception, since the
|
|
498
|
+
# exception causes the method to stop executing and stack unwends.
|
|
499
|
+
# We do not want two invocations of the trace point.
|
|
500
|
+
# Therefore, if a trace point is invoked with a :line event,
|
|
501
|
+
# mark it as such and ignore subsequent :return events.
|
|
502
|
+
if probe.executed_on_line?
|
|
503
|
+
return unless tp.event == :line
|
|
504
|
+
else
|
|
505
|
+
_ = 42 # stop standard from changing this code
|
|
506
|
+
|
|
507
|
+
if tp.event == :line
|
|
508
|
+
probe.executed_on_line!
|
|
509
|
+
end
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
if condition = probe.condition
|
|
513
|
+
begin
|
|
514
|
+
context = build_trace_point_context(probe, tp)
|
|
515
|
+
return unless condition.satisfied?(context)
|
|
516
|
+
rescue => exc
|
|
517
|
+
# Evaluation error exception can be raised for "expected"
|
|
518
|
+
# errors, we probably need another setting to control whether
|
|
519
|
+
# these exceptions are propagated.
|
|
520
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions &&
|
|
521
|
+
!exc.is_a?(DI::Error::ExpressionEvaluationError)
|
|
522
|
+
|
|
523
|
+
if context
|
|
524
|
+
# We want to report evaluation errors for conditions
|
|
525
|
+
# as probe snapshots. However, if we failed to create
|
|
526
|
+
# the context, we won't be able to report anything as
|
|
527
|
+
# the probe notifier builder requires a context.
|
|
528
|
+
begin
|
|
529
|
+
responder.probe_condition_evaluation_failed_callback(context, condition, exc)
|
|
530
|
+
rescue => nested_exc
|
|
531
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
532
|
+
|
|
533
|
+
logger.debug { "di: error in probe condition evaluation failed callback: #{nested_exc.class}: #{nested_exc}" }
|
|
534
|
+
telemetry&.report(nested_exc, description: "Error in probe condition evaluation failed callback")
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
return
|
|
538
|
+
else
|
|
539
|
+
_ = 42 # stop standard from wrecking this code
|
|
540
|
+
|
|
541
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
542
|
+
|
|
543
|
+
logger.debug { "di: error evaluating condition without context (tracer bug?): #{exc.class}: #{exc}" }
|
|
544
|
+
telemetry&.report(exc, description: "Error evaluating condition without context")
|
|
545
|
+
# If execution gets here, there is probably a bug in the tracer.
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
# In practice we should always have a rate limiter, but be safe
|
|
551
|
+
# and check that it is in fact set.
|
|
552
|
+
return if probe.rate_limiter && !probe.rate_limiter.allow?
|
|
553
|
+
|
|
554
|
+
# The context creation is relatively expensive and we don't
|
|
555
|
+
# want to run it if the callback won't be executed due to the
|
|
556
|
+
# rate limit.
|
|
557
|
+
# Thus the copy-paste of the creation call here.
|
|
558
|
+
context ||= build_trace_point_context(probe, tp)
|
|
559
|
+
|
|
560
|
+
responder.probe_executed_callback(context)
|
|
561
|
+
|
|
562
|
+
check_and_disable_if_exceeded(probe, responder, di_start_time)
|
|
563
|
+
rescue => exc
|
|
564
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
565
|
+
logger.debug { "di: unhandled exception in line trace point: #{exc.class}: #{exc}" }
|
|
566
|
+
telemetry&.report(exc, description: "Unhandled exception in line trace point")
|
|
567
|
+
# TODO test this path
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
def build_trace_point_context(probe, tp)
|
|
571
|
+
stack = caller_locations
|
|
572
|
+
# We have two helper methods being invoked from the trace point
|
|
573
|
+
# handler block, remove them from the stack.
|
|
574
|
+
#
|
|
575
|
+
# According to steep stack may be nil.
|
|
576
|
+
stack&.shift(2)
|
|
577
|
+
Context.new(
|
|
578
|
+
locals: Instrumenter.get_local_variables(tp),
|
|
579
|
+
target_self: tp.self,
|
|
580
|
+
probe: probe,
|
|
581
|
+
settings: settings,
|
|
582
|
+
serializer: serializer,
|
|
583
|
+
path: tp.path,
|
|
584
|
+
caller_locations: stack,
|
|
585
|
+
)
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
# Circuit breaker: disables the probe if total CPU time consumed by
|
|
589
|
+
# DI processing exceeds the configured threshold.
|
|
590
|
+
def check_and_disable_if_exceeded(probe, responder, di_start_time, accumulated_duration = 0.0)
|
|
591
|
+
return unless max_processing_time = settings.dynamic_instrumentation.internal.max_processing_time
|
|
592
|
+
|
|
593
|
+
di_duration = accumulated_duration + Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID) - di_start_time
|
|
594
|
+
if di_duration > max_processing_time
|
|
595
|
+
logger.debug { "di: disabling probe: consumed #{di_duration}: #{probe}" }
|
|
596
|
+
# We disable the probe here rather than remove it to
|
|
597
|
+
# avoid a dependency on ProbeManager from Instrumenter.
|
|
598
|
+
probe.disable!
|
|
599
|
+
responder.probe_disabled_callback(probe, di_duration)
|
|
600
|
+
end
|
|
601
|
+
end
|
|
602
|
+
|
|
554
603
|
def raise_if_probe_in_loaded_features(probe)
|
|
555
604
|
return unless probe.file
|
|
556
605
|
|
data/lib/datadog/di/probe.rb
CHANGED
|
@@ -97,6 +97,7 @@ module Datadog
|
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
@emitting_notified = false
|
|
100
|
+
@enabled = true
|
|
100
101
|
end
|
|
101
102
|
|
|
102
103
|
attr_reader :id
|
|
@@ -219,13 +220,21 @@ module Datadog
|
|
|
219
220
|
end
|
|
220
221
|
|
|
221
222
|
def executed_on_line?
|
|
222
|
-
|
|
223
|
+
!!(defined?(@executed_on_line) && @executed_on_line)
|
|
223
224
|
end
|
|
224
225
|
|
|
225
226
|
def executed_on_line!
|
|
226
227
|
# TODO lock?
|
|
227
228
|
@executed_on_line = true
|
|
228
229
|
end
|
|
230
|
+
|
|
231
|
+
def enabled?
|
|
232
|
+
@enabled
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def disable!
|
|
236
|
+
@enabled = false
|
|
237
|
+
end
|
|
229
238
|
end
|
|
230
239
|
end
|
|
231
240
|
end
|
|
@@ -46,7 +46,7 @@ module Datadog
|
|
|
46
46
|
component.telemetry&.report(exc, description: "Line probe is targeting a loaded file that is not in code tracker")
|
|
47
47
|
|
|
48
48
|
payload = component.probe_notification_builder.build_errored(probe, exc)
|
|
49
|
-
component.probe_notifier_worker.add_status(payload)
|
|
49
|
+
component.probe_notifier_worker.add_status(payload, probe: probe)
|
|
50
50
|
rescue => exc
|
|
51
51
|
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
52
52
|
|
|
@@ -55,7 +55,7 @@ module Datadog
|
|
|
55
55
|
|
|
56
56
|
# TODO test this path
|
|
57
57
|
payload = component.probe_notification_builder.build_errored(probe, exc)
|
|
58
|
-
component.probe_notifier_worker.add_status(payload)
|
|
58
|
+
component.probe_notifier_worker.add_status(payload, probe: probe)
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
rescue => exc
|