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
@@ -1,12 +1,14 @@
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"
6
+ require_relative "hooks/evaluation_telemetry_opt_out_hook"
5
7
  require "open_feature/sdk"
6
8
 
7
9
  module Datadog
8
10
  module OpenFeature
9
- # OpenFeature feature flagging provider backed by Datadog Remote Configuration.
11
+ # OpenFeature feature flagging provider backed by Datadog configuration delivery.
10
12
  #
11
13
  # Requires openfeature-sdk >= 0.5.1 for flag evaluation metrics and EVP hook support.
12
14
  #
@@ -24,13 +26,14 @@ module Datadog
24
26
  #
25
27
  # Example:
26
28
  #
27
- # Make sure to enable Remote Configuration and OpenFeature in the Datadog configuration.
29
+ # Feature Flags use agentless configuration delivery by default. To use
30
+ # Remote Configuration delivery instead, configure the source explicitly.
28
31
  #
29
32
  # ```ruby
30
33
  # # FILE: initializers/datadog.rb
31
34
  # Datadog.configure do |config|
32
35
  # config.remote.enabled = true
33
- # config.open_feature.enabled = true
36
+ # config.feature_flags.configuration_source = "remote_config"
34
37
  # end
35
38
  # ```
36
39
  #
@@ -58,28 +61,129 @@ module Datadog
58
61
  # # => 'Welcome back!'
59
62
  # ```
60
63
  class Provider
64
+ include ::OpenFeature::SDK::Provider::EventEmitter
65
+
61
66
  NAME = "Datadog Feature Flagging Provider"
67
+ INITIALIZATION_CANCELLED_MESSAGE = "Feature Flags provider initialization was cancelled by shutdown"
62
68
 
63
69
  attr_reader :metadata
64
70
 
65
- def initialize
71
+ def initialize(enable_evaluation_telemetry_opt_out_parameter: nil)
72
+ @enable_evaluation_telemetry_opt_out_parameter = case enable_evaluation_telemetry_opt_out_parameter
73
+ when nil
74
+ Datadog.configuration.feature_flags.evaluation_telemetry_per_subject_opt_out_enabled
75
+ when true, false
76
+ enable_evaluation_telemetry_opt_out_parameter
77
+ else
78
+ raise ArgumentError, "enable_evaluation_telemetry_opt_out_parameter expects true, false, or nil"
79
+ end
66
80
  @metadata = ::OpenFeature::SDK::Provider::ProviderMetadata.new(name: NAME).freeze
81
+ @initialization_mutex = Mutex.new
82
+ @initializing = false
83
+ @initialization_thread = nil
84
+ @awaiting_ready_after_fork = false
85
+ @initialization_failed = false
86
+ @provider_error_observed = false
87
+ @ready_pending = false
88
+ @ready_dispatch_claimed = false
89
+ @stale_emitted = false
90
+ @stale_pending = false
91
+ @error_handler = nil
92
+ @initialization_ready_handler = nil
93
+ @waiting_component = nil
94
+ @shutdown = false
67
95
  end
68
96
 
69
97
  def init
