datadog 2.44.0 → 2.46.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -2
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +114 -141
  4. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -5
  5. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +0 -2
  6. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +13 -13
  7. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.h +5 -1
  8. data/ext/datadog_profiling_native_extension/collectors_stack.c +1 -0
  9. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +106 -103
  10. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +3 -3
  11. data/ext/datadog_profiling_native_extension/extconf.rb +2 -0
  12. data/ext/datadog_profiling_native_extension/heap_recorder.c +2 -2
  13. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +102 -54
  14. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +7 -2
  15. data/ext/datadog_profiling_native_extension/profiling.c +27 -23
  16. data/ext/datadog_profiling_native_extension/ruby_helpers.c +3 -1
  17. data/ext/datadog_profiling_native_extension/ruby_helpers.h +4 -0
  18. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +0 -2
  19. data/ext/datadog_profiling_native_extension/stack_recorder.c +6 -24
  20. data/ext/datadog_profiling_native_extension/stack_recorder.h +0 -1
  21. data/ext/datadog_profiling_native_extension/time_helpers.c +2 -4
  22. data/ext/datadog_profiling_native_extension/time_helpers.h +10 -11
  23. data/ext/libdatadog_api/di.c +30 -5
  24. data/ext/libdatadog_api/extconf.rb +2 -0
  25. data/ext/libdatadog_api/otel_thread_context.c +20 -14
  26. data/ext/libdatadog_api/process_discovery.c +15 -1
  27. data/ext/libdatadog_api/trace_exporter.c +182 -36
  28. data/ext/libdatadog_extconf_helpers.rb +1 -1
  29. data/lib/datadog/core/configuration/components.rb +29 -8
  30. data/lib/datadog/core/configuration/supported_configurations.rb +5 -2
  31. data/lib/datadog/core/process_discovery.rb +5 -1
  32. data/lib/datadog/core/remote/client/capabilities.rb +34 -29
  33. data/lib/datadog/core/remote/component.rb +28 -12
  34. data/lib/datadog/core/remote/dispatcher.rb +13 -3
  35. data/lib/datadog/di/boot.rb +1 -0
  36. data/lib/datadog/di/capture_expression_evaluator/result.rb +30 -0
  37. data/lib/datadog/di/capture_expression_evaluator.rb +39 -9
  38. data/lib/datadog/di/component.rb +38 -3
  39. data/lib/datadog/di/configuration.rb +53 -2
  40. data/lib/datadog/di/context.rb +7 -2
  41. data/lib/datadog/di/contrib/active_record.rb +8 -2
  42. data/lib/datadog/di/evaluation_failure.rb +28 -0
  43. data/lib/datadog/di/guardrails_telemetry/reason.rb +87 -0
  44. data/lib/datadog/di/guardrails_telemetry.rb +203 -0
  45. data/lib/datadog/di/instrumenter.rb +65 -15
  46. data/lib/datadog/di/logger.rb +30 -8
  47. data/lib/datadog/di/probe_manager.rb +48 -5
  48. data/lib/datadog/di/probe_notification_builder.rb +28 -26
  49. data/lib/datadog/di/probe_notifier_worker.rb +56 -6
  50. data/lib/datadog/di/serializer.rb +130 -54
  51. data/lib/datadog/di/snapshot_event.rb +38 -0
  52. data/lib/datadog/di/transport/http.rb +13 -3
  53. data/lib/datadog/di/transport/input.rb +32 -7
  54. data/lib/datadog/open_feature/activation.rb +268 -0
  55. data/lib/datadog/open_feature/component.rb +31 -15
  56. data/lib/datadog/open_feature/provider.rb +282 -5
  57. data/lib/datadog/open_feature.rb +31 -1
  58. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +5 -0
  59. data/lib/datadog/profiling/component.rb +2 -3
  60. data/lib/datadog/profiling/exporter.rb +7 -5
  61. data/lib/datadog/tracing/component.rb +15 -1
  62. data/lib/datadog/tracing/configuration/settings.rb +6 -3
  63. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +6 -3
  64. data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -0
  65. data/lib/datadog/tracing/otel_thread_context.rb +3 -5
  66. data/lib/datadog/tracing/transport/http/telemetry.rb +94 -0
  67. data/lib/datadog/tracing/transport/http/traces.rb +2 -0
  68. data/lib/datadog/tracing/transport/native/telemetry.rb +17 -0
  69. data/lib/datadog/tracing/transport/native.rb +38 -22
  70. data/lib/datadog/tracing/transport/telemetry.rb +62 -0
  71. data/lib/datadog/tracing/transport/traces.rb +82 -15
  72. data/lib/datadog/version.rb +1 -1
  73. metadata +16 -7
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "ext"
4
+ require_relative "../open_feature"
4
5
  require_relative "../core/utils/time"
