datadog 2.23.0 → 2.28.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 (215) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +132 -2
  3. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +2 -1
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +100 -29
  5. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +2 -2
  6. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +3 -2
  7. data/ext/datadog_profiling_native_extension/collectors_stack.c +23 -10
  8. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +16 -12
  9. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
  10. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +48 -1
  11. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +41 -0
  12. data/ext/datadog_profiling_native_extension/encoded_profile.c +2 -1
  13. data/ext/datadog_profiling_native_extension/extconf.rb +4 -1
  14. data/ext/datadog_profiling_native_extension/heap_recorder.c +24 -24
  15. data/ext/datadog_profiling_native_extension/http_transport.c +10 -4
  16. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +3 -22
  17. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +0 -5
  18. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +21 -8
  19. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +4 -0
  20. data/ext/datadog_profiling_native_extension/profiling.c +22 -15
  21. data/ext/datadog_profiling_native_extension/ruby_helpers.c +55 -44
  22. data/ext/datadog_profiling_native_extension/ruby_helpers.h +17 -5
  23. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +8 -2
  24. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +3 -0
  25. data/ext/datadog_profiling_native_extension/stack_recorder.c +16 -16
  26. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +2 -1
  27. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +5 -2
  28. data/ext/libdatadog_api/crashtracker.c +5 -8
  29. data/ext/libdatadog_api/datadog_ruby_common.c +48 -1
  30. data/ext/libdatadog_api/datadog_ruby_common.h +41 -0
  31. data/ext/libdatadog_api/ddsketch.c +4 -8
  32. data/ext/libdatadog_api/feature_flags.c +5 -5
  33. data/ext/libdatadog_api/helpers.h +27 -0
  34. data/ext/libdatadog_api/init.c +4 -0
  35. data/ext/libdatadog_extconf_helpers.rb +1 -1
  36. data/lib/datadog/ai_guard/api_client.rb +82 -0
  37. data/lib/datadog/ai_guard/component.rb +42 -0
  38. data/lib/datadog/ai_guard/configuration/ext.rb +17 -0
  39. data/lib/datadog/ai_guard/configuration/settings.rb +110 -0
  40. data/lib/datadog/ai_guard/configuration.rb +11 -0
  41. data/lib/datadog/ai_guard/contrib/integration.rb +37 -0
  42. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +42 -0
  43. data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +41 -0
  44. data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +30 -0
  45. data/lib/datadog/ai_guard/evaluation/message.rb +25 -0
  46. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +34 -0
  47. data/lib/datadog/ai_guard/evaluation/request.rb +81 -0
  48. data/lib/datadog/ai_guard/evaluation/result.rb +43 -0
  49. data/lib/datadog/ai_guard/evaluation/tool_call.rb +18 -0
  50. data/lib/datadog/ai_guard/evaluation.rb +72 -0
  51. data/lib/datadog/ai_guard/ext.rb +16 -0
  52. data/lib/datadog/ai_guard.rb +155 -0
  53. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +8 -1
  54. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +9 -2
  55. data/lib/datadog/appsec/component.rb +1 -1
  56. data/lib/datadog/appsec/context.rb +5 -4
  57. data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
  58. data/lib/datadog/appsec/contrib/active_record/patcher.rb +1 -1
  59. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  60. data/lib/datadog/appsec/contrib/excon/patcher.rb +1 -1
  61. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +47 -12
  62. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +32 -15
  63. data/lib/datadog/appsec/contrib/rails/patcher.rb +10 -2
  64. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  65. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +1 -1
  66. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +50 -14
  67. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +5 -4
  68. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  69. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +4 -4
  70. data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +1 -1
  71. data/lib/datadog/appsec/ext.rb +2 -0
  72. data/lib/datadog/appsec/metrics/collector.rb +8 -3
  73. data/lib/datadog/appsec/metrics/exporter.rb +7 -0
  74. data/lib/datadog/appsec/metrics/telemetry.rb +7 -2
  75. data/lib/datadog/appsec/metrics.rb +5 -5
  76. data/lib/datadog/appsec/remote.rb +7 -14
  77. data/lib/datadog/appsec/security_engine/engine.rb +3 -3
  78. data/lib/datadog/appsec/security_engine/result.rb +2 -1
  79. data/lib/datadog/appsec/security_engine/runner.rb +2 -2
  80. data/lib/datadog/appsec/utils/http/media_type.rb +37 -23
  81. data/lib/datadog/appsec.rb +7 -1
  82. data/lib/datadog/core/configuration/components.rb +7 -0
  83. data/lib/datadog/core/configuration/config_helper.rb +1 -1
  84. data/lib/datadog/core/configuration/deprecations.rb +2 -2
  85. data/lib/datadog/core/configuration/option_definition.rb +4 -2
  86. data/lib/datadog/core/configuration/options.rb +8 -5
  87. data/lib/datadog/core/configuration/settings.rb +31 -3
  88. data/lib/datadog/core/configuration/supported_configurations.rb +10 -1
  89. data/lib/datadog/core/crashtracking/tag_builder.rb +6 -0
  90. data/lib/datadog/core/environment/cgroup.rb +52 -25
  91. data/lib/datadog/core/environment/container.rb +140 -46
  92. data/lib/datadog/core/environment/ext.rb +1 -0
  93. data/lib/datadog/core/environment/process.rb +9 -1
  94. data/lib/datadog/core/error.rb +6 -6
  95. data/lib/datadog/core/knuth_sampler.rb +57 -0
  96. data/lib/datadog/core/pin.rb +4 -0
  97. data/lib/datadog/core/rate_limiter.rb +9 -1
  98. data/lib/datadog/core/remote/client.rb +14 -6
  99. data/lib/datadog/core/remote/component.rb +6 -4
  100. data/lib/datadog/core/remote/configuration/content.rb +15 -2
  101. data/lib/datadog/core/remote/configuration/digest.rb +14 -7
  102. data/lib/datadog/core/remote/configuration/repository.rb +1 -1
  103. data/lib/datadog/core/remote/configuration/target.rb +13 -6
  104. data/lib/datadog/core/remote/transport/config.rb +3 -16
  105. data/lib/datadog/core/remote/transport/http/config.rb +4 -44
  106. data/lib/datadog/core/remote/transport/http/negotiation.rb +0 -39
  107. data/lib/datadog/core/remote/transport/http.rb +13 -24
  108. data/lib/datadog/core/remote/transport/negotiation.rb +7 -16
  109. data/lib/datadog/core/runtime/metrics.rb +11 -1
  110. data/lib/datadog/core/semaphore.rb +1 -4
  111. data/lib/datadog/core/telemetry/component.rb +52 -13
  112. data/lib/datadog/core/telemetry/event/app_started.rb +36 -1
  113. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
  114. data/lib/datadog/core/telemetry/logger.rb +2 -0
  115. data/lib/datadog/core/telemetry/logging.rb +20 -2
  116. data/lib/datadog/core/telemetry/metrics_manager.rb +9 -0
  117. data/lib/datadog/core/telemetry/request.rb +17 -3
  118. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +2 -32
  119. data/lib/datadog/core/telemetry/transport/http.rb +21 -16
  120. data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -10
  121. data/lib/datadog/core/telemetry/worker.rb +88 -32
  122. data/lib/datadog/core/transport/ext.rb +2 -0
  123. data/lib/datadog/core/transport/http/api/endpoint.rb +9 -4
  124. data/lib/datadog/core/transport/http/api/instance.rb +4 -21
  125. data/lib/datadog/core/transport/http/builder.rb +9 -5
  126. data/lib/datadog/core/transport/http/client.rb +19 -8
  127. data/lib/datadog/core/transport/http.rb +22 -19
  128. data/lib/datadog/core/transport/response.rb +12 -1
  129. data/lib/datadog/core/transport/transport.rb +90 -0
  130. data/lib/datadog/core/utils/only_once_successful.rb +2 -0
  131. data/lib/datadog/core/utils/safe_dup.rb +2 -2
  132. data/lib/datadog/core/utils/sequence.rb +2 -0
  133. data/lib/datadog/core/utils/time.rb +1 -1
  134. data/lib/datadog/core/workers/async.rb +10 -1
  135. data/lib/datadog/core/workers/interval_loop.rb +44 -3
  136. data/lib/datadog/core/workers/polling.rb +2 -0
  137. data/lib/datadog/core/workers/queue.rb +100 -1
  138. data/lib/datadog/data_streams/processor.rb +1 -1
  139. data/lib/datadog/data_streams/transport/http/stats.rb +1 -36
  140. data/lib/datadog/data_streams/transport/http.rb +5 -6
  141. data/lib/datadog/data_streams/transport/stats.rb +3 -17
  142. data/lib/datadog/di/boot.rb +4 -2
  143. data/lib/datadog/di/configuration/settings.rb +22 -0
  144. data/lib/datadog/di/contrib/active_record.rb +30 -5
  145. data/lib/datadog/di/el/compiler.rb +8 -4
  146. data/lib/datadog/di/error.rb +5 -0
  147. data/lib/datadog/di/instrumenter.rb +26 -7
  148. data/lib/datadog/di/logger.rb +2 -2
  149. data/lib/datadog/di/probe_builder.rb +2 -1
  150. data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
  151. data/lib/datadog/di/probe_manager.rb +37 -31
  152. data/lib/datadog/di/probe_notification_builder.rb +15 -2
  153. data/lib/datadog/di/probe_notifier_worker.rb +5 -5
  154. data/lib/datadog/di/redactor.rb +8 -1
  155. data/lib/datadog/di/remote.rb +89 -84
  156. data/lib/datadog/di/transport/diagnostics.rb +7 -35
  157. data/lib/datadog/di/transport/http/diagnostics.rb +1 -31
  158. data/lib/datadog/di/transport/http/input.rb +1 -31
  159. data/lib/datadog/di/transport/http.rb +28 -17
  160. data/lib/datadog/di/transport/input.rb +7 -34
  161. data/lib/datadog/di.rb +61 -5
  162. data/lib/datadog/error_tracking/filters.rb +2 -2
  163. data/lib/datadog/kit/appsec/events/v2.rb +2 -3
  164. data/lib/datadog/open_feature/evaluation_engine.rb +2 -1
  165. data/lib/datadog/open_feature/remote.rb +3 -10
  166. data/lib/datadog/open_feature/transport.rb +9 -11
  167. data/lib/datadog/opentelemetry/api/baggage.rb +1 -1
  168. data/lib/datadog/opentelemetry/configuration/settings.rb +2 -2
  169. data/lib/datadog/opentelemetry/metrics.rb +21 -14
  170. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +5 -8
  171. data/lib/datadog/profiling/collectors/code_provenance.rb +27 -2
  172. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +3 -2
  173. data/lib/datadog/profiling/collectors/info.rb +5 -4
  174. data/lib/datadog/profiling/component.rb +25 -11
  175. data/lib/datadog/profiling/exporter.rb +4 -0
  176. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +18 -0
  177. data/lib/datadog/profiling/ext/exec_monkey_patch.rb +32 -0
  178. data/lib/datadog/profiling/flush.rb +3 -0
  179. data/lib/datadog/profiling/http_transport.rb +4 -1
  180. data/lib/datadog/profiling/profiler.rb +3 -5
  181. data/lib/datadog/profiling/scheduler.rb +8 -7
  182. data/lib/datadog/profiling/tag_builder.rb +1 -0
  183. data/lib/datadog/tracing/contrib/extensions.rb +10 -2
  184. data/lib/datadog/tracing/contrib/karafka/patcher.rb +31 -32
  185. data/lib/datadog/tracing/contrib/status_range_matcher.rb +2 -1
  186. data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +3 -1
  187. data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +6 -3
  188. data/lib/datadog/tracing/contrib/waterdrop.rb +4 -0
  189. data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
  190. data/lib/datadog/tracing/distributed/baggage.rb +3 -2
  191. data/lib/datadog/tracing/remote.rb +1 -9
  192. data/lib/datadog/tracing/sampling/priority_sampler.rb +3 -1
  193. data/lib/datadog/tracing/sampling/rate_sampler.rb +8 -19
  194. data/lib/datadog/tracing/span.rb +1 -1
  195. data/lib/datadog/tracing/span_event.rb +2 -2
  196. data/lib/datadog/tracing/span_operation.rb +20 -9
  197. data/lib/datadog/tracing/trace_operation.rb +44 -6
  198. data/lib/datadog/tracing/tracer.rb +42 -16
  199. data/lib/datadog/tracing/transport/http/traces.rb +2 -50
  200. data/lib/datadog/tracing/transport/http.rb +15 -9
  201. data/lib/datadog/tracing/transport/io/client.rb +1 -1
  202. data/lib/datadog/tracing/transport/traces.rb +6 -66
  203. data/lib/datadog/tracing/workers/trace_writer.rb +5 -0
  204. data/lib/datadog/tracing/writer.rb +1 -0
  205. data/lib/datadog/version.rb +2 -2
  206. data/lib/datadog.rb +1 -0
  207. metadata +33 -19
  208. data/lib/datadog/core/remote/transport/http/api.rb +0 -53
  209. data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
  210. data/lib/datadog/core/transport/http/api/spec.rb +0 -36
  211. data/lib/datadog/data_streams/transport/http/api.rb +0 -33
  212. data/lib/datadog/data_streams/transport/http/client.rb +0 -21
  213. data/lib/datadog/di/transport/http/api.rb +0 -42
  214. data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
  215. data/lib/datadog/tracing/transport/http/api.rb +0 -44