70
- # no-op
98
+ @initialization_mutex.synchronize do
99
+ raise INITIALIZATION_CANCELLED_MESSAGE if @shutdown
100
+
101
+ @initializing = true
102
+ @initialization_thread = Thread.current
103
+ @awaiting_ready_after_fork = false
104
+ @initialization_failed = false
105
+ @provider_error_observed = false
106
+ @ready_pending = false
107
+ @ready_dispatch_claimed = false
108
+ @stale_emitted = false
109
+ @stale_pending = false
110
+ end
111
+ ready_handler_installed = install_initialization_ready_handler
112
+
113
+ component, failure = OpenFeature.activate_provider(self)
114
+ cancel_initialization_if_shutdown!
115
+ fail_initialization(component, failure || "Feature Flags component could not be activated") unless component
116
+
117
+ @initialization_mutex.synchronize do
118
+ raise INITIALIZATION_CANCELLED_MESSAGE if @shutdown
119
+
120
+ @waiting_component = component
121
+ end
122
+ # Shutdown publishes this flag through the component lock; taking our mutex here would invert lock order.
123
+ wait_result = component.wait_for_configuration { @shutdown }
124
+ cancel_initialization_if_shutdown!
125
+
126
+ case wait_result
127
+ when Component::CONFIGURATION_READY
128
+ @initialization_mutex.synchronize { @initializing = false } unless ready_handler_installed
129
+ when Component::CONFIGURATION_TIMEOUT
130
+ message = "Feature Flags provider initialization timed out while waiting for configuration"
131
+ Datadog.logger.error(message)
132
+ fail_initialization(component, message)
133
+ else
134
+ fail_initialization(component, "Feature Flags provider initialization stopped before configuration arrived")
135
+ end
136
+ rescue
137
+ prepare_initialization_failure(component) if @initialization_mutex.synchronize { @initializing }
138
+ raise
139
+ ensure
140
+ @initialization_mutex.synchronize do
141
+ @waiting_component = nil
142
+ # The SDK still owes READY after init returns; the initializing thread owns that dispatch.
143
+ @initialization_thread = nil unless @initializing
144
+ end
71
145
  end
72
146
 
73
147
  def shutdown
74
- # no-op
148
+ configuration = @configuration
149
+ # @type var error_handler: Provider::provider_event_handler?
150
+ error_handler = nil
151
+ # @type var initialization_ready_handler: Provider::provider_event_handler?
152
+ initialization_ready_handler = nil
153
+ waiting_component = nil #: Component?
154
+ @initialization_mutex.synchronize do
155
+ return if @shutdown
156
+
157
+ @shutdown = true
158
+ @initializing = false
159
+ @initialization_thread = nil
160
+ error_handler = @error_handler
161
+ initialization_ready_handler = @initialization_ready_handler
162
+ waiting_component = @waiting_component
163
+ @error_handler = nil
164
+ @initialization_ready_handler = nil
165
+ end
166
+
167
+ waiting_component&.wake_configuration_waiters
168
+ configuration&.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_ERROR, error_handler) if error_handler
169
+ if initialization_ready_handler
170
+ configuration&.remove_handler(
171
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_READY,
172
+ initialization_ready_handler,
173
+ )
174
+ end
175
+ OpenFeature.deactivate_provider(self)
75
176
  end
76
177
 
77
178
  def hooks
78
179
  component = Datadog.send(:components).open_feature
79
- [
180
+ hooks = [
80
181
  component&.flag_eval_metrics_hook,
81
182
  component&.flag_eval_evp_hook,
82
183
  ].compact
184
+ return hooks unless @enable_evaluation_telemetry_opt_out_parameter
185
+
186
+ hooks.map { |hook| Hooks::EvaluationTelemetryOptOutHook.new(hook) }
83
187
  end
84
188
 
85
189
  def fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)
@@ -108,10 +212,196 @@ module Datadog
108
212
 
109
213
  private
110
214
 
