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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +85 -2
  3. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +3 -0
  4. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +67 -52
  5. data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.c +22 -14
  6. data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.h +4 -0
  7. data/ext/ddtrace_profiling_native_extension/collectors_gc_profiling_helper.c +156 -0
  8. data/ext/ddtrace_profiling_native_extension/collectors_gc_profiling_helper.h +5 -0
  9. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +43 -102
  10. data/ext/ddtrace_profiling_native_extension/collectors_stack.h +10 -3
  11. data/ext/ddtrace_profiling_native_extension/collectors_thread_context.c +167 -125
  12. data/ext/ddtrace_profiling_native_extension/collectors_thread_context.h +2 -1
  13. data/ext/ddtrace_profiling_native_extension/extconf.rb +44 -10
  14. data/ext/ddtrace_profiling_native_extension/heap_recorder.c +970 -0
  15. data/ext/ddtrace_profiling_native_extension/heap_recorder.h +155 -0
  16. data/ext/ddtrace_profiling_native_extension/helpers.h +2 -0
  17. data/ext/ddtrace_profiling_native_extension/http_transport.c +5 -2
  18. data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.c +20 -0
  19. data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.h +11 -0
  20. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +83 -18
  21. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +6 -0
  22. data/ext/ddtrace_profiling_native_extension/profiling.c +2 -0
  23. data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +147 -0
  24. data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +28 -0
  25. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +330 -13
  26. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +3 -0
  27. data/lib/datadog/appsec/component.rb +4 -1
  28. data/lib/datadog/appsec/configuration/settings.rb +4 -0
  29. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +2 -0
  30. data/lib/datadog/appsec/processor/rule_loader.rb +60 -0
  31. data/lib/datadog/appsec/remote.rb +12 -9
  32. data/lib/datadog/core/configuration/settings.rb +139 -22
  33. data/lib/datadog/core/configuration.rb +4 -0
  34. data/lib/datadog/core/remote/worker.rb +1 -0
  35. data/lib/datadog/core/telemetry/collector.rb +10 -0
  36. data/lib/datadog/core/telemetry/event.rb +2 -1
  37. data/lib/datadog/core/telemetry/ext.rb +3 -0
  38. data/lib/datadog/core/telemetry/v1/app_event.rb +8 -1
  39. data/lib/datadog/core/telemetry/v1/install_signature.rb +38 -0
  40. data/lib/datadog/core/workers/async.rb +1 -0
  41. data/lib/datadog/kit/enable_core_dumps.rb +5 -6
  42. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +7 -11
  43. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
  44. data/lib/datadog/profiling/component.rb +210 -18
  45. data/lib/datadog/profiling/scheduler.rb +4 -6
  46. data/lib/datadog/profiling/stack_recorder.rb +13 -2
  47. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +4 -0
  48. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +2 -1
  49. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
  50. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +24 -0
  51. data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +0 -2
  52. data/lib/datadog/tracing/workers.rb +1 -0
  53. data/lib/ddtrace/version.rb +1 -1
  54. 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: false, # Always disabled for now -- work in progress
48
- )
49
- thread_context_collector = Datadog::Profiling::Collectors::ThreadContext.new(
50
- recorder: recorder,
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
- allocation_sample_every: 0,
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 web server is in use. ' \
177
- 'This is needed because passenger is currently incompatible with the normal working mode ' \
178
- 'of the profiler, as detailed in <https://github.com/DataDog/dd-trace-rb/issues/2976>. ' \
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
- libmysqlclient_version = Gem::Version.new(mysql2_client_class.info[:version])
359
+ info = mysql2_client_class.info
360
+ libmysqlclient_version = Gem::Version.new(info[:version])
222
361
 
223
- compatible = libmysqlclient_version >= Gem::Version.new('8.0.0')
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 DEFAULT_INTERVAL_SECONDS) takes a profile from the `Exporter` and reports it using the
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 DEFAULT_INTERVAL_SECONDS + DEFAULT_FLUSH_JITTER_MAXIMUM_SECONDS instead of the
119
- # usual DEFAULT_INTERVAL_SECONDS size.
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(cpu_time_enabled:, alloc_samples_enabled:)
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(self, cpu_time_enabled, alloc_samples_enabled)
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
@@ -50,6 +50,10 @@ module Datadog
50
50
  o.type :string, nilable: true
51
51
  o.env Ext::ENV_PEER_SERVICE
52
52
  end
53
+
54
+ option :on_error do |o|
55
+ o.type :proc, nilable: true
56
+ end
53
57
  end
54
58
  end
55
59
  end
@@ -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
@@ -1,5 +1,3 @@
1
- require_relative '../auto_instrument'
2
-
3
1
  # Railtie to include AutoInstrumentation in rails loading
4
2
  class DatadogAutoInstrumentRailtie < Rails::Railtie
5
3
  # we want to load before config initializers so that any user supplied config
@@ -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
@@ -3,7 +3,7 @@
3
3
  module DDTrace
4
4
  module VERSION
5
5
  MAJOR = 1
6
- MINOR = 17
6
+ MINOR = 19
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
  BUILD = nil
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.17.0
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: 2023-11-22 00:00:00.000000000 Z
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.2.2
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.2.2
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.4.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.4.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