datadog 2.39.0 → 2.47.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 (296) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +269 -44
  3. data/README.md +3 -0
  4. data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +12 -24
  5. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +256 -193
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -5
  7. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +0 -2
  8. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +19 -20
  9. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.h +5 -1
  10. data/ext/datadog_profiling_native_extension/collectors_stack.c +267 -171
  11. data/ext/datadog_profiling_native_extension/collectors_stack.h +17 -3
  12. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +307 -217
  13. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +10 -5
  14. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +5 -4
  15. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +19 -11
  16. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -10
  17. data/ext/datadog_profiling_native_extension/extconf.rb +67 -99
  18. data/ext/datadog_profiling_native_extension/heap_recorder.c +353 -257
  19. data/ext/datadog_profiling_native_extension/heap_recorder.h +50 -31
  20. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -27
  21. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +853 -496
  22. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +42 -15
  23. data/ext/datadog_profiling_native_extension/profiling.c +30 -23
  24. data/ext/datadog_profiling_native_extension/ruby_helpers.c +4 -80
  25. data/ext/datadog_profiling_native_extension/ruby_helpers.h +4 -7
  26. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +0 -2
  27. data/ext/datadog_profiling_native_extension/stack_recorder.c +116 -89
  28. data/ext/datadog_profiling_native_extension/stack_recorder.h +12 -5
  29. data/ext/datadog_profiling_native_extension/time_helpers.c +2 -4
  30. data/ext/datadog_profiling_native_extension/time_helpers.h +15 -15
  31. data/ext/libdatadog_api/datadog_ruby_common.c +19 -11
  32. data/ext/libdatadog_api/datadog_ruby_common.h +7 -10
  33. data/ext/libdatadog_api/di.c +43 -3
  34. data/ext/libdatadog_api/extconf.rb +6 -1
  35. data/ext/libdatadog_api/feature_flags.c +8 -0
  36. data/ext/libdatadog_api/init.c +9 -1
  37. data/ext/libdatadog_api/otel_thread_context.c +274 -0
  38. data/ext/libdatadog_api/otel_thread_context.h +5 -0
  39. data/ext/libdatadog_api/process_discovery.c +15 -1
  40. data/ext/libdatadog_api/trace_exporter.c +2078 -0
  41. data/ext/libdatadog_api/trace_exporter.h +5 -0
  42. data/ext/libdatadog_extconf_helpers.rb +14 -9
  43. data/lib/datadog/ai_guard/component.rb +17 -8
  44. data/lib/datadog/ai_guard/configuration/ext.rb +2 -0
  45. data/lib/datadog/ai_guard/configuration.rb +13 -0
  46. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +48 -55
  47. data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +1 -1
  48. data/lib/datadog/ai_guard/contrib/ruby_llm/message_adapter.rb +76 -0
  49. data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +1 -0
  50. data/lib/datadog/ai_guard/contrib/ruby_llm/redaction_change_set.rb +135 -0
  51. data/lib/datadog/ai_guard/evaluation/client.rb +50 -0
  52. data/lib/datadog/ai_guard/evaluation/content_part.rb +12 -0
  53. data/lib/datadog/ai_guard/evaluation/message.rb +25 -7
  54. data/lib/datadog/ai_guard/evaluation/message_builder.rb +31 -0
  55. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +6 -6
  56. data/lib/datadog/ai_guard/evaluation/outcome.rb +24 -0
  57. data/lib/datadog/ai_guard/evaluation/request.rb +8 -64
  58. data/lib/datadog/ai_guard/evaluation/response.rb +33 -0
  59. data/lib/datadog/ai_guard/evaluation/result.rb +11 -18
  60. data/lib/datadog/ai_guard/evaluation/tool_call.rb +15 -2
  61. data/lib/datadog/ai_guard/evaluation.rb +36 -14
  62. data/lib/datadog/ai_guard/ext.rb +4 -1
  63. data/lib/datadog/ai_guard/{api_client.rb → http_client.rb} +7 -5
  64. data/lib/datadog/ai_guard/metrics/telemetry.rb +43 -0
  65. data/lib/datadog/ai_guard/redaction/replacements.rb +97 -0
  66. data/lib/datadog/ai_guard/redaction/result.rb +29 -0
  67. data/lib/datadog/ai_guard/redaction.rb +80 -0
  68. data/lib/datadog/ai_guard.rb +58 -57
  69. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +21 -42
  70. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +1 -1
  71. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +1 -1
  72. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +1 -1
  73. data/lib/datadog/appsec/assets/blocked.html +1 -108
  74. data/lib/datadog/appsec/configuration.rb +11 -2
  75. data/lib/datadog/appsec/context.rb +1 -1
  76. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +1 -1
  77. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +2 -2
  78. data/lib/datadog/appsec/contrib/devise/configuration.rb +1 -1
  79. data/lib/datadog/appsec/contrib/devise/patcher.rb +1 -1
  80. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +2 -2
  81. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +2 -2
  82. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
  83. data/lib/datadog/appsec/contrib/rack/ext.rb +2 -2
  84. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +2 -2
  85. data/lib/datadog/appsec/contrib/rack/patcher.rb +1 -1
  86. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +6 -3
  87. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +30 -3
  88. data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +8 -7
  89. data/lib/datadog/appsec/contrib/rails/request_middleware.rb +2 -1
  90. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +2 -2
  91. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +15 -3
  92. data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +8 -7
  93. data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
  94. data/lib/datadog/appsec/processor/rule_loader.rb +12 -12
  95. data/lib/datadog/appsec/response.rb +1 -1
  96. data/lib/datadog/appsec/route_normalizer/route_pattern.rb +3 -3
  97. data/lib/datadog/appsec/security_engine/engine.rb +5 -4
  98. data/lib/datadog/core/configuration/components.rb +50 -19
  99. data/lib/datadog/core/configuration/components_state.rb +8 -1
  100. data/lib/datadog/core/configuration/option_definition.rb +1 -1
  101. data/lib/datadog/core/configuration/options.rb +1 -1
  102. data/lib/datadog/core/configuration/settings.rb +38 -43
  103. data/lib/datadog/core/configuration/supported_configurations.rb +18 -2
  104. data/lib/datadog/core/crashtracking/component.rb +5 -1
  105. data/lib/datadog/core/diagnostics/environment_logger.rb +36 -1
  106. data/lib/datadog/core/environment/gc.rb +1 -1
  107. data/lib/datadog/core/environment/vm_cache.rb +1 -1
  108. data/lib/datadog/core/environment/yjit.rb +2 -2
  109. data/lib/datadog/core/metrics/helpers.rb +1 -1
  110. data/lib/datadog/core/metrics/options.rb +2 -2
  111. data/lib/datadog/core/process_discovery.rb +6 -2
  112. data/lib/datadog/core/remote/client/capabilities.rb +32 -21
  113. data/lib/datadog/core/remote/client.rb +45 -4
  114. data/lib/datadog/core/remote/component.rb +30 -7
  115. data/lib/datadog/core/remote/configuration/repository.rb +2 -2
  116. data/lib/datadog/core/remote/dispatcher.rb +47 -6
  117. data/lib/datadog/core/remote/worker.rb +8 -0
  118. data/lib/datadog/core/telemetry/configuration_value.rb +38 -0
  119. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +3 -1
  120. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +1 -1
  121. data/lib/datadog/core/telemetry/event/app_started.rb +5 -24
  122. data/lib/datadog/core/telemetry/event/generate_metrics.rb +1 -1
  123. data/lib/datadog/core/telemetry/event/log.rb +2 -2
  124. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
  125. data/lib/datadog/core/telemetry/metric.rb +2 -2
  126. data/lib/datadog/core/telemetry/request.rb +2 -2
  127. data/lib/datadog/core/transport/http.rb +1 -1
  128. data/lib/datadog/core/transport/transport.rb +1 -1
  129. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +170 -18
  130. data/lib/datadog/core/utils/sequence.rb +3 -6
  131. data/lib/datadog/core/utils/time.rb +16 -54
  132. data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
  133. data/lib/datadog/data_streams/pathway_context.rb +20 -22
  134. data/lib/datadog/data_streams/processor.rb +45 -14
  135. data/lib/datadog/di/boot.rb +1 -0
  136. data/lib/datadog/di/capture_expression_evaluator/result.rb +30 -0
  137. data/lib/datadog/di/capture_expression_evaluator.rb +39 -9
  138. data/lib/datadog/di/component.rb +108 -3
  139. data/lib/datadog/di/configuration.rb +53 -2
  140. data/lib/datadog/di/context.rb +7 -2
  141. data/lib/datadog/di/contrib/active_record.rb +8 -2
  142. data/lib/datadog/di/el/compiler.rb +88 -12
  143. data/lib/datadog/di/el/evaluator.rb +82 -2
  144. data/lib/datadog/di/el/expression.rb +13 -2
  145. data/lib/datadog/di/evaluation_failure.rb +28 -0
  146. data/lib/datadog/di/guardrails_telemetry/reason.rb +87 -0
  147. data/lib/datadog/di/guardrails_telemetry.rb +203 -0
  148. data/lib/datadog/di/instrumenter.rb +106 -15
  149. data/lib/datadog/di/logger.rb +32 -10
  150. data/lib/datadog/di/probe.rb +9 -1
  151. data/lib/datadog/di/probe_builder.rb +7 -6
  152. data/lib/datadog/di/probe_manager.rb +56 -8
  153. data/lib/datadog/di/probe_notification_builder.rb +31 -28
  154. data/lib/datadog/di/probe_notifier_worker.rb +56 -6
  155. data/lib/datadog/di/proc_responder.rb +1 -1
  156. data/lib/datadog/di/remote.rb +49 -5
  157. data/lib/datadog/di/serializer.rb +172 -55
  158. data/lib/datadog/di/snapshot_event.rb +38 -0
  159. data/lib/datadog/di/transport/http.rb +13 -3
  160. data/lib/datadog/di/transport/input.rb +32 -7
  161. data/lib/datadog/error_tracking/component.rb +1 -1
  162. data/lib/datadog/kit/appsec/events/v2.rb +2 -2
  163. data/lib/datadog/open_feature/activation.rb +268 -0
  164. data/lib/datadog/open_feature/agentless/configuration_source.rb +246 -0
  165. data/lib/datadog/open_feature/agentless/parser.rb +43 -0
  166. data/lib/datadog/open_feature/agentless/response.rb +19 -0
  167. data/lib/datadog/open_feature/agentless/transport.rb +103 -0
  168. data/lib/datadog/open_feature/component.rb +85 -13
  169. data/lib/datadog/open_feature/configuration/agentless_endpoint.rb +90 -0
  170. data/lib/datadog/open_feature/configuration/source/resolution.rb +22 -0
  171. data/lib/datadog/open_feature/configuration/source.rb +43 -0
  172. data/lib/datadog/open_feature/configuration.rb +124 -0
  173. data/lib/datadog/open_feature/evaluation_engine.rb +29 -3
  174. data/lib/datadog/open_feature/exposures/batch_builder.rb +1 -1
  175. data/lib/datadog/open_feature/exposures/event.rb +15 -8
  176. data/lib/datadog/open_feature/ext.rb +19 -0
  177. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +236 -80
  178. data/lib/datadog/open_feature/flag_evaluation/writer.rb +179 -68
  179. data/lib/datadog/open_feature/hooks/evaluation_telemetry_opt_out_hook.rb +25 -0
  180. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +24 -21
  181. data/lib/datadog/open_feature/native_evaluator.rb +20 -6
  182. data/lib/datadog/open_feature/noop_evaluator.rb +5 -0
  183. data/lib/datadog/open_feature/provider.rb +315 -10
  184. data/lib/datadog/open_feature/remote.rb +5 -5
  185. data/lib/datadog/open_feature/transport.rb +5 -0
  186. data/lib/datadog/open_feature.rb +31 -1
  187. data/lib/datadog/opentelemetry/sdk/propagator.rb +1 -1
  188. data/lib/datadog/opentelemetry/signal_configuration.rb +13 -9
  189. data/lib/datadog/opentelemetry/trace.rb +3 -0
  190. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +10 -2
  191. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +5 -7
  192. data/lib/datadog/profiling/collectors/info.rb +40 -13
  193. data/lib/datadog/profiling/collectors/thread_context.rb +6 -17
  194. data/lib/datadog/profiling/component.rb +33 -39
  195. data/lib/datadog/profiling/exporter.rb +10 -10
  196. data/lib/datadog/profiling/tasks/exec.rb +1 -1
  197. data/lib/datadog/profiling.rb +4 -0
  198. data/lib/datadog/symbol_database/extractor.rb +89 -107
  199. data/lib/datadog/tracing/component.rb +44 -2
  200. data/lib/datadog/tracing/configuration/dynamic/option.rb +4 -0
  201. data/lib/datadog/tracing/configuration/dynamic.rb +5 -3
  202. data/lib/datadog/tracing/configuration/ext.rb +4 -0
  203. data/lib/datadog/tracing/configuration/settings.rb +36 -0
  204. data/lib/datadog/tracing/context.rb +24 -2
  205. data/lib/datadog/tracing/context_provider.rb +17 -5
  206. data/lib/datadog/tracing/contrib/action_cable/events.rb +1 -1
  207. data/lib/datadog/tracing/contrib/action_mailer/events.rb +1 -1
  208. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +2 -2
  209. data/lib/datadog/tracing/contrib/action_view/events.rb +1 -1
  210. data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +1 -1
  211. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +1 -1
  212. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -0
  213. data/lib/datadog/tracing/contrib/active_record/events.rb +1 -1
  214. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +2 -2
  215. data/lib/datadog/tracing/contrib/aws/ext.rb +1 -1
  216. data/lib/datadog/tracing/contrib/aws/services.rb +1 -1
  217. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +1 -1
  218. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +10 -5
  219. data/lib/datadog/tracing/contrib/excon/middleware.rb +10 -3
  220. data/lib/datadog/tracing/contrib/ext.rb +3 -3
  221. data/lib/datadog/tracing/contrib/faraday/middleware.rb +10 -4
  222. data/lib/datadog/tracing/contrib/grape/endpoint.rb +32 -5
  223. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +1 -1
  224. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +1 -1
  225. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +1 -1
  226. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +2 -1
  227. data/lib/datadog/tracing/contrib/http/instrumentation.rb +16 -1
  228. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +8 -2
  229. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +10 -4
  230. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +4 -0
  231. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +7 -2
  232. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +7 -2
  233. data/lib/datadog/tracing/contrib/kafka/events.rb +1 -1
  234. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +1 -1
  235. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -1
  236. data/lib/datadog/tracing/contrib/opensearch/ext.rb +1 -1
  237. data/lib/datadog/tracing/contrib/opensearch/quantize.rb +1 -1
  238. data/lib/datadog/tracing/contrib/patchable.rb +1 -1
  239. data/lib/datadog/tracing/contrib/patcher.rb +1 -1
  240. data/lib/datadog/tracing/contrib/que/tracer.rb +1 -1
  241. data/lib/datadog/tracing/contrib/racecar/events.rb +1 -1
  242. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +1 -1
  243. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +1 -1
  244. data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
  245. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +1 -1
  246. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +1 -1
  247. data/lib/datadog/tracing/contrib/redis/quantize.rb +36 -2
  248. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +9 -3
  249. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +10 -3
  250. data/lib/datadog/tracing/contrib/sequel/database.rb +1 -5
  251. data/lib/datadog/tracing/contrib/sequel/jdbc_connection_string.rb +140 -0
  252. data/lib/datadog/tracing/contrib/sequel/utils.rb +50 -63
  253. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +1 -1
  254. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +1 -1
  255. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +1 -1
  256. data/lib/datadog/tracing/contrib/utils/quantization/hash_formatter.rb +1 -1
  257. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +108 -3
  258. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +1 -1
  259. data/lib/datadog/tracing/correlation.rb +2 -2
  260. data/lib/datadog/tracing/diagnostics/environment_logger.rb +3 -2
  261. data/lib/datadog/tracing/distributed/baggage.rb +1 -3
  262. data/lib/datadog/tracing/distributed/datadog.rb +3 -3
  263. data/lib/datadog/tracing/distributed/propagation.rb +3 -0
  264. data/lib/datadog/tracing/distributed/propagation_policy.rb +5 -0
  265. data/lib/datadog/tracing/distributed/trace_context.rb +14 -271
  266. data/lib/datadog/tracing/distributed/trace_state/datadog.rb +233 -0
  267. data/lib/datadog/tracing/distributed/trace_state/ext.rb +44 -0
  268. data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +156 -0
  269. data/lib/datadog/tracing/distributed/trace_state.rb +121 -0
  270. data/lib/datadog/tracing/metadata/ext.rb +3 -0
  271. data/lib/datadog/tracing/metadata/tagging.rb +1 -1
  272. data/lib/datadog/tracing/otel_thread_context.rb +97 -0
  273. data/lib/datadog/tracing/remote.rb +236 -37
  274. data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -0
  275. data/lib/datadog/tracing/span.rb +1 -1
  276. data/lib/datadog/tracing/span_operation.rb +1 -1
  277. data/lib/datadog/tracing/sync_writer.rb +8 -3
  278. data/lib/datadog/tracing/trace_digest.rb +22 -4
  279. data/lib/datadog/tracing/trace_operation.rb +22 -10
  280. data/lib/datadog/tracing/tracer.rb +28 -7
  281. data/lib/datadog/tracing/transport/http/telemetry.rb +94 -0
  282. data/lib/datadog/tracing/transport/http/traces.rb +2 -0
  283. data/lib/datadog/tracing/transport/io/traces.rb +1 -1
  284. data/lib/datadog/tracing/transport/native/response.rb +71 -0
  285. data/lib/datadog/tracing/transport/native/telemetry.rb +17 -0
  286. data/lib/datadog/tracing/transport/native.rb +395 -0
  287. data/lib/datadog/tracing/transport/span_events_negotiation.rb +41 -0
  288. data/lib/datadog/tracing/transport/telemetry.rb +62 -0
  289. data/lib/datadog/tracing/transport/trace_formatter.rb +14 -4
  290. data/lib/datadog/tracing/transport/traces.rb +85 -38
  291. data/lib/datadog/tracing/writer.rb +17 -4
  292. data/lib/datadog/version.rb +1 -1
  293. metadata +51 -13
  294. data/lib/datadog/ai_guard/evaluation/content_builder.rb +0 -31
  295. data/lib/datadog/appsec/utils/hash_coercion.rb +0 -23
  296. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -69