@@ -4,9 +4,6 @@ module Datadog
4
4
  module Profiling
5
5
  # Responsible for wiring up the Profiler for execution
6
6
  module Component
7
- ALLOCATION_WITH_RACTORS_ONLY_ONCE = Datadog::Core::Utils::OnlyOnce.new
8
- private_constant :ALLOCATION_WITH_RACTORS_ONLY_ONCE
9
-
10
7
  # Passing in a `nil` tracer is supported and will disable the following profiling features:
11
8
  # * Profiling in the trace viewer, as well as scoping a profile down to a span
12
9
  # * Endpoint aggregation in the profiler UX, including normalization (resource per endpoint call)
@@ -85,6 +82,10 @@ module Datadog
85
82
  Datadog::Profiling::Ext::DirMonkeyPatches.apply!
86
83
  end
87
84
 
85
+ if can_apply_exec_monkey_patch?(settings)
86
+ Datadog::Profiling::Ext::ExecMonkeyPatch.apply!
87
+ end
88
+
88
89
  [profiler, {profiling_enabled: true}]
89
90
  end
90
91
 
@@ -145,7 +146,7 @@ module Datadog
145
146
  logger.debug(
146
147
  "Using Ractors may result in GC profiling unexpectedly " \
147
148
  "stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
148
- "application stability or performance. This does not happen if Ractors are not used."
149
+ "application stability or performance. This issue is fixed on Ruby 4."
149
150
  )
