datadog 2.30.0 → 2.31.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 +44 -1
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +18 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +2 -0
- data/ext/libdatadog_api/crashtracker.c +5 -8
- data/ext/libdatadog_api/datadog_ruby_common.c +18 -0
- data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
- data/ext/libdatadog_api/di.c +79 -0
- data/ext/libdatadog_api/extconf.rb +2 -0
- data/ext/libdatadog_api/init.c +5 -2
- data/ext/libdatadog_extconf_helpers.rb +9 -1
- data/lib/datadog/ai_guard/component.rb +2 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +41 -3
- data/lib/datadog/ai_guard/evaluation/content_builder.rb +31 -0
- data/lib/datadog/ai_guard/evaluation/content_part.rb +36 -0
- data/lib/datadog/ai_guard/evaluation/no_op_result.rb +3 -1
- data/lib/datadog/ai_guard/evaluation/request.rb +14 -9
- data/lib/datadog/ai_guard/evaluation/result.rb +3 -1
- data/lib/datadog/ai_guard/evaluation.rb +36 -7
- data/lib/datadog/ai_guard.rb +26 -8
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +11 -7
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +6 -7
- data/lib/datadog/appsec/contrib/rails/patcher.rb +2 -2
- data/lib/datadog/appsec/instrumentation/gateway.rb +0 -13
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +2 -0
- data/lib/datadog/appsec/utils/http/media_type.rb +1 -2
- data/lib/datadog/appsec/utils/http/url_encoded.rb +2 -2
- data/lib/datadog/appsec.rb +5 -9
- data/lib/datadog/core/configuration/base.rb +17 -5
- data/lib/datadog/core/configuration/components.rb +21 -8
- data/lib/datadog/core/configuration/config_helper.rb +9 -0
- data/lib/datadog/core/configuration/option.rb +30 -5
- data/lib/datadog/core/configuration/option_definition.rb +38 -12
- data/lib/datadog/core/configuration/options.rb +40 -6
- data/lib/datadog/core/configuration/settings.rb +15 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +1 -0
- data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
- data/lib/datadog/core/contrib/rails/utils.rb +7 -3
- data/lib/datadog/core/crashtracking/component.rb +3 -3
- data/lib/datadog/core/environment/container.rb +2 -2
- data/lib/datadog/core/environment/ext.rb +1 -0
- data/lib/datadog/core/environment/identity.rb +25 -3
- data/lib/datadog/core/environment/process.rb +12 -0
- data/lib/datadog/core/metrics/client.rb +5 -5
- data/lib/datadog/core/remote/component.rb +38 -21
- data/lib/datadog/core/runtime/metrics.rb +1 -1
- data/lib/datadog/core/telemetry/component.rb +3 -0
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +2 -3
- data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +151 -169
- data/lib/datadog/core/telemetry/event.rb +1 -7
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -0
- data/lib/datadog/core/telemetry/worker.rb +20 -0
- data/lib/datadog/core/utils/only_once.rb +1 -1
- data/lib/datadog/core/utils/spawn_monkey_patch.rb +36 -0
- data/lib/datadog/core/workers/async.rb +1 -1
- data/lib/datadog/core.rb +0 -1
- data/lib/datadog/data_streams/pathway_context.rb +1 -1
- data/lib/datadog/di/boot.rb +2 -4
- data/lib/datadog/di/component.rb +4 -0
- data/lib/datadog/di/instrumenter.rb +10 -4
- data/lib/datadog/di/probe_notification_builder.rb +109 -1
- data/lib/datadog/di/serializer.rb +1 -1
- data/lib/datadog/di.rb +81 -0
- data/lib/datadog/kit/enable_core_dumps.rb +1 -1
- data/lib/datadog/open_feature/evaluation_engine.rb +1 -1
- data/lib/datadog/open_feature/exposures/reporter.rb +1 -1
- data/lib/datadog/open_feature/exposures/worker.rb +1 -1
- data/lib/datadog/open_feature/remote.rb +1 -1
- data/lib/datadog/open_feature/transport.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +2 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +2 -3
- 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/component.rb +11 -1
- data/lib/datadog/profiling/load_native_extension.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +0 -4
- data/lib/datadog/profiling/scheduler.rb +2 -2
- data/lib/datadog/profiling/tasks/exec.rb +2 -2
- data/lib/datadog/profiling/tasks/setup.rb +2 -2
- data/lib/datadog/profiling.rb +1 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/tracing/buffer.rb +3 -3
- data/lib/datadog/tracing/component.rb +11 -0
- data/lib/datadog/tracing/configuration/settings.rb +2 -1
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +20 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +3 -1
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/configurable.rb +18 -3
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +5 -5
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/patcher.rb +0 -1
- data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
- data/lib/datadog/tracing/contrib/rake/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +4 -0
- data/lib/datadog/tracing/contrib/stripe/request.rb +1 -1
- data/lib/datadog/tracing/distributed/datadog.rb +4 -2
- data/lib/datadog/tracing/event.rb +1 -1
- data/lib/datadog/tracing/remote.rb +1 -1
- data/lib/datadog/tracing/sampling/ext.rb +2 -0
- data/lib/datadog/tracing/sampling/priority_sampler.rb +13 -0
- data/lib/datadog/tracing/sampling/rule.rb +1 -1
- data/lib/datadog/tracing/sampling/rule_sampler.rb +54 -25
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +1 -1
- data/lib/datadog/tracing/span_operation.rb +1 -1
- data/lib/datadog/tracing/trace_operation.rb +50 -6
- data/lib/datadog/tracing/tracer.rb +25 -0
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/transport/trace_formatter.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- metadata +13 -7
|
@@ -79,7 +79,7 @@ module Datadog
|
|
|
79
79
|
},
|
|
80
80
|
return: {
|
|
81
81
|
arguments: return_arguments,
|
|
82
|
-
throwable: nil,
|
|
82
|
+
throwable: context.exception ? serialize_throwable(context.exception) : nil,
|
|
83
83
|
},
|
|
84
84
|
}
|
|
85
85
|
elsif probe.line?
|
|
@@ -153,6 +153,114 @@ module Datadog
|
|
|
153
153
|
|
|
154
154
|
private
|
|
155
155
|
|
|
156
|
+
# Serializes an exception for the throwable field in snapshot captures.
|
|
157
|
+
#
|
|
158
|
+
# Uses the C extension's exception_message to get the original message
|
|
159
|
+
# without invoking any Ruby-level message method override, which
|
|
160
|
+
# could be customer code.
|
|
161
|
+
#
|
|
162
|
+
# Caveats:
|
|
163
|
+
#
|
|
164
|
+
# 1. The value returned by exception_message is not guaranteed to be
|
|
165
|
+
# a string — it is whatever was passed to the Exception constructor.
|
|
166
|
+
# Calling .to_s on an arbitrary object would invoke customer code,
|
|
167
|
+
# violating DI's constraint of never executing customer methods
|
|
168
|
+
# during instrumentation. We only use the value directly when it
|
|
169
|
+
# is a String; for non-string values we return a redacted
|
|
170
|
+
# placeholder (reporting the class name would duplicate the
|
|
171
|
+
# exception type already present in the :type field).
|
|
172
|
+
#
|
|
173
|
+
# 2. Custom exception classes may not store a meaningful message via
|
|
174
|
+
# the constructor (e.g. they may compute it in an overridden
|
|
175
|
+
# +message+ method). In such cases exception_message may return
|
|
176
|
+
# nil or an unrelated constructor argument. This is acceptable:
|
|
177
|
+
# we still report the exception type, and a missing/wrong message
|
|
178
|
+
# is better than invoking customer code or reporting nothing.
|
|
179
|
+
#
|
|
180
|
+
# @param exception [Exception] the exception to serialize
|
|
181
|
+
# @return [Hash{Symbol => String?}] hash with :type and :message keys
|
|
182
|
+
def serialize_throwable(exception)
|
|
183
|
+
msg = DI.exception_message(exception)
|
|
184
|
+
message = if msg.nil? || String === msg
|
|
185
|
+
msg
|
|
186
|
+
else
|
|
187
|
+
# Non-string constructor argument — return a redacted placeholder
|
|
188
|
+
# rather than calling .to_s which could be customer code.
|
|
189
|
+
# The exception class is already reported via the :type field.
|
|
190
|
+
'<REDACTED: not a string value>'
|
|
191
|
+
end
|
|
192
|
+
# Prefer backtrace_locations (structured Location objects) over
|
|
193
|
+
# backtrace (formatted strings that need regex parsing).
|
|
194
|
+
#
|
|
195
|
+
# However, backtrace_locations returns nil when someone has called
|
|
196
|
+
# Exception#set_backtrace with Array<String> — the VM cannot
|
|
197
|
+
# reconstruct Location objects from formatted strings. This happens
|
|
198
|
+
# in exception wrapping patterns (catch, create new exception, copy
|
|
199
|
+
# original's string backtrace via set_backtrace, re-raise).
|
|
200
|
+
# In that case, fall back to backtrace strings.
|
|
201
|
+
#
|
|
202
|
+
# Both accessors use the UnboundMethod trick to bypass subclass
|
|
203
|
+
# overrides, consistent with the rest of this method.
|
|
204
|
+
#
|
|
205
|
+
# If a subclass overrides #backtrace, MRI's raise never stores
|
|
206
|
+
# the real backtrace — both backtrace_locations and backtrace
|
|
207
|
+
# return nil, and stacktrace is [].
|
|
208
|
+
# This is unrecoverable without calling customer code.
|
|
209
|
+
# See DI::EXCEPTION_BACKTRACE comment for details.
|
|
210
|
+
locations = DI::EXCEPTION_BACKTRACE_LOCATIONS.bind(exception).call
|
|
211
|
+
stacktrace = if locations
|
|
212
|
+
format_backtrace_locations(locations)
|
|
213
|
+
else
|
|
214
|
+
format_backtrace_strings(DI::EXCEPTION_BACKTRACE.bind(exception).call)
|
|
215
|
+
end
|
|
216
|
+
{
|
|
217
|
+
type: exception.class.name,
|
|
218
|
+
message: message,
|
|
219
|
+
stacktrace: stacktrace,
|
|
220
|
+
}
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Matches Ruby backtrace frame format: "/path/file.rb:42:in `method_name'"
|
|
224
|
+
# Captures: $1 = file path, $2 = line number, $3 = method name
|
|
225
|
+
BACKTRACE_FRAME_PATTERN = /\A(.+):(\d+):in\s+[`'](.+)'\z/
|
|
226
|
+
|
|
227
|
+
# Converts backtrace locations into the stack frame format
|
|
228
|
+
# expected by the Datadog UI.
|
|
229
|
+
#
|
|
230
|
+
# Uses Thread::Backtrace::Location objects which provide structured
|
|
231
|
+
# path/lineno/label directly, avoiding the round-trip of formatting
|
|
232
|
+
# to strings and regex-parsing back.
|
|
233
|
+
#
|
|
234
|
+
# @param locations [Array<Thread::Backtrace::Location>]
|
|
235
|
+
# @return [Array<Hash>]
|
|
236
|
+
def format_backtrace_locations(locations)
|
|
237
|
+
locations.map do |loc|
|
|
238
|
+
{fileName: loc.path, function: loc.label, lineNumber: loc.lineno}
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Parses Ruby backtrace strings into the stack frame format
|
|
243
|
+
# expected by the Datadog UI.
|
|
244
|
+
#
|
|
245
|
+
# Fallback for when backtrace_locations returns nil (see
|
|
246
|
+
# serialize_throwable for details on when this happens).
|
|
247
|
+
#
|
|
248
|
+
# Ruby backtrace format: "/path/file.rb:42:in `method_name'"
|
|
249
|
+
#
|
|
250
|
+
# @param backtrace [Array<String>, nil] from Exception#backtrace
|
|
251
|
+
# @return [Array<Hash>]
|
|
252
|
+
def format_backtrace_strings(backtrace)
|
|
253
|
+
return [] if backtrace.nil?
|
|
254
|
+
|
|
255
|
+
backtrace.map do |frame|
|
|
256
|
+
if frame =~ BACKTRACE_FRAME_PATTERN
|
|
257
|
+
{fileName: $1, function: $3, lineNumber: $2.to_i}
|
|
258
|
+
else
|
|
259
|
+
{fileName: frame, function: '', lineNumber: 0}
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
156
264
|
def build_snapshot_base(context, evaluation_errors: [], captures: nil, message: nil)
|
|
157
265
|
probe = context.probe
|
|
158
266
|
|
|
@@ -186,7 +186,7 @@ module Datadog
|
|
|
186
186
|
# surface errors so they can fix their serializers) or they may be defined
|
|
187
187
|
# internally by dd-trace-rb (in which case we need to fix them). We use
|
|
188
188
|
# WARN level to surface these errors in either case.
|
|
189
|
-
Datadog.logger.warn("DI: Custom serializer condition failed: #{e.class}: #{e
|
|
189
|
+
Datadog.logger.warn("DI: Custom serializer condition failed: #{e.class}: #{e}")
|
|
190
190
|
telemetry&.report(e, description: "Custom serializer condition failed")
|
|
191
191
|
next
|
|
192
192
|
end
|
data/lib/datadog/di.rb
CHANGED
|
@@ -11,11 +11,92 @@ module Datadog
|
|
|
11
11
|
module DI
|
|
12
12
|
INSTRUMENTED_COUNTERS_LOCK = Mutex.new
|
|
13
13
|
|
|
14
|
+
# Captured at load time from Exception itself (not a subclass).
|
|
15
|
+
# Used to bypass subclass overrides of backtrace_locations.
|
|
16
|
+
#
|
|
17
|
+
# This does NOT protect against monkeypatching Exception#backtrace_locations
|
|
18
|
+
# before dd-trace-rb loads — in that case we'd capture the monkeypatch.
|
|
19
|
+
# The practical threat model is customer subclasses overriding the method:
|
|
20
|
+
#
|
|
21
|
+
# class MyError < StandardError
|
|
22
|
+
# def backtrace_locations; []; end
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# The UnboundMethod bypasses subclass overrides: bind(exception).call
|
|
26
|
+
# always dispatches to the original Exception implementation.
|
|
27
|
+
#
|
|
28
|
+
# Note: if the subclass overrides #backtrace (not #backtrace_locations),
|
|
29
|
+
# MRI's setup_exception skips storing the VM backtrace entirely — both
|
|
30
|
+
# @bt and @bt_locations stay nil. In that case this UnboundMethod also
|
|
31
|
+
# returns nil. See EXCEPTION_BACKTRACE comment for details.
|
|
32
|
+
EXCEPTION_BACKTRACE_LOCATIONS = Exception.instance_method(:backtrace_locations)
|
|
33
|
+
|
|
34
|
+
# Same UnboundMethod trick for Exception#backtrace (Array<String>).
|
|
35
|
+
# Used as a fallback when backtrace_locations returns nil — which happens
|
|
36
|
+
# when someone calls Exception#set_backtrace with an Array<String>.
|
|
37
|
+
#
|
|
38
|
+
# set_backtrace accepts Array<String> or nil. When called with strings,
|
|
39
|
+
# it replaces the VM-level backtrace: backtrace returns the new strings,
|
|
40
|
+
# but backtrace_locations returns nil because the VM cannot reconstruct
|
|
41
|
+
# Location objects from formatted strings. This occurs in exception
|
|
42
|
+
# wrapping patterns where a library catches an exception, creates a new
|
|
43
|
+
# one, and copies the original's string backtrace onto it via
|
|
44
|
+
# set_backtrace before re-raising.
|
|
45
|
+
#
|
|
46
|
+
# Ruby 3.4+ also allows set_backtrace(Array<Location>), which preserves
|
|
47
|
+
# backtrace_locations — but older Rubies and most existing code use
|
|
48
|
+
# the string form.
|
|
49
|
+
#
|
|
50
|
+
# Like EXCEPTION_BACKTRACE_LOCATIONS, this UnboundMethod bypasses
|
|
51
|
+
# subclass overrides of #backtrace: bind(exception).call dispatches
|
|
52
|
+
# to Exception#backtrace regardless of what the subclass defines.
|
|
53
|
+
#
|
|
54
|
+
# However, when a subclass overrides #backtrace, MRI's setup_exception
|
|
55
|
+
# (eval.c) calls the override via rb_get_backtrace during raise. If it
|
|
56
|
+
# gets a non-nil result, it skips storing the VM backtrace in @bt and
|
|
57
|
+
# @bt_locations entirely. So the UnboundMethod bypasses the override
|
|
58
|
+
# at dispatch but reads nil from @bt because the data was never stored.
|
|
59
|
+
#
|
|
60
|
+
# This constant is used as a fallback when backtrace_locations returns
|
|
61
|
+
# nil. In the common set_backtrace-with-strings case, no subclass
|
|
62
|
+
# override is involved and the fallback works. The only unrecoverable
|
|
63
|
+
# case: a subclass overrides #backtrace, the exception is raised
|
|
64
|
+
# normally, and set_backtrace is never called. Both @bt and
|
|
65
|
+
# @bt_locations are nil — DI reports an empty stacktrace (type and
|
|
66
|
+
# message are still reported).
|
|
67
|
+
EXCEPTION_BACKTRACE = Exception.instance_method(:backtrace)
|
|
68
|
+
|
|
14
69
|
class << self
|
|
15
70
|
def enabled?
|
|
16
71
|
Datadog.configuration.dynamic_instrumentation.enabled
|
|
17
72
|
end
|
|
18
73
|
|
|
74
|
+
# Returns iseqs that correspond to loaded files (filtering out eval'd code).
|
|
75
|
+
#
|
|
76
|
+
# There are several types of iseqs returned by +all_iseqs+:
|
|
77
|
+
#
|
|
78
|
+
# 1. Eval'd code — these have a nil +absolute_path+ and are filtered out here.
|
|
79
|
+
# 2. Whole-file iseqs — have +absolute_path+ set and +first_lineno+ of 0.
|
|
80
|
+
# Only available for a subset of loaded files (the full-file iseq may be
|
|
81
|
+
# garbage collected after loading completes). Easiest to work with since
|
|
82
|
+
# we just match the file path to the probe specification.
|
|
83
|
+
# 3. Per-method iseqs — have +absolute_path+ set and +first_lineno+ > 0.
|
|
84
|
+
# Often the only iseqs available for third-party code. Require identifying
|
|
85
|
+
# the correct iseq containing the target line, which may involve examining
|
|
86
|
+
# the iseq's +trace_points+ since +define_method+ can create nested,
|
|
87
|
+
# non-contiguous line ranges.
|
|
88
|
+
#
|
|
89
|
+
# Note: the same line of code can appear in multiple iseqs (e.g. when
|
|
90
|
+
# +define_method+ is used inside a method). DI treats this as an error
|
|
91
|
+
# since a probe must resolve to exactly one code location.
|
|
92
|
+
#
|
|
93
|
+
# @return [Array<RubyVM::InstructionSequence>] iseqs with non-nil +absolute_path+
|
|
94
|
+
def file_iseqs
|
|
95
|
+
all_iseqs.select do |iseq|
|
|
96
|
+
iseq.absolute_path
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
19
100
|
# This method is called from DI Remote handler to issue DI operations
|
|
20
101
|
# to the probe manager (add or remove probes).
|
|
21
102
|
#
|
|
@@ -30,7 +30,7 @@ module Datadog
|
|
|
30
30
|
Process.setrlimit(:CORE, maximum_size)
|
|
31
31
|
rescue => e
|
|
32
32
|
Kernel.warn(
|
|
33
|
-
"[datadog] Failed to enable core dumps. Cause: #{e.class
|
|
33
|
+
"[datadog] Failed to enable core dumps. Cause: #{e.class}: #{e} " \
|
|
34
34
|
"Location: #{Array(e.backtrace).first}"
|
|
35
35
|
)
|
|
36
36
|
return
|
|
@@ -60,7 +60,7 @@ module Datadog
|
|
|
60
60
|
rescue => e
|
|
61
61
|
message = 'OpenFeature: Failed to reconfigure, reverting to the previous configuration'
|
|
62
62
|
|
|
63
|
-
@logger.error("#{message}, #{e.class}: #{e
|
|
63
|
+
@logger.error("#{message}, #{e.class}: #{e}")
|
|
64
64
|
@telemetry.report(e, description: "#{message} (#{e.class})")
|
|
65
65
|
|
|
66
66
|
raise ReconfigurationError, e.message
|
|
@@ -29,7 +29,7 @@ module Datadog
|
|
|
29
29
|
event = Event.build(result, flag_key: flag_key, context: context)
|
|
30
30
|
@worker.enqueue(event)
|
|
31
31
|
rescue => e
|
|
32
|
-
@logger.debug { "OpenFeature: Failed to report resolution details: #{e.class}: #{e
|
|
32
|
+
@logger.debug { "OpenFeature: Failed to report resolution details: #{e.class}: #{e}" }
|
|
33
33
|
@telemetry.report(e, description: 'OpenFeature: Failed to report resolution details')
|
|
34
34
|
|
|
35
35
|
false
|
|
@@ -105,7 +105,7 @@ module Datadog
|
|
|
105
105
|
|
|
106
106
|
response
|
|
107
107
|
rescue => e
|
|
108
|
-
@logger.debug { "OpenFeature: Failed to flush resolution details events: #{e.class}: #{e
|
|
108
|
+
@logger.debug { "OpenFeature: Failed to flush resolution details events: #{e.class}: #{e}" }
|
|
109
109
|
@telemetry.report(e, description: 'OpenFeature: Failed to flush resolution details events')
|
|
110
110
|
|
|
111
111
|
nil
|
|
@@ -41,7 +41,7 @@ module Datadog
|
|
|
41
41
|
engine.reconfigure!(read_content(content))
|
|
42
42
|
content.applied
|
|
43
43
|
rescue EvaluationEngine::ReconfigurationError => e
|
|
44
|
-
content.errored("Error applying OpenFeature configuration: #{e.
|
|
44
|
+
content.errored("Error applying OpenFeature configuration: #{e.class}: #{e}")
|
|
45
45
|
end
|
|
46
46
|
when :delete
|
|
47
47
|
# NOTE: For now, we treat deletion as clearing the configuration
|
|
@@ -55,7 +55,7 @@ module Datadog
|
|
|
55
55
|
@api.call(env)
|
|
56
56
|
end
|
|
57
57
|
rescue => e
|
|
58
|
-
message = "Internal error during request. Cause: #{e.class
|
|
58
|
+
message = "Internal error during request. Cause: #{e.class}: #{e} " \
|
|
59
59
|
"Location: #{Array(e.backtrace).first}"
|
|
60
60
|
@logger.debug(message)
|
|
61
61
|
|
|
@@ -76,6 +76,7 @@ module Datadog
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
option :headers do |o|
|
|
79
|
+
o.skip_telemetry true
|
|
79
80
|
o.type :hash
|
|
80
81
|
o.env 'OTEL_EXPORTER_OTLP_HEADERS'
|
|
81
82
|
o.default { {} }
|
|
@@ -131,6 +132,7 @@ module Datadog
|
|
|
131
132
|
end
|
|
132
133
|
|
|
133
134
|
option :headers do |o|
|
|
135
|
+
o.skip_telemetry true
|
|
134
136
|
o.type :hash, nilable: true
|
|
135
137
|
o.env 'OTEL_EXPORTER_OTLP_METRICS_HEADERS'
|
|
136
138
|
o.default nil
|
|
@@ -135,7 +135,7 @@ module Datadog
|
|
|
135
135
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
136
136
|
Datadog.logger.debug(
|
|
137
137
|
"CodeProvenance#bundler_bin_path failed. " \
|
|
138
|
-
"Cause: #{e.class
|
|
138
|
+
"Cause: #{e.class}: #{e} Location: #{Array(e.backtrace).first}"
|
|
139
139
|
)
|
|
140
140
|
nil
|
|
141
141
|
end
|
|
@@ -161,8 +161,7 @@ module Datadog
|
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
def to_json(arg = nil)
|
|
164
|
-
|
|
165
|
-
{kind: @kind, name: @name, version: @version, paths: @paths}.to_json(arg) # steep:ignore ArgumentTypeMismatch
|
|
164
|
+
{kind: @kind, name: @name, version: @version, paths: @paths}.to_json(arg)
|
|
166
165
|
end
|
|
167
166
|
|
|
168
167
|
def path
|
|
@@ -93,7 +93,7 @@ module Datadog
|
|
|
93
93
|
operation_name = self.class._native_failure_exception_during_operation(self).inspect
|
|
94
94
|
Datadog.logger.warn(
|
|
95
95
|
"CpuAndWallTimeWorker thread error. " \
|
|
96
|
-
"Operation: #{operation_name} Cause: #{e.class
|
|
96
|
+
"Operation: #{operation_name} Cause: #{e.class}: #{e} Location: #{Array(e.backtrace).first}"
|
|
97
97
|
)
|
|
98
98
|
on_failure_proc&.call
|
|
99
99
|
Datadog::Core::Telemetry::Logger.report(e, description: "CpuAndWallTimeWorker thread error: #{operation_name}")
|
|
@@ -39,7 +39,7 @@ module Datadog
|
|
|
39
39
|
@failure_exception = e
|
|
40
40
|
Datadog.logger.warn(
|
|
41
41
|
"IdleSamplingHelper thread error. " \
|
|
42
|
-
"Cause: #{e.class
|
|
42
|
+
"Cause: #{e.class}: #{e} Location: #{Array(e.backtrace).first}"
|
|
43
43
|
)
|
|
44
44
|
Datadog::Core::Telemetry::Logger.report(e, description: "IdleSamplingHelper thread error")
|
|
45
45
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../core/telemetry/logger"
|
|
4
|
+
|
|
3
5
|
module Datadog
|
|
4
6
|
module Profiling
|
|
5
7
|
# Responsible for wiring up the Profiler for execution
|
|
@@ -90,6 +92,14 @@ module Datadog
|
|
|
90
92
|
end
|
|
91
93
|
|
|
92
94
|
[profiler, {profiling_enabled: true}]
|
|
95
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
96
|
+
logger.warn do
|
|
97
|
+
"Failed to initialize profiling: #{e.class}: #{e} " \
|
|
98
|
+
"Location: #{Array(e.backtrace).first}"
|
|
99
|
+
end
|
|
100
|
+
Datadog::Core::Telemetry::Logger.report(e, description: "Failed to initialize profiling")
|
|
101
|
+
|
|
102
|
+
[nil, {profiling_enabled: false}]
|
|
93
103
|
end
|
|
94
104
|
|
|
95
105
|
private_class_method def self.build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
|
|
@@ -368,7 +378,7 @@ module Datadog
|
|
|
368
378
|
rescue StandardError, LoadError => e
|
|
369
379
|
logger.warn(
|
|
370
380
|
"Failed to probe `mysql2` gem information. " \
|
|
371
|
-
"Cause: #{e.class
|
|
381
|
+
"Cause: #{e.class}: #{e} Location: #{Array(e.backtrace).first}"
|
|
372
382
|
)
|
|
373
383
|
|
|
374
384
|
true
|
|
@@ -4,6 +4,6 @@ begin
|
|
|
4
4
|
require "datadog_profiling_native_extension.#{RUBY_VERSION}_#{RUBY_PLATFORM}"
|
|
5
5
|
rescue LoadError => e
|
|
6
6
|
raise LoadError,
|
|
7
|
-
"Failed to load the profiling
|
|
7
|
+
"Failed to load the profiling native extension. To fix this, please remove and then reinstall datadog " \
|
|
8
8
|
"(Details: #{e.message})"
|
|
9
9
|
end
|
|
@@ -65,7 +65,7 @@ module Datadog
|
|
|
65
65
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
66
66
|
Datadog.logger.warn(
|
|
67
67
|
"Profiling::Scheduler thread error. " \
|
|
68
|
-
"Cause: #{e.class
|
|
68
|
+
"Cause: #{e.class}: #{e} Location: #{Array(e.backtrace).first}"
|
|
69
69
|
)
|
|
70
70
|
on_failure_proc&.call
|
|
71
71
|
Datadog::Core::Telemetry::Logger.report(e, description: "Profiling::Scheduler thread error")
|
|
@@ -136,7 +136,7 @@ module Datadog
|
|
|
136
136
|
transport.export(flush)
|
|
137
137
|
rescue => e
|
|
138
138
|
Datadog.logger.warn(
|
|
139
|
-
"Unable to report profile. Cause: #{e.class
|
|
139
|
+
"Unable to report profile. Cause: #{e.class}: #{e} Location: #{Array(e.backtrace).first}"
|
|
140
140
|
)
|
|
141
141
|
Datadog::Core::Telemetry::Logger.report(e, description: "Unable to report profile")
|
|
142
142
|
end
|
|
@@ -38,10 +38,10 @@ module Datadog
|
|
|
38
38
|
def exec_with_error_handling(args)
|
|
39
39
|
Kernel.exec(*args)
|
|
40
40
|
rescue Errno::ENOENT => e
|
|
41
|
-
Kernel.warn "ddprofrb exec failed: #{e.class
|
|
41
|
+
Kernel.warn "ddprofrb exec failed: #{e.class}: #{e} (command was '#{args.join(" ")}')"
|
|
42
42
|
Kernel.exit 127
|
|
43
43
|
rescue Errno::EACCES, Errno::ENOEXEC => e
|
|
44
|
-
Kernel.warn "ddprofrb exec failed: #{e.class
|
|
44
|
+
Kernel.warn "ddprofrb exec failed: #{e.class}: #{e} (command was '#{args.join(" ")}')"
|
|
45
45
|
Kernel.exit 126
|
|
46
46
|
end
|
|
47
47
|
end
|
|
@@ -16,7 +16,7 @@ module Datadog
|
|
|
16
16
|
setup_at_fork_hooks
|
|
17
17
|
rescue StandardError, ScriptError => e
|
|
18
18
|
Datadog.logger.warn do
|
|
19
|
-
"Profiler extensions unavailable. Cause: #{e.class
|
|
19
|
+
"Profiler extensions unavailable. Cause: #{e.class}: #{e} " \
|
|
20
20
|
"Location: #{Array(e.backtrace).first}"
|
|
21
21
|
end
|
|
22
22
|
Datadog::Core::Telemetry::Logger.report(e, description: "Profiler extensions unavailable")
|
|
@@ -31,7 +31,7 @@ module Datadog
|
|
|
31
31
|
Profiling.start_if_enabled
|
|
32
32
|
rescue => e
|
|
33
33
|
Datadog.logger.warn do
|
|
34
|
-
"Error during post-fork hooks. Cause: #{e.class
|
|
34
|
+
"Error during post-fork hooks. Cause: #{e.class}: #{e} " \
|
|
35
35
|
"Location: #{Array(e.backtrace).first}"
|
|
36
36
|
end
|
|
37
37
|
Datadog::Core::Telemetry::Logger.report(e, description: "Error during post-fork hooks")
|
data/lib/datadog/profiling.rb
CHANGED
|
@@ -17,5 +17,5 @@ begin
|
|
|
17
17
|
require_relative 'auto_instrument'
|
|
18
18
|
Datadog::SingleStepInstrument.const_set(:LOADED, true)
|
|
19
19
|
rescue StandardError, LoadError => e
|
|
20
|
-
warn "Single step instrumentation failed: #{e.class}
|
|
20
|
+
warn "Single step instrumentation failed: #{e.class}: #{e}\n\tSource:\n\t#{Array(e.backtrace).join("\n\t")}"
|
|
21
21
|
end
|
|
@@ -56,7 +56,7 @@ module Datadog
|
|
|
56
56
|
@buffer_spans += trace.length
|
|
57
57
|
rescue => e
|
|
58
58
|
Datadog.logger.debug(
|
|
59
|
-
"Failed to measure queue accept. Cause: #{e.class
|
|
59
|
+
"Failed to measure queue accept. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
60
60
|
)
|
|
61
61
|
end
|
|
62
62
|
|
|
@@ -66,7 +66,7 @@ module Datadog
|
|
|
66
66
|
@buffer_spans -= trace.length
|
|
67
67
|
rescue => e
|
|
68
68
|
Datadog.logger.debug(
|
|
69
|
-
"Failed to measure queue drop. Cause: #{e.class
|
|
69
|
+
"Failed to measure queue drop. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
70
70
|
)
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -91,7 +91,7 @@ module Datadog
|
|
|
91
91
|
@buffer_spans = 0
|
|
92
92
|
rescue => e
|
|
93
93
|
Datadog.logger.debug(
|
|
94
|
-
"Failed to measure queue. Cause: #{e.class
|
|
94
|
+
"Failed to measure queue. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
95
95
|
)
|
|
96
96
|
end
|
|
97
97
|
end
|
|
@@ -161,6 +161,17 @@ module Datadog
|
|
|
161
161
|
@sampler.sample!(trace)
|
|
162
162
|
end
|
|
163
163
|
|
|
164
|
+
def reconsider_sample_resource!(trace)
|
|
165
|
+
return unless @sampler.respond_to?(:reconsider_sample_resource!)
|
|
166
|
+
|
|
167
|
+
@sampler.reconsider_sample_resource!(trace)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def resource_sampling?
|
|
171
|
+
@sampler.respond_to?(:resource_sampling?) &&
|
|
172
|
+
@sampler.resource_sampling?
|
|
173
|
+
end
|
|
174
|
+
|
|
164
175
|
def update(*args, **kwargs)
|
|
165
176
|
return unless @sampler.respond_to?(:update)
|
|
166
177
|
|
|
@@ -430,7 +430,7 @@ module Datadog
|
|
|
430
430
|
rescue => e
|
|
431
431
|
# `File#read` errors have clear and actionable messages, no need to add extra exception info.
|
|
432
432
|
Datadog.logger.warn(
|
|
433
|
-
"Cannot read span sampling rules file `#{rules_file}`: #{e.
|
|
433
|
+
"Cannot read span sampling rules file `#{rules_file}`: #{e.class}: #{e}." \
|
|
434
434
|
'No span sampling rules will be applied.'
|
|
435
435
|
)
|
|
436
436
|
nil
|
|
@@ -481,6 +481,7 @@ module Datadog
|
|
|
481
481
|
# @default `{}`
|
|
482
482
|
# @return [Hash]
|
|
483
483
|
option :writer_options do |o|
|
|
484
|
+
o.skip_telemetry true
|
|
484
485
|
o.type :hash
|
|
485
486
|
o.default({})
|
|
486
487
|
end
|
|
@@ -43,7 +43,7 @@ module Datadog
|
|
|
43
43
|
span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
|
|
44
44
|
span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_CONTROLLER)
|
|
45
45
|
rescue => e
|
|
46
|
-
Datadog.logger.error(e.
|
|
46
|
+
Datadog.logger.error("#{e.class}: #{e}")
|
|
47
47
|
Datadog::Core::Telemetry::Logger.report(e)
|
|
48
48
|
end
|
|
49
49
|
|
|
@@ -88,7 +88,7 @@ module Datadog
|
|
|
88
88
|
span.finish
|
|
89
89
|
end
|
|
90
90
|
rescue => e
|
|
91
|
-
Datadog.logger.error(e.
|
|
91
|
+
Datadog.logger.error("#{e.class}: #{e}")
|
|
92
92
|
Datadog::Core::Telemetry::Logger.report(e)
|
|
93
93
|
end
|
|
94
94
|
|
|
@@ -76,6 +76,26 @@ module Datadog
|
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
|
+
|
|
80
|
+
# Since Rails 8.1, `Router#find_routes` was removed by inlining its body into `recognize`.
|
|
81
|
+
# https://github.com/rails/rails/commit/e533a32ddf06668dfa3dfbe9b665607e235b06ac
|
|
82
|
+
module RecognizeRouter
|
|
83
|
+
def recognize(req)
|
|
84
|
+
# recognize modifies SCRIPT_NAME before yielding; capture it before super.
|
|
85
|
+
original_script_name = req.env[SCRIPT_NAME_KEY]
|
|
86
|
+
|
|
87
|
+
super do |route, parameters|
|
|
88
|
+
if Instrumentation.dispatcher_route?(route)
|
|
89
|
+
http_route = route.path.spec.to_s
|
|
90
|
+
http_route = http_route.delete_suffix(FORMAT_SUFFIX)
|
|
91
|
+
|
|
92
|
+
Instrumentation.set_http_route_tags(http_route, original_script_name)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
yield route, parameters
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
79
99
|
end
|
|
80
100
|
end
|
|
81
101
|
end
|
|
@@ -19,7 +19,9 @@ module Datadog
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def patch
|
|
22
|
-
if ::ActionPack.gem_version >= Gem::Version.new('
|
|
22
|
+
if ::ActionPack.gem_version >= Gem::Version.new('8.1')
|
|
23
|
+
::ActionDispatch::Journey::Router.prepend(ActionDispatch::Instrumentation::Journey::RecognizeRouter)
|
|
24
|
+
elsif ::ActionPack.gem_version >= Gem::Version.new('7.1')
|
|
23
25
|
::ActionDispatch::Journey::Router.prepend(ActionDispatch::Instrumentation::Journey::LazyRouter)
|
|
24
26
|
else
|
|
25
27
|
::ActionDispatch::Journey::Router.prepend(ActionDispatch::Instrumentation::Journey::Router)
|