ddtrace 1.17.0 → 1.19.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 +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
|