150
151
  end
151
152
 
@@ -195,13 +196,11 @@ module Datadog
195
196
  # On all known versions of Ruby 3.x, due to https://bugs.ruby-lang.org/issues/19112, when a ractor gets
196
197
  # garbage collected, Ruby will disable all active tracepoints, which this feature internally relies on.
197
198
  elsif RUBY_VERSION.start_with?("3.")
198
- ALLOCATION_WITH_RACTORS_ONLY_ONCE.run do
199
- logger.info(
200
- "Using Ractors may result in allocation profiling " \
201
- "stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
202
- "application stability or performance. This does not happen if Ractors are not used."
203
- )
204
- end
199
+ logger.debug(
200
+ "Using Ractors may result in allocation profiling " \
201
+ "stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
202
+ "application stability or performance. This issue is fixed on Ruby 4."
203
+ )
205
204
  end
206
205
 
207
206
  logger.debug("Enabled allocation profiling")
@@ -220,6 +219,12 @@ module Datadog
220
219
  "Please upgrade to Ruby >= 3.1 in order to use this feature. Heap profiling has been disabled."
221
220
  )
222
221
  return false
222
+ elsif RUBY_VERSION.start_with?("4.")
223
+ logger.warn(
224
+ "Datadog Ruby heap profiler is currently incompatible with Ruby 4. " \
225
+ "Heap profiling has been disabled."
226
+ )
227
+ return false
223
228
  end
