datadog 2.7.1 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +69 -1
- data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +64 -54
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
- data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +259 -132
- data/ext/datadog_profiling_native_extension/extconf.rb +0 -8
- data/ext/datadog_profiling_native_extension/heap_recorder.c +11 -89
- data/ext/datadog_profiling_native_extension/heap_recorder.h +1 -1
- data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +4 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
- data/ext/datadog_profiling_native_extension/profiling.c +10 -8
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
- data/ext/datadog_profiling_native_extension/stack_recorder.c +54 -88
- data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -1
- data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
- data/ext/libdatadog_api/crashtracker.c +3 -0
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
- data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
- data/lib/datadog/appsec/component.rb +1 -8
- data/lib/datadog/appsec/context.rb +54 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +73 -0
- data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +53 -0
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +19 -28
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +5 -5
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +64 -96
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +10 -10
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +5 -5
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +6 -6
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -49
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +21 -32
- data/lib/datadog/appsec/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +6 -6
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +41 -63
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +2 -2
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +5 -5
- data/lib/datadog/appsec/event.rb +6 -6
- data/lib/datadog/appsec/ext.rb +3 -1
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +22 -32
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +5 -5
- data/lib/datadog/appsec/processor/context.rb +2 -2
- data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
- data/lib/datadog/appsec/remote.rb +1 -3
- data/lib/datadog/appsec/response.rb +7 -11
- data/lib/datadog/appsec.rb +6 -5
- data/lib/datadog/auto_instrument.rb +3 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
- data/lib/datadog/core/configuration/components.rb +20 -2
- data/lib/datadog/core/configuration/settings.rb +10 -0
- data/lib/datadog/core/configuration.rb +10 -2
- data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +1 -3
- data/lib/datadog/core/remote/client/capabilities.rb +6 -0
- data/lib/datadog/core/remote/client.rb +65 -59
- data/lib/datadog/core/telemetry/component.rb +9 -3
- data/lib/datadog/core/telemetry/event.rb +87 -3
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/core/telemetry/logging.rb +2 -2
- data/lib/datadog/core/telemetry/metric.rb +22 -0
- data/lib/datadog/core/telemetry/worker.rb +33 -0
- data/lib/datadog/di/base.rb +115 -0
- data/lib/datadog/di/code_tracker.rb +11 -7
- data/lib/datadog/di/component.rb +21 -11
- data/lib/datadog/di/configuration/settings.rb +11 -1
- data/lib/datadog/di/contrib/active_record.rb +1 -0
- data/lib/datadog/di/contrib/railtie.rb +15 -0
- data/lib/datadog/di/contrib.rb +26 -0
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +111 -20
- data/lib/datadog/di/preload.rb +18 -0
- data/lib/datadog/di/probe.rb +11 -1
- data/lib/datadog/di/probe_builder.rb +1 -0
- data/lib/datadog/di/probe_manager.rb +8 -5
- data/lib/datadog/di/probe_notification_builder.rb +27 -7
- data/lib/datadog/di/probe_notifier_worker.rb +5 -6
- data/lib/datadog/di/remote.rb +124 -0
- data/lib/datadog/di/serializer.rb +14 -7
- data/lib/datadog/di/transport.rb +3 -5
- data/lib/datadog/di/utils.rb +7 -0
- data/lib/datadog/di.rb +23 -62
- data/lib/datadog/kit/appsec/events.rb +3 -3
- data/lib/datadog/kit/identity.rb +4 -4
- data/lib/datadog/profiling/component.rb +59 -69
- data/lib/datadog/profiling/http_transport.rb +1 -26
- data/lib/datadog/tracing/configuration/settings.rb +4 -8
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +16 -4
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
- data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
- data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
- data/lib/datadog/tracing/span.rb +12 -4
- data/lib/datadog/tracing/span_event.rb +123 -3
- data/lib/datadog/tracing/span_operation.rb +6 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +3 -0
- metadata +30 -17
- data/lib/datadog/appsec/processor/actions.rb +0 -49
- data/lib/datadog/appsec/reactive/operation.rb +0 -68
- data/lib/datadog/appsec/scope.rb +0 -58
- data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
@@ -32,7 +32,7 @@ module Datadog
|
|
32
32
|
install_pending_method_probes(tp.self)
|
33
33
|
rescue => exc
|
34
34
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
35
|
-
logger.
|
35
|
+
logger.debug { "di: unhandled exception in definition trace point: #{exc.class}: #{exc}" }
|
36
36
|
telemetry&.report(exc, description: "Unhandled exception in definition trace point")
|
37
37
|
# TODO test this path
|
38
38
|
end
|
@@ -120,7 +120,7 @@ module Datadog
|
|
120
120
|
# In "propagate all exceptions" mode we will try to instrument again.
|
121
121
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
122
122
|
|
123
|
-
logger.
|
123
|
+
logger.debug { "di: error processing probe configuration: #{exc.class}: #{exc}" }
|
124
124
|
telemetry&.report(exc, description: "Error processing probe configuration")
|
125
125
|
# TODO report probe as failed to agent since we won't attempt to
|
126
126
|
# install it again.
|
@@ -160,8 +160,8 @@ module Datadog
|
|
160
160
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
161
161
|
# Silence all exceptions?
|
162
162
|
# TODO should we propagate here and rescue upstream?
|
163
|
-
logger.
|
164
|
-
telemetry&.report(exc, description: "Error removing probe
|
163
|
+
logger.debug { "di: error removing probe #{probe.id}: #{exc.class}: #{exc}" }
|
164
|
+
telemetry&.report(exc, description: "Error removing probe")
|
165
165
|
end
|
166
166
|
end
|
167
167
|
end
|
@@ -190,7 +190,7 @@ module Datadog
|
|
190
190
|
rescue => exc
|
191
191
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
192
192
|
|
193
|
-
logger.
|
193
|
+
logger.debug { "di: error installing probe after class is defined: #{exc.class}: #{exc}" }
|
194
194
|
telemetry&.report(exc, description: "Error installing probe after class is defined")
|
195
195
|
end
|
196
196
|
end
|
@@ -206,6 +206,9 @@ module Datadog
|
|
206
206
|
# point, which is invoked for each required or loaded file
|
207
207
|
# (and also for eval'd code, but those invocations are filtered out).
|
208
208
|
def install_pending_line_probes(path)
|
209
|
+
if path.nil?
|
210
|
+
raise ArgumentError, "path must not be nil"
|
211
|
+
end
|
209
212
|
@lock.synchronize do
|
210
213
|
@pending_probes.values.each do |probe|
|
211
214
|
if probe.line?
|
@@ -65,14 +65,18 @@ module Datadog
|
|
65
65
|
arguments: if serialized_entry_args
|
66
66
|
serialized_entry_args
|
67
67
|
else
|
68
|
-
(args || kwargs) && serializer.serialize_args(args, kwargs
|
68
|
+
(args || kwargs) && serializer.serialize_args(args, kwargs,
|
69
|
+
depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
|
70
|
+
attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count)
|
69
71
|
end,
|
70
72
|
throwable: nil,
|
71
73
|
# standard:enable all
|
72
74
|
},
|
73
75
|
return: {
|
74
76
|
arguments: {
|
75
|
-
"@return": serializer.serialize_value(rv
|
77
|
+
"@return": serializer.serialize_value(rv,
|
78
|
+
depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
|
79
|
+
attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count),
|
76
80
|
},
|
77
81
|
throwable: nil,
|
78
82
|
},
|
@@ -80,7 +84,9 @@ module Datadog
|
|
80
84
|
elsif probe.line?
|
81
85
|
{
|
82
86
|
lines: snapshot && {
|
83
|
-
probe.line_no => {locals: serializer.serialize_vars(snapshot
|
87
|
+
probe.line_no => {locals: serializer.serialize_vars(snapshot,
|
88
|
+
depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
|
89
|
+
attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count,)},
|
84
90
|
},
|
85
91
|
}
|
86
92
|
end
|
@@ -121,7 +127,7 @@ module Datadog
|
|
121
127
|
},
|
122
128
|
# In python tracer duration is under debugger.snapshot,
|
123
129
|
# but UI appears to expect it here at top level.
|
124
|
-
duration: duration ? (duration * 10**9).to_i :
|
130
|
+
duration: duration ? (duration * 10**9).to_i : 0,
|
125
131
|
host: nil,
|
126
132
|
logger: {
|
127
133
|
name: probe.file,
|
@@ -135,15 +141,17 @@ module Datadog
|
|
135
141
|
version: 2,
|
136
142
|
},
|
137
143
|
# TODO add tests that the trace/span id is correctly propagated
|
138
|
-
"dd.trace_id":
|
139
|
-
"dd.span_id":
|
144
|
+
"dd.trace_id": active_trace&.id&.to_s,
|
145
|
+
"dd.span_id": active_span&.id&.to_s,
|
140
146
|
ddsource: 'dd_debugger',
|
141
147
|
message: probe.template && evaluate_template(probe.template,
|
142
|
-
duration: duration ? duration * 1000 :
|
148
|
+
duration: duration ? duration * 1000 : 0),
|
143
149
|
timestamp: timestamp,
|
144
150
|
}
|
145
151
|
end
|
146
152
|
|
153
|
+
private
|
154
|
+
|
147
155
|
def build_status(probe, message:, status:)
|
148
156
|
{
|
149
157
|
service: settings.service,
|
@@ -194,6 +202,18 @@ module Datadog
|
|
194
202
|
map[name] = value
|
195
203
|
end
|
196
204
|
end
|
205
|
+
|
206
|
+
def active_trace
|
207
|
+
if defined?(Datadog::Tracing)
|
208
|
+
Datadog::Tracing.active_trace
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def active_span
|
213
|
+
if defined?(Datadog::Tracing)
|
214
|
+
Datadog::Tracing.active_span
|
215
|
+
end
|
216
|
+
end
|
197
217
|
end
|
198
218
|
end
|
199
219
|
end
|
@@ -77,7 +77,7 @@ module Datadog
|
|
77
77
|
rescue => exc
|
78
78
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
79
79
|
|
80
|
-
logger.
|
80
|
+
logger.debug { "di: error in probe notifier worker: #{exc.class}: #{exc} (at #{exc.backtrace.first})" }
|
81
81
|
telemetry&.report(exc, description: "Error in probe notifier worker")
|
82
82
|
end
|
83
83
|
@lock.synchronize do
|
@@ -183,9 +183,8 @@ module Datadog
|
|
183
183
|
define_method("add_#{event_type}") do |event|
|
184
184
|
@lock.synchronize do
|
185
185
|
queue = send("#{event_type}_queue")
|
186
|
-
|
187
|
-
|
188
|
-
logger.warn("#{self.class.name}: dropping #{event_type} because queue is full")
|
186
|
+
if queue.length > settings.dynamic_instrumentation.internal.snapshot_queue_capacity
|
187
|
+
logger.debug { "di: #{self.class.name}: dropping #{event_type} because queue is full" }
|
189
188
|
else
|
190
189
|
queue << event
|
191
190
|
end
|
@@ -242,7 +241,7 @@ module Datadog
|
|
242
241
|
end
|
243
242
|
rescue => exc
|
244
243
|
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
245
|
-
logger.
|
244
|
+
logger.debug { "di: failed to send #{event_name}: #{exc.class}: #{exc} (at #{exc.backtrace.first})" }
|
246
245
|
# Should we report this error to telemetry? Most likely failure
|
247
246
|
# to send is due to a network issue, and trying to send a
|
248
247
|
# telemetry message would also fail.
|
@@ -253,7 +252,7 @@ module Datadog
|
|
253
252
|
# Normally the queue should only be consumed in this method,
|
254
253
|
# however if anyone consumes it elsewhere we don't want to block
|
255
254
|
# while consuming it here. Rescue ThreadError and return.
|
256
|
-
logger.
|
255
|
+
logger.debug { "di: unexpected #{event_name} queue underflow - consumed elsewhere?" }
|
257
256
|
telemetry&.report(exc, description: "Unexpected #{event_name} queue underflow")
|
258
257
|
ensure
|
259
258
|
@lock.synchronize do
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module DI
|
5
|
+
# Provides an interface expected by the core Remote subsystem to
|
6
|
+
# receive DI-specific remote configuration.
|
7
|
+
#
|
8
|
+
# In order to apply (i.e., act on) the configuration, we need the
|
9
|
+
# state stored under DI Component. Thus, this module forwards actual
|
10
|
+
# configuration application to the ProbeManager associated with the
|
11
|
+
# global DI Component.
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
module Remote
|
15
|
+
class ReadError < StandardError; end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
PRODUCT = 'LIVE_DEBUGGING'
|
19
|
+
|
20
|
+
def products
|
21
|
+
[PRODUCT]
|
22
|
+
end
|
23
|
+
|
24
|
+
def capabilities
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
|
28
|
+
def receivers(telemetry)
|
29
|
+
receiver do |repository, _changes|
|
30
|
+
# DEV: Filter our by product. Given it will be very common
|
31
|
+
# DEV: we can filter this out before we receive the data in this method.
|
32
|
+
# DEV: Apply this refactor to AppSec as well if implemented.
|
33
|
+
|
34
|
+
component = DI.component
|
35
|
+
# We should always have a non-nil DI component here, because we
|
36
|
+
# only add DI product to remote config request if DI is enabled.
|
37
|
+
# Ideally, we should be injected with the DI component here
|
38
|
+
# rather than having to retrieve it from global state.
|
39
|
+
# If the component is nil for some reason, we also don't have a
|
40
|
+
# logger instance to report the issue.
|
41
|
+
if component
|
42
|
+
|
43
|
+
probe_manager = component.probe_manager
|
44
|
+
|
45
|
+
current_probe_ids = {}
|
46
|
+
repository.contents.each do |content|
|
47
|
+
case content.path.product
|
48
|
+
when PRODUCT
|
49
|
+
begin
|
50
|
+
probe_spec = parse_content(content)
|
51
|
+
probe = ProbeBuilder.build_from_remote_config(probe_spec)
|
52
|
+
payload = component.probe_notification_builder.build_received(probe)
|
53
|
+
component.probe_notifier_worker.add_status(payload)
|
54
|
+
component.logger.debug { "di: received probe from RC: #{probe.type} #{probe.location}" }
|
55
|
+
|
56
|
+
begin
|
57
|
+
# TODO test exception capture
|
58
|
+
probe_manager.add_probe(probe)
|
59
|
+
content.applied
|
60
|
+
rescue => exc
|
61
|
+
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
62
|
+
|
63
|
+
component.logger.debug { "di: unhandled exception adding probe in DI remote receiver: #{exc.class}: #{exc}" }
|
64
|
+
component.telemetry&.report(exc, description: "Unhandled exception adding probe in DI remote receiver")
|
65
|
+
|
66
|
+
# If a probe fails to install, we will mark the content
|
67
|
+
# as errored. On subsequent remote configuration application
|
68
|
+
# attemps, probe manager will raise the "previously errored"
|
69
|
+
# exception and we'll rescue it here, again marking the
|
70
|
+
# content as errored but with a somewhat different exception
|
71
|
+
# message.
|
72
|
+
# TODO stack trace must be redacted or not sent at all
|
73
|
+
content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}: #{Array(exc.backtrace).join("\n")}")
|
74
|
+
end
|
75
|
+
|
76
|
+
# Important: even if processing fails for this probe config,
|
77
|
+
# we need to note it as being current so that we do not
|
78
|
+
# try to remove instrumentation that is still supposed to be
|
79
|
+
# active.
|
80
|
+
current_probe_ids[probe_spec.fetch('id')] = true
|
81
|
+
rescue => exc
|
82
|
+
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
83
|
+
|
84
|
+
component.logger.debug { "di: unhandled exception handling probe in DI remote receiver: #{exc.class}: #{exc}" }
|
85
|
+
component.telemetry&.report(exc, description: "Unhandled exception handling probe in DI remote receiver")
|
86
|
+
|
87
|
+
content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}: #{Array(exc.backtrace).join("\n")}")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
begin
|
93
|
+
# TODO test exception capture
|
94
|
+
probe_manager.remove_other_probes(current_probe_ids.keys)
|
95
|
+
rescue => exc
|
96
|
+
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
97
|
+
|
98
|
+
component.logger.debug { "di: unhandled exception removing probes in DI remote receiver: #{exc.class}: #{exc}" }
|
99
|
+
component.telemetry&.report(exc, description: "Unhandled exception removing probes in DI remote receiver")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def receiver(products = [PRODUCT], &block)
|
106
|
+
matcher = Core::Remote::Dispatcher::Matcher::Product.new(products)
|
107
|
+
[Core::Remote::Dispatcher::Receiver.new(matcher, &block)]
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def parse_content(content)
|
113
|
+
data = content.data.read
|
114
|
+
|
115
|
+
content.data.rewind
|
116
|
+
|
117
|
+
raise ReadError, 'EOF reached' if data.nil?
|
118
|
+
|
119
|
+
JSON.parse(data)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -82,7 +82,9 @@ module Datadog
|
|
82
82
|
# between positional and keyword arguments. We convert positional
|
83
83
|
# arguments to keyword arguments ("arg1", "arg2", ...) and ensure
|
84
84
|
# the positional arguments are listed first.
|
85
|
-
def serialize_args(args, kwargs
|
85
|
+
def serialize_args(args, kwargs,
|
86
|
+
depth: settings.dynamic_instrumentation.max_capture_depth,
|
87
|
+
attribute_count: settings.dynamic_instrumentation.max_capture_attribute_count)
|
86
88
|
counter = 0
|
87
89
|
combined = args.each_with_object({}) do |value, c|
|
88
90
|
counter += 1
|
@@ -90,16 +92,18 @@ module Datadog
|
|
90
92
|
# kwargs when they are merged below.
|
91
93
|
c[:"arg#{counter}"] = value
|
92
94
|
end.update(kwargs)
|
93
|
-
serialize_vars(combined)
|
95
|
+
serialize_vars(combined, depth: depth, attribute_count: attribute_count)
|
94
96
|
end
|
95
97
|
|
96
98
|
# Serializes variables captured by a line probe.
|
97
99
|
#
|
98
100
|
# These are normally local variables that exist on a particular line
|
99
101
|
# of executed code.
|
100
|
-
def serialize_vars(vars
|
102
|
+
def serialize_vars(vars,
|
103
|
+
depth: settings.dynamic_instrumentation.max_capture_depth,
|
104
|
+
attribute_count: settings.dynamic_instrumentation.max_capture_attribute_count)
|
101
105
|
vars.each_with_object({}) do |(k, v), agg|
|
102
|
-
agg[k] = serialize_value(v, name: k)
|
106
|
+
agg[k] = serialize_value(v, name: k, depth: depth, attribute_count: attribute_count)
|
103
107
|
end
|
104
108
|
end
|
105
109
|
|
@@ -115,7 +119,11 @@ module Datadog
|
|
115
119
|
# (integers, strings, arrays, hashes).
|
116
120
|
#
|
117
121
|
# Respects string length, collection size and traversal depth limits.
|
118
|
-
def serialize_value(value, name: nil,
|
122
|
+
def serialize_value(value, name: nil,
|
123
|
+
depth: settings.dynamic_instrumentation.max_capture_depth,
|
124
|
+
attribute_count: nil,
|
125
|
+
type: nil)
|
126
|
+
attribute_count ||= settings.dynamic_instrumentation.max_capture_attribute_count
|
119
127
|
cls = type || value.class
|
120
128
|
begin
|
121
129
|
if redactor.redact_type?(value)
|
@@ -203,7 +211,6 @@ module Datadog
|
|
203
211
|
serialized.update(notCapturedReason: "depth")
|
204
212
|
else
|
205
213
|
fields = {}
|
206
|
-
max = settings.dynamic_instrumentation.max_capture_attribute_count
|
207
214
|
cur = 0
|
208
215
|
|
209
216
|
# MRI and JRuby 9.4.5+ preserve instance variable definition
|
@@ -229,7 +236,7 @@ module Datadog
|
|
229
236
|
ivars = value.instance_variables
|
230
237
|
|
231
238
|
ivars.each do |ivar|
|
232
|
-
if cur >=
|
239
|
+
if cur >= attribute_count
|
233
240
|
serialized.update(notCapturedReason: "fieldCount", fields: fields)
|
234
241
|
break
|
235
242
|
end
|
data/lib/datadog/di/transport.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'ostruct'
|
4
3
|
require_relative 'error'
|
4
|
+
require_relative '../core/transport/http/adapters/net'
|
5
5
|
|
6
6
|
module Datadog
|
7
7
|
module DI
|
@@ -45,7 +45,7 @@ module Datadog
|
|
45
45
|
|
46
46
|
def send_input(payload)
|
47
47
|
send_request('Probe snapshot submission',
|
48
|
-
path: INPUT_PATH, body: payload.
|
48
|
+
path: INPUT_PATH, body: payload.to_json,
|
49
49
|
headers: {'content-type' => 'application/json'},)
|
50
50
|
end
|
51
51
|
|
@@ -60,9 +60,7 @@ module Datadog
|
|
60
60
|
attr_reader :client
|
61
61
|
|
62
62
|
def send_request(desc, **options)
|
63
|
-
|
64
|
-
env = OpenStruct.new(**options)
|
65
|
-
# steep:ignore:end
|
63
|
+
env = Core::Transport::HTTP::Env.new(nil, options)
|
66
64
|
response = client.post(env)
|
67
65
|
unless response.ok?
|
68
66
|
raise Error::AgentCommunicationError, "#{desc} failed: #{response.code}: #{response.payload}"
|
data/lib/datadog/di/utils.rb
CHANGED
@@ -12,6 +12,13 @@ module Datadog
|
|
12
12
|
# If suffix is not an absolute path, the path matches if its suffix is
|
13
13
|
# the provided suffix, at a path component boundary.
|
14
14
|
module_function def path_matches_suffix?(path, suffix)
|
15
|
+
if path.nil?
|
16
|
+
raise ArgumentError, "nil path passed"
|
17
|
+
end
|
18
|
+
if suffix.nil?
|
19
|
+
raise ArgumentError, "nil suffix passed"
|
20
|
+
end
|
21
|
+
|
15
22
|
if suffix.start_with?('/')
|
16
23
|
path == suffix
|
17
24
|
else
|
data/lib/datadog/di.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'di/base'
|
3
4
|
require_relative 'di/error'
|
4
5
|
require_relative 'di/code_tracker'
|
5
6
|
require_relative 'di/component'
|
@@ -12,22 +13,11 @@ require_relative 'di/probe_manager'
|
|
12
13
|
require_relative 'di/probe_notification_builder'
|
13
14
|
require_relative 'di/probe_notifier_worker'
|
14
15
|
require_relative 'di/redactor'
|
16
|
+
require_relative 'di/remote'
|
15
17
|
require_relative 'di/serializer'
|
16
18
|
require_relative 'di/transport'
|
17
19
|
require_relative 'di/utils'
|
18
20
|
|
19
|
-
if defined?(ActiveRecord::Base)
|
20
|
-
# The third-party library integrations need to be loaded after the
|
21
|
-
# third-party libraries are loaded. Tracing and appsec use Railtie
|
22
|
-
# to delay integrations until all of the application's dependencies
|
23
|
-
# are loaded, when running under Rails. We should do the same here in
|
24
|
-
# principle, however DI currently only has an ActiveRecord integration
|
25
|
-
# and AR should be loaded before any application code is loaded, being
|
26
|
-
# part of Rails, therefore for now we should be OK to just require the
|
27
|
-
# AR integration from here.
|
28
|
-
require_relative 'di/contrib/active_record'
|
29
|
-
end
|
30
|
-
|
31
21
|
module Datadog
|
32
22
|
# Namespace for Datadog dynamic instrumentation.
|
33
23
|
#
|
@@ -43,63 +33,34 @@ module Datadog
|
|
43
33
|
Extensions.activate!
|
44
34
|
|
45
35
|
class << self
|
46
|
-
attr_reader :code_tracker
|
47
36
|
|
48
|
-
#
|
49
|
-
#
|
50
|
-
# code tracking needs to be enabled before the third-party libraries
|
51
|
-
# are loaded. If you definitely will not be instrumenting
|
52
|
-
# third-party libraries, activating tracking after third-party libraries
|
53
|
-
# have been loaded may improve lookup performance.
|
37
|
+
# This method is called from DI Remote handler to issue DI operations
|
38
|
+
# to the probe manager (add or remove probes).
|
54
39
|
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
def activate_tracking!
|
58
|
-
(@code_tracker ||= CodeTracker.new).start
|
59
|
-
end
|
60
|
-
|
61
|
-
# Deactivates code tracking. In normal usage of DI this method should
|
62
|
-
# never be called, however it is used by DI's test suite to reset
|
63
|
-
# state for individual tests.
|
40
|
+
# When DI Remote is executing, Datadog.components should be initialized
|
41
|
+
# and we should be able to reference it to get to the DI component.
|
64
42
|
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
def deactivate_tracking!
|
69
|
-
code_tracker&.stop
|
70
|
-
end
|
71
|
-
|
72
|
-
# Returns whether code tracking is available.
|
73
|
-
# This method should be used instead of querying #code_tracker
|
74
|
-
# because the latter one may be nil.
|
75
|
-
def code_tracking_active?
|
76
|
-
code_tracker&.active? || false
|
77
|
-
end
|
78
|
-
|
43
|
+
# Given that we need the current_component anyway for code tracker,
|
44
|
+
# perhaps we should delete the +component+ method and just use
|
45
|
+
# +current_component+ in all cases.
|
79
46
|
def component
|
80
|
-
|
81
|
-
#Datadog.send(:components).dynamic_instrumentation
|
47
|
+
Datadog.send(:components).dynamic_instrumentation
|
82
48
|
end
|
83
49
|
end
|
84
50
|
end
|
85
51
|
end
|
86
52
|
|
87
|
-
|
88
|
-
#
|
89
|
-
if
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
Datadog.logger.warn("Failed to activate code tracking for DI: #{exc.class}: #{exc}")
|
97
|
-
else
|
98
|
-
# We do not have Datadog logger potentially because DI code tracker is
|
99
|
-
# being loaded early in application boot process and the rest of datadog
|
100
|
-
# wasn't loaded yet. Output to standard error.
|
101
|
-
warn("Failed to activate code tracking for DI: #{exc.class}: #{exc}")
|
102
|
-
end
|
103
|
-
end
|
53
|
+
if %w(1 true).include?(ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED']) # steep:ignore
|
54
|
+
# For initial release of Dynamic Instrumentation, activate code tracking
|
55
|
+
# only if DI is explicitly requested in the environment.
|
56
|
+
# Code tracking is required for line probes to work; see the comments
|
57
|
+
# above for the implementation of the method.
|
58
|
+
#
|
59
|
+
# If DI is enabled programmatically, the application can (and must,
|
60
|
+
# for line probes to work) activate tracking in an initializer.
|
61
|
+
Datadog::DI.activate_tracking
|
104
62
|
end
|
105
|
-
|
63
|
+
|
64
|
+
require_relative 'di/contrib'
|
65
|
+
|
66
|
+
Datadog::DI::Contrib.load_now_or_later
|
@@ -136,9 +136,9 @@ module Datadog
|
|
136
136
|
private
|
137
137
|
|
138
138
|
def set_trace_and_span_context(method, trace = nil, span = nil)
|
139
|
-
if (
|
140
|
-
trace =
|
141
|
-
span =
|
139
|
+
if (appsec_context = Datadog::AppSec.active_context)
|
140
|
+
trace = appsec_context.trace
|
141
|
+
span = appsec_context.span
|
142
142
|
end
|
143
143
|
|
144
144
|
trace ||= Datadog::Tracing.active_trace
|
data/lib/datadog/kit/identity.rb
CHANGED
@@ -66,7 +66,7 @@ module Datadog
|
|
66
66
|
active_span.set_tag("usr.#{k}", v) unless v.nil?
|
67
67
|
end
|
68
68
|
|
69
|
-
if Datadog::AppSec.
|
69
|
+
if Datadog::AppSec.active_context
|
70
70
|
user = ::Datadog::AppSec::Instrumentation::Gateway::User.new(id)
|
71
71
|
::Datadog::AppSec::Instrumentation.gateway.push('identity.set_user', user)
|
72
72
|
end
|
@@ -78,9 +78,9 @@ module Datadog
|
|
78
78
|
private
|
79
79
|
|
80
80
|
def set_trace_and_span_context(method, trace = nil, span = nil)
|
81
|
-
if (
|
82
|
-
trace =
|
83
|
-
span =
|
81
|
+
if (appsec_context = Datadog::AppSec.active_context)
|
82
|
+
trace = appsec_context.trace
|
83
|
+
span = appsec_context.span
|
84
84
|
end
|
85
85
|
|
86
86
|
trace ||= Datadog::Tracing.active_trace
|