5
6
  require "open_feature/sdk"
6
7
 
7
8
  module Datadog
8
9
  module OpenFeature
9
- # OpenFeature feature flagging provider backed by Datadog Remote Configuration.
10
+ # OpenFeature feature flagging provider backed by Datadog configuration delivery.
10
11
  #
11
12
  # Requires openfeature-sdk >= 0.5.1 for flag evaluation metrics and EVP hook support.
12
13
  #
@@ -24,13 +25,14 @@ module Datadog
24
25
  #
25
26
  # Example:
26
27
  #
27
- # Make sure to enable Remote Configuration and OpenFeature in the Datadog configuration.
28
+ # Feature Flags use agentless configuration delivery by default. To use
29
+ # Remote Configuration delivery instead, configure the source explicitly.
28
30
  #
29
31
  # ```ruby
30
32
  # # FILE: initializers/datadog.rb
31
33
  # Datadog.configure do |config|
32
34
  # config.remote.enabled = true
33
- # config.open_feature.enabled = true
35
+ # config.feature_flags.configuration_source = "remote_config"
34
36
  # end
35
37
  # ```
36
38
  #
@@ -58,20 +60,110 @@ module Datadog
58
60
  # # => 'Welcome back!'
59
61
  # ```
60
62
  class Provider
63
+ include ::OpenFeature::SDK::Provider::EventEmitter
64
+
61
65
  NAME = "Datadog Feature Flagging Provider"
66
+ INITIALIZATION_CANCELLED_MESSAGE = "Feature Flags provider initialization was cancelled by shutdown"
62
67
 
63
68
  attr_reader :metadata
64
69
 
65
70
  def initialize
66
71
  @metadata = ::OpenFeature::SDK::Provider::ProviderMetadata.new(name: NAME).freeze
72
+ @initialization_mutex = Mutex.new
73
+ @initializing = false
74
+ @initialization_thread = nil
75
+ @awaiting_ready_after_fork = false
76
+ @initialization_failed = false
77
+ @provider_error_observed = false
78
+ @ready_pending = false
79
+ @ready_dispatch_claimed = false
80
+ @stale_emitted = false
81
+ @stale_pending = false
82
+ @error_handler = nil
83
+ @initialization_ready_handler = nil
84
+ @waiting_component = nil
85
+ @shutdown = false
67
86
  end
68
87
 
69
88
  def init
70
- # no-op
89
+ @initialization_mutex.synchronize do
90
+ raise INITIALIZATION_CANCELLED_MESSAGE if @shutdown
91
+
92
+ @initializing = true
93
+ @initialization_thread = Thread.current
94
+ @awaiting_ready_after_fork = false
95
+ @initialization_failed = false
96
+ @provider_error_observed = false
97
+ @ready_pending = false
98
+ @ready_dispatch_claimed = false
99
+ @stale_emitted = false
100
+ @stale_pending = false
101
+ end
102
+ ready_handler_installed = install_initialization_ready_handler
103
+
104
+ component, failure = OpenFeature.activate_provider(self)
105
+ cancel_initialization_if_shutdown!
106
+ fail_initialization(component, failure || "Feature Flags component could not be activated") unless component
107
+
108
+ @initialization_mutex.synchronize do
109
+ raise INITIALIZATION_CANCELLED_MESSAGE if @shutdown
110
+
111
+ @waiting_component = component
112
+ end
113
+ # Shutdown publishes this flag through the component lock; taking our mutex here would invert lock order.
114
+ wait_result = component.wait_for_configuration { @shutdown }
115
+ cancel_initialization_if_shutdown!
116
+
117
+ case wait_result
118
+ when Component::CONFIGURATION_READY
119
+ @initialization_mutex.synchronize { @initializing = false } unless ready_handler_installed
120
+ when Component::CONFIGURATION_TIMEOUT
121
+ message = "Feature Flags provider initialization timed out while waiting for configuration"
122
+ Datadog.logger.error(message)
123
+ fail_initialization(component, message)
124
+ else
125
+ fail_initialization(component, "Feature Flags provider initialization stopped before configuration arrived")
126
+ end
127
+ rescue
128
+ prepare_initialization_failure(component) if @initialization_mutex.synchronize { @initializing }
129
+ raise
130
+ ensure
131
+ @initialization_mutex.synchronize do
132
+ @waiting_component = nil
133
+ # The SDK still owes READY after init returns; the initializing thread owns that dispatch.
134
+ @initialization_thread = nil unless @initializing
135
+ end
71
136
  end