224
229
 
225
230
  unless allocation_profiling_enabled
@@ -433,6 +438,15 @@ module Datadog
433
438
  settings.profiling.advanced.dir_interruption_workaround_enabled
434
439
  end
435
440
 
441
+ private_class_method def self.can_apply_exec_monkey_patch?(settings)
442
+ return false if RUBY_VERSION < "2.7"
443
+
444
+ # This file is 2.7+ only so we only require it here once we've checked the Ruby version
445
+ require "datadog/profiling/ext/exec_monkey_patch"
446
+
447
+ settings.profiling.advanced.shutdown_on_exec_enabled
448
+ end
449
+
436
450
  private_class_method def self.enable_gvl_profiling?(settings, logger)
437
451
  return false if RUBY_VERSION < "3.2"
438
452
 
@@ -70,6 +70,9 @@ module Datadog
70
70
 
71
71
  uncompressed_code_provenance = code_provenance_collector.refresh.generate_json if code_provenance_collector
72
72
 
73
+ process_tags = Datadog.configuration.experimental_propagate_process_tags_enabled ?
74
+ Core::Environment::Process.serialized : ''
75
+
73
76
  Flush.new(
74
77
  start: start,
75
78
  finish: finish,
@@ -80,6 +83,7 @@ module Datadog
80
83
  settings: Datadog.configuration,
81
84
  profile_seq: sequence_tracker.get_next,
82
85
  ).to_a,