@@ -15,52 +15,265 @@ module Datadog
15
15
  1 << 13, # APM_TRACING_LOGS_INJECTION: Dynamic trace logs injection configuration
16
16
  1 << 14, # APM_TRACING_HTTP_HEADER_TAGS: Dynamic trace HTTP header tags configuration
17
17
  1 << 29, # APM_TRACING_SAMPLE_RULES: Dynamic trace sampling rules configuration
18
+ 1 << 45, # APM_TRACING_MULTICONFIG: merge multiple org/env-level APM_TRACING configs
18
19
  # APM_TRACING_ENABLE_DYNAMIC_INSTRUMENTATION (bit 38) is declared in
19
20
  # DI::Remote.capabilities, not here, so it is registered only when DI
20
21
  # is not explicitly disabled and the runtime supports DI.
21
22
  ].freeze
22
23
 
24
+ # Diagnostic scope label per specificity priority.
25
+ SCOPE_LABELS = {
26
+ 5 => "service+env",
27
+ 4 => "service",
28
+ 3 => "env",
29
+ 2 => "cluster",
30
+ 1 => "org",
31
+ }.freeze
32
+
33
+ # @return [Array[String]] the remote config products this module handles
23
34
  def products
24
35
  [PRODUCT]
25
36
  end
26
37
 
