ddtrace 1.17.0 → 1.19.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 +85 -2
- data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +3 -0
- data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +67 -52
- data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.c +22 -14
- data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.h +4 -0
- data/ext/ddtrace_profiling_native_extension/collectors_gc_profiling_helper.c +156 -0
- data/ext/ddtrace_profiling_native_extension/collectors_gc_profiling_helper.h +5 -0
- data/ext/ddtrace_profiling_native_extension/collectors_stack.c +43 -102
- data/ext/ddtrace_profiling_native_extension/collectors_stack.h +10 -3
- data/ext/ddtrace_profiling_native_extension/collectors_thread_context.c +167 -125
- data/ext/ddtrace_profiling_native_extension/collectors_thread_context.h +2 -1
- data/ext/ddtrace_profiling_native_extension/extconf.rb +44 -10
- data/ext/ddtrace_profiling_native_extension/heap_recorder.c +970 -0
- data/ext/ddtrace_profiling_native_extension/heap_recorder.h +155 -0
- data/ext/ddtrace_profiling_native_extension/helpers.h +2 -0
- data/ext/ddtrace_profiling_native_extension/http_transport.c +5 -2
- data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.c +20 -0
- data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.h +11 -0
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +83 -18
- data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +6 -0
- data/ext/ddtrace_profiling_native_extension/profiling.c +2 -0
- data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +147 -0
- data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +28 -0
- data/ext/ddtrace_profiling_native_extension/stack_recorder.c +330 -13
- data/ext/ddtrace_profiling_native_extension/stack_recorder.h +3 -0
- data/lib/datadog/appsec/component.rb +4 -1
- data/lib/datadog/appsec/configuration/settings.rb +4 -0
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +2 -0
- data/lib/datadog/appsec/processor/rule_loader.rb +60 -0
- data/lib/datadog/appsec/remote.rb +12 -9
- data/lib/datadog/core/configuration/settings.rb +139 -22
- data/lib/datadog/core/configuration.rb +4 -0
- data/lib/datadog/core/remote/worker.rb +1 -0
- data/lib/datadog/core/telemetry/collector.rb +10 -0
- data/lib/datadog/core/telemetry/event.rb +2 -1
- data/lib/datadog/core/telemetry/ext.rb +3 -0
- data/lib/datadog/core/telemetry/v1/app_event.rb +8 -1
- data/lib/datadog/core/telemetry/v1/install_signature.rb +38 -0
- data/lib/datadog/core/workers/async.rb +1 -0
- data/lib/datadog/kit/enable_core_dumps.rb +5 -6
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +7 -11
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
- data/lib/datadog/profiling/component.rb +210 -18
- data/lib/datadog/profiling/scheduler.rb +4 -6
- data/lib/datadog/profiling/stack_recorder.rb +13 -2
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +4 -0
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +2 -1
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +24 -0
- data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +0 -2
- data/lib/datadog/tracing/workers.rb +1 -0
- data/lib/ddtrace/version.rb +1 -1
- metadata +11 -6
@@ -7,7 +7,7 @@ module Datadog
|
|
7
7
|
# Passing in a `nil` tracer is supported and will disable the following profiling features:
|
8
8
|
# * Code Hotspots panel in the trace viewer, as well as scoping a profile down to a span
|
9
9
|
# * Endpoint aggregation in the profiler UX, including normalization (resource per endpoint call)
|
10
|
-
def self.build_profiler_component(settings:, agent_settings:, optional_tracer:)
|
10
|
+
def self.build_profiler_component(settings:, agent_settings:, optional_tracer:) # rubocop:disable Metrics/MethodLength
|
11
11
|
require_relative '../profiling/diagnostics/environment_logger'
|
12
12
|
|
13
13
|
Profiling::Diagnostics::EnvironmentLogger.collect_and_log!
|
@@ -41,38 +41,57 @@ module Datadog
|
|
41
41
|
|
42
42
|
no_signals_workaround_enabled = no_signals_workaround_enabled?(settings)
|
43
43
|
timeline_enabled = settings.profiling.advanced.experimental_timeline_enabled
|
44
|
+
allocation_sample_every = get_allocation_sample_every(settings)
|
45
|
+
allocation_profiling_enabled = enable_allocation_profiling?(settings, allocation_sample_every)
|
46
|
+
heap_sample_every = get_heap_sample_every(settings)
|
47
|
+
heap_profiling_enabled = enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_every)
|
48
|
+
heap_size_profiling_enabled = enable_heap_size_profiling?(settings, heap_profiling_enabled)
|
49
|
+
|
50
|
+
overhead_target_percentage = valid_overhead_target(settings.profiling.advanced.overhead_target_percentage)
|
51
|
+
upload_period_seconds = [60, settings.profiling.advanced.upload_period_seconds].max
|
44
52
|
|
45
53
|
recorder = Datadog::Profiling::StackRecorder.new(
|
46
54
|
cpu_time_enabled: RUBY_PLATFORM.include?('linux'), # Only supported on Linux currently
|
47
|
-
alloc_samples_enabled:
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
max_frames: settings.profiling.advanced.max_frames,
|
52
|
-
tracer: optional_tracer,
|
53
|
-
endpoint_collection_enabled: settings.profiling.advanced.endpoint.collection.enabled,
|
55
|
+
alloc_samples_enabled: allocation_profiling_enabled,
|
56
|
+
heap_samples_enabled: heap_profiling_enabled,
|
57
|
+
heap_size_enabled: heap_size_profiling_enabled,
|
58
|
+
heap_sample_every: heap_sample_every,
|
54
59
|
timeline_enabled: timeline_enabled,
|
55
60
|
)
|
61
|
+
thread_context_collector = build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
|
56
62
|
worker = Datadog::Profiling::Collectors::CpuAndWallTimeWorker.new(
|
57
63
|
gc_profiling_enabled: enable_gc_profiling?(settings),
|
58
|
-
allocation_counting_enabled: settings.profiling.advanced.allocation_counting_enabled,
|
59
64
|
no_signals_workaround_enabled: no_signals_workaround_enabled,
|
60
65
|
thread_context_collector: thread_context_collector,
|
61
|
-
|
66
|
+
dynamic_sampling_rate_overhead_target_percentage: overhead_target_percentage,
|
67
|
+
allocation_sample_every: allocation_sample_every,
|
68
|
+
allocation_profiling_enabled: allocation_profiling_enabled,
|
62
69
|
)
|
63
70
|
|
64
71
|
internal_metadata = {
|
65
72
|
no_signals_workaround_enabled: no_signals_workaround_enabled,
|
66
73
|
timeline_enabled: timeline_enabled,
|
74
|
+
allocation_sample_every: allocation_sample_every,
|
75
|
+
heap_sample_every: heap_sample_every,
|
67
76
|
}.freeze
|
68
77
|
|
69
78
|
exporter = build_profiler_exporter(settings, recorder, internal_metadata: internal_metadata)
|
70
79
|
transport = build_profiler_transport(settings, agent_settings)
|
71
|
-
scheduler = Profiling::Scheduler.new(exporter: exporter, transport: transport)
|
80
|
+
scheduler = Profiling::Scheduler.new(exporter: exporter, transport: transport, interval: upload_period_seconds)
|
72
81
|
|
73
82
|
Profiling::Profiler.new(worker: worker, scheduler: scheduler)
|
74
83
|
end
|
75
84
|
|
85
|
+
private_class_method def self.build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
|
86
|
+
Datadog::Profiling::Collectors::ThreadContext.new(
|
87
|
+
recorder: recorder,
|
88
|
+
max_frames: settings.profiling.advanced.max_frames,
|
89
|
+
tracer: optional_tracer,
|
90
|
+
endpoint_collection_enabled: settings.profiling.advanced.endpoint.collection.enabled,
|
91
|
+
timeline_enabled: timeline_enabled,
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
76
95
|
private_class_method def self.build_profiler_exporter(settings, recorder, internal_metadata:)
|
77
96
|
code_provenance_collector =
|
78
97
|
(Profiling::Collectors::CodeProvenance.new if settings.profiling.advanced.code_provenance_enabled)
|
@@ -110,6 +129,126 @@ module Datadog
|
|
110
129
|
end
|
111
130
|
end
|
112
131
|
|
132
|
+
private_class_method def self.get_allocation_sample_every(settings)
|
133
|
+
allocation_sample_rate = settings.profiling.advanced.experimental_allocation_sample_rate
|
134
|
+
|
135
|
+
if allocation_sample_rate <= 0
|
136
|
+
raise ArgumentError, "Allocation sample rate must be a positive integer. Was #{allocation_sample_rate}"
|
137
|
+
end
|
138
|
+
|
139
|
+
allocation_sample_rate
|
140
|
+
end
|
141
|
+
|
142
|
+
private_class_method def self.get_heap_sample_every(settings)
|
143
|
+
heap_sample_rate = settings.profiling.advanced.experimental_heap_sample_rate
|
144
|
+
|
145
|
+
raise ArgumentError, "Heap sample rate must be a positive integer. Was #{heap_sample_rate}" if heap_sample_rate <= 0
|
146
|
+
|
147
|
+
heap_sample_rate
|
148
|
+
end
|
149
|
+
|
150
|
+
private_class_method def self.enable_allocation_profiling?(settings, allocation_sample_every)
|
151
|
+
unless settings.profiling.advanced.experimental_allocation_enabled
|
152
|
+
# Allocation profiling disabled, short-circuit out
|
153
|
+
return false
|
154
|
+
end
|
155
|
+
|
156
|
+
# Allocation sampling is safe and supported on Ruby 2.x, but has a few caveats on Ruby 3.x.
|
157
|
+
|
158
|
+
# SEVERE - All configurations
|
159
|
+
# Ruby 3.2.0 to 3.2.2 have a bug in the newobj tracepoint (https://bugs.ruby-lang.org/issues/19482,
|
160
|
+
# https://github.com/ruby/ruby/pull/7464) that makes this crash in any configuration. This bug is
|
161
|
+
# fixed on Ruby versions 3.2.3 and 3.3.0.
|
162
|
+
if RUBY_VERSION.start_with?('3.2.') && RUBY_VERSION < '3.2.3'
|
163
|
+
Datadog.logger.warn(
|
164
|
+
'Allocation profiling is not supported in Ruby versions 3.2.0, 3.2.1 and 3.2.2 and will be forcibly '\
|
165
|
+
'disabled. This is due to a VM bug that can lead to crashes (https://bugs.ruby-lang.org/issues/19482). '\
|
166
|
+
'Other Ruby versions do not suffer from this issue.'
|
167
|
+
)
|
168
|
+
return false
|
169
|
+
end
|
170
|
+
|
171
|
+
# SEVERE - Only with Ractors
|
172
|
+
# On Ruby versions 3.0 (all), 3.1.0 to 3.1.3, and 3.2.0 to 3.2.2 allocation profiling can trigger a VM bug
|
173
|
+
# that causes a segmentation fault during garbage collection of Ractors
|
174
|
+
# (https://bugs.ruby-lang.org/issues/18464). We don't recommend using this feature on such Rubies.
|
175
|
+
# This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0.
|
176
|
+
if RUBY_VERSION.start_with?('3.0.') ||
|
177
|
+
(RUBY_VERSION.start_with?('3.1.') && RUBY_VERSION < '3.1.4') ||
|
178
|
+
(RUBY_VERSION.start_with?('3.2.') && RUBY_VERSION < '3.2.3')
|
179
|
+
Datadog.logger.warn(
|
180
|
+
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling allocation profiling while using "\
|
181
|
+
'Ractors may cause unexpected issues, including crashes (https://bugs.ruby-lang.org/issues/18464). '\
|
182
|
+
'This does not happen if Ractors are not used.'
|
183
|
+
)
|
184
|
+
# ANNOYANCE - Only with Ractors
|
185
|
+
# On all known versions of Ruby 3.x, due to https://bugs.ruby-lang.org/issues/19112, when a ractor gets
|
186
|
+
# garbage collected, Ruby will disable all active tracepoints, which this feature internally relies on.
|
187
|
+
elsif RUBY_VERSION.start_with?('3.')
|
188
|
+
Datadog.logger.warn(
|
189
|
+
'In all known versions of Ruby 3.x, using Ractors may result in allocation profiling unexpectedly ' \
|
190
|
+
'stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your ' \
|
191
|
+
'application stability or performance. This does not happen if Ractors are not used.'
|
192
|
+
)
|
193
|
+
end
|
194
|
+
|
195
|
+
Datadog.logger.warn(
|
196
|
+
"Enabled experimental allocation profiling: allocation_sample_rate=#{allocation_sample_every}. This is " \
|
197
|
+
'experimental, not recommended, and will increase overhead!'
|
198
|
+
)
|
199
|
+
|
200
|
+
true
|
201
|
+
end
|
202
|
+
|
203
|
+
private_class_method def self.enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_rate)
|
204
|
+
heap_profiling_enabled = settings.profiling.advanced.experimental_heap_enabled
|
205
|
+
|
206
|
+
return false unless heap_profiling_enabled
|
207
|
+
|
208
|
+
if RUBY_VERSION.start_with?('2.') && RUBY_VERSION < '2.7'
|
209
|
+
Datadog.logger.warn(
|
210
|
+
'Heap profiling currently relies on features introduced in Ruby 2.7 and will be forcibly disabled. '\
|
211
|
+
'Please upgrade to Ruby >= 2.7 in order to use this feature.'
|
212
|
+
)
|
213
|
+
return false
|
214
|
+
end
|
215
|
+
|
216
|
+
if RUBY_VERSION < '3.1'
|
217
|
+
Datadog.logger.debug(
|
218
|
+
"Current Ruby version (#{RUBY_VERSION}) supports forced object recycling which has a bug that the " \
|
219
|
+
'heap profiler is forced to work around to remain accurate. This workaround requires force-setting '\
|
220
|
+
"the SEEN_OBJ_ID flag on objects that should have it but don't. Full details can be found in " \
|
221
|
+
'https://github.com/DataDog/dd-trace-rb/pull/3360. This workaround should be safe but can be ' \
|
222
|
+
'bypassed by disabling the heap profiler or upgrading to Ruby >= 3.1 where forced object recycling ' \
|
223
|
+
'was completely removed (https://bugs.ruby-lang.org/issues/18290).'
|
224
|
+
)
|
225
|
+
end
|
226
|
+
|
227
|
+
unless allocation_profiling_enabled
|
228
|
+
raise ArgumentError,
|
229
|
+
'Heap profiling requires allocation profiling to be enabled'
|
230
|
+
end
|
231
|
+
|
232
|
+
Datadog.logger.warn(
|
233
|
+
"Enabled experimental heap profiling: heap_sample_rate=#{heap_sample_rate}. This is experimental, not " \
|
234
|
+
'recommended, and will increase overhead!'
|
235
|
+
)
|
236
|
+
|
237
|
+
true
|
238
|
+
end
|
239
|
+
|
240
|
+
private_class_method def self.enable_heap_size_profiling?(settings, heap_profiling_enabled)
|
241
|
+
heap_size_profiling_enabled = settings.profiling.advanced.experimental_heap_size_enabled
|
242
|
+
|
243
|
+
return false unless heap_profiling_enabled && heap_size_profiling_enabled
|
244
|
+
|
245
|
+
Datadog.logger.warn(
|
246
|
+
'Enabled experimental heap size profiling. This is experimental, not recommended, and will increase overhead!'
|
247
|
+
)
|
248
|
+
|
249
|
+
true
|
250
|
+
end
|
251
|
+
|
113
252
|
private_class_method def self.no_signals_workaround_enabled?(settings) # rubocop:disable Metrics/MethodLength
|
114
253
|
setting_value = settings.profiling.advanced.no_signals_workaround_enabled
|
115
254
|
legacy_ruby_that_should_use_workaround = RUBY_VERSION.start_with?('2.3.', '2.4.', '2.5.')
|
@@ -171,12 +310,11 @@ module Datadog
|
|
171
310
|
return true
|
172
311
|
end
|
173
312
|
|
174
|
-
if defined?(::PhusionPassenger)
|
313
|
+
if (defined?(::PhusionPassenger) || Gem.loaded_specs['passenger']) && incompatible_passenger_version?
|
175
314
|
Datadog.logger.warn(
|
176
|
-
'Enabling the profiling "no signals" workaround because the passenger
|
177
|
-
'
|
178
|
-
'
|
179
|
-
'Profiling data will have lower quality.'
|
315
|
+
'Enabling the profiling "no signals" workaround because an incompatible version of the passenger gem is ' \
|
316
|
+
'installed. Profiling data will have lower quality.' \
|
317
|
+
'To fix this, upgrade the passenger gem to version 6.0.19 or above.'
|
180
318
|
)
|
181
319
|
return true
|
182
320
|
end
|
@@ -218,9 +356,12 @@ module Datadog
|
|
218
356
|
|
219
357
|
return true unless mysql2_client_class && mysql2_client_class.respond_to?(:info)
|
220
358
|
|
221
|
-
|
359
|
+
info = mysql2_client_class.info
|
360
|
+
libmysqlclient_version = Gem::Version.new(info[:version])
|
222
361
|
|
223
|
-
compatible =
|
362
|
+
compatible =
|
363
|
+
libmysqlclient_version >= Gem::Version.new('8.0.0') ||
|
364
|
+
looks_like_mariadb?(info, libmysqlclient_version)
|
224
365
|
|
225
366
|
Datadog.logger.debug(
|
226
367
|
"The `mysql2` gem is using #{compatible ? 'a compatible' : 'an incompatible'} version of " \
|
@@ -237,6 +378,57 @@ module Datadog
|
|
237
378
|
true
|
238
379
|
end
|
239
380
|
end
|
381
|
+
|
382
|
+
# See https://github.com/datadog/dd-trace-rb/issues/2976 for details.
|
383
|
+
private_class_method def self.incompatible_passenger_version?
|
384
|
+
if Gem.loaded_specs['passenger']
|
385
|
+
Gem.loaded_specs['passenger'].version < Gem::Version.new('6.0.19')
|
386
|
+
else
|
387
|
+
true
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
private_class_method def self.valid_overhead_target(overhead_target_percentage)
|
392
|
+
if overhead_target_percentage > 0 && overhead_target_percentage <= 20
|
393
|
+
overhead_target_percentage
|
394
|
+
else
|
395
|
+
Datadog.logger.error(
|
396
|
+
'Ignoring invalid value for profiling overhead_target_percentage setting: ' \
|
397
|
+
"#{overhead_target_percentage.inspect}. Falling back to default value."
|
398
|
+
)
|
399
|
+
|
400
|
+
2.0
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
# To add just a bit more complexity to our detection code, in https://github.com/DataDog/dd-trace-rb/issues/3334
|
405
|
+
# a user reported that our code was incorrectly flagging the mariadb variant of libmysqlclient as being
|
406
|
+
# incompatible. In fact we have no reports of the mariadb variant needing the "no signals" workaround,
|
407
|
+
# so we flag it as compatible when it's in use.
|
408
|
+
#
|
409
|
+
# A problem is that there doesn't seem to be an obvious way to query the mysql2 gem on which kind of
|
410
|
+
# libmysqlclient it's using, so we detect it by looking at the version.
|
411
|
+
#
|
412
|
+
# The info method for mysql2 with mariadb looks something like this:
|
413
|
+
# `{:id=>30308, :version=>"3.3.8", :header_version=>"11.2.2"}`
|
414
|
+
#
|
415
|
+
# * The version seems to come from https://github.com/mariadb-corporation/mariadb-connector-c and the latest
|
416
|
+
# one is 3.x.
|
417
|
+
# * The header_version is what people usually see as the "mariadb version"
|
418
|
+
#
|
419
|
+
# As a comparison, for libmysql the info looks like:
|
420
|
+
# * `{:id=>80035, :version=>"8.0.35", :header_version=>"8.0.35"}`
|
421
|
+
#
|
422
|
+
# Thus our detection is version 4 or older, because libmysqlclient 4 is almost 20 years old so it's most probably
|
423
|
+
# not that one + header_version being 10 or newer, since according to https://endoflife.date/mariadb that's a
|
424
|
+
# sane range for modern mariadb releases.
|
425
|
+
private_class_method def self.looks_like_mariadb?(info, libmysqlclient_version)
|
426
|
+
header_version = Gem::Version.new(info[:header_version]) if info[:header_version]
|
427
|
+
|
428
|
+
!!(header_version &&
|
429
|
+
libmysqlclient_version < Gem::Version.new('5.0.0') &&
|
430
|
+
header_version >= Gem::Version.new('10.0.0'))
|
431
|
+
end
|
240
432
|
end
|
241
433
|
end
|
242
434
|
end
|
@@ -5,12 +5,11 @@ require_relative '../core/workers/polling'
|
|
5
5
|
|
6
6
|
module Datadog
|
7
7
|
module Profiling
|
8
|
-
# Periodically (every
|
8
|
+
# Periodically (every interval, 60 seconds by default) takes a profile from the `Exporter` and reports it using the
|
9
9
|
# configured transport. Runs on its own background thread.
|
10
10
|
class Scheduler < Core::Worker
|
11
11
|
include Core::Workers::Polling
|
12
12
|
|
13
|
-
DEFAULT_INTERVAL_SECONDS = 60
|
14
13
|
MINIMUM_INTERVAL_SECONDS = 0
|
15
14
|
|
16
15
|
# We sleep for at most this duration seconds before reporting data to avoid multi-process applications all
|
@@ -28,8 +27,7 @@ module Datadog
|
|
28
27
|
def initialize(
|
29
28
|
exporter:,
|
30
29
|
transport:,
|
31
|
-
fork_policy: Core::Workers::Async::Thread::FORK_POLICY_RESTART, # Restart in forks by default
|
32
|
-
interval: DEFAULT_INTERVAL_SECONDS,
|
30
|
+
interval:, fork_policy: Core::Workers::Async::Thread::FORK_POLICY_RESTART, # Restart in forks by default, # seconds
|
33
31
|
enabled: true
|
34
32
|
)
|
35
33
|
@exporter = exporter
|
@@ -115,8 +113,8 @@ module Datadog
|
|
115
113
|
#
|
116
114
|
# During PR review (https://github.com/DataDog/dd-trace-rb/pull/1807) we discussed the possible alternative of
|
117
115
|
# just sleeping before starting the scheduler loop. We ended up not going with that option to avoid the first
|
118
|
-
# profile containing up to
|
119
|
-
# usual
|
116
|
+
# profile containing up to interval + DEFAULT_FLUSH_JITTER_MAXIMUM_SECONDS instead of the
|
117
|
+
# usual interval seconds.
|
120
118
|
if run_loop?
|
121
119
|
jitter_seconds = rand * DEFAULT_FLUSH_JITTER_MAXIMUM_SECONDS # floating point number between (0.0...maximum)
|
122
120
|
sleep(jitter_seconds)
|
@@ -4,7 +4,10 @@ module Datadog
|
|
4
4
|
# Note that `record_sample` is only accessible from native code.
|
5
5
|
# Methods prefixed with _native_ are implemented in `stack_recorder.c`
|
6
6
|
class StackRecorder
|
7
|
-
def initialize(
|
7
|
+
def initialize(
|
8
|
+
cpu_time_enabled:, alloc_samples_enabled:, heap_samples_enabled:, heap_size_enabled:,
|
9
|
+
heap_sample_every:, timeline_enabled:
|
10
|
+
)
|
8
11
|
# This mutex works in addition to the fancy C-level mutexes we have in the native side (see the docs there).
|
9
12
|
# It prevents multiple Ruby threads calling serialize at the same time -- something like
|
10
13
|
# `10.times { Thread.new { stack_recorder.serialize } }`.
|
@@ -13,7 +16,15 @@ module Datadog
|
|
13
16
|
# accidentally happening.
|
14
17
|
@no_concurrent_synchronize_mutex = Mutex.new
|
15
18
|
|
16
|
-
self.class._native_initialize(
|
19
|
+
self.class._native_initialize(
|
20
|
+
self,
|
21
|
+
cpu_time_enabled,
|
22
|
+
alloc_samples_enabled,
|
23
|
+
heap_samples_enabled,
|
24
|
+
heap_size_enabled,
|
25
|
+
heap_sample_every,
|
26
|
+
timeline_enabled,
|
27
|
+
)
|
17
28
|
end
|
18
29
|
|
19
30
|
def serialize
|
@@ -21,8 +21,9 @@ module Datadog
|
|
21
21
|
module InstanceMethods
|
22
22
|
def query(sql, options = {})
|
23
23
|
service = Datadog.configuration_for(self, :service_name) || datadog_configuration[:service_name]
|
24
|
+
on_error = Datadog.configuration_for(self, :on_error) || datadog_configuration[:on_error]
|
24
25
|
|
25
|
-
Tracing.trace(Ext::SPAN_QUERY, service: service) do |span, trace_op|
|
26
|
+
Tracing.trace(Ext::SPAN_QUERY, service: service, on_error: on_error) do |span, trace_op|
|
26
27
|
span.resource = sql
|
27
28
|
span.span_type = Tracing::Metadata::Ext::SQL::TYPE
|
28
29
|
|
@@ -25,6 +25,11 @@ module Datadog
|
|
25
25
|
o.default false
|
26
26
|
end
|
27
27
|
|
28
|
+
option :error_handler do |o|
|
29
|
+
o.type :proc
|
30
|
+
o.default_proc(&Tracing::SpanOperation::Events::DEFAULT_ON_ERROR)
|
31
|
+
end
|
32
|
+
|
28
33
|
option :analytics_sample_rate do |o|
|
29
34
|
o.type :float
|
30
35
|
o.env Ext::ENV_ANALYTICS_SAMPLE_RATE
|
@@ -21,18 +21,24 @@ module Datadog
|
|
21
21
|
# PG::Connection patch methods
|
22
22
|
module InstanceMethods
|
23
23
|
def exec(sql, *args, &block)
|
24
|
+
return super unless enabled?
|
25
|
+
|
24
26
|
trace(Ext::SPAN_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block|
|
25
27
|
super(sql_statement, *args, &wrapped_block)
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
31
|
def exec_params(sql, params, *args, &block)
|
32
|
+
return super unless enabled?
|
33
|
+
|
30
34
|
trace(Ext::SPAN_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block|
|
31
35
|
super(sql_statement, params, *args, &wrapped_block)
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
35
39
|
def exec_prepared(statement_name, params, *args, &block)
|
40
|
+
return super unless enabled?
|
41
|
+
|
36
42
|
trace(Ext::SPAN_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block|
|
37
43
|
super(statement_name, params, *args, &wrapped_block)
|
38
44
|
end
|
@@ -40,6 +46,8 @@ module Datadog
|
|
40
46
|
|
41
47
|
# async_exec is an alias to exec
|
42
48
|
def async_exec(sql, *args, &block)
|
49
|
+
return super unless enabled?
|
50
|
+
|
43
51
|
trace(Ext::SPAN_ASYNC_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block|
|
44
52
|
super(sql_statement, *args, &wrapped_block)
|
45
53
|
end
|
@@ -47,6 +55,8 @@ module Datadog
|
|
47
55
|
|
48
56
|
# async_exec_params is an alias to exec_params
|
49
57
|
def async_exec_params(sql, params, *args, &block)
|
58
|
+
return super unless enabled?
|
59
|
+
|
50
60
|
trace(Ext::SPAN_ASYNC_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block|
|
51
61
|
super(sql_statement, params, *args, &wrapped_block)
|
52
62
|
end
|
@@ -54,24 +64,32 @@ module Datadog
|
|
54
64
|
|
55
65
|
# async_exec_prepared is an alias to exec_prepared
|
56
66
|
def async_exec_prepared(statement_name, params, *args, &block)
|
67
|
+
return super unless enabled?
|
68
|
+
|
57
69
|
trace(Ext::SPAN_ASYNC_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block|
|
58
70
|
super(statement_name, params, *args, &wrapped_block)
|
59
71
|
end
|
60
72
|
end
|
61
73
|
|
62
74
|
def sync_exec(sql, *args, &block)
|
75
|
+
return super unless enabled?
|
76
|
+
|
63
77
|
trace(Ext::SPAN_SYNC_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block|
|
64
78
|
super(sql_statement, *args, &wrapped_block)
|
65
79
|
end
|
66
80
|
end
|
67
81
|
|
68
82
|
def sync_exec_params(sql, params, *args, &block)
|
83
|
+
return super unless enabled?
|
84
|
+
|
69
85
|
trace(Ext::SPAN_SYNC_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block|
|
70
86
|
super(sql_statement, params, *args, &wrapped_block)
|
71
87
|
end
|
72
88
|
end
|
73
89
|
|
74
90
|
def sync_exec_prepared(statement_name, params, *args, &block)
|
91
|
+
return super unless enabled?
|
92
|
+
|
75
93
|
trace(Ext::SPAN_SYNC_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block|
|
76
94
|
super(statement_name, params, *args, &wrapped_block)
|
77
95
|
end
|
@@ -81,10 +99,12 @@ module Datadog
|
|
81
99
|
|
82
100
|
def trace(name, sql: nil, statement_name: nil, block: nil)
|
83
101
|
service = Datadog.configuration_for(self, :service_name) || datadog_configuration[:service_name]
|
102
|
+
error_handler = datadog_configuration[:error_handler]
|
84
103
|
resource = statement_name || sql
|
85
104
|
|
86
105
|
Tracing.trace(
|
87
106
|
name,
|
107
|
+
on_error: error_handler,
|
88
108
|
service: service,
|
89
109
|
resource: resource,
|
90
110
|
type: Tracing::Metadata::Ext::SQL::TYPE
|
@@ -172,6 +192,10 @@ module Datadog
|
|
172
192
|
def comment_propagation
|
173
193
|
datadog_configuration[:comment_propagation]
|
174
194
|
end
|
195
|
+
|
196
|
+
def enabled?
|
197
|
+
datadog_configuration[:enabled]
|
198
|
+
end
|
175
199
|
end
|
176
200
|
end
|
177
201
|
end
|
@@ -69,6 +69,7 @@ module Datadog
|
|
69
69
|
Datadog.logger.debug { "Starting thread for: #{self}" }
|
70
70
|
@worker = Thread.new { perform }
|
71
71
|
@worker.name = self.class.name unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3')
|
72
|
+
@worker.thread_variable_set(:fork_safe, true)
|
72
73
|
|
73
74
|
nil
|
74
75
|
end
|
data/lib/ddtrace/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ddtrace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.19.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Datadog, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 3.
|
33
|
+
version: 3.3.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 3.
|
40
|
+
version: 3.3.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: libddwaf
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.
|
75
|
+
version: 0.6.0
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.
|
82
|
+
version: 0.6.0
|
83
83
|
description: |
|
84
84
|
ddtrace is Datadog's tracing client for Ruby. It is used to trace requests
|
85
85
|
as they flow across web servers, databases and microservices so that developers
|
@@ -110,6 +110,8 @@ files:
|
|
110
110
|
- ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c
|
111
111
|
- ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.c
|
112
112
|
- ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.h
|
113
|
+
- ext/ddtrace_profiling_native_extension/collectors_gc_profiling_helper.c
|
114
|
+
- ext/ddtrace_profiling_native_extension/collectors_gc_profiling_helper.h
|
113
115
|
- ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.c
|
114
116
|
- ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.h
|
115
117
|
- ext/ddtrace_profiling_native_extension/collectors_stack.c
|
@@ -117,6 +119,8 @@ files:
|
|
117
119
|
- ext/ddtrace_profiling_native_extension/collectors_thread_context.c
|
118
120
|
- ext/ddtrace_profiling_native_extension/collectors_thread_context.h
|
119
121
|
- ext/ddtrace_profiling_native_extension/extconf.rb
|
122
|
+
- ext/ddtrace_profiling_native_extension/heap_recorder.c
|
123
|
+
- ext/ddtrace_profiling_native_extension/heap_recorder.h
|
120
124
|
- ext/ddtrace_profiling_native_extension/helpers.h
|
121
125
|
- ext/ddtrace_profiling_native_extension/http_transport.c
|
122
126
|
- ext/ddtrace_profiling_native_extension/libdatadog_helpers.c
|
@@ -301,6 +305,7 @@ files:
|
|
301
305
|
- lib/datadog/core/telemetry/v1/configuration.rb
|
302
306
|
- lib/datadog/core/telemetry/v1/dependency.rb
|
303
307
|
- lib/datadog/core/telemetry/v1/host.rb
|
308
|
+
- lib/datadog/core/telemetry/v1/install_signature.rb
|
304
309
|
- lib/datadog/core/telemetry/v1/integration.rb
|
305
310
|
- lib/datadog/core/telemetry/v1/product.rb
|
306
311
|
- lib/datadog/core/telemetry/v1/telemetry_request.rb
|