86
+ process_tags: process_tags,
83
87
  internal_metadata: internal_metadata.merge(
84
88
  {
85
89
  worker_stats: worker_stats,
@@ -30,6 +30,10 @@ module Datadog
30
30
  if RUBY_VERSION.start_with?("2.")
31
31
  # Monkey patches for Dir.singleton_class (Ruby 2 version). See DirMonkeyPatches above for more details.
32
32
  module DirClassMonkeyPatches
33
+ # Steep: Workaround that defines args and block only for Ruby 2.x.
34
+ # @type var args: ::Array[any]
35
+ # @type var block: ^(?) -> any | nil
36
+
33
37
  def [](*args, &block)
34
38
  Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
35
39
  super
@@ -148,6 +152,11 @@ module Datadog
148
152
  else
149
153
  # Monkey patches for Dir.singleton_class (Ruby 3 version). See DirMonkeyPatches above for more details.
150
154
  module DirClassMonkeyPatches
155
+ # Steep: Workaround that defines args, kwargs and block only for Ruby 3.x.
156
+ # @type var args: ::Array[any]
157
+ # @type var kwargs: ::Hash[::Symbol, any]
158
+ # @type var block: ^(?) -> any | nil
159
+
151
160
  def [](*args, **kwargs, &block)
152
161
  Datadog::Profiling::Collectors::CpuAndWallTimeWorker._native_hold_signals
153
162
  super
@@ -263,6 +272,10 @@ module Datadog
263
272
  if RUBY_VERSION.start_with?("2.")
264
273
  # Monkey patches for Dir (Ruby 2 version). See DirMonkeyPatches above for more details.
265
274
  module DirInstanceMonkeyPatches
275
+ # Steep: Workaround that defines args and block only for Ruby 2.x.
276
+ # @type var args: ::Array[any]
277
+ # @type var block: ^(?) -> any | nil
278
+
266
279
  # See note on methods that yield above.
267
280
  def each(*args, &block)
268
281
  if block
@@ -336,6 +349,11 @@ module Datadog
336
349
  else
337
350
  # Monkey patches for Dir (Ruby 3 version). See DirMonkeyPatches above for more details.
338
351
  module DirInstanceMonkeyPatches
352
+ # Steep: Workaround that defines args, kwargs and block only for Ruby 3.x.
353
+ # @type var args: ::Array[any]
354
+ # @type var kwargs: ::Hash[::Symbol, any]
355
+ # @type var block: ^(?) -> any | nil
356
+
339
357
  # See note on methods that yield above.
340
358
  def each(*args, **kwargs, &block)
341
359
  if block
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module Profiling
5
+ module Ext
6
+ # The profiler gathers data by sending `SIGPROF` unix signals to Ruby application threads.
7
+ #
8
+ # When using `Kernel#exec` on Linux, it can happen that a signal sent before calling `exec` arrives after
9
+ # the new process is running, causing it to fail with the `Profiling timer expired` error message.
10
+ # To avoid this, the profiler installs a monkey patch on `Kernel#exec` to stop profiling before actually
11
+ # calling `exec`.
12
+ # This monkey patch is available for Ruby 2.7+; let us know if you need it on earlier Rubies.
13
+ # For more details see https://github.com/DataDog/dd-trace-rb/issues/5101 .
14
+ module ExecMonkeyPatch
15
+ def self.apply!
16
+ ::Object.prepend(ObjectMonkeyPatch)
17
+
18
+ true
19
+ end
20
+
21
+ module ObjectMonkeyPatch
22
+ private
23
+
24
+ def exec(...)
25
+ Datadog.send(:components, allow_initialization: false)&.profiler&.shutdown!(report_last_profile: false)
26
+ super
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -13,6 +13,7 @@ module Datadog
13
13
  :code_provenance_file_name,
14
14
  :code_provenance_data,
15
15
  :tags_as_array,
16
+ :process_tags,
16
17
  :internal_metadata_json,
17
18
  :info_json
18
19
 
@@ -23,6 +24,7 @@ module Datadog
23
24
  code_provenance_file_name:,
24
25
  code_provenance_data:,
25
26
  tags_as_array:,
27
+ process_tags:,
26
28
  internal_metadata:,
27
29
  info_json:
28
30
  )
@@ -32,6 +34,7 @@ module Datadog
32
34
  @code_provenance_file_name = code_provenance_file_name
33
35
  @code_provenance_data = code_provenance_data
34
36
  @tags_as_array = tags_as_array
37
+ @process_tags = process_tags
35
38
  @internal_metadata_json = JSON.generate(internal_metadata)
36
39
  @info_json = info_json
37
40
  end
@@ -13,7 +13,10 @@ module Datadog
13
13
  def initialize(agent_settings:, site:, api_key:, upload_timeout_seconds:)
14
14
  @upload_timeout_milliseconds = (upload_timeout_seconds * 1_000).to_i
15
15
 
16
- @exporter_configuration =
16
+ # Steep: multiple issues here
17
+ # first https://github.com/soutaro/steep/issues/363
18
+ # then https://github.com/soutaro/steep/issues/1603 (remove the .freeze to see it)
19
+ @exporter_configuration = # steep:ignore IncompatibleAssignment
17
20
  if agentless?(site, api_key)
18
21
  [:agentless, site, api_key].freeze
19
22
  else
@@ -31,10 +31,11 @@ module Datadog
31
31
  scheduler.start(on_failure_proc: proc { component_failed(:scheduler) })
32
32
  end
33
33
 
34
- def shutdown!
34
+ def shutdown!(report_last_profile: true)
35
35
  Datadog.logger.debug("Shutting down profiler")
36
36
 
37
37
  stop_worker
38
+ scheduler.disable_reporting unless report_last_profile
38
39
  stop_scheduler
39
40
  end
40
41
 
@@ -57,11 +58,8 @@ module Datadog
57
58
  Datadog::Core::Telemetry::Logger
58
59
  .error("Detected issue with profiler (#{failed_component} component), stopping profiling")
59
60
 
60
- # We explicitly not stop the crash tracker in this situation, under the assumption that, if a component failed,
61
- # we're operating in a degraded state and crash tracking may still be helpful.
62
-
63
61
  if failed_component == :worker
64
- scheduler.mark_profiler_failed
62
+ scheduler.disable_reporting
65
63
  stop_scheduler
66
64
  elsif failed_component == :scheduler
67
65
  stop_worker
@@ -24,7 +24,7 @@ module Datadog
24
24
  attr_reader \
25
25
  :exporter,
26
26
  :transport,
27
- :profiler_failed
27
+ :reporting_disabled
28
28
 
29
29
  public
30
30
 
@@ -36,7 +36,7 @@ module Datadog
36
36
  )
37
37
  @exporter = exporter
38
38
  @transport = transport
39
- @profiler_failed = false
39
+ @reporting_disabled = false
40
40
  @stop_requested = false
41
41
 
42
42
  # Workers::Async::Thread settings
@@ -83,14 +83,15 @@ module Datadog
83
83
  true
84
84
  end
85
85
 