215
+ def after_fork(component)
216
+ handler = @initialization_mutex.synchronize do
217
+ return if @shutdown || !@initializing || @initialization_thread&.alive?
218
+
219
+ @initializing = false
220
+ @initialization_thread = nil
221
+ @waiting_component = nil
222
+ @awaiting_ready_after_fork = true
223
+ @stale_pending = false
224
+ previous_handler = @initialization_ready_handler
225
+ @initialization_ready_handler = nil
226
+ previous_handler
227
+ end
228
+ if handler
229
+ @configuration&.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler)
230
+ end
231
+ configuration_changed(Component::CONFIGURATION_READY) if component&.configuration_received?
232
+ end
233
+
234
+ def fail_initialization(component, message)
235
+ prepare_initialization_failure(component)
236
+ cancel_initialization_if_shutdown!
237
+ raise message.to_s
238
+ end
239
+
240
+ def prepare_initialization_failure(component)
241
+ cancelled, initialization_ready_handler = @initialization_mutex.synchronize do
242
+ handler = @initialization_ready_handler
243
+ @initialization_ready_handler = nil
244
+ @stale_pending = false
245
+ @initializing = false
246
+ @initialization_thread = nil
247
+ if @shutdown
248
+ [true, handler]
249
+ else
250
+ @initialization_failed = true
251
+ @ready_pending ||= !!component&.configuration_received?
252
+ [false, handler]
253
+ end
254
+ end
255
+ if initialization_ready_handler
256
+ @configuration&.remove_handler(
257
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_READY,
258
+ initialization_ready_handler,
259
+ )
260
+ end
261
+ return if cancelled
262
+
263
+ install_error_handler
264
+ end
265
+
266
+ def cancel_initialization_if_shutdown!
267
+ cancelled = @initialization_mutex.synchronize do
268
+ @initializing = false if @shutdown
269
+ @shutdown
270
+ end
271
+ raise INITIALIZATION_CANCELLED_MESSAGE if cancelled
272
+ end
273
+
274
+ def shutdown?
275
+ @initialization_mutex.synchronize { @shutdown }
276
+ end
277
+
278
+ def install_initialization_ready_handler
279
+ configuration = @configuration
280
+ return false unless configuration
281
+
282
+ handler = @initialization_mutex.synchronize do
283
+ return false if @shutdown
284
+ return true if @initialization_ready_handler
285
+
286
+ @initialization_ready_handler = ->(details) { provider_ready(details) }
287
+ end
288
+ configuration.add_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler)
289
+
290
+ cancelled = @initialization_mutex.synchronize { @shutdown }
291
+ configuration.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler) if cancelled
292
+ return false if cancelled
293
+
294
+ true
295
+ end
296
+
297
+ def install_error_handler
298
+ configuration = @configuration
299
+ return unless configuration
300
+
301
+ handler = @initialization_mutex.synchronize do
302
+ return if @shutdown
303
+
304
+ @error_handler ||= ->(details) { provider_error(details) }
305
+ end
306
+ configuration.add_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_ERROR, handler)
307
+
308
+ cancelled = @initialization_mutex.synchronize { @shutdown }
309
+ configuration.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_ERROR, handler) if cancelled
310
+ end
311
+
312
+ def provider_error(_details)
313
+ configuration = @configuration
314
+ return unless configuration
315
+ return unless configuration.send(:provider_state, self) == ::OpenFeature::SDK::ProviderState::ERROR
316
+
317
+ emit_ready = @initialization_mutex.synchronize do
318
+ if @shutdown
319
+ false
320
+ else
321
+ @provider_error_observed = true
322
+ if @ready_pending && !@ready_dispatch_claimed
323
+ @ready_dispatch_claimed = true
324
+ else
325
+ false
326
+ end
327
+ end
328
+ end
329
+ emit_event(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY) if emit_ready
330
+ end
331
+
332
+ def provider_ready(_details)
333
+ configuration = @configuration
334
+ return unless configuration
335
+ return unless configuration.send(:provider_state, self) == ::OpenFeature::SDK::ProviderState::READY
336
+
337
+ handler, emit_stale = @initialization_mutex.synchronize do
338
+ handler = @initialization_ready_handler
339
+ @initialization_ready_handler = nil
340
+ @initializing = false
341
+ @initialization_thread = nil
342
+ if @stale_pending && !@shutdown
343
+ @stale_pending = false
344
+ @stale_emitted = true
345
+ [handler, true]
346
+ else
347
+ [handler, false]
348
+ end
349
+ end
350
+ configuration.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler) if handler
351
+ emit_event(::OpenFeature::SDK::ProviderEvent::PROVIDER_STALE) if emit_stale
352
+ end
353
+
354
+ def configuration_changed(event)
355
+ event_type = @initialization_mutex.synchronize do
356
+ if @shutdown
357
+ nil
358
+ elsif event == Component::CONFIGURATION_READY
359
+ if @initializing
360
+ @ready_pending = true
361
+ @stale_pending = false
362
+ nil
363
+ elsif @awaiting_ready_after_fork
364
+ @awaiting_ready_after_fork = false
365
+ @stale_emitted = false
366
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_READY
367
+ elsif @initialization_failed && !@provider_error_observed
368
+ @stale_emitted = false
369
+ @ready_pending = true
370
+ nil
371
+ elsif @stale_emitted
372
+ @stale_emitted = false
373
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_READY
374
+ elsif @initialization_failed
375
+ if @provider_error_observed && !@ready_dispatch_claimed
376
+ @ready_dispatch_claimed = true
377
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_READY
378
+ else
379
+ @ready_pending = true
380
+ nil
381
+ end
382
+ end
383
+ elsif event == Component::CONFIGURATION_CHANGED && !@initializing
384
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_CONFIGURATION_CHANGED
385
+ elsif event == Component::CONFIGURATION_LOST
386
+ @ready_pending = false
387
+ if @initializing
388
+ @stale_pending = true
389
+ nil
390
+ else
391
+ @stale_emitted = true
392
+ ::OpenFeature::SDK::ProviderEvent::PROVIDER_STALE
393
+ end
394
+ end
395
+ end
396
+
397
+ emit_event(event_type) if event_type
398
+ end
399
+
111
400
  def evaluate(flag_key, default_value:, expected_type:, evaluation_context:)