38
+ # @return [Array[Integer]] the remote config capability bits advertised
27
39
  def capabilities
28
40
  CAPABILITIES
29
41
  end
30
42
 
31
- def process_config(config, content, repository = nil)
32
- lib_config = config["lib_config"]
43
+ # Merges every active APM_TRACING config in the repository and applies the
44
+ # result once. Org/env-level (multi-config) remote enablement delivers
45
+ # several APM_TRACING configs in parallel (a (service, env)-specific one,
46
+ # an env-wide one, and/or an org-wide "*" one); for each lib_config field
47
+ # the value from the most-specific matching config wins. The RC repository
48
+ # prunes deleted configs, so this recomputes the merge from the repository's
49
+ # current contents on each dispatch.
50
+ #
51
+ # @param repository [Core::Remote::Configuration::Repository] the current RC repository
52
+ # @return [nil]
53
+ def merge_and_apply_configs(repository)
54
+ # Resolve the service identity the same way the RC client registers
55
+ # it with the backend (Core::Remote::Client#service_name =
56
+ # remote.service || service). When a customer sets remote.service,
57
+ # the backend delivers service_target.service values targeting that
58
+ # override; matching against the local service instead would drop
59
+ # every service-scoped config and let a less-specific org config win.
60
+ service = Datadog.configuration.remote.service || Datadog.configuration.service
61
+ env = Datadog.configuration.env
62
+
63
+ # @type var parsed: Array[[::Datadog::Core::Remote::Configuration::Content, ::Hash[::String, untyped]]]
64
+ parsed = []
65
+ # @type var unparseable_contents: Array[Datadog::Core::Remote::Configuration::Content]
66
+ unparseable_contents = []
67
+ repository.contents.each do |content|
68
+ next unless content.path.product == PRODUCT
69
+
70
+ begin
71
+ config = parse_content(content)
72
+ unless config.is_a?(Hash)
73
+ # A syntactically valid but non-object payload (null, [], 42)
74
+ # would later make config_matches? raise outside this per-content
75
+ # rescue and abort the whole merge, erroring valid configs too.
76
+ raise TypeError, "APM_TRACING remote config must be a JSON object, got #{config.class}"
77
+ end
78
+ # A present but non-object lib_config (e.g. {"lib_config": []}) is a
79
+ # schema violation the customer can fix. Acknowledging it as applied
80
+ # would tell the backend the config was successfully applied when it
81
+ # was not. Reject it per content so the malformed payload is
82
+ # reported errored instead. A null or absent lib_config
83
+ # carries no overrides and is left as a no-op.
84
+ lib_config = config["lib_config"]
85
+ if !lib_config.nil? && !lib_config.is_a?(Hash)
86
+ raise TypeError, "APM_TRACING lib_config must be a JSON object, got #{lib_config.class}"
87
+ end
88
+ parsed << [content, config]
89
+ rescue => e
90
+ Datadog.logger.debug { "APM_TRACING RC: skipping unparseable config: #{e.class}: #{e.message}" }
91
+ Datadog.send(:components, allow_initialization: false)&.telemetry&.report(
92
+ e,
93
+ description: "Failed to parse APM_TRACING remote config",
94
+ )
95
+ content.errored("#{e.class}: #{e.message}: #{Array(e.backtrace).join("\n")}")
96
+ unparseable_contents << content
97
+ end
98
+ end
99
+
100
+ Datadog.logger.debug { "APM_TRACING RC: received #{parsed.length} config(s)" }
101
+
102
+ applicable = parsed.select do |content, config|
103
+ if config_matches?(config, service, env)
104
+ Datadog.logger.debug do
105
+ "APM_TRACING RC: config #{content.path.config_id} " \
106
+ "scope=#{SCOPE_LABELS[config_priority(config)]} priority=#{config_priority(config)}"
107
+ end
108
+ true
109
+ else
110
+ Datadog.logger.debug do
111
+ "APM_TRACING RC: dropped config #{content.path.config_id} " \
112
+ "(service_target=#{config["service_target"].inspect}, self=#{service}/#{env})"
113
+ end
114
+ false
115
+ end
116
+ end
117
+
118
+ # Most-specific first; ties broken by config id (ascending) for a
119
+ # deterministic merge.
120
+ ordered = applicable.sort_by { |content, config| [-config_priority(config), content.path.config_id] }
121
+ merged = merge_lib_configs(ordered.map { |_content, config| config })
122
+ # The applicable configs carrying a non-null dynamic_instrumentation_enabled
123
+ # value: any of their paths can still supply the signal after a later
124
+ # replacement, so the DI component records them all.
125
+ # @type var enable_signal_paths: Array[Datadog::Core::Remote::Configuration::Path]
126
+ enable_signal_paths = Core::Utils::EnumerableCompat.filter_map(ordered) do |pair|
127
+ content, config = pair
128
+ lib_config = config["lib_config"]
129
+ if lib_config.is_a?(Hash) && !lib_config["dynamic_instrumentation_enabled"].nil?
130
+ content.path
131
+ end
132
+ end
133
+
134
+ # Applied even when the set is empty: an emptied repository (last config
135
+ # removed) reverts the tracing overrides to their non-RC values.
136
+ apply_lib_config(
137
+ merged,
138
+ repository,
139
+ unparseable_contents: unparseable_contents,
140
+ enable_signal_paths: enable_signal_paths,
141
+ )
142
+
143
+ parsed.each { |content, _config| content.applied }
144
+ nil
145
+ rescue => e
146
+ Datadog.logger.debug { "APM_TRACING RC: failed to apply configs: #{e.class}: #{e.message}" }
147
+ Datadog.send(:components, allow_initialization: false)&.telemetry&.report(
148
+ e,
149
+ description: "Failed to apply APM_TRACING remote configs",
150
+ )
151
+ parsed&.each do |content, _config|
152
+ content.errored("#{e.class}: #{e.message}: #{Array(e.backtrace).join("\n")}")
153
+ end
154
+ nil
155
+ end
156
+
157
+ # Whether a config targets this tracer. A concrete (non-"*") service or
158
+ # env that differs from ours excludes the config; "*" and an absent
159
+ # service_target match anything.
160
+ #
161
+ # @param config [Hash[String, untyped]] a parsed config
162
+ # @param service [String, nil] this tracer's service
163
+ # @param env [String, nil] this tracer's env
164
+ # @return [bool] true when the config applies to this tracer
165
+ def config_matches?(config, service, env)
166
+ target = config["service_target"]
167
+ return true unless target.is_a?(Hash)
33
168
 
