ddtrace 1.17.0 → 1.19.0

Sign up to get free protection for your applications and to get access to all the features.
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