72
137
 
73
138
  def shutdown
74
- # no-op
139
+ configuration = @configuration
140
+ # @type var error_handler: Provider::provider_event_handler?
141
+ error_handler = nil
142
+ # @type var initialization_ready_handler: Provider::provider_event_handler?
143
+ initialization_ready_handler = nil
144
+ waiting_component = nil #: Component?
145
+ @initialization_mutex.synchronize do
146
+ return if @shutdown
147
+
148
+ @shutdown = true
149
+ @initializing = false
150
+ @initialization_thread = nil
151
+ error_handler = @error_handler
152
+ initialization_ready_handler = @initialization_ready_handler
153
+ waiting_component = @waiting_component
154
+ @error_handler = nil
155
+ @initialization_ready_handler = nil
156
+ end
157
+
158
+ waiting_component&.wake_configuration_waiters
159
+ configuration&.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_ERROR, error_handler) if error_handler
160
+ if initialization_ready_handler
161
+ configuration&.remove_handler(
162
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_READY,
163
+ initialization_ready_handler,
164
+ )
165
+ end
166
+ OpenFeature.deactivate_provider(self)
75
167
  end
76
168
 
77
169
  def hooks
@@ -108,6 +200,191 @@ module Datadog
108
200
 
109
201
  private
110
202
 