169
+ target_service = target["service"]
170
+ target_env = target["env"]
171
+ return false if target_service && target_service != "*" && target_service != service
172
+ return false if target_env && target_env != "*" && target_env != env
173
+
174
+ true
175
+ end
176
+
177
+ # Specificity of a config, higher meaning more specific: service+env (5),
178
+ # service (4), env (3), cluster (2), org (1). A target counts as concrete
179
+ # only when present and not "*".
180
+ #
181
+ # @param config [Hash[String, untyped]] a parsed config
182
+ # @return [Integer] the specificity rank, 1 through 5
183
+ def config_priority(config)
184
+ target = config["service_target"]
185
+ service = target.is_a?(Hash) ? target["service"] : nil
186
+ env = target.is_a?(Hash) ? target["env"] : nil
187
+ single_service = !service.nil? && service != "*"
188
+ single_env = !env.nil? && env != "*"
189
+
190
+ return 5 if single_service && single_env
191
+ return 4 if single_service
192
+ return 3 if single_env
193
+ return 2 unless config["k8s_target_v2"].nil?
194
+
195
+ 1
196
+ end
197
+
198
+ # Merges lib_configs from configs ordered most-specific first: for each
199
+ # field, the first (most-specific) non-nil value wins. Fields are
200
+ # independent, so a lower-priority config can supply a field the
201
+ # higher-priority one omits.
202
+ #
203
+ # @param configs_most_specific_first [Array[Hash[String, untyped]]] configs, most-specific first
204
+ # @return [Hash[String, untyped]] the merged lib_config
205
+ def merge_lib_configs(configs_most_specific_first)
206
+ merged = {}
207
+ configs_most_specific_first.each do |config|
208
+ lib_config = config["lib_config"]
209
+ next unless lib_config.is_a?(Hash)
210
+
211
+ lib_config.each do |key, value|
212
+ next if value.nil?
213
+
214
+ merged[key] = value unless merged.key?(key)
215
+ end
216
+ end
217
+ merged
218
+ end
219
+
220
+ # Applies one lib_config: maps the dynamic OPTIONS to telemetry, drives DI
221
+ # enablement from "dynamic_instrumentation_enabled", and reports the
222
+ # configuration change to telemetry.
223
+ #
224
+ # @param lib_config [Hash[String, untyped]] the lib_config to apply
225
+ # @param repository [Core::Remote::Configuration::Repository, nil] forwarded to DI enablement
226
+ # @param unparseable_contents [Array<Core::Remote::Configuration::Content>] the APM_TRACING contents that failed to parse
227
+ # @param enable_signal_paths [Array<Core::Remote::Configuration::Path>] the paths of the applicable configs carrying the field
228
+ # @return [nil]
229
+ def apply_lib_config(lib_config, repository, unparseable_contents:, enable_signal_paths:)
34
230
  env_vars = Datadog::Tracing::Configuration::Dynamic::OPTIONS.map do |name, env_var, option|