112
401
  # Stamp evaluation entry time once, here on the eval thread. The EVP path uses this for
113
402
  # accurate first/last_evaluation bounds instead of a later hook-fire clock read.
114
403
  eval_time_ms = (Core::Utils::Time.now.to_f * 1000).to_i
404
+ flag_meta = nil
115
405
 
116
406
  engine = OpenFeature.engine
117
407
  return component_not_configured_default(default_value, eval_time_ms) if engine.nil?
@@ -128,7 +418,9 @@ module Datadog
128
418
  # Drive APM span enrichment directly from the evaluation path. This is the only reliable
129
419
  # way to attach `ffe_*` tags across all supported OpenFeature SDK versions, since older
130
420
  # SDKs do not dispatch provider hooks. Guarded so enrichment can never break evaluation.
131
- enrich_span(flag_key, result, evaluation_context)
421
+ unless evaluation_telemetry_opted_out?(evaluation_context)
422
+ enrich_span(flag_key, result, evaluation_context)
423
+ end
132
424
 
133
425
  sdk_success_details(result, flag_meta)
134
426
  rescue => e
@@ -138,7 +430,10 @@ module Datadog
138
430
  error_code: Ext::GENERAL,
139
431
  error_message: error_message
140
432
  )
141
- error_flag_meta = build_flag_metadata(error_result, eval_time_ms || (Core::Utils::Time.now.to_f * 1000).to_i)
433
+ error_flag_meta = flag_meta
434
+ error_flag_meta ||= build_flag_metadata(
435
+ error_result, eval_time_ms || (Core::Utils::Time.now.to_f * 1000).to_i
436
+ )
142
437
 
143
438
  sdk_error_details(default_value, Ext::GENERAL, error_message, Ext::ERROR, error_flag_meta)
144
439
  end
@@ -173,6 +468,8 @@ module Datadog
173
468
 
174
469
  def build_flag_metadata(result, eval_time_ms)
175
470
  metadata = result.flag_metadata&.dup || {}
471
+ metadata[Ext::METADATA_OBSERVE_FULL_EVALUATION_DATA] =
472
+ metadata[Ext::METADATA_OBSERVE_FULL_EVALUATION_DATA] == true
176
473
  allocation_key = result.allocation_key
177
474
  metadata[Ext::METADATA_ALLOCATION_KEY] = allocation_key if allocation_key && !allocation_key.empty?
178
475
 
@@ -212,13 +509,21 @@ module Datadog
212
509
  Datadog.send(:components).open_feature&.span_enrichment_hook
213
510
  end
214
511
 
512
+ def evaluation_telemetry_opted_out?(evaluation_context)
513
+ @enable_evaluation_telemetry_opt_out_parameter &&
514
+ Hooks::EvaluationTelemetryOptOutHook.opted_out?(evaluation_context)
515
+ end
516
+
215
517
  def component_not_configured_default(value, eval_time_ms)