203
+ def after_fork(component)
204
+ handler = @initialization_mutex.synchronize do
205
+ return if @shutdown || !@initializing || @initialization_thread&.alive?
206
+
207
+ @initializing = false
208
+ @initialization_thread = nil
209
+ @waiting_component = nil
210
+ @awaiting_ready_after_fork = true
211
+ @stale_pending = false
212
+ previous_handler = @initialization_ready_handler
213
+ @initialization_ready_handler = nil
214
+ previous_handler
215
+ end
216
+ if handler
217
+ @configuration&.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler)
218
+ end
219
+ configuration_changed(Component::CONFIGURATION_READY) if component&.configuration_received?
220
+ end
221
+
222
+ def fail_initialization(component, message)
223
+ prepare_initialization_failure(component)
224
+ cancel_initialization_if_shutdown!
225
+ raise message.to_s
226
+ end
227
+
228
+ def prepare_initialization_failure(component)
229
+ cancelled, initialization_ready_handler = @initialization_mutex.synchronize do
230
+ handler = @initialization_ready_handler
231
+ @initialization_ready_handler = nil
232
+ @stale_pending = false
233
+ @initializing = false
234
+ @initialization_thread = nil
235
+ if @shutdown
236
+ [true, handler]
237
+ else
238
+ @initialization_failed = true
239
+ @ready_pending ||= !!component&.configuration_received?
240
+ [false, handler]
241
+ end
242
+ end
243
+ if initialization_ready_handler
244
+ @configuration&.remove_handler(
245
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_READY,
246
+ initialization_ready_handler,
247
+ )
248
+ end
249
+ return if cancelled
250
+
251
+ install_error_handler
252
+ end
253
+
254
+ def cancel_initialization_if_shutdown!
255
+ cancelled = @initialization_mutex.synchronize do
256
+ @initializing = false if @shutdown
257
+ @shutdown
258
+ end
259
+ raise INITIALIZATION_CANCELLED_MESSAGE if cancelled
260
+ end
261
+
262
+ def shutdown?
263
+ @initialization_mutex.synchronize { @shutdown }
264
+ end
265
+
266
+ def install_initialization_ready_handler
267
+ configuration = @configuration
268
+ return false unless configuration
269
+
270
+ handler = @initialization_mutex.synchronize do
271
+ return false if @shutdown
272
+ return true if @initialization_ready_handler
273
+
274
+ @initialization_ready_handler = ->(details) { provider_ready(details) }
275
+ end
276
+ configuration.add_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler)
277
+
278
+ cancelled = @initialization_mutex.synchronize { @shutdown }
279
+ configuration.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler) if cancelled
280
+ return false if cancelled
281
+
282
+ true
283
+ end
284
+
285
+ def install_error_handler
286
+ configuration = @configuration
287
+ return unless configuration
288
+
289
+ handler = @initialization_mutex.synchronize do
290
+ return if @shutdown
291
+
292
+ @error_handler ||= ->(details) { provider_error(details) }
293
+ end
294
+ configuration.add_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_ERROR, handler)
295
+
296
+ cancelled = @initialization_mutex.synchronize { @shutdown }
297
+ configuration.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_ERROR, handler) if cancelled
298
+ end
299
+
300
+ def provider_error(_details)
301
+ configuration = @configuration
302
+ return unless configuration
303
+ return unless configuration.send(:provider_state, self) == ::OpenFeature::SDK::ProviderState::ERROR
304
+
305
+ emit_ready = @initialization_mutex.synchronize do
306
+ if @shutdown
307
+ false
308
+ else
309
+ @provider_error_observed = true
310
+ if @ready_pending && !@ready_dispatch_claimed
311
+ @ready_dispatch_claimed = true
312
+ else
313
+ false
314
+ end
315
+ end
316
+ end
317
+ emit_event(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY) if emit_ready
318
+ end
319
+
320
+ def provider_ready(_details)
321
+ configuration = @configuration
322
+ return unless configuration
323
+ return unless configuration.send(:provider_state, self) == ::OpenFeature::SDK::ProviderState::READY
324
+
325
+ handler, emit_stale = @initialization_mutex.synchronize do
326
+ handler = @initialization_ready_handler
327
+ @initialization_ready_handler = nil
328
+ @initializing = false
329
+ @initialization_thread = nil
330
+ if @stale_pending && !@shutdown
331
+ @stale_pending = false
332
+ @stale_emitted = true
333
+ [handler, true]
334
+ else
335
+ [handler, false]
336
+ end
337
+ end
338
+ configuration.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler) if handler
339
+ emit_event(::OpenFeature::SDK::ProviderEvent::PROVIDER_STALE) if emit_stale
340
+ end
341
+
342
+ def configuration_changed(event)
343
+ event_type = @initialization_mutex.synchronize do
344
+ if @shutdown
345
+ nil
346
+ elsif event == Component::CONFIGURATION_READY
347
+ if @initializing
348
+ @ready_pending = true
349
+ @stale_pending = false
350
+ nil
351
+ elsif @awaiting_ready_after_fork
352
+ @awaiting_ready_after_fork = false
353
+ @stale_emitted = false
354
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_READY
355
+ elsif @initialization_failed && !@provider_error_observed
356
+ @stale_emitted = false
357
+ @ready_pending = true
358
+ nil
359
+ elsif @stale_emitted
360
+ @stale_emitted = false
361
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_READY
362
+ elsif @initialization_failed
363
+ if @provider_error_observed && !@ready_dispatch_claimed
364
+ @ready_dispatch_claimed = true
365
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_READY
366
+ else
367
+ @ready_pending = true
368
+ nil
369
+ end
370
+ end
371
+ elsif event == Component::CONFIGURATION_CHANGED && !@initializing
372
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_CONFIGURATION_CHANGED
373
+ elsif event == Component::CONFIGURATION_LOST
374
+ @ready_pending = false
375
+ if @initializing
376
+ @stale_pending = true
377
+ nil
378
+ else
379
+ @stale_emitted = true
380
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_STALE
381
+ end
382
+ end
383
+ end
384
+
385
+ emit_event(event_type) if event_type
386
+ end
387
+
111
388
  def evaluate(flag_key, default_value:, expected_type:, evaluation_context:)
112
389
  # Stamp evaluation entry time once, here on the eval thread. The EVP path uses this for
113
390
  # accurate first/last_evaluation bounds instead of a later hook-fire clock read.
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "core/configuration"
4
4
  require_relative "open_feature/configuration"
5
+ require_relative "open_feature/configuration/source"
5
6
 
6
7
  module Datadog
7
8
  # A namespace for the OpenFeature component.
@@ -9,11 +10,40 @@ module Datadog
9
10
  Core::Configuration::Settings.extend(Configuration::Settings)
10
11
 