35
231
  value = lib_config[name]
36
232
 
37
233
  # Guard for RBS/Steep
38
234
  raise "option is a #{option.class}, expected Option" unless option.is_a?(Configuration::Dynamic::Option)
39
235
 
40
- option.call(value)
236
+ telemetry_value = option.call(value)
237
+
238
+ [env_var, telemetry_value]
239
+ end
240
+
241
+ di_enabled = lib_config["dynamic_instrumentation_enabled"]
242
+ # allow_initialization: false because this runs on the remote-config worker
243
+ # thread, and the default would build the component tree from that thread.
244
+ components = Datadog.send(:components, allow_initialization: false)
245
+ di_component = components&.dynamic_instrumentation
246
+ if di_enabled.nil? && di_component&.rc_enablement_signal_withdrawn?(unparseable_contents)
247
+ di_enabled = false
248
+ end
41
249
 
42
- [env_var, value]
250
+ # Records the parsed carrier paths and the previously recorded paths whose
251
+ # replacements remain unparseable, on every merge including merges that keep
252
+ # the DI state.
253
+ if di_component
254
+ unparseable_recorded_paths = di_component.rc_enablement_signal_paths.select do |path|
255
+ unparseable_contents.any? { |content| content.path == path }
256
+ end
257
+ di_component.record_rc_enablement_signal_paths(enable_signal_paths + unparseable_recorded_paths)
43
258
  end
44
259
 
45
- if (di_enabled = lib_config["dynamic_instrumentation_enabled"]) != nil # rubocop:disable Style/NonNilCheck
46
- # repository is forwarded so that an enable signal can reconcile DI
47
- # against probes delivered in an earlier poll while DI was stopped
48
- # (see Datadog::DI::Remote.handle_rc_enablement).
260
+ unless di_enabled.nil?
261
+ # repository is forwarded for the stopped->started replay in
262
+ # Datadog::DI::Remote.handle_rc_enablement.
49
263
  Datadog::DI::Remote.handle_rc_enablement(di_enabled, repository)