216
518
  ::OpenFeature::SDK::Provider::ResolutionDetails.new(
217
519
  value: value,
218
520
  error_code: Ext::PROVIDER_FATAL,
219
521
  error_message: "Datadog's OpenFeature component must be configured",
220
522
  reason: Ext::ERROR,
221
- flag_metadata: {"dd.eval.timestamp_ms" => eval_time_ms}
523
+ flag_metadata: {
524
+ "dd.eval.timestamp_ms" => eval_time_ms,
525
+ Ext::METADATA_OBSERVE_FULL_EVALUATION_DATA => false,
526
+ }
222
527
  )
223
528
  end
224
529
  end
@@ -19,11 +19,11 @@ module Datadog
19
19
  FFE_PRODUCTS
20
20
  end
21
21
 
22
- def receivers(telemetry)
22
+ def receivers(telemetry, component_provider:)
23
23
  matcher = Core::Remote::Dispatcher::Matcher::Product.new(FFE_PRODUCTS)
24
24
  receiver = Core::Remote::Dispatcher::Receiver.new(matcher) do |repository, changes|
25
- engine = OpenFeature.engine
26
- next unless engine
25
+ component = component_provider.call
26
+ next unless component
27
27
 
28
28
  changes.each do |change|
29
29
  content = repository[change.path]
@@ -38,7 +38,7 @@ module Datadog
38
38
  when :insert, :update
39
39
  begin
40
40
  # @type var content: Core::Remote::Configuration::Content
41
- engine.reconfigure!(read_content(content))
41
+ component.reconfigure!(read_content(content))
42
42
  content.applied
43
43
  rescue EvaluationEngine::ReconfigurationError => e
44
44
  content.errored("Error applying OpenFeature configuration: #{e.class}: #{e.message}")
@@ -46,7 +46,7 @@ module Datadog
46
46
  when :delete
47
47
  # NOTE: For now, we treat deletion as clearing the configuration
48
48
  # In a multi-config scenario, we might track configs per path
49
- engine.reconfigure!(nil)
49
+ component.reconfigure!(nil)
50
50
  end
51
51
  end
52
52
  end
@@ -8,6 +8,7 @@ require_relative "../core/transport/http/api/endpoint"
8
8
  require_relative "../core/transport/http/api/instance"
9
9
  require_relative "../core/transport/parcel"
10
10
  require_relative "../core/transport/request"
11
+ require_relative "../version"
11
12
 
12
13
  module Datadog
13
14
  module OpenFeature
@@ -27,6 +28,8 @@ module Datadog
27
28
  request_env.headers["Content-Type"] = env.request.parcel.content_type
28
29
  request_env.headers[Core::EVP::SUBDOMAIN_HEADER_NAME] =
29
30
  Core::EVP::EVENT_PLATFORM_INTAKE_SUBDOMAIN
31
+ request_env.headers["DD-EVP-ORIGIN"] = "dd-trace-rb"
32
+ request_env.headers["DD-EVP-ORIGIN-VERSION"] = Datadog::VERSION::STRING
30
33
  request_env.body = env.request.parcel.data
31
34
 
32
35
  block.call(request_env)
@@ -49,6 +52,8 @@ module Datadog
49
52
  request_env.headers["Content-Type"] = env.request.parcel.content_type
50
53
  request_env.headers[Core::EVP::SUBDOMAIN_HEADER_NAME] =
51
54
  Core::EVP::EVENT_PLATFORM_INTAKE_SUBDOMAIN
55
+ request_env.headers["DD-EVP-ORIGIN"] = "dd-trace-rb"
56
+ request_env.headers["DD-EVP-ORIGIN-VERSION"] = Datadog::VERSION::STRING
52
57
  request_env.body = env.request.parcel.data
53
58
 
54
59
  block.call(request_env)
@@ -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
@@ -60,7 +60,7 @@ module Datadog
60
60
 
61
61
  if digest.trace_state || digest.trace_flags
62
62
  trace_flags = ::OpenTelemetry::Trace::TraceFlags.from_byte(digest.trace_flags)
