datadog 2.10.0 → 2.12.2
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 +72 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +3 -3
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +44 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +4 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
- data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +64 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +7 -0
- data/ext/datadog_profiling_native_extension/profiling.c +7 -0
- data/ext/libdatadog_api/crashtracker.c +4 -4
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/configuration/settings.rb +64 -11
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +23 -6
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +63 -15
- data/lib/datadog/appsec/contrib/devise/configuration.rb +76 -0
- data/lib/datadog/appsec/contrib/devise/event.rb +4 -7
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +16 -21
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +8 -15
- data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/devise/tracking.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +43 -0
- data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
- data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
- data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
- data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +42 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +10 -12
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rack/ext.rb +20 -0
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +84 -72
- data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +3 -0
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +20 -25
- data/lib/datadog/appsec/contrib/rails/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +39 -0
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +38 -49
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +0 -3
- data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
- data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +19 -25
- data/lib/datadog/appsec/processor/rule_merger.rb +2 -1
- data/lib/datadog/appsec/remote.rb +11 -0
- data/lib/datadog/appsec.rb +3 -0
- data/lib/datadog/core/configuration/components.rb +17 -10
- data/lib/datadog/core/configuration/ext.rb +1 -1
- data/lib/datadog/core/configuration/option_definition.rb +2 -0
- data/lib/datadog/core/configuration/settings.rb +22 -6
- data/lib/datadog/core/encoding.rb +16 -0
- data/lib/datadog/core/environment/agent_info.rb +77 -0
- data/lib/datadog/core/metrics/client.rb +9 -8
- data/lib/datadog/core/remote/client.rb +5 -4
- data/lib/datadog/core/remote/component.rb +14 -12
- data/lib/datadog/core/remote/negotiation.rb +1 -1
- data/lib/datadog/core/remote/transport/http/api.rb +13 -18
- data/lib/datadog/core/remote/transport/http/config.rb +0 -18
- data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -18
- data/lib/datadog/core/remote/transport/http.rb +6 -40
- data/lib/datadog/core/remote/transport/negotiation.rb +13 -1
- data/lib/datadog/core/remote/worker.rb +10 -7
- data/lib/datadog/core/telemetry/component.rb +5 -1
- data/lib/datadog/core/telemetry/event.rb +5 -0
- data/lib/datadog/core/telemetry/worker.rb +9 -5
- data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/api/spec.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/builder.rb +37 -17
- data/lib/datadog/core/transport/http.rb +38 -0
- data/lib/datadog/core/transport/response.rb +4 -0
- data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
- data/lib/datadog/di/code_tracker.rb +15 -8
- data/lib/datadog/di/component.rb +2 -3
- data/lib/datadog/di/configuration/settings.rb +14 -0
- data/lib/datadog/di/contrib.rb +2 -0
- data/lib/datadog/di/logger.rb +30 -0
- data/lib/datadog/di/probe.rb +3 -6
- data/lib/datadog/di/probe_manager.rb +5 -2
- data/lib/datadog/di/probe_notifier_worker.rb +35 -8
- data/lib/datadog/di/remote.rb +3 -3
- data/lib/datadog/di/transport/diagnostics.rb +61 -0
- data/lib/datadog/di/transport/http/api.rb +52 -0
- data/lib/datadog/di/transport/http/client.rb +46 -0
- data/lib/datadog/di/transport/http/diagnostics.rb +92 -0
- data/lib/datadog/di/transport/http/input.rb +94 -0
- data/lib/datadog/di/transport/http.rb +105 -0
- data/lib/datadog/di/transport/input.rb +61 -0
- data/lib/datadog/di/utils.rb +91 -0
- data/lib/datadog/di.rb +5 -1
- data/lib/datadog/profiling/component.rb +2 -8
- data/lib/datadog/profiling/load_native_extension.rb +1 -33
- data/lib/datadog/tracing/component.rb +1 -0
- data/lib/datadog/tracing/configuration/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/extensions.rb +14 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
- data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
- data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
- data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
- data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
- data/lib/datadog/tracing/metadata.rb +2 -0
- data/lib/datadog/tracing/span.rb +10 -1
- data/lib/datadog/tracing/span_operation.rb +6 -1
- data/lib/datadog/tracing/sync_writer.rb +9 -4
- data/lib/datadog/tracing/tracer.rb +15 -7
- data/lib/datadog/tracing/transport/http/api.rb +11 -2
- data/lib/datadog/tracing/transport/http/traces.rb +0 -3
- data/lib/datadog/tracing/transport/http.rb +7 -31
- data/lib/datadog/tracing/transport/serializable_trace.rb +11 -5
- data/lib/datadog/tracing/transport/traces.rb +25 -8
- data/lib/datadog/tracing/workers/trace_writer.rb +10 -3
- data/lib/datadog/tracing/workers.rb +5 -4
- data/lib/datadog/tracing/writer.rb +12 -4
- data/lib/datadog/version.rb +2 -2
- metadata +37 -29
- data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
- data/ext/datadog_profiling_loader/extconf.rb +0 -60
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
- data/lib/datadog/appsec/contrib/patcher.rb +0 -12
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
- data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
- data/lib/datadog/appsec/reactive/engine.rb +0 -47
- data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
- data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
- data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
- data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
- data/lib/datadog/di/transport.rb +0 -79
data/lib/datadog/di/component.rb
CHANGED
@@ -74,14 +74,14 @@ module Datadog
|
|
74
74
|
def initialize(settings, agent_settings, logger, code_tracker: nil, telemetry: nil)
|
75
75
|
@settings = settings
|
76
76
|
@agent_settings = agent_settings
|
77
|
+
logger = DI::Logger.new(settings, logger)
|
77
78
|
@logger = logger
|
78
79
|
@telemetry = telemetry
|
79
80
|
@code_tracker = code_tracker
|
80
81
|
@redactor = Redactor.new(settings)
|
81
82
|
@serializer = Serializer.new(settings, redactor, telemetry: telemetry)
|
82
83
|
@instrumenter = Instrumenter.new(settings, serializer, logger, code_tracker: code_tracker, telemetry: telemetry)
|
83
|
-
@
|
84
|
-
@probe_notifier_worker = ProbeNotifierWorker.new(settings, transport, logger, telemetry: telemetry)
|
84
|
+
@probe_notifier_worker = ProbeNotifierWorker.new(settings, logger, agent_settings: agent_settings, telemetry: telemetry)
|
85
85
|
@probe_notification_builder = ProbeNotificationBuilder.new(settings, serializer)
|
86
86
|
@probe_manager = ProbeManager.new(settings, instrumenter, probe_notification_builder, probe_notifier_worker, logger, telemetry: telemetry)
|
87
87
|
probe_notifier_worker.start
|
@@ -93,7 +93,6 @@ module Datadog
|
|
93
93
|
attr_reader :telemetry
|
94
94
|
attr_reader :code_tracker
|
95
95
|
attr_reader :instrumenter
|
96
|
-
attr_reader :transport
|
97
96
|
attr_reader :probe_notifier_worker
|
98
97
|
attr_reader :probe_notification_builder
|
99
98
|
attr_reader :probe_manager
|
@@ -188,6 +188,20 @@ module Datadog
|
|
188
188
|
o.type :bool
|
189
189
|
o.default false
|
190
190
|
end
|
191
|
+
|
192
|
+
# Enable logging of dynamic instrumentation activity.
|
193
|
+
# This is quite verbose.
|
194
|
+
option :trace_logging do |o|
|
195
|
+
o.type :bool
|
196
|
+
o.default false
|
197
|
+
|
198
|
+
# Use the same environment variable as the rest of
|
199
|
+
# dd-trace-rb logging for now. Could change to a
|
200
|
+
# dedicated environment variable in the future but
|
201
|
+
# will likely need a way to turn on remote config
|
202
|
+
# debugging (since DI uses RC for configuration).
|
203
|
+
o.env 'DD_TRACE_DEBUG'
|
204
|
+
end
|
191
205
|
end
|
192
206
|
end
|
193
207
|
end
|
data/lib/datadog/di/contrib.rb
CHANGED
@@ -7,6 +7,7 @@ module Datadog
|
|
7
7
|
module Contrib
|
8
8
|
module_function def load_now_or_later
|
9
9
|
if Datadog::Core::Contrib::Rails::Utils.railtie_supported?
|
10
|
+
Datadog.logger.debug('di: loading contrib/railtie')
|
10
11
|
require_relative 'contrib/railtie'
|
11
12
|
else
|
12
13
|
load_now
|
@@ -18,6 +19,7 @@ module Datadog
|
|
18
19
|
# dependencies are loaded (or potentially loaded).
|
19
20
|
module_function def load_now
|
20
21
|
if defined?(ActiveRecord::Base)
|
22
|
+
Datadog.logger.debug('di: loading contrib/active_record')
|
21
23
|
require_relative 'contrib/active_record'
|
22
24
|
end
|
23
25
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module DI
|
7
|
+
# Logger facade to add the +trace+ method.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class Logger
|
11
|
+
extend Forwardable # steep:ignore
|
12
|
+
|
13
|
+
def initialize(settings, target)
|
14
|
+
@settings = settings
|
15
|
+
@target = target
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :settings
|
19
|
+
attr_reader :target
|
20
|
+
|
21
|
+
def_delegators :target, :debug # steep:ignore
|
22
|
+
|
23
|
+
def trace(&block)
|
24
|
+
if settings.dynamic_instrumentation.internal.trace_logging
|
25
|
+
debug(&block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/datadog/di/probe.rb
CHANGED
@@ -155,11 +155,8 @@ module Datadog
|
|
155
155
|
# Returns whether the provided +path+ matches the user-designated
|
156
156
|
# file (of a line probe).
|
157
157
|
#
|
158
|
-
#
|
159
|
-
#
|
160
|
-
#
|
161
|
-
# If file is not an absolute path, the path matches if the file is its suffix,
|
162
|
-
# at a path component boundary.
|
158
|
+
# Delegates to Utils.path_can_match_spec? which performs fuzzy
|
159
|
+
# matching. See the comments in utils.rb for details.
|
163
160
|
def file_matches?(path)
|
164
161
|
if path.nil?
|
165
162
|
raise ArgumentError, "Cannot match against a nil path"
|
@@ -167,7 +164,7 @@ module Datadog
|
|
167
164
|
unless file
|
168
165
|
raise ArgumentError, "Probe does not have a file to match against"
|
169
166
|
end
|
170
|
-
Utils.
|
167
|
+
Utils.path_can_match_spec?(path, file)
|
171
168
|
end
|
172
169
|
|
173
170
|
# Instrumentation module for method probes.
|
@@ -111,9 +111,11 @@ module Datadog
|
|
111
111
|
# Always remove from pending list here because it makes the
|
112
112
|
# API smaller and shouldn't cause any actual problems.
|
113
113
|
@pending_probes.delete(probe.id)
|
114
|
+
logger.trace { "di: installed #{probe.type} probe at #{probe.location} (#{probe.id})" }
|
114
115
|
true
|
115
116
|
rescue Error::DITargetNotDefined
|
116
117
|
@pending_probes[probe.id] = probe
|
118
|
+
logger.trace { "di: could not install #{probe.type} probe at #{probe.location} (#{probe.id}) because its target is not defined, adding it to pending list" }
|
117
119
|
false
|
118
120
|
end
|
119
121
|
rescue => exc
|
@@ -160,7 +162,7 @@ module Datadog
|
|
160
162
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
161
163
|
# Silence all exceptions?
|
162
164
|
# TODO should we propagate here and rescue upstream?
|
163
|
-
logger.debug { "di: error removing probe #{probe.id}: #{exc.class}: #{exc}" }
|
165
|
+
logger.debug { "di: error removing #{probe.type} probe at #{probe.location} (#{probe.id}): #{exc.class}: #{exc}" }
|
164
166
|
telemetry&.report(exc, description: "Error removing probe")
|
165
167
|
end
|
166
168
|
end
|
@@ -190,7 +192,7 @@ module Datadog
|
|
190
192
|
rescue => exc
|
191
193
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
192
194
|
|
193
|
-
logger.debug { "di: error installing probe after class is defined: #{exc.class}: #{exc}" }
|
195
|
+
logger.debug { "di: error installing #{probe.type} probe at #{probe.location} (#{probe.id}) after class is defined: #{exc.class}: #{exc}" }
|
194
196
|
telemetry&.report(exc, description: "Error installing probe after class is defined")
|
195
197
|
end
|
196
198
|
end
|
@@ -228,6 +230,7 @@ module Datadog
|
|
228
230
|
# backend (once per the probe's lifetime) and a snapshot corresponding
|
229
231
|
# to the current invocation.
|
230
232
|
def probe_executed_callback(probe:, **opts)
|
233
|
+
logger.trace { "di: executed #{probe.type} probe at #{probe.location} (#{probe.id})" }
|
231
234
|
unless probe.emitting_notified?
|
232
235
|
payload = probe_notification_builder.build_emitting(probe)
|
233
236
|
probe_notifier_worker.add_status(payload)
|
@@ -10,7 +10,7 @@ module Datadog
|
|
10
10
|
# The loop inside the worker rescues all exceptions to prevent termination
|
11
11
|
# due to unhandled exceptions raised by any downstream code.
|
12
12
|
# This includes communication and protocol errors when sending the
|
13
|
-
#
|
13
|
+
# events to the agent.
|
14
14
|
#
|
15
15
|
# The worker groups the data to send into batches. The goal is to perform
|
16
16
|
# no more than one network operation per event type per second.
|
@@ -23,12 +23,12 @@ module Datadog
|
|
23
23
|
#
|
24
24
|
# @api private
|
25
25
|
class ProbeNotifierWorker
|
26
|
-
def initialize(settings,
|
26
|
+
def initialize(settings, logger, agent_settings:, telemetry: nil)
|
27
27
|
@settings = settings
|
28
28
|
@telemetry = telemetry
|
29
29
|
@status_queue = []
|
30
30
|
@snapshot_queue = []
|
31
|
-
@
|
31
|
+
@agent_settings = agent_settings
|
32
32
|
@logger = logger
|
33
33
|
@lock = Mutex.new
|
34
34
|
@wake = Core::Semaphore.new
|
@@ -36,15 +36,18 @@ module Datadog
|
|
36
36
|
@sleep_remaining = nil
|
37
37
|
@wake_scheduled = false
|
38
38
|
@thread = nil
|
39
|
+
@pid = nil
|
39
40
|
@flush = 0
|
40
41
|
end
|
41
42
|
|
42
43
|
attr_reader :settings
|
43
44
|
attr_reader :logger
|
44
45
|
attr_reader :telemetry
|
46
|
+
attr_reader :agent_settings
|
45
47
|
|
46
48
|
def start
|
47
|
-
return if @thread
|
49
|
+
return if @thread && @pid == Process.pid
|
50
|
+
logger.trace { "di: starting probe notifier: pid #{$$}" }
|
48
51
|
@thread = Thread.new do
|
49
52
|
loop do
|
50
53
|
# TODO If stop is requested, we stop immediately without
|
@@ -86,6 +89,7 @@ module Datadog
|
|
86
89
|
wake.wait(more ? min_send_interval : nil)
|
87
90
|
end
|
88
91
|
end
|
92
|
+
@pid = Process.pid
|
89
93
|
end
|
90
94
|
|
91
95
|
# Stops the background thread.
|
@@ -94,6 +98,7 @@ module Datadog
|
|
94
98
|
# to killing the thread using Thread#kill.
|
95
99
|
def stop(timeout = 1)
|
96
100
|
@stop_requested = true
|
101
|
+
logger.trace { "di: stopping probe notifier: pid #{$$}" }
|
97
102
|
wake.signal
|
98
103
|
if thread
|
99
104
|
unless thread.join(timeout)
|
@@ -150,7 +155,6 @@ module Datadog
|
|
150
155
|
|
151
156
|
private
|
152
157
|
|
153
|
-
attr_reader :transport
|
154
158
|
attr_reader :wake
|
155
159
|
attr_reader :thread
|
156
160
|
|
@@ -166,6 +170,22 @@ module Datadog
|
|
166
170
|
|
167
171
|
attr_reader :last_sent
|
168
172
|
|
173
|
+
def status_transport
|
174
|
+
@status_transport ||= DI::Transport::HTTP.diagnostics(agent_settings: agent_settings)
|
175
|
+
end
|
176
|
+
|
177
|
+
def do_send_status(batch)
|
178
|
+
status_transport.send_diagnostics(batch)
|
179
|
+
end
|
180
|
+
|
181
|
+
def snapshot_transport
|
182
|
+
@snapshot_transport ||= DI::Transport::HTTP.input(agent_settings: agent_settings)
|
183
|
+
end
|
184
|
+
|
185
|
+
def do_send_snapshot(batch)
|
186
|
+
snapshot_transport.send_input(batch)
|
187
|
+
end
|
188
|
+
|
169
189
|
[
|
170
190
|
[:status, 'probe status'],
|
171
191
|
[:snapshot, 'snapshot'],
|
@@ -184,8 +204,9 @@ module Datadog
|
|
184
204
|
@lock.synchronize do
|
185
205
|
queue = send("#{event_type}_queue")
|
186
206
|
if queue.length > settings.dynamic_instrumentation.internal.snapshot_queue_capacity
|
187
|
-
logger.debug { "di: #{self.class.name}: dropping #{event_type} because queue is full" }
|
207
|
+
logger.debug { "di: #{self.class.name}: dropping #{event_type} event because queue is full" }
|
188
208
|
else
|
209
|
+
logger.trace { "di: #{self.class.name}: queueing #{event_type} event" }
|
189
210
|
queue << event
|
190
211
|
end
|
191
212
|
end
|
@@ -200,6 +221,10 @@ module Datadog
|
|
200
221
|
wake.signal
|
201
222
|
end
|
202
223
|
end
|
224
|
+
|
225
|
+
# Worker could be not running if the process forked - check and
|
226
|
+
# start it again in this case.
|
227
|
+
start
|
203
228
|
end
|
204
229
|
|
205
230
|
# Determine how much longer the worker thread should sleep
|
@@ -232,9 +257,11 @@ module Datadog
|
|
232
257
|
instance_variable_set("@#{event_type}_queue", [])
|
233
258
|
@io_in_progress = batch.any? # steep:ignore
|
234
259
|
end
|
260
|
+
logger.trace { "di: #{self.class.name}: checking #{event_type} queue - #{batch.length} entries" } # steep:ignore
|
235
261
|
if batch.any? # steep:ignore
|
236
262
|
begin
|
237
|
-
|
263
|
+
logger.trace { "di: sending #{batch.length} #{event_type} event(s) to agent" } # steep:ignore
|
264
|
+
send("do_send_#{event_type}", batch)
|
238
265
|
time = Core::Utils::Time.get_time
|
239
266
|
@lock.synchronize do
|
240
267
|
@last_sent = time
|
@@ -263,7 +290,7 @@ module Datadog
|
|
263
290
|
|
264
291
|
def maybe_send
|
265
292
|
rv = maybe_send_status
|
266
|
-
|
293
|
+
maybe_send_snapshot || rv
|
267
294
|
end
|
268
295
|
end
|
269
296
|
end
|
data/lib/datadog/di/remote.rb
CHANGED
@@ -53,7 +53,7 @@ module Datadog
|
|
53
53
|
payload = probe_notification_builder.build_received(probe)
|
54
54
|
probe_notifier_worker = component.probe_notifier_worker
|
55
55
|
probe_notifier_worker.add_status(payload)
|
56
|
-
component.logger.debug { "di: received probe
|
56
|
+
component.logger.debug { "di: received #{probe.type} probe at #{probe.location} (#{probe.id}) via RC" }
|
57
57
|
|
58
58
|
begin
|
59
59
|
# TODO test exception capture
|
@@ -76,7 +76,7 @@ module Datadog
|
|
76
76
|
rescue => exc
|
77
77
|
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
78
78
|
|
79
|
-
component.logger.debug { "di: unhandled exception adding probe in DI remote receiver: #{exc.class}: #{exc}" }
|
79
|
+
component.logger.debug { "di: unhandled exception adding #{probe.type} probe at #{probe.location} (#{probe.id}) in DI remote receiver: #{exc.class}: #{exc}" }
|
80
80
|
component.telemetry&.report(exc, description: "Unhandled exception adding probe in DI remote receiver")
|
81
81
|
|
82
82
|
# TODO test this path
|
@@ -101,7 +101,7 @@ module Datadog
|
|
101
101
|
rescue => exc
|
102
102
|
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
103
103
|
|
104
|
-
component.logger.debug { "di: unhandled exception handling probe in DI remote receiver: #{exc.class}: #{exc}" }
|
104
|
+
component.logger.debug { "di: unhandled exception handling a probe in DI remote receiver: #{exc.class}: #{exc}" }
|
105
105
|
component.telemetry&.report(exc, description: "Unhandled exception handling probe in DI remote receiver")
|
106
106
|
|
107
107
|
# TODO assert content state (errored for this example)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../core/transport/parcel'
|
4
|
+
require_relative 'http/client'
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module DI
|
8
|
+
module Transport
|
9
|
+
module Diagnostics
|
10
|
+
class EncodedParcel
|
11
|
+
include Datadog::Core::Transport::Parcel
|
12
|
+
end
|
13
|
+
|
14
|
+
class Request < Datadog::Core::Transport::Request
|
15
|
+
end
|
16
|
+
|
17
|
+
class Transport
|
18
|
+
attr_reader :client, :apis, :default_api, :current_api_id
|
19
|
+
|
20
|
+
def initialize(apis, default_api)
|
21
|
+
@apis = apis
|
22
|
+
|
23
|
+
@client = HTTP::Client.new(current_api)
|
24
|
+
end
|
25
|
+
|
26
|
+
def current_api
|
27
|
+
@apis[HTTP::API::DIAGNOSTICS]
|
28
|
+
end
|
29
|
+
|
30
|
+
def send_diagnostics(payload)
|
31
|
+
json = JSON.dump(payload)
|
32
|
+
parcel = EncodedParcel.new(json)
|
33
|
+
request = Request.new(parcel)
|
34
|
+
|
35
|
+
response = @client.send_diagnostics_payload(request)
|
36
|
+
unless response.ok?
|
37
|
+
# TODO Datadog::Core::Transport::InternalErrorResponse
|
38
|
+
# does not have +code+ method, what is the actual API of
|
39
|
+
# these response objects?
|
40
|
+
raise Error::AgentCommunicationError, "send_diagnostics failed: #{begin
|
41
|
+
response.code
|
42
|
+
rescue
|
43
|
+
"???"
|
44
|
+
end}: #{response.payload}"
|
45
|
+
end
|
46
|
+
rescue Error::AgentCommunicationError
|
47
|
+
raise
|
48
|
+
# Datadog::Core::Transport does not perform any exception mapping,
|
49
|
+
# therefore we could have any exception here from failure to parse
|
50
|
+
# agent URI for example.
|
51
|
+
# If we ever implement retries for network errors, we should distinguish
|
52
|
+
# actual network errors from non-network errors that are raised by
|
53
|
+
# transport code.
|
54
|
+
rescue => exc
|
55
|
+
raise Error::AgentCommunicationError, "send_diagnostics failed: #{exc.class}: #{exc}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../core/encoding'
|
4
|
+
require_relative '../../../core/transport/http/api/map'
|
5
|
+
require_relative '../../../core/transport/http/api/instance'
|
6
|
+
require_relative '../../../core/transport/http/api/spec'
|
7
|
+
require_relative 'diagnostics'
|
8
|
+
require_relative 'input'
|
9
|
+
|
10
|
+
module Datadog
|
11
|
+
module DI
|
12
|
+
module Transport
|
13
|
+
module HTTP
|
14
|
+
# Namespace for API components
|
15
|
+
module API
|
16
|
+
# Default API versions
|
17
|
+
DIAGNOSTICS = 'diagnostics'
|
18
|
+
INPUT = 'input'
|
19
|
+
|
20
|
+
module_function
|
21
|
+
|
22
|
+
def defaults
|
23
|
+
Datadog::Core::Transport::HTTP::API::Map[
|
24
|
+
DIAGNOSTICS => Spec.new do |s|
|
25
|
+
s.diagnostics = Diagnostics::API::Endpoint.new(
|
26
|
+
'/debugger/v1/diagnostics',
|
27
|
+
Core::Encoding::JSONEncoder,
|
28
|
+
)
|
29
|
+
end,
|
30
|
+
INPUT => Spec.new do |s|
|
31
|
+
s.input = Input::API::Endpoint.new(
|
32
|
+
'/debugger/v1/input',
|
33
|
+
Core::Encoding::JSONEncoder,
|
34
|
+
)
|
35
|
+
end,
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
class Instance < Core::Transport::HTTP::API::Instance
|
40
|
+
include Diagnostics::API::Instance
|
41
|
+
include Input::API::Instance
|
42
|
+
end
|
43
|
+
|
44
|
+
class Spec < Core::Transport::HTTP::API::Spec
|
45
|
+
include Diagnostics::API::Spec
|
46
|
+
include Input::API::Spec
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../core/transport/http/env'
|
4
|
+
require_relative '../../../core/transport/http/response'
|
5
|
+
|
6
|
+
# TODO: Decouple transport/http/client
|
7
|
+
#
|
8
|
+
# The standard one does `include Transport::HTTP::Statistics` and performs
|
9
|
+
# stats updates, which may or may not be desirable in general.
|
10
|
+
|
11
|
+
module Datadog
|
12
|
+
module DI
|
13
|
+
module Transport
|
14
|
+
module HTTP
|
15
|
+
# Routes, encodes, and sends DI data to the trace agent via HTTP.
|
16
|
+
class Client
|
17
|
+
attr_reader :api
|
18
|
+
|
19
|
+
def initialize(api)
|
20
|
+
@api = api
|
21
|
+
end
|
22
|
+
|
23
|
+
def send_request(request, &block)
|
24
|
+
# Build request into env
|
25
|
+
env = build_env(request)
|
26
|
+
|
27
|
+
# Get responses from API
|
28
|
+
yield(api, env)
|
29
|
+
rescue => e
|
30
|
+
message =
|
31
|
+
"Internal error during #{self.class.name} request. Cause: #{e.class.name} #{e.message} " \
|
32
|
+
"Location: #{Array(e.backtrace).first}"
|
33
|
+
|
34
|
+
Datadog.logger.debug(message)
|
35
|
+
|
36
|
+
Datadog::Core::Transport::InternalErrorResponse.new(e)
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_env(request)
|
40
|
+
Datadog::Core::Transport::HTTP::Env.new(request)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'client'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module DI
|
7
|
+
module Transport
|
8
|
+
module HTTP
|
9
|
+
module Diagnostics
|
10
|
+
module Client
|
11
|
+
def send_diagnostics_payload(request)
|
12
|
+
send_request(request) do |api, env|
|
13
|
+
api.send_diagnostics(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module API
|
19
|
+
module Instance
|
20
|
+
def send_diagnostics(env)
|
21
|
+
raise DiagnosticsNotSupportedError, spec unless spec.is_a?(Diagnostics::API::Spec)
|
22
|
+
|
23
|
+
spec.send_diagnostics(env) do |request_env|
|
24
|
+
call(request_env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class DiagnosticsNotSupportedError < StandardError
|
29
|
+
attr_reader :spec
|
30
|
+
|
31
|
+
def initialize(spec)
|
32
|
+
super
|
33
|
+
|
34
|
+
@spec = spec
|
35
|
+
end
|
36
|
+
|
37
|
+
def message
|
38
|
+
'Diagnostics not supported for this API!'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Spec
|
44
|
+
attr_accessor :diagnostics
|
45
|
+
|
46
|
+
def send_diagnostics(env, &block)
|
47
|
+
raise NoDiagnosticsEndpointDefinedError, self if diagnostics.nil?
|
48
|
+
|
49
|
+
diagnostics.call(env, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
class NoDiagnosticsEndpointDefinedError < StandardError
|
53
|
+
attr_reader :spec
|
54
|
+
|
55
|
+
def initialize(spec)
|
56
|
+
super
|
57
|
+
|
58
|
+
@spec = spec
|
59
|
+
end
|
60
|
+
|
61
|
+
def message
|
62
|
+
'No diagnostics endpoint is defined for API specification!'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Endpoint for negotiation
|
68
|
+
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
69
|
+
attr_reader :encoder
|
70
|
+
|
71
|
+
def initialize(path, encoder)
|
72
|
+
super(:post, path)
|
73
|
+
@encoder = encoder
|
74
|
+
end
|
75
|
+
|
76
|
+
def call(env, &block)
|
77
|
+
event_payload = Core::Vendor::Multipart::Post::UploadIO.new(
|
78
|
+
StringIO.new(env.request.parcel.data), 'application/json', 'event.json'
|
79
|
+
)
|
80
|
+
env.form = {'event' => event_payload}
|
81
|
+
|
82
|
+
super(env, &block)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
HTTP::Client.include(Diagnostics::Client)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'client'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module DI
|
7
|
+
module Transport
|
8
|
+
module HTTP
|
9
|
+
module Input
|
10
|
+
module Client
|
11
|
+
def send_input_payload(request)
|
12
|
+
send_request(request) do |api, env|
|
13
|
+
api.send_input(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module API
|
19
|
+
module Instance
|
20
|
+
def send_input(env)
|
21
|
+
raise InputNotSupportedError, spec unless spec.is_a?(Input::API::Spec)
|
22
|
+
|
23
|
+
spec.send_input(env) do |request_env|
|
24
|
+
call(request_env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class InputNotSupportedError < StandardError
|
29
|
+
attr_reader :spec
|
30
|
+
|
31
|
+
def initialize(spec)
|
32
|
+
super
|
33
|
+
|
34
|
+
@spec = spec
|
35
|
+
end
|
36
|
+
|
37
|
+
def message
|
38
|
+
'Input not supported for this API!'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Spec
|
44
|
+
attr_accessor :input
|
45
|
+
|
46
|
+
def send_input(env, &block)
|
47
|
+
raise NoInputEndpointDefinedError, self if input.nil?
|
48
|
+
|
49
|
+
input.call(env, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
class NoInputEndpointDefinedError < StandardError
|
53
|
+
attr_reader :spec
|
54
|
+
|
55
|
+
def initialize(spec)
|
56
|
+
super
|
57
|
+
|
58
|
+
@spec = spec
|
59
|
+
end
|
60
|
+
|
61
|
+
def message
|
62
|
+
'No input endpoint is defined for API specification!'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Endpoint for negotiation
|
68
|
+
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
69
|
+
HEADER_CONTENT_TYPE = 'Content-Type'
|
70
|
+
|
71
|
+
attr_reader \
|
72
|
+
:encoder
|
73
|
+
|
74
|
+
def initialize(path, encoder)
|
75
|
+
super(:post, path)
|
76
|
+
@encoder = encoder
|
77
|
+
end
|
78
|
+
|
79
|
+
def call(env, &block)
|
80
|
+
# Encode body & type
|
81
|
+
env.headers[HEADER_CONTENT_TYPE] = encoder.content_type
|
82
|
+
env.body = env.request.parcel.data
|
83
|
+
|
84
|
+
super(env, &block)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
HTTP::Client.include(Input::Client)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|