50
264
 
51
- components = Datadog.send(:components, allow_initialization: false)
52
265
  di_products = Datadog::DI::Remote.products +
53
266
  Datadog::SymbolDatabase::Remote.deferred_products(Datadog.configuration)
54
267
 
55
268
  if di_enabled
56
269
  components&.symbol_database&.resume_pending_upload
57
270
  # Advertise the DI products only if the component actually started.
58
- # handle_rc_enablement above no-ops when DI cannot run — the
59
- # component is nil on an unsupported runtime, or the enable signal
60
- # is blocked by DD_DYNAMIC_INSTRUMENTATION_ENABLED=false. Advertising
61
- # then would report DI as in use when it is not and invite probe
62
- # configs the tracer must refuse; withdraw the products otherwise.
63
- if components&.dynamic_instrumentation&.started?
271
+ # handle_rc_enablement above no-ops when DI cannot run: the component
272
+ # is nil on an unsupported runtime, or the enable signal is blocked
273
+ # by DD_DYNAMIC_INSTRUMENTATION_ENABLED=false. Advertising then would
274
+ # report DI as in use when it is not and invite probe configs the
275
+ # tracer must refuse; withdraw the products otherwise.
276
+ if di_component&.started?
64
277
  components&.remote&.add_products(*di_products)
65
278
  else
66
279
  components&.remote&.remove_products(*di_products)
@@ -69,39 +282,25 @@ module Datadog
69
282
  components&.symbol_database&.stop_for_di_disable
70
283
  components&.remote&.remove_products(*di_products)
71
284
  end
72
- end
73
285
 
74
- content.applied
286
+ Datadog.logger.debug { "APM_TRACING RC: merged dynamic_instrumentation_enabled=#{di_enabled}" }
287
+ end
75
288
 
76
- # allow_initialization: false because process_config runs on the
77
- # remote-config worker thread. If components haven't been built yet
78
- # (e.g. during a teardown/reset window), the default `true` would
79
- # synchronously build the entire component tree from this thread.
80
- # The &. chain matches the pattern used by DI::Remote.handle_rc_enablement
81
- # in the same dispatch path.
82
- Datadog.send(:components, allow_initialization: false)&.telemetry&.client_configuration_change!(env_vars)
83
- rescue => e
84
- content.errored("#{e.class}: #{e.message}: #{Array(e.backtrace).join("\n")}")
289
+ components&.telemetry&.client_configuration_change!(env_vars)
290
+ nil
85
291
  end
86
292
 
293
+ # @param _telemetry [Core::Telemetry::Component] unused; kept for the receiver contract
294
+ # @return [Array[Core::Remote::Dispatcher::Receiver]] the APM_TRACING receiver
87
295
  def receivers(_telemetry)
88
296
  receiver do |repository, _changes|
89
- # DEV: Filter our by product. Given it will be very common
90
- # DEV: we can filter this out before we receive the data in this method.
91
- # DEV: Apply this refactor to AppSec as well if implemented.
92
- repository.contents.map do |content|
93
- case content.path.product
94
- when PRODUCT
95
- config = parse_content(content)
96
- process_config(config, content, repository)
97
- end
98
- end
297
+ merge_and_apply_configs(repository)
99
298
  end
100
299
  end
101
300
 
102
301
  def receiver(products = [PRODUCT], &block)
103
302
  matcher = Core::Remote::Dispatcher::Matcher::Product.new(products)
104
- [Core::Remote::Dispatcher::Receiver.new(matcher, &block)]
303
+ [Core::Remote::Dispatcher::Receiver.new(matcher, initial_reconcile: true, &block)]
105
304
  end
106
305
 
107
306
  private
@@ -192,6 +192,8 @@ module Datadog
192
192
 
193
193
  def reconsider_matching_rule!(trace, rule)
194
194
  trace.agent_sample_rate = nil
195
+ # Avoid mistaking a reconsidered probabilistic drop for a limiter drop.
196
+ trace.rate_limiter_rate = nil
195
197
  trace.clear_tag(Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER)
196
198
  apply_rule!(trace, rule)
197
199
  end
@@ -157,7 +157,7 @@ module Datadog
157
157
  span_id: @id,
158
158
  trace_id: @trace_id,
159
159
  type: @type,
160
- span_links: @links.map(&:to_hash)
160
+ span_links: @links.map(&:to_hash),
161
161
  }
162
162
 
163
163
  if stopped?
@@ -346,7 +346,7 @@ module Datadog
346
346
  resource: @resource,
347
347
  service: @service,
348
348
  trace_id: @trace_id,
349
- type: @type
349
+ type: @type,
350
350
  }
351
351
 
352
352
  if stopped?
@@ -46,10 +46,15 @@ module Datadog
46
46
  logger.debug(e)
47
47
  end
48
48
 
49
- # Does nothing.
50
- # The {SyncWriter} does not need to be stopped as it holds no state.
49
+ # Stops the {SyncWriter}.
50
+ # The {SyncWriter} holds no worker thread, but it owns its transport, so
51
+ # on teardown we deterministically release transports that hold native
52
+ # resources (e.g. the native trace exporter's Rust runtime and
53
+ # process-global fork hooks) rather than relying on the GC finalizer.
54
+ # The default HTTP transport has no `#close` and is left untouched, and
55
+ # `#close` is idempotent so repeated `#stop` calls are safe.
51
56
  def stop
52
- # No cleanup to do for the SyncWriter
57
+ @transport.close if @transport.respond_to?(:close)
53
58
  true
54
59
  end
55
60
 
@@ -72,10 +72,7 @@ module Datadog
72
72
  # @return [Integer]
73
73
  # @see https://www.w3.org/TR/trace-context/#trace-flags
74
74
  # @!attribute [r] trace_state
75
- # The W3C "tracestate" extracted from a distributed context.
76
- # This field is a string representing vendor-specific distribution data.
77
- # The `dd=` entry is removed from `trace_state` as its value is dynamically calculated
78
- # on every propagation injection.
75
+ # W3C "tracestate" members other than `dd=` and `ot=`, which are stored in parsed fields.
79
76
  # @return [String]