63
- tracestate = Tracing::Distributed::TraceContext.new(fetcher: nil).send(:build_tracestate, digest)
63
+ tracestate = Tracing::Distributed::TraceState.serialize_digest(digest)
64
64
  else
65
65
  trace_flags = if Tracing::Sampling::PrioritySampler.sampled?(digest.trace_sampling_priority)
66
66
  ::OpenTelemetry::Trace::TraceFlags::SAMPLED
@@ -12,23 +12,24 @@ module Datadog
12
12
  def create_resource
13
13
  resource_attributes = {}
14
14
 
15
- @settings.tags&.each do |key, value| # steep:ignore
15
+ @settings.tags&.each do |key, value|
16
16
  otel_key = case key
17
17
  when "service" then "service.name"
18
- when "env" then "deployment.environment"
18
+ when "env", "deployment.environment.name", "deployment.environment" then next
19
19
  when "version" then "service.version"
20
20
  else key
21
21
  end
22
22
  resource_attributes[otel_key] = value
23
23
  end
24
24
 
25
- resource_attributes["service.name"] = @settings.service_without_fallback || resource_attributes["service.name"] || Datadog::Core::Environment::Ext::FALLBACK_SERVICE_NAME # steep:ignore
26
- resource_attributes["deployment.environment"] = @settings.env if @settings.env # steep:ignore
27
- resource_attributes["service.version"] = @settings.version if @settings.version # steep:ignore
25
+ resource_attributes["service.name"] = @settings.service_without_fallback || resource_attributes["service.name"] || Datadog::Core::Environment::Ext::FALLBACK_SERVICE_NAME
26
+ environment = @settings.env || @settings.tags["env"] || @settings.tags["deployment.environment.name"] || @settings.tags["deployment.environment"]
27
+ resource_attributes["deployment.environment.name"] = environment if environment
28
+ resource_attributes["service.version"] = @settings.version if @settings.version
28
29
 
29
- hostname = Datadog::Core::Environment::Socket.resolved_hostname(@settings) # steep:ignore
30
+ hostname = Datadog::Core::Environment::Socket.resolved_hostname(@settings)
30
31
  if hostname
31
- if hostname == @settings.hostname # steep:ignore
32
+ if hostname == @settings.hostname
32
33
  resource_attributes["host.name"] = hostname
33
34
  elsif !resource_attributes.key?("host.name")
34
35
  resource_attributes["host.name"] = hostname
@@ -41,9 +42,12 @@ module Datadog
41
42
  # Returns the signal-specific option value when explicitly set,
42
43
  # otherwise falls back to the general OTLP exporter config or computed_default.
43
44
  def config_or_exporter_fallback(signal:, option_name:, computed_default: nil)
44
- signal_settings = @settings.opentelemetry.public_send(signal) # steep:ignore
45
+ signal_settings = case signal
46
+ when :logs then @settings.opentelemetry.logs
47
+ when :metrics then @settings.opentelemetry.metrics
48
+ end
45
49
  if signal_settings.using_default?(option_name)
46
- @settings.opentelemetry.exporter.public_send(option_name) || computed_default # steep:ignore
50
+ @settings.opentelemetry.exporter.public_send(option_name) || computed_default
47
51
  else
48
52
  signal_settings.public_send(option_name)
49
53
  end
@@ -50,6 +50,9 @@ module Datadog
50
50
  trace_service: digest.trace_service,
51
51
  trace_state: digest.trace_state,
52
52
  trace_state_unknown_fields: digest.trace_state_unknown_fields,
53
+ trace_otel_random_value: digest.trace_otel_random_value,
54
+ trace_otel_threshold: digest.trace_otel_threshold,
55
+ trace_otel_unknown_fields: digest.trace_otel_unknown_fields,
53
56
  span_remote: digest.span_remote,
54
57
  ).freeze
55
58
  end
@@ -33,6 +33,7 @@ module Datadog
33
33
  # @rbs allocation_counting_enabled: bool
34
34
  # @rbs gvl_profiling_enabled: bool