11
12
  def self.enabled?
12
- Datadog.configuration.open_feature.enabled
13
+ Configuration::Source.resolve(Datadog.configuration).enabled?
13
14
  end
14
15
 
15
16
  def self.engine
16
17
  Datadog.send(:components).open_feature&.engine
17
18
  end
19
+
20
+ def self.activate_provider(provider)
21
+ # Initialize the component tree before taking its reconfiguration lock.
22
+ Datadog.send(:components)
23
+ Datadog.send(:safely_synchronize) do
24
+ return [nil, nil] if provider.send(:shutdown?)
25
+
26
+ components = Datadog.send(:components, allow_initialization: false)
27
+ activation = components&.send(:open_feature_activation)
28
+ providers = @adopted_providers ||= {}.compare_by_identity
29
+ providers[provider] = true
30
+ [activation&.activate(provider), activation&.failure]
31
+ end
32
+ end
33
+
34
+ def self.deactivate_provider(provider)
35
+ Datadog.send(:safely_synchronize) do
36
+ @adopted_providers&.delete(provider)
37
+ components = Datadog.send(:components, allow_initialization: false)
38
+ components&.send(:open_feature_activation)&.deactivate(provider)
39
+ end
40
+ end
41
+
42
+ # Components startup already holds the non-reentrant reconfiguration lock.
43
+ def self.reattach(activation)
44
+ providers = @adopted_providers&.keys || []
45
+ providers.each { |provider| activation.activate(provider) }
46
+ nil
47
+ end
18
48
  end
19
49
  end
@@ -147,6 +147,11 @@ module Datadog
147
147
  end
148
148
  end
149
149
 
150
+ # @rbs return: Datadog::Profiling::StackRecorder
151
+ def prepare_serialize
152
+ self.class._native_prepare_serialize(self)
153
+ end
154
+
150
155
  #: () -> true
151
156
  def reset_after_fork
152
157
  self.class._native_reset_after_fork(self)
@@ -73,7 +73,7 @@ module Datadog
73
73
  heap_sample_every: heap_sample_every,
74
74
  }.freeze
75
75
 
76
- exporter = build_profiler_exporter(settings, recorder, worker, internal_metadata: internal_metadata)
76
+ exporter = build_profiler_exporter(settings, worker, internal_metadata: internal_metadata)
77
77
  transport = build_profiler_transport(settings, agent_settings)
78
78
  scheduler = Profiling::Scheduler.new(exporter: exporter, transport: transport, interval: upload_period_seconds)
79
79
  profiler = Profiling::Profiler.new(worker: worker, scheduler: scheduler)
@@ -109,13 +109,12 @@ module Datadog
109
109
  )
110
110
  end
111
111
 
112
- private_class_method def self.build_profiler_exporter(settings, recorder, worker, internal_metadata:)
112
+ private_class_method def self.build_profiler_exporter(settings, worker, internal_metadata:)
113
113
  info_collector = Profiling::Collectors::Info.new(settings)
114
114
  code_provenance_collector =
115
115
  (Profiling::Collectors::CodeProvenance.new if settings.profiling.advanced.code_provenance_enabled)
116
116
 