80
77
  # @see https://www.w3.org/TR/trace-context/#tracestate-header
81
78
  # @!attribute [r] trace_state_unknown_fields
@@ -83,6 +80,15 @@ module Datadog
83
80
  # This allows later propagation to include those unknown fields, as they can represent future versions of the spec
84
81
  # sending data through this service. This value ends in a trailing `;` to facilitate serialization.
85
82
  # @return [String]
83
+ # @!attribute [r] trace_otel_random_value
84
+ # OpenTelemetry consistent probability sampling random value.
85
+ # @return [String]
86
+ # @!attribute [r] trace_otel_threshold
87
+ # OpenTelemetry consistent probability sampling threshold.
88
+ # @return [String]
89
+ # @!attribute [r] trace_otel_unknown_fields
90
+ # Unrecognized `ot=` fields, retained with a trailing `;` for propagation.
91
+ # @return [String]
86
92
  # @!attribute [r] baggage
87
93
  # The W3C "baggage" extracted from a distributed context. This field is a hash of key/value pairs.
88
94
  # @return [Hash<String,String>]
@@ -109,6 +115,9 @@ module Datadog
109
115
  :trace_flags,
110
116
  :trace_state,
111
117
  :trace_state_unknown_fields,
118
+ :trace_otel_random_value,
119
+ :trace_otel_threshold,
120
+ :trace_otel_unknown_fields,
112
121
  :span_remote,
113
122
  :baggage
114
123
 
@@ -133,6 +142,9 @@ module Datadog
133
142
  trace_flags: nil,
134
143
  trace_state: nil,
135
144
  trace_state_unknown_fields: nil,
145
+ trace_otel_random_value: nil,
146
+ trace_otel_threshold: nil,
147
+ trace_otel_unknown_fields: nil,
136
148
  span_remote: true,
137
149
  baggage: nil
138
150
  )
@@ -156,6 +168,9 @@ module Datadog
156
168
  @trace_flags = trace_flags
157
169
  @trace_state = trace_state && trace_state.dup.freeze
158
170
  @trace_state_unknown_fields = trace_state_unknown_fields && trace_state_unknown_fields.dup.freeze
171
+ @trace_otel_random_value = trace_otel_random_value && trace_otel_random_value.dup.freeze
172
+ @trace_otel_threshold = trace_otel_threshold && trace_otel_threshold.dup.freeze
173
+ @trace_otel_unknown_fields = trace_otel_unknown_fields && trace_otel_unknown_fields.dup.freeze
159
174
  @span_remote = span_remote
160
175
  @baggage = baggage && baggage.dup.freeze
161
176
  freeze
@@ -188,6 +203,9 @@ module Datadog
188
203
  trace_flags: trace_flags,
189
204
  trace_state: trace_state,
190
205
  trace_state_unknown_fields: trace_state_unknown_fields,
206
+ trace_otel_random_value: trace_otel_random_value,
207
+ trace_otel_threshold: trace_otel_threshold,
208
+ trace_otel_unknown_fields: trace_otel_unknown_fields,
191
209
  span_remote: span_remote,
192
210
  baggage: baggage, **field_value_pairs
193
211
  )
@@ -5,6 +5,7 @@ require_relative "../core/utils"
5
5
  require_relative "event"
6
6
  require_relative "metadata/tagging"
7
7
  require_relative "sampling/ext"
8
+ require_relative "distributed/trace_state"
8
9
  require_relative "span_operation"
9
10
  require_relative "trace_digest"
10
11
  require_relative "correlation"
@@ -48,8 +49,7 @@ module Datadog
48
49
  :id,
49
50
  :max_length,
50
51
  :parent_span_id,
51
- :trace_state,
52
- :trace_state_unknown_fields
52
+ :trace_state
53
53
 
54
54
  attr_writer \
55
55
  :name,
@@ -86,8 +86,8 @@ module Datadog
86
86
  tags: nil,
87
87
  metrics: nil,
88
88
  trace_state: nil,
89
- trace_state_unknown_fields: nil,
90
89
  remote_parent: false,
90
+ distributed_sampling_priority: false,
91
91
  tracer: nil, # DEV-3.0: deprecated, remove in 3.0
92
92
  baggage: nil,
93
93
  auto_finish: true
@@ -100,6 +100,7 @@ module Datadog
100
100
  @parent_span_id = parent_span_id
101
101
  @sampled = sampled.nil? || sampled
102
102
  @remote_parent = remote_parent
103
+ @distributed_sampling_priority = distributed_sampling_priority
103
104
  @span_links = span_links
104
105
  # Tags
105
106
  @agent_sample_rate = agent_sample_rate
@@ -114,8 +115,7 @@ module Datadog
114
115
  @service = service
115
116
  @profiling_enabled = profiling_enabled
116
117
  @apm_tracing_enabled = apm_tracing_enabled
117
- @trace_state = trace_state
118
- @trace_state_unknown_fields = trace_state_unknown_fields
118
+ @trace_state = trace_state || Distributed::TraceState.new
119
119
  @baggage = baggage
120
120
 
121
121
  # Generic tags
@@ -391,6 +391,15 @@ module Datadog
391
391
  @propagated = true
392
392
  events.trace_propagated.publish(self)
393
393
 
394
+ open_telemetry = @trace_state.open_telemetry.outbound(
395
+ trace_id: @id,
396
+ sampling_priority: @sampling_priority,
397
+ decision_maker: get_tag(Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER),
398
+ applied_rate: @rule_sample_rate || @agent_sample_rate,
399
+ rate_limiter_rate: @rate_limiter_rate,
400
+ distributed_sampling_priority: @distributed_sampling_priority,
401
+ )
402
+
394
403
  TraceDigest.new(
395
404
  span_id: span_id,
396
405
  span_name: @active_span && @active_span.name,
@@ -407,8 +416,11 @@ module Datadog
407
416
  trace_runtime_id: Core::Environment::Identity.id,
408
417
  trace_sampling_priority: @sampling_priority,
409
418
  trace_service: service,
410
- trace_state: @trace_state,
411
- trace_state_unknown_fields: @trace_state_unknown_fields,
419
+ trace_state: @trace_state.unknown_vendors,
420
+ trace_state_unknown_fields: @trace_state.datadog.unknown_fields,
421
+ trace_otel_random_value: open_telemetry.random_value,
422
+ trace_otel_threshold: open_telemetry.threshold,
423
+ trace_otel_unknown_fields: open_telemetry.unknown_fields,
412
424
  span_remote: @remote_parent && @active_span.nil?,
413
425
  baggage: (@baggage.nil? || @baggage.empty?) ? nil : @baggage
414
426
  ).freeze