86
- # This is called by the Profiler class whenever an issue happened in the profiler. This makes sure that even
87
- # if there is data to be flushed, we don't try to flush it.
88
- def mark_profiler_failed
89
- @profiler_failed = true
86
+ # Called by the Profiler when it wants to prevent any further reporting,
87
+ # even if there is data to be flushed.
88
+ # Used when the profiler failed or we're otherwise in a hurry to shut down.
89
+ def disable_reporting
90
+ @reporting_disabled = true
90
91
  end
91
92
 
92
93
  def work_pending?
93
- !profiler_failed && exporter.can_flush? && (run_loop? || !stop_requested?)
94
+ !reporting_disabled && exporter.can_flush? && (run_loop? || !stop_requested?)
94
95
  end
95
96
 
96
97
  def reset_after_fork
@@ -50,6 +50,7 @@ module Datadog
50
50
  FORM_FIELD_TAG_PROFILER_VERSION => profiler_version,
51
51
  'profile_seq' => profile_seq.to_s,
52
52
  )
53
+
53
54
  user_tag_keys = settings.tags.keys
54
55
  hash.keep_if { |tag| user_tag_keys.include?(tag) || ALLOWED_TAGS.include?(tag) }
55
56
  Core::Utils.encode_tags(hash)
@@ -220,12 +220,20 @@ module Datadog
220
220
  # `@instrumented_integrations` hash.
221
221
  # @!visibility private
222
222
  def instrumented_integrations
223
- INSTRUMENTED_INTEGRATIONS_LOCK.synchronize { (@instrumented_integrations&.dup || {}).freeze }
223
+ INSTRUMENTED_INTEGRATIONS_LOCK.synchronize do
224
+ (if defined?(@instrumented_integrations)
225
+ @instrumented_integrations&.dup
226
+ end || {}).freeze
227
+ end
224
228
  end
225
229
 
226
230
  # @!visibility private
227
231
  def reset!
228
- INSTRUMENTED_INTEGRATIONS_LOCK.synchronize { @instrumented_integrations&.clear }
232
+ INSTRUMENTED_INTEGRATIONS_LOCK.synchronize do
233
+ if defined?(@instrumented_integrations)
234
+ @instrumented_integrations&.clear
235
+ end
236
+ end
229
237
  super
230
238
  end
231
239
 
@@ -25,35 +25,34 @@ module Datadog
25
25
  # @see https://github.com/karafka/karafka/blob/b06d1f7c17818e1605f80c2bb573454a33376b40/README.md?plain=1#L29-L35
26
26
  def each(&block)
27
27
  @messages_array.each do |message|
28
- if configuration[:distributed_tracing]
28
+ trace_digest = if configuration[:distributed_tracing]
29
29
  headers = if message.metadata.respond_to?(:raw_headers)
30
30
  message.metadata.raw_headers
31
31
  else
32
32
  message.metadata.headers
33
33
  end
34
- trace_digest = Karafka.extract(headers)
35
- Datadog::Tracing.continue_trace!(trace_digest) if trace_digest
34
+ Karafka.extract(headers)
36
35
  end
37
36
 
38
- if Datadog::DataStreams.enabled?
39
- begin
40
- headers = if message.metadata.respond_to?(:raw_headers)
41
- message.metadata.raw_headers
42
- else
43
- message.metadata.headers
37
+ Tracing.trace(Ext::SPAN_MESSAGE_CONSUME, continue_from: trace_digest) do |span, trace|
38
+ if Datadog::DataStreams.enabled?
39
+ begin
40
+ headers = if message.metadata.respond_to?(:raw_headers)
41
+ message.metadata.raw_headers
42
+ else
43
+ message.metadata.headers
44
+ end
45
+
46
+ Datadog::DataStreams.set_consume_checkpoint(
47
+ type: 'kafka',
48
+ source: message.topic,
49
+ auto_instrumentation: true
50
+ ) { |key| headers[key] }
51
+ rescue => e
52
+ Datadog.logger.debug("Error setting DSM checkpoint: #{e.class}: #{e}")
44
53
  end
45
-
46
- Datadog::DataStreams.set_consume_checkpoint(
47
- type: 'kafka',
48
- source: message.topic,
49
- auto_instrumentation: true
50
- ) { |key| headers[key] }
51
- rescue => e
52
- Datadog.logger.debug("Error setting DSM checkpoint: #{e.class}: #{e}")
53
54
  end
54
- end
55
55
 
56
- Tracing.trace(Ext::SPAN_MESSAGE_CONSUME) do |span|
57
56
  span.set_tag(Ext::TAG_OFFSET, message.metadata.offset)
58
57
  span.set_tag(Contrib::Ext::Messaging::TAG_DESTINATION, message.topic)
59
58
  span.set_tag(Contrib::Ext::Messaging::TAG_SYSTEM, Ext::TAG_SYSTEM)
@@ -66,22 +65,12 @@ module Datadog
66
65
  end
67
66
  end
68
67
 