117
117
  Profiling::Exporter.new(
118
- pprof_recorder: recorder,
119
118
  worker: worker,
120
119
  info_collector: info_collector,
121
120
  code_provenance_collector: code_provenance_collector,
@@ -20,7 +20,6 @@ module Datadog
20
20
 
21
21
  private
22
22
 
23
- attr_reader :pprof_recorder #: Datadog::Profiling::StackRecorder
24
23
  # The code provenance collector acts both as collector and as a recorder
25
24
  attr_reader :code_provenance_collector #: Datadog::Profiling::Collectors::CodeProvenance?
26
25
  attr_reader :minimum_duration_seconds #: ::Integer
@@ -33,7 +32,6 @@ module Datadog
33
32
 
34
33
  public
35
34
 
36
- # @rbs pprof_recorder: Datadog::Profiling::StackRecorder
37
35
  # @rbs worker: Datadog::Profiling::Collectors::CpuAndWallTimeWorker
38
36
  # @rbs info_collector: Datadog::Profiling::Collectors::Info
39
37
  # @rbs code_provenance_collector: Datadog::Profiling::Collectors::CodeProvenance?
@@ -43,7 +41,6 @@ module Datadog
43
41
  # @rbs sequence_tracker: singleton(Datadog::Profiling::SequenceTracker)
44
42
  # @rbs return: void
45
43
  def initialize(
46
- pprof_recorder:,
47
44
  worker:,
48
45
  info_collector:,
49
46
  code_provenance_collector:,
@@ -52,7 +49,6 @@ module Datadog
52
49
  time_provider: Time,
53
50
  sequence_tracker: Datadog::Profiling::SequenceTracker
54
51
  )
55
- @pprof_recorder = pprof_recorder
56
52
  @worker = worker
57
53
  @code_provenance_collector = code_provenance_collector
58
54
  @minimum_duration_seconds = minimum_duration_seconds
@@ -68,6 +64,7 @@ module Datadog
68
64
 
69
65
  #: () -> Datadog::Profiling::Flush?
70
66
  def flush
67
+ pprof_recorder = @worker.prepare_serialize
71
68
  worker_stats = @worker.stats_and_reset_not_thread_safe
72
69
  serialization_result = pprof_recorder.serialize
73
70
  return if serialization_result.nil?
@@ -111,7 +108,7 @@ module Datadog
111
108
  worker_stats: worker_stats,
112
109
  profile_stats: profile_stats,
113
110
  recorder_stats: pprof_recorder.stats,
114
- gc: GC.stat,
111
+ gc: gc_stats,
115
112
  }
116
113
  ),
117
114
  info_json: info_json,
@@ -131,6 +128,11 @@ module Datadog
131
128
 
132
129
  private
133
130
 
131
+ # @rbs return: Hash[Symbol, Integer | bool]
132
+ def gc_stats
133
+ GC.stat.merge(auto_compact: GC.respond_to?(:auto_compact) && GC.auto_compact)
134
+ end
135
+
134
136
  #: (::Time, ::Time) -> bool
135
137
  def duration_below_threshold?(start, finish)
136
138
  (finish - start) < minimum_duration_seconds
@@ -62,6 +62,20 @@ module Datadog
62
62
  end
63
63
  end
64
64
 
65
+ def bind_transport_telemetry(tracer, telemetry)
66
+ return unless tracer.is_a?(Tracing::Tracer)
67
+
68
+ writer = tracer.writer
69
+ return unless writer.respond_to?(:transport)
70
+
71
+ transport = writer.transport
72
+ if transport.is_a?(Transport::Traces::Transport) ||
73
+ (defined?(Transport::Native::Transport) && transport.is_a?(Transport::Native::Transport))
74
+ transport.telemetry = telemetry
75
+ end
76
+ nil
77
+ end
78
+
65
79
  def build_sampler(settings)
66
80
  # A custom sampler is provided
67
81
  if (sampler = settings.tracing.sampler)
@@ -106,7 +120,7 @@ module Datadog
106
120
  return writer
107
121
  end
108
122
 
109
- if settings.tracing.native_transport && (transport = build_native_transport(agent_settings))
123
+ if !options.key?(:transport) && settings.tracing.native_transport && (transport = build_native_transport(agent_settings))
110
124
  options = options.merge(transport: transport)
111
125
  end
112
126
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "../../tracing/configuration/ext"
4
4
  require_relative "../../core/environment/variable_helpers"
5
+ require_relative "../../ruby_version"
5
6
  require_relative "../contrib/status_range_matcher"
6
7
  require_relative "../contrib/status_range_env_parser"
7
8
  require_relative "http"
@@ -257,7 +258,9 @@ module Datadog
257
258
 
258
259
  option :otel_thread_context_enabled do |o|
259
260
  o.env Tracing::Configuration::Ext::ENV_OTEL_CONTEXT_ENABLED
260
- o.default true
261
+ o.default do
262
+ RUBY_ENGINE == "ruby" && RUBY_PLATFORM.include?("linux")
263
+ end
261
264
  o.type :bool
262
265
  end
263
266
 
@@ -496,11 +499,11 @@ module Datadog
496
499
  #
497
500
  # This option is recommended for internal use only.
498
501
  #
499
- # @default `false`
502
+ # @default `true` on CRuby 4.0.0 and later, otherwise `false`
500
503
  # @return [Boolean]
501
504
  option :native_transport do |o|
502
505
  o.env Configuration::Ext::ENV_EXPERIMENTAL_NATIVE_TRANSPORT_ENABLED
