datadog 2.20.0 → 2.26.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 +212 -1
- data/README.md +0 -1
- data/ext/LIBDATADOG_DEVELOPMENT.md +3 -0
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +93 -23
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +21 -5
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +1 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +9 -4
- data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
- data/ext/datadog_profiling_native_extension/http_transport.c +1 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +12 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +4 -0
- data/ext/datadog_profiling_native_extension/profiling.c +2 -0
- data/ext/libdatadog_api/datadog_ruby_common.h +1 -1
- data/ext/libdatadog_api/ddsketch.c +106 -0
- data/ext/libdatadog_api/feature_flags.c +554 -0
- data/ext/libdatadog_api/feature_flags.h +5 -0
- data/ext/libdatadog_api/init.c +5 -0
- data/ext/libdatadog_api/library_config.c +34 -25
- data/ext/libdatadog_api/process_discovery.c +24 -18
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/ai_guard/api_client.rb +82 -0
- data/lib/datadog/ai_guard/component.rb +42 -0
- data/lib/datadog/ai_guard/configuration/ext.rb +17 -0
- data/lib/datadog/ai_guard/configuration/settings.rb +98 -0
- data/lib/datadog/ai_guard/configuration.rb +11 -0
- data/lib/datadog/ai_guard/evaluation/message.rb +25 -0
- data/lib/datadog/ai_guard/evaluation/no_op_result.rb +34 -0
- data/lib/datadog/ai_guard/evaluation/request.rb +81 -0
- data/lib/datadog/ai_guard/evaluation/result.rb +43 -0
- data/lib/datadog/ai_guard/evaluation/tool_call.rb +18 -0
- data/lib/datadog/ai_guard/evaluation.rb +72 -0
- data/lib/datadog/ai_guard/ext.rb +16 -0
- data/lib/datadog/ai_guard.rb +153 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +59 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +29 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
- data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
- data/lib/datadog/appsec/api_security/route_extractor.rb +26 -5
- data/lib/datadog/appsec/api_security/sampler.rb +7 -4
- data/lib/datadog/appsec/assets/blocked.html +8 -0
- data/lib/datadog/appsec/assets/blocked.json +1 -1
- data/lib/datadog/appsec/assets/blocked.text +3 -1
- data/lib/datadog/appsec/assets/waf_rules/README.md +30 -36
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +359 -4
- data/lib/datadog/appsec/assets/waf_rules/strict.json +43 -2
- data/lib/datadog/appsec/assets.rb +1 -1
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/compressed_json.rb +1 -1
- data/lib/datadog/appsec/configuration/settings.rb +9 -0
- data/lib/datadog/appsec/context.rb +2 -1
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +3 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +3 -2
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +3 -1
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +3 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -4
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +5 -1
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +7 -2
- data/lib/datadog/appsec/contrib/rails/patcher.rb +30 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +3 -1
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +10 -4
- data/lib/datadog/appsec/event.rb +12 -14
- data/lib/datadog/appsec/metrics/collector.rb +19 -3
- data/lib/datadog/appsec/metrics/telemetry_exporter.rb +2 -1
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +4 -4
- data/lib/datadog/appsec/remote.rb +34 -25
- data/lib/datadog/appsec/response.rb +18 -4
- data/lib/datadog/appsec/security_engine/engine.rb +3 -3
- data/lib/datadog/appsec/security_engine/result.rb +29 -9
- data/lib/datadog/appsec/security_engine/runner.rb +19 -9
- data/lib/datadog/appsec/security_event.rb +5 -7
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +4 -4
- data/lib/datadog/core/configuration/components.rb +59 -11
- data/lib/datadog/core/configuration/config_helper.rb +100 -0
- data/lib/datadog/core/configuration/deprecations.rb +36 -0
- data/lib/datadog/core/configuration/ext.rb +0 -1
- data/lib/datadog/core/configuration/option.rb +38 -43
- data/lib/datadog/core/configuration/option_definition.rb +4 -11
- data/lib/datadog/core/configuration/options.rb +9 -10
- data/lib/datadog/core/configuration/settings.rb +38 -9
- data/lib/datadog/core/configuration/stable_config.rb +10 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +373 -0
- data/lib/datadog/core/configuration.rb +2 -2
- data/lib/datadog/core/ddsketch.rb +19 -0
- data/lib/datadog/core/deprecations.rb +2 -2
- data/lib/datadog/core/environment/cgroup.rb +52 -25
- data/lib/datadog/core/environment/container.rb +140 -46
- data/lib/datadog/core/environment/ext.rb +7 -2
- data/lib/datadog/core/environment/git.rb +2 -2
- data/lib/datadog/core/environment/process.rb +87 -0
- data/lib/datadog/core/environment/variable_helpers.rb +3 -3
- data/lib/datadog/core/environment/yjit.rb +2 -1
- data/lib/datadog/core/error.rb +6 -6
- data/lib/datadog/core/feature_flags.rb +61 -0
- data/lib/datadog/core/metrics/client.rb +2 -2
- data/lib/datadog/core/pin.rb +8 -8
- data/lib/datadog/core/process_discovery/tracer_memfd.rb +2 -4
- data/lib/datadog/core/process_discovery.rb +48 -23
- data/lib/datadog/core/rate_limiter.rb +9 -1
- data/lib/datadog/core/remote/client/capabilities.rb +7 -0
- data/lib/datadog/core/remote/client.rb +14 -6
- data/lib/datadog/core/remote/component.rb +10 -10
- data/lib/datadog/core/remote/configuration/content.rb +15 -2
- data/lib/datadog/core/remote/configuration/digest.rb +14 -7
- data/lib/datadog/core/remote/configuration/repository.rb +1 -1
- data/lib/datadog/core/remote/configuration/target.rb +13 -6
- data/lib/datadog/core/remote/transport/config.rb +4 -25
- data/lib/datadog/core/remote/transport/http/config.rb +10 -50
- data/lib/datadog/core/remote/transport/http/negotiation.rb +14 -44
- data/lib/datadog/core/remote/transport/http.rb +15 -24
- data/lib/datadog/core/remote/transport/negotiation.rb +8 -33
- data/lib/datadog/core/remote/worker.rb +25 -37
- data/lib/datadog/core/runtime/ext.rb +0 -1
- data/lib/datadog/core/runtime/metrics.rb +11 -1
- data/lib/datadog/core/semaphore.rb +1 -4
- data/lib/datadog/core/tag_builder.rb +0 -4
- data/lib/datadog/core/tag_normalizer.rb +84 -0
- data/lib/datadog/core/telemetry/component.rb +69 -15
- data/lib/datadog/core/telemetry/emitter.rb +6 -6
- data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +89 -51
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
- data/lib/datadog/core/telemetry/event.rb +1 -0
- data/lib/datadog/core/telemetry/logger.rb +2 -2
- data/lib/datadog/core/telemetry/logging.rb +2 -8
- data/lib/datadog/core/telemetry/metrics_manager.rb +9 -0
- data/lib/datadog/core/telemetry/request.rb +17 -3
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +3 -34
- data/lib/datadog/core/telemetry/transport/http.rb +21 -16
- data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -11
- data/lib/datadog/core/telemetry/worker.rb +88 -32
- data/lib/datadog/core/transport/ext.rb +2 -0
- data/lib/datadog/core/transport/http/api/endpoint.rb +9 -4
- data/lib/datadog/core/transport/http/api/instance.rb +4 -21
- data/lib/datadog/core/transport/http/builder.rb +9 -5
- data/lib/datadog/core/transport/http/client.rb +80 -0
- data/lib/datadog/core/transport/http.rb +22 -19
- data/lib/datadog/core/transport/response.rb +15 -1
- data/lib/datadog/core/transport/transport.rb +90 -0
- data/lib/datadog/core/utils/array.rb +29 -0
- data/lib/datadog/{appsec/api_security → core/utils}/lru_cache.rb +10 -21
- data/lib/datadog/core/utils/network.rb +22 -1
- data/lib/datadog/core/utils/only_once_successful.rb +8 -2
- data/lib/datadog/core/utils/safe_dup.rb +2 -2
- data/lib/datadog/core/utils/sequence.rb +2 -0
- data/lib/datadog/core/utils/time.rb +1 -1
- data/lib/datadog/core/utils.rb +2 -0
- data/lib/datadog/core/workers/async.rb +10 -1
- data/lib/datadog/core/workers/interval_loop.rb +44 -3
- data/lib/datadog/core/workers/polling.rb +2 -0
- data/lib/datadog/core/workers/queue.rb +100 -1
- data/lib/datadog/core.rb +2 -0
- data/lib/datadog/data_streams/configuration/settings.rb +49 -0
- data/lib/datadog/data_streams/configuration.rb +11 -0
- data/lib/datadog/data_streams/ext.rb +11 -0
- data/lib/datadog/data_streams/extensions.rb +16 -0
- data/lib/datadog/data_streams/pathway_context.rb +169 -0
- data/lib/datadog/data_streams/processor.rb +509 -0
- data/lib/datadog/data_streams/transport/http/stats.rb +52 -0
- data/lib/datadog/data_streams/transport/http.rb +40 -0
- data/lib/datadog/data_streams/transport/stats.rb +46 -0
- data/lib/datadog/data_streams.rb +100 -0
- data/lib/datadog/di/boot.rb +7 -3
- data/lib/datadog/di/component.rb +14 -16
- data/lib/datadog/di/context.rb +70 -0
- data/lib/datadog/di/contrib/active_record.rb +30 -5
- data/lib/datadog/di/el/compiler.rb +168 -0
- data/lib/datadog/di/el/evaluator.rb +159 -0
- data/lib/datadog/di/el/expression.rb +42 -0
- data/lib/datadog/di/el.rb +5 -0
- data/lib/datadog/di/error.rb +34 -0
- data/lib/datadog/di/instrumenter.rb +189 -55
- data/lib/datadog/di/logger.rb +2 -2
- data/lib/datadog/di/probe.rb +55 -15
- data/lib/datadog/di/probe_builder.rb +41 -2
- data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
- data/lib/datadog/di/probe_file_loader.rb +1 -1
- data/lib/datadog/di/probe_manager.rb +50 -35
- data/lib/datadog/di/probe_notification_builder.rb +121 -70
- data/lib/datadog/di/probe_notifier_worker.rb +5 -5
- data/lib/datadog/di/proc_responder.rb +32 -0
- data/lib/datadog/di/remote.rb +89 -84
- data/lib/datadog/di/serializer.rb +151 -7
- data/lib/datadog/di/transport/diagnostics.rb +8 -36
- data/lib/datadog/di/transport/http/diagnostics.rb +1 -33
- data/lib/datadog/di/transport/http/input.rb +1 -33
- data/lib/datadog/di/transport/http.rb +32 -17
- data/lib/datadog/di/transport/input.rb +67 -34
- data/lib/datadog/di.rb +61 -5
- data/lib/datadog/error_tracking/filters.rb +2 -2
- data/lib/datadog/kit/appsec/events/v2.rb +2 -3
- data/lib/datadog/open_feature/component.rb +60 -0
- data/lib/datadog/open_feature/configuration.rb +27 -0
- data/lib/datadog/open_feature/evaluation_engine.rb +70 -0
- data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
- data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
- data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
- data/lib/datadog/open_feature/exposures/event.rb +60 -0
- data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
- data/lib/datadog/open_feature/exposures/worker.rb +116 -0
- data/lib/datadog/open_feature/ext.rb +14 -0
- data/lib/datadog/open_feature/native_evaluator.rb +38 -0
- data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
- data/lib/datadog/open_feature/provider.rb +141 -0
- data/lib/datadog/open_feature/remote.rb +67 -0
- data/lib/datadog/open_feature/resolution_details.rb +35 -0
- data/lib/datadog/open_feature/transport.rb +70 -0
- data/lib/datadog/open_feature.rb +19 -0
- data/lib/datadog/opentelemetry/api/baggage.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
- data/lib/datadog/opentelemetry/metrics.rb +117 -0
- data/lib/datadog/opentelemetry/sdk/configurator.rb +26 -2
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +35 -0
- data/lib/datadog/opentelemetry.rb +3 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +41 -7
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +3 -2
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
- data/lib/datadog/profiling/collectors/info.rb +6 -5
- data/lib/datadog/profiling/component.rb +12 -11
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +18 -0
- data/lib/datadog/profiling/ext.rb +2 -1
- data/lib/datadog/profiling/http_transport.rb +5 -2
- data/lib/datadog/profiling/profiler.rb +4 -0
- data/lib/datadog/profiling/tag_builder.rb +36 -3
- data/lib/datadog/profiling/tasks/exec.rb +2 -2
- data/lib/datadog/profiling.rb +1 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/tracing/component.rb +6 -17
- data/lib/datadog/tracing/configuration/dynamic.rb +2 -2
- data/lib/datadog/tracing/configuration/ext.rb +9 -3
- data/lib/datadog/tracing/configuration/settings.rb +89 -10
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -2
- data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
- data/lib/datadog/tracing/contrib/active_job/patcher.rb +5 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +4 -2
- data/lib/datadog/tracing/contrib/component.rb +2 -2
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/extensions.rb +10 -2
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +11 -7
- data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +7 -3
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +7 -0
- data/lib/datadog/tracing/contrib/graphql/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +84 -43
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/patcher.rb +14 -0
- data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +11 -0
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +35 -4
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +59 -27
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -0
- data/lib/datadog/tracing/contrib/rack/route_inference.rb +53 -0
- data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +7 -1
- data/lib/datadog/tracing/contrib/rails/ext.rb +2 -1
- data/lib/datadog/tracing/contrib/rails/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/middlewares.rb +2 -2
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/roda/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +3 -1
- data/lib/datadog/tracing/contrib/span_attribute_schema.rb +1 -1
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +9 -1
- data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +3 -1
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +27 -0
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +48 -0
- data/lib/datadog/tracing/contrib/waterdrop/ext.rb +17 -0
- data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
- data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +49 -0
- data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
- data/lib/datadog/tracing/contrib/waterdrop.rb +41 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/tracing/distributed/baggage.rb +3 -2
- data/lib/datadog/tracing/metadata/ext.rb +9 -1
- data/lib/datadog/tracing/remote.rb +1 -9
- data/lib/datadog/tracing/sampling/priority_sampler.rb +3 -1
- data/lib/datadog/tracing/span.rb +1 -1
- data/lib/datadog/tracing/span_event.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +20 -9
- data/lib/datadog/tracing/trace_operation.rb +44 -6
- data/lib/datadog/tracing/tracer.rb +42 -16
- data/lib/datadog/tracing/transport/http/client.rb +12 -26
- data/lib/datadog/tracing/transport/http/traces.rb +2 -50
- data/lib/datadog/tracing/transport/http.rb +15 -9
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/transport/traces.rb +9 -71
- data/lib/datadog/tracing/workers/trace_writer.rb +5 -0
- data/lib/datadog/tracing/writer.rb +1 -0
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +3 -0
- metadata +110 -24
- data/ext/libdatadog_api/macos_development.md +0 -26
- data/lib/datadog/core/remote/transport/http/api.rb +0 -53
- data/lib/datadog/core/remote/transport/http/client.rb +0 -49
- data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
- data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
- data/lib/datadog/core/transport/http/api/spec.rb +0 -36
- data/lib/datadog/di/transport/http/api.rb +0 -42
- data/lib/datadog/di/transport/http/client.rb +0 -47
- data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
- data/lib/datadog/tracing/transport/http/api.rb +0 -44
|
@@ -94,6 +94,19 @@ module Datadog
|
|
|
94
94
|
# matches.
|
|
95
95
|
def add_probe(probe)
|
|
96
96
|
@lock.synchronize do
|
|
97
|
+
if @installed_probes[probe.id]
|
|
98
|
+
# Either this probe was already installed, or another probe was
|
|
99
|
+
# installed with the same id (previous version perhaps?).
|
|
100
|
+
# Since our state tracking is keyed by probe id, we cannot
|
|
101
|
+
# install this probe since we won't have a way of removing the
|
|
102
|
+
# instrumentation for the probe with the same id which is already
|
|
103
|
+
# installed.
|
|
104
|
+
#
|
|
105
|
+
# The exception raised here will be caught below and logged and
|
|
106
|
+
# reported to telemetry.
|
|
107
|
+
raise Error::AlreadyInstrumented, "Probe with id #{probe.id} is already in installed probes"
|
|
108
|
+
end
|
|
109
|
+
|
|
97
110
|
# Probe failed to install previously, do not try to install it again.
|
|
98
111
|
if msg = @failed_probes[probe.id]
|
|
99
112
|
# TODO test this path
|
|
@@ -101,7 +114,7 @@ module Datadog
|
|
|
101
114
|
end
|
|
102
115
|
|
|
103
116
|
begin
|
|
104
|
-
instrumenter.hook(probe,
|
|
117
|
+
instrumenter.hook(probe, self)
|
|
105
118
|
|
|
106
119
|
@installed_probes[probe.id] = probe
|
|
107
120
|
payload = probe_notification_builder.build_installed(probe)
|
|
@@ -134,38 +147,30 @@ module Datadog
|
|
|
134
147
|
end
|
|
135
148
|
end
|
|
136
149
|
|
|
137
|
-
# Removes
|
|
138
|
-
#
|
|
139
|
-
|
|
140
|
-
# Remote config contains the list of currently defined probes; any
|
|
141
|
-
# probes not in that list have been removed by user and should be
|
|
142
|
-
# de-instrumented from the application.
|
|
143
|
-
def remove_other_probes(probe_ids)
|
|
150
|
+
# Removes probe with specified id. The probe could be pending or
|
|
151
|
+
# installed. Does nothing if there is no probe with the specified id.
|
|
152
|
+
def remove_probe(probe_id)
|
|
144
153
|
@lock.synchronize do
|
|
145
|
-
@pending_probes.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
logger.debug { "di: error removing #{probe.type} probe at #{probe.location} (#{probe.id}): #{exc.class}: #{exc}" }
|
|
166
|
-
telemetry&.report(exc, description: "Error removing probe")
|
|
167
|
-
end
|
|
168
|
-
end
|
|
154
|
+
@pending_probes.delete(probe_id)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Do not delete the probe from the registry here in case
|
|
158
|
+
# deinstrumentation fails - though I don't know why deinstrumentation
|
|
159
|
+
# would fail and how we could recover if it does.
|
|
160
|
+
# I plan on tracking the number of outstanding (instrumented) probes
|
|
161
|
+
# in the future, and if deinstrumentation fails I would want to
|
|
162
|
+
# keep that probe as "installed" for the count, so that we can
|
|
163
|
+
# investigate the situation.
|
|
164
|
+
if probe = @installed_probes[probe_id]
|
|
165
|
+
begin
|
|
166
|
+
instrumenter.unhook(probe)
|
|
167
|
+
@installed_probes.delete(probe_id)
|
|
168
|
+
rescue => exc
|
|
169
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
170
|
+
# Silence all exceptions?
|
|
171
|
+
# TODO should we propagate here and rescue upstream?
|
|
172
|
+
logger.debug { "di: error removing #{probe.type} probe at #{probe.location} (#{probe.id}): #{exc.class}: #{exc}" }
|
|
173
|
+
telemetry&.report(exc, description: "Error removing probe")
|
|
169
174
|
end
|
|
170
175
|
end
|
|
171
176
|
end
|
|
@@ -184,7 +189,8 @@ module Datadog
|
|
|
184
189
|
begin
|
|
185
190
|
# TODO is it OK to hook from trace point handler?
|
|
186
191
|
# TODO the class is now defined, but can hooking still fail?
|
|
187
|
-
instrumenter.hook(probe,
|
|
192
|
+
instrumenter.hook(probe, self)
|
|
193
|
+
@installed_probes[probe.id] = probe
|
|
188
194
|
@pending_probes.delete(probe.id)
|
|
189
195
|
break
|
|
190
196
|
rescue Error::DITargetNotDefined
|
|
@@ -229,7 +235,8 @@ module Datadog
|
|
|
229
235
|
# This method is responsible for queueing probe status to be sent to the
|
|
230
236
|
# backend (once per the probe's lifetime) and a snapshot corresponding
|
|
231
237
|
# to the current invocation.
|
|
232
|
-
def probe_executed_callback(
|
|
238
|
+
def probe_executed_callback(context)
|
|
239
|
+
probe = context.probe
|
|
233
240
|
logger.trace { "di: executed #{probe.type} probe at #{probe.location} (#{probe.id})" }
|
|
234
241
|
unless probe.emitting_notified?
|
|
235
242
|
payload = probe_notification_builder.build_emitting(probe)
|
|
@@ -237,10 +244,18 @@ module Datadog
|
|
|
237
244
|
probe.emitting_notified = true
|
|
238
245
|
end
|
|
239
246
|
|
|
240
|
-
payload = probe_notification_builder.build_executed(
|
|
247
|
+
payload = probe_notification_builder.build_executed(context)
|
|
241
248
|
probe_notifier_worker.add_snapshot(payload)
|
|
242
249
|
end
|
|
243
250
|
|
|
251
|
+
def probe_condition_evaluation_failed_callback(context, expr, exc)
|
|
252
|
+
probe = context.probe
|
|
253
|
+
if probe.condition_evaluation_failed_rate_limiter&.allow?
|
|
254
|
+
payload = probe_notification_builder.build_condition_evaluation_failed(context, expr, exc)
|
|
255
|
+
probe_notifier_worker.add_snapshot(payload)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
244
259
|
# Class/module definition trace point (:end type).
|
|
245
260
|
# Used to install hooks when the target classes/modules aren't yet
|
|
246
261
|
# defined when the hook request is received.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# rubocop:disable Lint/AssignmentInCondition
|
|
4
|
+
|
|
3
5
|
module Datadog
|
|
4
6
|
module DI
|
|
5
7
|
# Builds probe status notification and snapshot payloads.
|
|
@@ -40,32 +42,17 @@ module Datadog
|
|
|
40
42
|
|
|
41
43
|
# Duration is in seconds.
|
|
42
44
|
# path is the actual path of the instrumented file.
|
|
43
|
-
def build_executed(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
caller_locations: caller_locations,
|
|
55
|
-
args: args, kwargs: kwargs,
|
|
56
|
-
target_self: target_self,
|
|
57
|
-
serialized_entry_args: serialized_entry_args)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def build_snapshot(probe, rv: nil, serialized_locals: nil, path: nil,
|
|
61
|
-
# In Ruby everything is a method, therefore we should always have
|
|
62
|
-
# a target self. However, if we are not capturing a snapshot,
|
|
63
|
-
# there is no need to pass in the target self.
|
|
64
|
-
target_self: nil,
|
|
65
|
-
duration: nil, caller_locations: nil,
|
|
66
|
-
args: nil, kwargs: nil,
|
|
67
|
-
serialized_entry_args: nil)
|
|
68
|
-
if probe.capture_snapshot? && !target_self
|
|
45
|
+
def build_executed(context)
|
|
46
|
+
build_snapshot(context)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
NANOSECONDS = 1_000_000_000
|
|
50
|
+
MILLISECONDS = 1000
|
|
51
|
+
|
|
52
|
+
def build_snapshot(context)
|
|
53
|
+
probe = context.probe
|
|
54
|
+
|
|
55
|
+
if probe.capture_snapshot? && !context.target_self
|
|
69
56
|
raise ArgumentError, "Asked to build snapshot with snapshot capture but target_self is nil"
|
|
70
57
|
end
|
|
71
58
|
|
|
@@ -74,22 +61,14 @@ module Datadog
|
|
|
74
61
|
captures = if probe.capture_snapshot?
|
|
75
62
|
if probe.method?
|
|
76
63
|
return_arguments = {
|
|
77
|
-
"@return": serializer.serialize_value(
|
|
64
|
+
"@return": serializer.serialize_value(context.return_value,
|
|
78
65
|
depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
|
|
79
66
|
attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count),
|
|
80
|
-
self: serializer.serialize_value(target_self),
|
|
67
|
+
self: serializer.serialize_value(context.target_self),
|
|
81
68
|
}
|
|
82
69
|
{
|
|
83
70
|
entry: {
|
|
84
|
-
|
|
85
|
-
arguments: if serialized_entry_args
|
|
86
|
-
serialized_entry_args
|
|
87
|
-
else
|
|
88
|
-
(args || kwargs) && serializer.serialize_args(args, kwargs, target_self,
|
|
89
|
-
depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
|
|
90
|
-
attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count)
|
|
91
|
-
end,
|
|
92
|
-
# standard:enable all
|
|
71
|
+
arguments: context.serialized_entry_args,
|
|
93
72
|
},
|
|
94
73
|
return: {
|
|
95
74
|
arguments: return_arguments,
|
|
@@ -98,20 +77,51 @@ module Datadog
|
|
|
98
77
|
}
|
|
99
78
|
elsif probe.line?
|
|
100
79
|
{
|
|
101
|
-
lines: serialized_locals && {
|
|
80
|
+
lines: (locals = context.serialized_locals) && {
|
|
102
81
|
probe.line_no => {
|
|
103
|
-
locals:
|
|
104
|
-
arguments: {self: serializer.serialize_value(target_self)},
|
|
82
|
+
locals: locals,
|
|
83
|
+
arguments: {self: serializer.serialize_value(context.target_self)},
|
|
105
84
|
},
|
|
106
85
|
},
|
|
107
86
|
}
|
|
108
87
|
end
|
|
109
88
|
end
|
|
110
89
|
|
|
90
|
+
message = nil
|
|
91
|
+
evaluation_errors = []
|
|
92
|
+
if segments = probe.template_segments
|
|
93
|
+
message, evaluation_errors = evaluate_template(segments, context)
|
|
94
|
+
end
|
|
95
|
+
build_snapshot_base(context,
|
|
96
|
+
evaluation_errors: evaluation_errors, message: message,
|
|
97
|
+
captures: captures)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def build_condition_evaluation_failed(context, expression, exception)
|
|
101
|
+
error = {
|
|
102
|
+
message: "#{exception.class}: #{exception}",
|
|
103
|
+
expr: expression.dsl_expr,
|
|
104
|
+
}
|
|
105
|
+
build_snapshot_base(context, evaluation_errors: [error])
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def build_snapshot_base(context, evaluation_errors: [], captures: nil, message: nil)
|
|
111
|
+
probe = context.probe
|
|
112
|
+
|
|
113
|
+
timestamp = timestamp_now
|
|
114
|
+
duration = context.duration
|
|
115
|
+
|
|
111
116
|
location = if probe.line?
|
|
112
117
|
{
|
|
113
|
-
file: path,
|
|
114
|
-
|
|
118
|
+
file: context.path,
|
|
119
|
+
# Line numbers are required to be strings by the
|
|
120
|
+
# system tests schema.
|
|
121
|
+
# Backend I think accepts them also as integers, but some
|
|
122
|
+
# other languages send strings and we decided to require
|
|
123
|
+
# strings for everyone.
|
|
124
|
+
lines: [probe.line_no.to_s],
|
|
115
125
|
}
|
|
116
126
|
elsif probe.method?
|
|
117
127
|
{
|
|
@@ -120,34 +130,50 @@ module Datadog
|
|
|
120
130
|
}
|
|
121
131
|
end
|
|
122
132
|
|
|
123
|
-
stack = if caller_locations
|
|
133
|
+
stack = if caller_locations = context.caller_locations
|
|
124
134
|
format_caller_locations(caller_locations)
|
|
125
135
|
end
|
|
126
136
|
|
|
127
|
-
|
|
128
|
-
{
|
|
137
|
+
payload = {
|
|
129
138
|
service: settings.service,
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
139
|
+
debugger: {
|
|
140
|
+
type: 'snapshot',
|
|
141
|
+
# Product can have three values: di, ld, er.
|
|
142
|
+
# We do not currently implement exception replay.
|
|
143
|
+
# There is currently no specification, and no consensus, for
|
|
144
|
+
# when product should be di (dynamic instrumentation) and when
|
|
145
|
+
# it should be ld (live debugger). I thought the backend was
|
|
146
|
+
# supposed to provide this in probe specification via remote
|
|
147
|
+
# config, but apparently this is not the case and the expectation
|
|
148
|
+
# is that the library figures out the product via heuristics,
|
|
149
|
+
# except there is currently no consensus on said heuristics.
|
|
150
|
+
# .NET always sends ld, other languages send nothing at the moment.
|
|
151
|
+
# Don't send anything for the time being.
|
|
152
|
+
#product: 'di/ld',
|
|
153
|
+
snapshot: {
|
|
154
|
+
id: SecureRandom.uuid,
|
|
155
|
+
timestamp: timestamp,
|
|
156
|
+
evaluationErrors: evaluation_errors,
|
|
157
|
+
probe: {
|
|
158
|
+
id: probe.id,
|
|
159
|
+
version: 0,
|
|
160
|
+
location: location,
|
|
161
|
+
},
|
|
162
|
+
language: 'ruby',
|
|
163
|
+
# TODO add test coverage for callers being nil
|
|
164
|
+
stack: stack,
|
|
165
|
+
# System tests schema validation requires captures to
|
|
166
|
+
# always be present
|
|
167
|
+
captures: captures || {},
|
|
138
168
|
},
|
|
139
|
-
language: 'ruby',
|
|
140
|
-
# TODO add test coverage for callers being nil
|
|
141
|
-
stack: stack,
|
|
142
|
-
captures: captures,
|
|
143
169
|
},
|
|
144
170
|
# In python tracer duration is under debugger.snapshot,
|
|
145
171
|
# but UI appears to expect it here at top level.
|
|
146
|
-
duration: duration ? (duration *
|
|
172
|
+
duration: duration ? (duration * NANOSECONDS).to_i : 0,
|
|
147
173
|
host: nil,
|
|
148
174
|
logger: {
|
|
149
175
|
name: probe.file,
|
|
150
|
-
method: probe.method_name
|
|
176
|
+
method: probe.method_name,
|
|
151
177
|
thread_name: Thread.current.name,
|
|
152
178
|
# Dynamic instrumentation currently does not need thread_id for
|
|
153
179
|
# anything. It can be sent if a customer requests it at which point
|
|
@@ -160,13 +186,14 @@ module Datadog
|
|
|
160
186
|
"dd.trace_id": active_trace&.id&.to_s,
|
|
161
187
|
"dd.span_id": active_span&.id&.to_s,
|
|
162
188
|
ddsource: 'dd_debugger',
|
|
163
|
-
message:
|
|
164
|
-
duration: duration ? duration * 1000 : 0),
|
|
189
|
+
message: message,
|
|
165
190
|
timestamp: timestamp,
|
|
166
191
|
}
|
|
167
|
-
end
|
|
168
192
|
|
|
169
|
-
|
|
193
|
+
tag_process_tags!(payload, settings)
|
|
194
|
+
|
|
195
|
+
payload
|
|
196
|
+
end
|
|
170
197
|
|
|
171
198
|
def build_status(probe, message:, status:)
|
|
172
199
|
{
|
|
@@ -192,16 +219,38 @@ module Datadog
|
|
|
192
219
|
end
|
|
193
220
|
end
|
|
194
221
|
|
|
195
|
-
def evaluate_template(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
222
|
+
def evaluate_template(template_segments, context)
|
|
223
|
+
evaluation_errors = []
|
|
224
|
+
message = template_segments.map do |segment|
|
|
225
|
+
case segment
|
|
226
|
+
when String
|
|
227
|
+
segment
|
|
228
|
+
when EL::Expression
|
|
229
|
+
serializer.serialize_value_for_message(segment.evaluate(context))
|
|
230
|
+
else
|
|
231
|
+
raise ArgumentError, "Invalid template segment type: #{segment}"
|
|
232
|
+
end
|
|
233
|
+
rescue => exc
|
|
234
|
+
evaluation_errors << {
|
|
235
|
+
message: "#{exc.class}: #{exc}",
|
|
236
|
+
expr: segment.dsl_expr,
|
|
237
|
+
}
|
|
238
|
+
'[evaluation error]'
|
|
239
|
+
end.join
|
|
240
|
+
[message, evaluation_errors]
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def tag_process_tags!(payload, settings)
|
|
244
|
+
return unless settings.experimental_propagate_process_tags_enabled
|
|
245
|
+
|
|
246
|
+
process_tags = Core::Environment::Process.serialized
|
|
247
|
+
return if process_tags.empty?
|
|
248
|
+
|
|
249
|
+
payload[:process_tags] = process_tags
|
|
201
250
|
end
|
|
202
251
|
|
|
203
252
|
def timestamp_now
|
|
204
|
-
(Core::Utils::Time.now.to_f *
|
|
253
|
+
(Core::Utils::Time.now.to_f * MILLISECONDS).to_i
|
|
205
254
|
end
|
|
206
255
|
|
|
207
256
|
def active_trace
|
|
@@ -218,3 +267,5 @@ module Datadog
|
|
|
218
267
|
end
|
|
219
268
|
end
|
|
220
269
|
end
|
|
270
|
+
|
|
271
|
+
# rubocop:enable Lint/AssignmentInCondition
|
|
@@ -249,12 +249,12 @@ module Datadog
|
|
|
249
249
|
@lock.synchronize do
|
|
250
250
|
batch = instance_variable_get("@#{event_type}_queue")
|
|
251
251
|
instance_variable_set("@#{event_type}_queue", [])
|
|
252
|
-
@io_in_progress = batch.any?
|
|
252
|
+
@io_in_progress = batch.any?
|
|
253
253
|
end
|
|
254
|
-
logger.trace { "di: #{self.class.name}: checking #{event_type} queue - #{batch.length} entries" }
|
|
255
|
-
if batch.any?
|
|
254
|
+
logger.trace { "di: #{self.class.name}: checking #{event_type} queue - #{batch.length} entries" }
|
|
255
|
+
if batch.any?
|
|
256
256
|
begin
|
|
257
|
-
logger.trace { "di: sending #{batch.length} #{event_type} event(s) to agent" }
|
|
257
|
+
logger.trace { "di: sending #{batch.length} #{event_type} event(s) to agent" }
|
|
258
258
|
send("do_send_#{event_type}", batch)
|
|
259
259
|
time = Core::Utils::Time.get_time
|
|
260
260
|
@lock.synchronize do
|
|
@@ -268,7 +268,7 @@ module Datadog
|
|
|
268
268
|
# telemetry message would also fail.
|
|
269
269
|
end
|
|
270
270
|
end
|
|
271
|
-
batch.any?
|
|
271
|
+
batch.any?
|
|
272
272
|
rescue ThreadError => exc
|
|
273
273
|
# Normally the queue should only be consumed in this method,
|
|
274
274
|
# however if anyone consumes it elsewhere we don't want to block
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module DI
|
|
5
|
+
# An adapter to convert procs to responders.
|
|
6
|
+
#
|
|
7
|
+
# Used in test suite and benchmarks.
|
|
8
|
+
#
|
|
9
|
+
# @api private
|
|
10
|
+
class ProcResponder
|
|
11
|
+
def initialize(executed_proc, failed_proc = nil)
|
|
12
|
+
@executed_proc = executed_proc
|
|
13
|
+
@failed_proc = failed_proc
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attr_reader :executed_proc
|
|
17
|
+
attr_reader :failed_proc
|
|
18
|
+
|
|
19
|
+
def probe_executed_callback(context)
|
|
20
|
+
executed_proc.call(context)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def probe_condition_evaluation_failed_callback(context, exc)
|
|
24
|
+
if failed_proc.nil?
|
|
25
|
+
raise NotImplementedError, "Failed proc not provided"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
failed_proc.call(context, exc)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/datadog/di/remote.rb
CHANGED
|
@@ -12,8 +12,6 @@ module Datadog
|
|
|
12
12
|
#
|
|
13
13
|
# @api private
|
|
14
14
|
module Remote
|
|
15
|
-
class ReadError < StandardError; end
|
|
16
|
-
|
|
17
15
|
class << self
|
|
18
16
|
PRODUCT = 'LIVE_DEBUGGING'
|
|
19
17
|
|
|
@@ -28,7 +26,7 @@ module Datadog
|
|
|
28
26
|
end
|
|
29
27
|
|
|
30
28
|
def receivers(telemetry)
|
|
31
|
-
receiver do |repository,
|
|
29
|
+
receiver do |repository, changes|
|
|
32
30
|
# DEV: Filter our by product. Given it will be very common
|
|
33
31
|
# DEV: we can filter this out before we receive the data in this method.
|
|
34
32
|
# DEV: Apply this refactor to AppSec as well if implemented.
|
|
@@ -41,84 +39,23 @@ module Datadog
|
|
|
41
39
|
# If the component is nil for some reason, we also don't have a
|
|
42
40
|
# logger instance to report the issue.
|
|
43
41
|
if component
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
# TODO test exception capture
|
|
60
|
-
probe_manager.add_probe(probe)
|
|
61
|
-
content.applied
|
|
62
|
-
rescue DI::Error::DITargetNotInRegistry => exc
|
|
63
|
-
component.telemetry&.report(exc, description: "Line probe is targeting a loaded file that is not in code tracker")
|
|
64
|
-
|
|
65
|
-
payload = probe_notification_builder.build_errored(probe, exc)
|
|
66
|
-
probe_notifier_worker.add_status(payload)
|
|
67
|
-
|
|
68
|
-
# If a probe fails to install, we will mark the content
|
|
69
|
-
# as errored. On subsequent remote configuration application
|
|
70
|
-
# attemps, probe manager will raise the "previously errored"
|
|
71
|
-
# exception and we'll rescue it here, again marking the
|
|
72
|
-
# content as errored but with a somewhat different exception
|
|
73
|
-
# message.
|
|
74
|
-
# TODO assert content state (errored for this example)
|
|
75
|
-
content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}")
|
|
76
|
-
rescue => exc
|
|
77
|
-
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
78
|
-
|
|
79
|
-
component.logger.debug { "di: unhandled exception adding #{probe.type} probe at #{probe.location} (#{probe.id}) in DI remote receiver: #{exc.class}: #{exc}" }
|
|
80
|
-
component.telemetry&.report(exc, description: "Unhandled exception adding probe in DI remote receiver")
|
|
81
|
-
|
|
82
|
-
# TODO test this path
|
|
83
|
-
payload = probe_notification_builder.build_errored(probe, exc)
|
|
84
|
-
probe_notifier_worker.add_status(payload)
|
|
85
|
-
|
|
86
|
-
# If a probe fails to install, we will mark the content
|
|
87
|
-
# as errored. On subsequent remote configuration application
|
|
88
|
-
# attemps, probe manager will raise the "previously errored"
|
|
89
|
-
# exception and we'll rescue it here, again marking the
|
|
90
|
-
# content as errored but with a somewhat different exception
|
|
91
|
-
# message.
|
|
92
|
-
# TODO assert content state (errored for this example)
|
|
93
|
-
content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}")
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# Important: even if processing fails for this probe config,
|
|
97
|
-
# we need to note it as being current so that we do not
|
|
98
|
-
# try to remove instrumentation that is still supposed to be
|
|
99
|
-
# active.
|
|
100
|
-
current_probe_ids[probe_spec.fetch('id')] = true
|
|
101
|
-
rescue => exc
|
|
102
|
-
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
103
|
-
|
|
104
|
-
component.logger.debug { "di: unhandled exception handling a probe in DI remote receiver: #{exc.class}: #{exc}" }
|
|
105
|
-
component.telemetry&.report(exc, description: "Unhandled exception handling probe in DI remote receiver")
|
|
106
|
-
|
|
107
|
-
# TODO assert content state (errored for this example)
|
|
108
|
-
content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}")
|
|
109
|
-
end
|
|
42
|
+
changes.each do |change|
|
|
43
|
+
case change.type
|
|
44
|
+
when :insert
|
|
45
|
+
add_probe(change.content, component)
|
|
46
|
+
when :update
|
|
47
|
+
# We do not implement updates at the moment, remove the
|
|
48
|
+
# probe and reinstall.
|
|
49
|
+
remove_probe(change.content, component)
|
|
50
|
+
add_probe(change.content, component)
|
|
51
|
+
when :delete
|
|
52
|
+
remove_probe(change.previous, component)
|
|
53
|
+
else
|
|
54
|
+
# This really should never happen since we generate the
|
|
55
|
+
# change types in the library.
|
|
56
|
+
component.logger.debug { "di: unrecognized change type: #{change.type}" }
|
|
110
57
|
end
|
|
111
58
|
end
|
|
112
|
-
|
|
113
|
-
begin
|
|
114
|
-
# TODO test exception capture
|
|
115
|
-
probe_manager.remove_other_probes(current_probe_ids.keys)
|
|
116
|
-
rescue => exc
|
|
117
|
-
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
118
|
-
|
|
119
|
-
component.logger.debug { "di: unhandled exception removing probes in DI remote receiver: #{exc.class}: #{exc}" }
|
|
120
|
-
component.telemetry&.report(exc, description: "Unhandled exception removing probes in DI remote receiver")
|
|
121
|
-
end
|
|
122
59
|
end
|
|
123
60
|
end
|
|
124
61
|
end
|
|
@@ -130,14 +67,82 @@ module Datadog
|
|
|
130
67
|
|
|
131
68
|
private
|
|
132
69
|
|
|
133
|
-
def
|
|
134
|
-
|
|
70
|
+
def add_probe(content, component)
|
|
71
|
+
probe_spec = parse_content(content)
|
|
72
|
+
probe = component.parse_probe_spec_and_notify(probe_spec)
|
|
73
|
+
component.logger.debug { "di: received #{probe.type} probe at #{probe.location} (#{probe.id}) via RC" }
|
|
74
|
+
|
|
75
|
+
begin
|
|
76
|
+
# TODO test exception capture
|
|
77
|
+
component.probe_manager.add_probe(probe)
|
|
78
|
+
content.applied
|
|
79
|
+
rescue DI::Error::DITargetNotInRegistry => exc
|
|
80
|
+
component.telemetry&.report(exc, description: "Line probe is targeting a loaded file that is not in code tracker")
|
|
81
|
+
|
|
82
|
+
payload = component.probe_notification_builder.build_errored(probe, exc)
|
|
83
|
+
component.probe_notifier_worker.add_status(payload)
|
|
84
|
+
|
|
85
|
+
# If a probe fails to install, we will mark the content
|
|
86
|
+
# as errored. On subsequent remote configuration application
|
|
87
|
+
# attemps, probe manager will raise the "previously errored"
|
|
88
|
+
# exception and we'll rescue it here, again marking the
|
|
89
|
+
# content as errored but with a somewhat different exception
|
|
90
|
+
# message.
|
|
91
|
+
# TODO assert content state (errored for this example)
|
|
92
|
+
content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}")
|
|
93
|
+
rescue => exc
|
|
94
|
+
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
95
|
+
|
|
96
|
+
component.logger.debug { "di: unhandled exception adding #{probe.type} probe at #{probe.location} (#{probe.id}) in DI remote receiver: #{exc.class}: #{exc}" }
|
|
97
|
+
component.telemetry&.report(exc, description: "Unhandled exception adding probe in DI remote receiver")
|
|
98
|
+
|
|
99
|
+
# TODO test this path
|
|
100
|
+
payload = component.probe_notification_builder.build_errored(probe, exc)
|
|
101
|
+
component.probe_notifier_worker.add_status(payload)
|
|
102
|
+
|
|
103
|
+
# If a probe fails to install, we will mark the content
|
|
104
|
+
# as errored. On subsequent remote configuration application
|
|
105
|
+
# attemps, probe manager will raise the "previously errored"
|
|
106
|
+
# exception and we'll rescue it here, again marking the
|
|
107
|
+
# content as errored but with a somewhat different exception
|
|
108
|
+
# message.
|
|
109
|
+
# TODO assert content state (errored for this example)
|
|
110
|
+
content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Important: even if processing fails for this probe config,
|
|
114
|
+
# we need to note it as being current so that we do not
|
|
115
|
+
# try to remove instrumentation that is still supposed to be
|
|
116
|
+
# active.
|
|
117
|
+
#current_probe_ids[probe_spec.fetch('id')] = true
|
|
118
|
+
rescue => exc
|
|
119
|
+
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
120
|
+
|
|
121
|
+
component.logger.debug { "di: unhandled exception handling a probe in DI remote receiver: #{exc.class}: #{exc}" }
|
|
122
|
+
component.telemetry&.report(exc, description: "Unhandled exception handling probe in DI remote receiver")
|
|
135
123
|
|
|
136
|
-
content
|
|
124
|
+
# TODO assert content state (errored for this example)
|
|
125
|
+
content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}")
|
|
126
|
+
end
|
|
137
127
|
|
|
138
|
-
|
|
128
|
+
# This method does not mark +previous_content+ as succeeded or errored,
|
|
129
|
+
# because that content is from a previous RC response and has already
|
|
130
|
+
# been marked. Removal of probes happens when an RC entry disappears,
|
|
131
|
+
# as such there is nothing to mark.
|
|
132
|
+
def remove_probe(previous_content, component)
|
|
133
|
+
# TODO test exception capture
|
|
134
|
+
probe_spec = parse_content(previous_content)
|
|
135
|
+
probe_id = probe_spec.fetch('id')
|
|
136
|
+
component.probe_manager.remove_probe(probe_id)
|
|
137
|
+
rescue => exc
|
|
138
|
+
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
139
|
+
|
|
140
|
+
component.logger.debug { "di: unhandled exception removing probes in DI remote receiver: #{exc.class}: #{exc}" }
|
|
141
|
+
component.telemetry&.report(exc, description: "Unhandled exception removing probes in DI remote receiver")
|
|
142
|
+
end
|
|
139
143
|
|
|
140
|
-
|
|
144
|
+
def parse_content(content)
|
|
145
|
+
JSON.parse(content.data)
|
|
141
146
|
end
|
|
142
147
|
end
|
|
143
148
|
end
|