@@ -444,11 +456,11 @@ module Datadog
444
456
  sampled: @sampled,
445
457
  sampling_priority: @sampling_priority,
446
458
  service: service&.dup,
447
- trace_state: @trace_state&.dup,
448
- trace_state_unknown_fields: @trace_state_unknown_fields&.dup,
459
+ trace_state: @trace_state,
449
460
  tags: meta.dup,
450
461
  metrics: metrics.dup,
451
- remote_parent: @remote_parent
462
+ remote_parent: @remote_parent,
463
+ distributed_sampling_priority: @distributed_sampling_priority
452
464
  )
453
465
  end
454
466
 
@@ -52,10 +52,11 @@ module Datadog
52
52
  # rubocop:disable Style/KeywordParametersOrder
53
53
  # https://github.com/rubocop/rubocop/issues/13933
54
54
  trace_flush: Flush::Finished.new,
55
- context_provider: DefaultContextProvider.new,
55
+ context_provider: nil,
56
56
  default_service: Core::Environment::Ext::FALLBACK_SERVICE_NAME,
57
57
  enabled: true,
58
58
  logger: Datadog.logger,
59
+ otel_thread_context: nil,
59
60
  sampler: Sampling::PrioritySampler.new(
60
61
  base_sampler: Sampling::AllSampler.new,
61
62
  post_sampler: Sampling::RuleSampler.new
@@ -71,11 +72,16 @@ module Datadog
71
72
  @default_service = default_service
72
73
  @enabled = enabled
73
74
  @logger = logger
74
- @provider = context_provider
75
75
  @sampler = sampler
76
76
  @span_sampler = span_sampler
77
77
  @tags = tags
78
78
  @writer = writer
79
+
80
+ @otel_thread_context = otel_thread_context
81
+
82
+ @provider = context_provider || DefaultContextProvider.new(
83
+ otel_thread_context: otel_thread_context
84
+ )
79
85
  end
80
86
 
81
87
  # Return a {Datadog::Tracing::SpanOperation span_op} and {Datadog::Tracing::TraceOperation trace_op}
@@ -341,6 +347,10 @@ module Datadog
341
347
  # rubocop:enable Lint/UselessMethodDefinition
342
348
  end
343
349
 
350
+ def after_fork
351
+ @otel_thread_context&.after_fork
352
+ end
353
+
344
354
  # Shorthand that calls the `shutdown!` method of a registered worker.
345
355
  # It's useful to ensure that the Trace Buffer is properly flushed before
346
356
  # shutting down the application.
@@ -352,6 +362,7 @@ module Datadog
352
362
  #
353
363
  # tracer.shutdown!
354
364
  def shutdown!
365
+ @otel_thread_context&.clear
355
366
  return unless @enabled
356
367
 
357
368
  @writer&.stop
@@ -375,9 +386,9 @@ module Datadog
375
386
  hostname = Core::Environment::Socket.resolved_hostname(Datadog.configuration)
376
387
 
377
388
  if digest
378
- sampling_priority = if propagate_sampling_priority?(upstream_tags: digest.trace_distributed_tags)
379
- digest.trace_sampling_priority
380
- end
389
+ propagate_sampling = propagate_sampling_priority?(upstream_tags: digest.trace_distributed_tags)
390
+ sampling_priority = digest.trace_sampling_priority if propagate_sampling
391
+ trace_state = Distributed::TraceState.from_digest(digest, propagate_sampling: propagate_sampling)
381
392
  TraceOperation.new(
382
393
  logger: logger,
383
394
  hostname: hostname,
@@ -390,9 +401,9 @@ module Datadog
390
401
  span_links: digest.span_links,
391
402
  # Distributed tags are just regular trace tags with special meaning to Datadog
392
403
  tags: digest.trace_distributed_tags,
393
- trace_state: digest.trace_state,
394
- trace_state_unknown_fields: digest.trace_state_unknown_fields,
404
+ trace_state: trace_state,
395
405
  remote_parent: digest.span_remote,
406
+ distributed_sampling_priority: !!sampling_priority,
396
407
  tracer: self,
397
408
  baggage: digest.baggage,
398
409
  auto_finish: auto_finish
@@ -445,6 +456,8 @@ module Datadog
445
456
  reconsider_trace_sampling_on_resource(event_trace_op)
446
457
  end
447
458
  end
459
+
460
+ @otel_thread_context&.subscribe_to_tracer_events!(events)
448
461
  end
449
462
 
450
463
  # Creates a new TraceOperation, with events bounds to this Tracer instance.
@@ -628,6 +641,10 @@ module Datadog
628
641
  appsec_bit = upstream_tags[Tracing::Metadata::Ext::Distributed::TAG_TRACE_SOURCE].to_i(16) &
629
642
  Datadog::AppSec::Ext::PRODUCT_BIT
630
643
  return appsec_enabled if appsec_bit != 0
644
+
645
+ ai_guard_bit = upstream_tags[Tracing::Metadata::Ext::Distributed::TAG_TRACE_SOURCE].to_i(16) &
646
+ Datadog::AIGuard::Ext::PRODUCT_BIT
647
+ return ai_guard_enabled if ai_guard_bit != 0
631
648
  end
632
649
 
633
650
  false
@@ -642,6 +659,10 @@ module Datadog
642
659
  @appsec_enabled ||= Datadog.configuration.appsec.enabled
643
660
  end
644
661
 
662
+ def ai_guard_enabled
663
+ @ai_guard_enabled ||= Datadog.configuration.respond_to?(:ai_guard) && Datadog.configuration.ai_guard.enabled
664
+ end
665
+
645
666
  # Due to APM Tracing (the product) and Tracing (the transport) being intertwined, we cannot completely disabled APM
646
667
  # without also disabling the tracer. When setting `@apm_tracing_enabled` to `false`, it does not disable the tracer,
647
668
  # but rather only sends heartbeat traces (1 per minutes), so that the service is considered alive in the backend.