35
35
  # @rbs sighandler_sampling_enabled: bool
36
+ # @rbs waiting_for_gvl_threshold_ns: ::Integer
36
37
  # @rbs skip_idle_samples_for_testing: false
37
38
  # @rbs return: void
38
39
  def initialize(
@@ -45,11 +46,12 @@ module Datadog
45
46
  gvl_profiling_enabled:,
46
47
  sighandler_sampling_enabled:,
47
48
  cpu_sampling_interval_ms:,
49
+ waiting_for_gvl_threshold_ns:,
48
50
  # **NOTE**: This should only be used for testing; disabling the dynamic sampling rate will increase the
49
51
  # profiler overhead!
50
52
  dynamic_sampling_rate_enabled: true,
51
53
  skip_idle_samples_for_testing: false,
52
- idle_sampling_helper: IdleSamplingHelper.new(thread_context_collector: thread_context_collector)
54
+ idle_sampling_helper: IdleSamplingHelper.new
53
55
  )
54
56
  unless dynamic_sampling_rate_enabled
55
57
  Datadog.logger.warn(
@@ -78,6 +80,7 @@ module Datadog
78
80
  sighandler_sampling_enabled: sighandler_sampling_enabled,
79
81
  skip_idle_samples_for_testing: skip_idle_samples_for_testing,
80
82
  cpu_sampling_interval_ms: cpu_sampling_interval_ms,
83
+ waiting_for_gvl_threshold_ns: waiting_for_gvl_threshold_ns,
81
84
  )
82
85
  @worker_thread = nil
83
86
  @failure_exception = nil
@@ -95,7 +98,7 @@ module Datadog
95
98
 
96
99
  Datadog.logger.debug { "Starting thread for: #{self}" }
97
100
 
98
- @idle_sampling_helper.start
101
+ @idle_sampling_helper.start(self)
99
102
 
100
103
  @worker_thread = Thread.new do
101
104
  Thread.current.name = self.class.name
@@ -144,6 +147,11 @@ module Datadog
144
147
  end
145
148
  end
146
149
 
150
+ # @rbs return: Datadog::Profiling::StackRecorder
151
+ def prepare_serialize
152
+ self.class._native_prepare_serialize(self)
153
+ end
154
+
147
155
  #: () -> true
148
156
  def reset_after_fork
149
157
  self.class._native_reset_after_fork(self)
@@ -10,7 +10,6 @@ module Datadog
10
10
  class IdleSamplingHelper
11
11
  # @rbs @worker_thread: untyped
12
12
  # @rbs @start_stop_mutex: ::Thread::Mutex
13
- # @rbs @thread_context_collector: Datadog::Profiling::Collectors::ThreadContext?
14
13
 
15
14
  private
16
15
 
@@ -18,15 +17,14 @@ module Datadog
18
17
 
19
18
  public
20
19
 
21
- #: (thread_context_collector: Datadog::Profiling::Collectors::ThreadContext) -> void
22
- def initialize(thread_context_collector:)
20
+ #: () -> void
21
+ def initialize
23
22
  @worker_thread = nil
24
23
  @start_stop_mutex = Mutex.new
25
- @thread_context_collector = thread_context_collector
26
24
  end
27
25
 
28
- #: () -> (nil | true)
29
- def start
26
+ #: (CpuAndWallTimeWorker cpu_and_wall_time_worker) -> true?
27
+ def start(cpu_and_wall_time_worker)
30
28
  @start_stop_mutex.synchronize do
31
29
  return if @worker_thread&.alive?
32
30
 
@@ -39,7 +37,7 @@ module Datadog
39
37
  @worker_thread = Thread.new do
40
38
  Thread.current.name = self.class.name
41
39
 
42
- self.class._native_idle_sampling_loop(self, @thread_context_collector)
40
+ self.class._native_idle_sampling_loop(self, cpu_and_wall_time_worker)
43
41
 
44
42
  Datadog.logger.debug("IdleSamplingHelper thread stopping cleanly")
45
43
  rescue Exception => e # rubocop:disable Lint/RescueException