69
- module AppPatch
70
- ONLY_ONCE_PER_APP = Hash.new { |h, key| h[key] = Core::Utils::OnlyOnce.new }
71
-
72
- def initialized!
73
- ONLY_ONCE_PER_APP[self].run do
74
- # Activate tracing on components related to Karafka (e.g. WaterDrop)
75
- Contrib::Karafka::Framework.setup
76
- end
77
- super
78
- end
79
- end
80
-
81
68
  # Patcher enables patching of 'karafka' module.
82
69
  module Patcher
83
70
  include Contrib::Patcher
84
71
 
72
+ ACTIVATE_FRAMEWORK_ONLY_ONCE = Core::Utils::OnlyOnce.new
73
+
85
74
  module_function
86
75
 
87
76
  def target_version
@@ -91,10 +80,20 @@ module Datadog
91
80
  def patch
92
81
  require_relative 'monitor'
93
82
  require_relative 'framework'
83
+ require_relative '../waterdrop'
94
84
 
95
85
  ::Karafka::Instrumentation::Monitor.prepend(Monitor)
96
86
  ::Karafka::Messages::Messages.prepend(MessagesPatch)
97
- ::Karafka::App.singleton_class.prepend(AppPatch)
87
+
88
+ if Contrib::WaterDrop::Integration.compatible?
89
+ ::Karafka.monitor.subscribe('app.initialized') do |event|
90
+ ACTIVATE_FRAMEWORK_ONLY_ONCE.run do
91
+ Contrib::Karafka::Framework.setup
92
+ end
93
+
94
+ Contrib::WaterDrop::Patcher.add_middleware(::Karafka.producer)
95
+ end
96
+ end
98
97
  end
99
98
  end
100
99
  end
@@ -8,7 +8,8 @@ module Datadog
8
8
  attr_reader :ranges
9
9
 
10
10
  def initialize(ranges)
11
- @ranges = Array(ranges)
11
+ # Steep: https://github.com/ruby/rbs/issues/1874
12
+ @ranges = Array(ranges) # steep:ignore IncompatibleAssignment
12
13
  end
13
14
 
14
15
  def +(other)
@@ -10,7 +10,9 @@ module Datadog
10
10
  PLACEHOLDER = '?'
11
11
  EXCLUDE_KEYS = [].freeze
12
12
  SHOW_KEYS = [].freeze