503
- o.default false
506
+ o.default { RUBY_ENGINE == "ruby" && RubyVersion.is?(">= 4.0.0") }
504
507
  o.type :bool
505
508
  end
506
509
 
@@ -60,6 +60,8 @@ module Datadog
60
60
  def query(query, options = {})
61
61
  query!(query, options)
62
62
  rescue
63
+ return "" if options && options[:obfuscate]
64
+
63
65
  options[:placeholder] || PLACEHOLDER
64
66
  end
65
67
 
@@ -136,7 +138,7 @@ module Datadog
136
138
  (?:"|%22)?
137
139
  )
138
140
  (?: # common keys
139
- (?:old[-_]?|new_?)?p(?:ass)?w(?:or)?d(?:1|2)? # pw, password variants
141
+ (?:old[-_]?|new[-_]?)?p(?:ass)?w(?:or)?d(?:1|2)? # pw, password variants
140
142
  |pass(?:[-_]?phrase)? # pass, passphrase variants
141
143
  |secret
142
144
  |(?: # key, key_id variants
@@ -145,6 +147,7 @@ module Datadog
145
147
  |public[-_]?
146
148
  |access[-_]?
147
149
  |secret[-_]?
150
+ |app(?:lication)?[-_]?
148
151
  )key(?:[-_]?id)?
149
152
  |token
150
153
  |consumer[-_]?(?:id|key|secret)
@@ -165,9 +168,9 @@ module Datadog
165
168
  bearer(?:\s|%20)+[a-z0-9._-]+
166
169
  |token(?::|%3A)[a-z0-9]{13}
167
170
  |gh[opsu]_[0-9a-zA-Z]{36}
168
- |ey[I-L](?:[\w=-]|%3D)+\.ey[I-L](?:[\w=-]|%3D)+(?:\.(?:[\w.+/=-]|%3D|%2F|%2B)+)?
171
+ |(?:^|[^\w%-]|%[0-9a-f]{2})ey[I-L][\w-]+(?:=|%3D)*\.ey[I-L][\w-]+(?:=|%3D)*(?:\.(?:[\w.+/=-]|%3D|%2F|%2B)+)?
169
172
  |-{5}BEGIN(?:[a-z\s]|%20)+PRIVATE(?:\s|%20)KEY-{5}[^-]+-{5}END(?:[a-z\s]|%20)+PRIVATE(?:\s|%20)KEY(?:-{5})?(?:\n|%0A)?
170
- |(?:ssh-(?:rsa|dss)|ecdsa-[a-z0-9]+-[a-z0-9]+)(?:\s|%20)*(?:[a-z0-9/.+]|%2F|%5C|%2B){100,}(?:=|%3D)*(?:(?:\s+)[a-z0-9._-]+)?
173
+ |(?:ssh-(?:rsa|dss)|ecdsa-[a-z0-9]+-[a-z0-9]+)(?:\s|%20|%09)+(?:[a-z0-9/.+]|%2F|%5C|%2B){100,}(?:=|%3D)*(?:(?:\s|%20|%09)+[a-z0-9._-]+)?
171
174
  )
172
175
  }ix.freeze
173
176
  # rubocop:enable Layout/LineLength
@@ -60,6 +60,7 @@ module Datadog
60
60
  def agent_url
61
61
  # Retrieve the effect agent URL, regardless of how it was configured
62
62
  transport = Tracing.send(:tracer).writer.transport
63
+ return transport.url if transport.respond_to?(:url)
63
64
 
64
65
  # return `nil` with IO transport
65
66
  return unless transport.respond_to?(:client)
@@ -14,9 +14,11 @@ module Datadog
14
14
 
15
15
  def self.build(tracing_settings)
16
16
  return unless tracing_settings.otel_thread_context_enabled
17
+ return unless Datadog::Core::LIBDATADOG_API_FAILURE.nil?
17
18
 
18
19
  instance = new
19
- instance if instance.supported? && instance._native_enable
20
+ instance._native_enable
21
+ instance
20
22
  end
21
23
 
22
24
  def initialize
@@ -65,10 +67,6 @@ module Datadog
65
67
  false
66
68
  end
67
69
 
68
- def supported?
69
- Datadog::Core::LIBDATADOG_API_FAILURE.nil? && _native_supported?
70
- end
71
-
72
70
  def update_from_trace_op(trace_op)
73
71
  active_span = trace_op.active_span
74
72