datadog 2.22.0 → 2.24.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 +100 -1
- data/ext/LIBDATADOG_DEVELOPMENT.md +1 -58
- 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/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/feature_flags.c +554 -0
- data/ext/libdatadog_api/feature_flags.h +5 -0
- data/ext/libdatadog_api/init.c +2 -0
- data/ext/libdatadog_api/library_config.c +12 -11
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/api_security/route_extractor.rb +23 -6
- 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.rb +1 -1
- data/lib/datadog/appsec/context.rb +2 -1
- data/lib/datadog/appsec/remote.rb +5 -9
- data/lib/datadog/appsec/response.rb +18 -4
- data/lib/datadog/appsec/security_engine/result.rb +2 -1
- data/lib/datadog/core/configuration/components.rb +30 -3
- data/lib/datadog/core/configuration/config_helper.rb +2 -2
- data/lib/datadog/core/configuration/deprecations.rb +2 -2
- data/lib/datadog/core/configuration/option_definition.rb +4 -2
- data/lib/datadog/core/configuration/options.rb +8 -5
- data/lib/datadog/core/configuration/settings.rb +28 -3
- data/lib/datadog/core/configuration/supported_configurations.rb +332 -302
- data/lib/datadog/core/ddsketch.rb +0 -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 -0
- data/lib/datadog/core/environment/process.rb +87 -0
- data/lib/datadog/core/feature_flags.rb +61 -0
- 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 +6 -4
- 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/tag_builder.rb +0 -4
- data/lib/datadog/core/tag_normalizer.rb +84 -0
- data/lib/datadog/core/telemetry/component.rb +59 -16
- data/lib/datadog/core/telemetry/event/app_started.rb +86 -49
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
- 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 +9 -0
- 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 +3 -1
- data/lib/datadog/core/utils/only_once_successful.rb +8 -2
- 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/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/component.rb +0 -16
- data/lib/datadog/di/contrib/active_record.rb +31 -5
- data/lib/datadog/di/el/compiler.rb +8 -4
- data/lib/datadog/di/el/evaluator.rb +1 -1
- data/lib/datadog/di/error.rb +9 -0
- data/lib/datadog/di/instrumenter.rb +93 -34
- data/lib/datadog/di/probe.rb +20 -0
- data/lib/datadog/di/probe_builder.rb +2 -1
- data/lib/datadog/di/probe_manager.rb +47 -33
- data/lib/datadog/di/probe_notification_builder.rb +77 -25
- data/lib/datadog/di/proc_responder.rb +32 -0
- data/lib/datadog/di/remote.rb +89 -84
- 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/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 +25 -1
- 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 +1 -1
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
- data/lib/datadog/profiling/collectors/info.rb +2 -1
- data/lib/datadog/profiling/component.rb +12 -11
- data/lib/datadog/profiling/http_transport.rb +4 -1
- data/lib/datadog/profiling/profiler.rb +4 -0
- data/lib/datadog/profiling/tag_builder.rb +36 -3
- data/lib/datadog/profiling.rb +1 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/tracing/configuration/ext.rb +9 -0
- data/lib/datadog/tracing/configuration/settings.rb +74 -0
- 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/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/unified_trace.rb +22 -17
- 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/route_inference.rb +53 -0
- 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/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 +37 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/tracing/metadata/ext.rb +1 -1
- data/lib/datadog/tracing/remote.rb +1 -9
- data/lib/datadog/tracing/span_event.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +9 -4
- 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 +2 -0
- metadata +78 -21
- 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
|
|
@@ -242,6 +248,14 @@ module Datadog
|
|
|
242
248
|
probe_notifier_worker.add_snapshot(payload)
|
|
243
249
|
end
|
|
244
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
|
+
|
|
245
259
|
# Class/module definition trace point (:end type).
|
|
246
260
|
# Used to install hooks when the target classes/modules aren't yet
|
|
247
261
|
# defined when the hook request is received.
|
|
@@ -46,7 +46,7 @@ module Datadog
|
|
|
46
46
|
build_snapshot(context)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
NANOSECONDS =
|
|
49
|
+
NANOSECONDS = 1_000_000_000
|
|
50
50
|
MILLISECONDS = 1000
|
|
51
51
|
|
|
52
52
|
def build_snapshot(context)
|
|
@@ -87,10 +87,41 @@ module Datadog
|
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
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
|
+
|
|
90
116
|
location = if probe.line?
|
|
91
117
|
{
|
|
92
118
|
file: context.path,
|
|
93
|
-
|
|
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],
|
|
94
125
|
}
|
|
95
126
|
elsif probe.method?
|
|
96
127
|
{
|
|
@@ -103,28 +134,38 @@ module Datadog
|
|
|
103
134
|
format_caller_locations(caller_locations)
|
|
104
135
|
end
|
|
105
136
|
|
|
106
|
-
|
|
107
|
-
message = nil
|
|
108
|
-
evaluation_errors = []
|
|
109
|
-
if segments = probe.template_segments
|
|
110
|
-
message, evaluation_errors = evaluate_template(segments, context)
|
|
111
|
-
end
|
|
112
|
-
duration = context.duration
|
|
113
|
-
{
|
|
137
|
+
payload = {
|
|
114
138
|
service: settings.service,
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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 || {},
|
|
123
168
|
},
|
|
124
|
-
language: 'ruby',
|
|
125
|
-
# TODO add test coverage for callers being nil
|
|
126
|
-
stack: stack,
|
|
127
|
-
captures: captures,
|
|
128
169
|
},
|
|
129
170
|
# In python tracer duration is under debugger.snapshot,
|
|
130
171
|
# but UI appears to expect it here at top level.
|
|
@@ -132,7 +173,7 @@ module Datadog
|
|
|
132
173
|
host: nil,
|
|
133
174
|
logger: {
|
|
134
175
|
name: probe.file,
|
|
135
|
-
method: probe.method_name
|
|
176
|
+
method: probe.method_name,
|
|
136
177
|
thread_name: Thread.current.name,
|
|
137
178
|
# Dynamic instrumentation currently does not need thread_id for
|
|
138
179
|
# anything. It can be sent if a customer requests it at which point
|
|
@@ -148,9 +189,11 @@ module Datadog
|
|
|
148
189
|
message: message,
|
|
149
190
|
timestamp: timestamp,
|
|
150
191
|
}
|
|
151
|
-
end
|
|
152
192
|
|
|
153
|
-
|
|
193
|
+
tag_process_tags!(payload, settings)
|
|
194
|
+
|
|
195
|
+
payload
|
|
196
|
+
end
|
|
154
197
|
|
|
155
198
|
def build_status(probe, message:, status:)
|
|
156
199
|
{
|
|
@@ -197,6 +240,15 @@ module Datadog
|
|
|
197
240
|
[message, evaluation_errors]
|
|
198
241
|
end
|
|
199
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
|
|
250
|
+
end
|
|
251
|
+
|
|
200
252
|
def timestamp_now
|
|
201
253
|
(Core::Utils::Time.now.to_f * MILLISECONDS).to_i
|
|
202
254
|
end
|
|
@@ -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
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
3
5
|
require_relative '../../core/transport/parcel'
|
|
4
|
-
require_relative '
|
|
6
|
+
require_relative '../../core/transport/request'
|
|
7
|
+
require_relative '../../core/transport/transport'
|
|
8
|
+
require_relative 'http/diagnostics'
|
|
5
9
|
|
|
6
10
|
module Datadog
|
|
7
11
|
module DI
|
|
@@ -14,46 +18,14 @@ module Datadog
|
|
|
14
18
|
class Request < Datadog::Core::Transport::Request
|
|
15
19
|
end
|
|
16
20
|
|
|
17
|
-
class Transport
|
|
18
|
-
attr_reader :client, :apis, :default_api, :current_api_id, :logger
|
|
19
|
-
|
|
20
|
-
def initialize(apis, default_api, logger:)
|
|
21
|
-
@apis = apis
|
|
22
|
-
@logger = logger
|
|
23
|
-
|
|
24
|
-
@client = HTTP::Client.new(current_api, logger: logger)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def current_api
|
|
28
|
-
@apis[HTTP::API::DIAGNOSTICS]
|
|
29
|
-
end
|
|
30
|
-
|
|
21
|
+
class Transport < Core::Transport::Transport
|
|
31
22
|
def send_diagnostics(payload)
|
|
23
|
+
# TODO use transport encoder functionality?
|
|
32
24
|
json = JSON.dump(payload)
|
|
33
25
|
parcel = EncodedParcel.new(json)
|
|
34
26
|
request = Request.new(parcel)
|
|
35
27
|
|
|
36
|
-
|
|
37
|
-
unless response.ok?
|
|
38
|
-
# TODO Datadog::Core::Transport::InternalErrorResponse
|
|
39
|
-
# does not have +code+ method, what is the actual API of
|
|
40
|
-
# these response objects?
|
|
41
|
-
raise Error::AgentCommunicationError, "send_diagnostics failed: #{begin
|
|
42
|
-
response.code
|
|
43
|
-
rescue
|
|
44
|
-
"???"
|
|
45
|
-
end}: #{response.payload}"
|
|
46
|
-
end
|
|
47
|
-
rescue Error::AgentCommunicationError
|
|
48
|
-
raise
|
|
49
|
-
# Datadog::Core::Transport does not perform any exception mapping,
|
|
50
|
-
# therefore we could have any exception here from failure to parse
|
|
51
|
-
# agent URI for example.
|
|
52
|
-
# If we ever implement retries for network errors, we should distinguish
|
|
53
|
-
# actual network errors from non-network errors that are raised by
|
|
54
|
-
# transport code.
|
|
55
|
-
rescue => exc
|
|
56
|
-
raise Error::AgentCommunicationError, "send_diagnostics failed: #{exc.class}: #{exc}"
|
|
28
|
+
client.send_request(:diagnostics, request)
|
|
57
29
|
end
|
|
58
30
|
end
|
|
59
31
|
end
|
|
@@ -1,43 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../../core/transport/http/api/
|
|
4
|
-
require_relative '../../../core/transport/http/api/spec'
|
|
5
|
-
require_relative 'client'
|
|
3
|
+
require_relative '../../../core/transport/http/api/endpoint'
|
|
6
4
|
|
|
7
5
|
module Datadog
|
|
8
6
|
module DI
|
|
9
7
|
module Transport
|
|
10
8
|
module HTTP
|
|
11
9
|
module Diagnostics
|
|
12
|
-
module Client
|
|
13
|
-
def send_diagnostics_payload(request)
|
|
14
|
-
send_request(request) do |api, env|
|
|
15
|
-
api.send_diagnostics(env)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
10
|
module API
|
|
21
|
-
class Instance < Core::Transport::HTTP::API::Instance
|
|
22
|
-
def send_diagnostics(env)
|
|
23
|
-
raise Core::Transport::HTTP::API::Instance::EndpointNotSupportedError.new('diagnostics', self) unless spec.is_a?(Diagnostics::API::Spec)
|
|
24
|
-
|
|
25
|
-
spec.send_diagnostics(env) do |request_env|
|
|
26
|
-
call(request_env)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
class Spec < Core::Transport::HTTP::API::Spec
|
|
32
|
-
attr_accessor :diagnostics
|
|
33
|
-
|
|
34
|
-
def send_diagnostics(env, &block)
|
|
35
|
-
raise Core::Transport::HTTP::API::Spec::EndpointNotDefinedError.new('diagnostics', self) if diagnostics.nil?
|
|
36
|
-
|
|
37
|
-
diagnostics.call(env, &block)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
11
|
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
|
42
12
|
attr_reader :encoder
|
|
43
13
|
|
|
@@ -57,8 +27,6 @@ module Datadog
|
|
|
57
27
|
end
|
|
58
28
|
end
|
|
59
29
|
end
|
|
60
|
-
|
|
61
|
-
HTTP::Client.include(Diagnostics::Client)
|
|
62
30
|
end
|
|
63
31
|
end
|
|
64
32
|
end
|
|
@@ -1,43 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../../core/transport/http/api/
|
|
4
|
-
require_relative '../../../core/transport/http/api/spec'
|
|
5
|
-
require_relative 'client'
|
|
3
|
+
require_relative '../../../core/transport/http/api/endpoint'
|
|
6
4
|
|
|
7
5
|
module Datadog
|
|
8
6
|
module DI
|
|
9
7
|
module Transport
|
|
10
8
|
module HTTP
|
|
11
9
|
module Input
|
|
12
|
-
module Client
|
|
13
|
-
def send_input_payload(request)
|
|
14
|
-
send_request(request) do |api, env|
|
|
15
|
-
api.send_input(env)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
10
|
module API
|
|
21
|
-
class Instance < Core::Transport::HTTP::API::Instance
|
|
22
|
-
def send_input(env)
|
|
23
|
-
raise Core::Transport::HTTP::API::Instance::EndpointNotSupportedError.new('input', self) unless spec.is_a?(Input::API::Spec)
|
|
24
|
-
|
|
25
|
-
spec.send_input(env) do |request_env|
|
|
26
|
-
call(request_env)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
class Spec < Core::Transport::HTTP::API::Spec
|
|
32
|
-
attr_accessor :input
|
|
33
|
-
|
|
34
|
-
def send_input(env, &block)
|
|
35
|
-
raise Core::Transport::HTTP::API::Spec::EndpointNotDefinedError.new('input', self) if input.nil?
|
|
36
|
-
|
|
37
|
-
input.call(env, &block)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
11
|
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
|
42
12
|
HEADER_CONTENT_TYPE = 'Content-Type'
|
|
43
13
|
|
|
@@ -69,8 +39,6 @@ module Datadog
|
|
|
69
39
|
end
|
|
70
40
|
end
|
|
71
41
|
end
|
|
72
|
-
|
|
73
|
-
HTTP::Client.include(Input::Client)
|
|
74
42
|
end
|
|
75
43
|
end
|
|
76
44
|
end
|