13
- DEFAULT_OPTIONS = {
13
+
14
+ # Steep: https://github.com/soutaro/steep/issues/363
15
+ DEFAULT_OPTIONS = { # steep:ignore IncompatibleAssignment
14
16
  exclude: EXCLUDE_KEYS,
15
17
  show: SHOW_KEYS,
16
18
  placeholder: PLACEHOLDER
@@ -25,9 +25,7 @@ module Datadog
25
25
  ::WaterDrop::Producer.prepend(Producer)
26
26
  ::WaterDrop.instrumentation.subscribe('producer.configured') do |event|
27
27
  producer = event[:producer]
28
-
29
- included_middlewares = producer.middleware.instance_variable_get(:@steps)
30
- producer.middleware.append(Middleware) unless included_middlewares.include?(Middleware)
28
+ add_middleware(producer)
31
29
 
32
30
  if Datadog.configuration.data_streams.enabled
33
31
  producer.monitor.subscribe('message.acknowledged') do |ack_event|
@@ -39,6 +37,11 @@ module Datadog
39
37
  end
40
38
  end
41
39
  end
40
+
41
+ def add_middleware(producer)
42
+ included_middlewares = producer.middleware.instance_variable_get(:@steps)
43
+ producer.middleware.append(Middleware) unless included_middlewares.include?(Middleware)
44
+ end
42
45
  end
43
46
  end
44
47
  end
@@ -12,12 +12,16 @@ module Datadog
12
12
  def self.inject(digest, data)
13
13
  raise 'Please invoke Datadog.configure at least once before calling this method' unless @propagation
14
14
 
15
+ # Steep: https://github.com/soutaro/steep/issues/477
16
+ # @type ivar @propagation: WaterDrop::Distributed::Propagation
15
17
  @propagation.inject!(digest, data)
16
18
  end
17
19
 
18
20
  def self.extract(data)
19
21
  raise 'Please invoke Datadog.configure at least once before calling this method' unless @propagation
20
22
 
23
+ # Steep: https://github.com/soutaro/steep/issues/477
24
+ # @type ivar @propagation: WaterDrop::Distributed::Propagation
21
25
  @propagation.extract(data)
22
26
  end
23
27
 
@@ -62,7 +62,7 @@ module Datadog
62
62
  # return `nil` with IO transport
63
63
  return unless transport.respond_to?(:client)
64
64
 
65
- adapter = transport.client.api.adapter
65
+ adapter = transport.client.instance.adapter
66
66
  adapter.url
67
67
  end
68
68
 
@@ -175,8 +175,9 @@ module Datadog
175
175
 
176
176
  tags = {}
177
177
 
178
- baggage_tag_keys.each do |key, _| # rubocop:disable Style/HashEachMethods
179
- value = baggage[key]
178
+ baggage_tag_keys.each do |key, _|
179
+ # Steep: https://github.com/soutaro/steep/issues/2031
180
+ value = baggage[key] # steep:ignore ArgumentTypeMismatch
180
181
  next if value.nil? || value.empty?
181
182
 
182
183
  tags["baggage.#{key}"] = value
@@ -7,8 +7,6 @@ module Datadog
7
7
  module Tracing
8
8
  # Remote configuration declaration
9
9
  module Remote
10
- class ReadError < StandardError; end
11
-
12
10
  class << self
13
11
  PRODUCT = 'APM_TRACING'
14
12
 
@@ -71,13 +69,7 @@ module Datadog
71
69
  private
72
70
 
73
71
  def parse_content(content)
74
- data = content.data.read
75
-
76
- content.data.rewind
77
-
78
- raise ReadError, 'EOF reached' if data.nil?
79
-
80
- JSON.parse(data)
72
+ JSON.parse(content.data)
81
73
  end
82
74
  end
83
75
  end
@@ -60,7 +60,9 @@ module Datadog
60
60
  ensure
61
61
  if trace.sampling_priority && trace.sampling_priority > 0
62
62
  # Don't modify decision if priority was set upstream.
63
- if !distributed_sampling_priority && !trace.has_tag?(Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER)
63
+ # Steep: https://github.com/soutaro/steep/issues/1971
64
+ if !distributed_sampling_priority && # steep:ignore FallbackAny
65
+ !trace.has_tag?(Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER)
64
66
  # If no sampling priority being assigned at this point, a custom
65
67
  # sampler implementation is configured: this means the user has
66
68
  # full control over the sampling decision.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'sampler'
4
- require_relative '../utils'
4
+ require_relative '../../core/knuth_sampler'
5
5
 
6
6
  module Datadog
7
7
  module Tracing
@@ -9,46 +9,35 @@ module Datadog
9
9
  # {Datadog::Tracing::Sampling::RateSampler} is based on a sample rate.
10
10
  class RateSampler < Sampler
11
11
  KNUTH_FACTOR = 1111111111111111111
12
- UINT64_MODULO = (1 << 64)
13
12
 
14
13
  # Initialize a {Datadog::Tracing::Sampling::RateSampler}.
15
14
  # This sampler keeps a random subset of the traces. Its main purpose is to
16
15
  # reduce the instrumentation footprint.
17
16
  #
18
17
  # @param sample_rate [Numeric] the sample rate between 0.0 and 1.0, inclusive.
19
- # 0.0 means that no trace will be sampled; 1.0 means that all traces will be sampled.
18
+ # 0.0 means that no trace will be sampled; 1.0 means that all traces will be sampled.
20
19
  def initialize(sample_rate = 1.0, decision: nil)
21
20
  super()
22
-
23
- unless sample_rate >= 0.0 && sample_rate <= 1.0
24
- Datadog.logger.warn('sample rate is not between 0 and 1, falling back to 1')
25
- sample_rate = 1.0
26
- end
27
-
28
- self.sample_rate = sample_rate
29
-
21
+ @sampler = Core::KnuthSampler.new(sample_rate, knuth_factor: KNUTH_FACTOR)
30
22
  @decision = decision
31
23
  end
32
24
 
33
25
  def sample_rate(*_)
34
- @sample_rate
26
+ @sampler.rate
35
27
  end
36
28
 
37
29
  def sample_rate=(sample_rate)
38
- @sample_rate = sample_rate
39
- @sampling_id_threshold = sample_rate * Tracing::Utils::EXTERNAL_MAX_ID
30
+ @sampler = Core::KnuthSampler.new(sample_rate, knuth_factor: KNUTH_FACTOR)
40
31
  end
41
32
 
42
33
  def sample?(trace)
43
- ((trace.id * KNUTH_FACTOR) % UINT64_MODULO) <= @sampling_id_threshold
34
+ @sampler.sample?(trace.id)
44
35
  end
45
36
 
46
37
  def sample!(trace)
47
- sampled = sample?(trace)
48
-
49
- return false unless sampled
38
+ return false unless sample?(trace)
50
39
 
51
- trace.sample_rate = @sample_rate
40
+ trace.sample_rate = sample_rate
52
41
  trace.set_tag(Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER, @decision) if @decision
53
42
 
54
43
  true
@@ -80,7 +80,7 @@ module Datadog
80
80
 
81
81
  @meta = meta || {}
82
82
  @metrics = metrics || {}
83
- @metastruct = metastruct || {}
83
+ @metastruct = metastruct || Metastruct.new
84
84
  @status = status || 0
85
85
 
86
86
  # start_time and end_time track wall clock. In Ruby, wall clock
@@ -69,8 +69,8 @@ module Datadog
69
69
 
70
70
  private
71
71
 
72
- MIN_INT64_SIGNED = -2**63
73
- MAX_INT64_SIGNED = 2 << 63 - 1
72
+ MIN_INT64_SIGNED = -2 << 62
73
+ MAX_INT64_SIGNED = (2 << 62) - 1
74
74
 
75
75
  # Checks the attributes hash to ensure it only contains serializable values.
76
76
  # Invalid values are removed from the hash.