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
@@ -14,6 +14,7 @@ module Datadog
14
14
  "DD_AI_GUARD_ENDPOINT",
15
15
  "DD_AI_GUARD_MAX_CONTENT_SIZE",
16
16
  "DD_AI_GUARD_MAX_MESSAGES_LENGTH",
17
+ "DD_AI_GUARD_REDACTION_ENABLED",
17
18
  "DD_AI_GUARD_TIMEOUT",
18
19
  "DD_API_KEY",
19
20
  "DD_API_SECURITY_DOWNSTREAM_BODY_ANALYSIS_SAMPLE_RATE",
@@ -24,6 +25,7 @@ module Datadog
24
25
  "DD_API_SECURITY_REQUEST_SAMPLE_RATE",
25
26
  "DD_API_SECURITY_SAMPLE_DELAY",
26
27
  "DD_APM_TRACING_ENABLED",
28
+ "DD_APPSEC_AGENTIC_ONBOARDING",
27
29
  "DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING",
28
30
  "DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE",
29
31
  "DD_APPSEC_BODY_PARSING_SIZE_LIMIT",
@@ -49,6 +51,7 @@ module Datadog
49
51
  "DD_DBM_INJECT_SQL_BASEHASH",
50
52
  "DD_DBM_PROPAGATION_MODE",
51
53
  "DD_DISABLE_DATADOG_RAILS",
54
+ "DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS",
52
55
  "DD_DYNAMIC_INSTRUMENTATION_ENABLED",
53
56
  "DD_DYNAMIC_INSTRUMENTATION_MAX_TIME_TO_SERIALIZE",
54
57
  "DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE",
@@ -59,9 +62,17 @@ module Datadog
59
62
  "DD_ERROR_TRACKING_HANDLED_ERRORS",
60
63
  "DD_ERROR_TRACKING_HANDLED_ERRORS_INCLUDE",
61
64
  "DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED",
65
+ "DD_EXPERIMENTAL_FLAGGING_PROVIDER_INITIALIZATION_TIMEOUT_MS",
62
66
  "DD_EXPERIMENTAL_FLAGGING_PROVIDER_SPAN_ENRICHMENT_ENABLED",
67
+ "DD_EXPERIMENTAL_NATIVE_TRANSPORT_ENABLED",
63
68
  "DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED",
64
69
  "DD_EXTERNAL_ENV",
70
+ "DD_FEATURE_FLAGS_CONFIGURATION_SOURCE",
71
+ "DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL",
72
+ "DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS",
73
+ "DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS",
74
+ "DD_FEATURE_FLAGS_ENABLED",
75
+ "DD_FEATURE_FLAGS_EVALUATION_TELEMETRY_PER_SUBJECT_OPT_OUT_ENABLED",
65
76
  "DD_FLAGGING_EVALUATION_COUNTS_ENABLED",
66
77
  "DD_GIT_COMMIT_SHA",
67
78
  "DD_GIT_REPOSITORY_URL",
@@ -85,6 +96,7 @@ module Datadog
85
96
  "DD_PROFILING_EXPERIMENTAL_HEAP_ENABLED",
86
97
  "DD_PROFILING_EXPERIMENTAL_HEAP_SAMPLE_RATE",
87
98
  "DD_PROFILING_EXPERIMENTAL_HEAP_SIZE_ENABLED",
99
+ "DD_PROFILING_EXPERIMENTAL_SHOW_CLASSES_ENABLED",
88
100
  "DD_PROFILING_EXPERIMENTAL_USE_SYSTEM_DNS",
89
101
  "DD_PROFILING_GC_ENABLED",
90
102
  "DD_PROFILING_GVL_ENABLED",
@@ -231,6 +243,7 @@ module Datadog
231
243
  "DD_TRACE_HTTP_ANALYTICS_ENABLED",
232
244
  "DD_TRACE_HTTP_ANALYTICS_SAMPLE_RATE",
233
245
  "DD_TRACE_HTTP_CLIENT_ERROR_STATUSES",
246
+ "DD_TRACE_HTTP_CLIENT_RESOURCE_NAME_QUANTIZE",
234
247
  "DD_TRACE_HTTP_DISTRIBUTED_TRACING",
235
248
  "DD_TRACE_HTTP_ENABLED",
236
249
  "DD_TRACE_HTTP_ERROR_STATUS_CODES",
@@ -263,6 +276,7 @@ module Datadog
263
276
  "DD_TRACE_OPENSEARCH_PEER_SERVICE",
264
277
  "DD_TRACE_OPENSEARCH_RESOURCE_PATTERN",
265
278
  "DD_TRACE_OPENSEARCH_SERVICE_NAME",
279
+ "DD_TRACE_OTEL_CTX_ENABLED",
266
280
  "DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED",
267
281
  "DD_TRACE_PEER_SERVICE_MAPPING",
268
282
  "DD_TRACE_PG_ANALYTICS_ENABLED",
@@ -388,6 +402,7 @@ module Datadog
388
402
 
389
403
  ALIASES =
390
404
  {"DD_DISABLE_DATADOG_RAILS" => ["DISABLE_DATADOG_RAILS"],
405
+ "DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS" => ["DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT"],
391
406
  "DD_PROFILING_GVL_ENABLED" => ["DD_PROFILING_PREVIEW_GVL_ENABLED"],
392
407
  "DD_RUNTIME_METRICS_RUNTIME_ID_ENABLED" => ["DD_TRACE_EXPERIMENTAL_RUNTIME_ID_ENABLED"],
393
408
  "DD_SERVICE" => ["OTEL_SERVICE_NAME"],
@@ -398,10 +413,11 @@ module Datadog
398
413
  "DD_TRACE_SAMPLE_RATE" => ["OTEL_TRACES_SAMPLER"]}.freeze
399
414
 
400
415
  DEPRECATIONS =
401
- Set["DD_PROFILING_PREVIEW_GVL_ENABLED", "DISABLE_DATADOG_RAILS"]
416
+ Set["DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT", "DD_PROFILING_PREVIEW_GVL_ENABLED", "DISABLE_DATADOG_RAILS"]
402
417
 
403
418
  ALIAS_TO_CANONICAL =
404
- {"DD_PROFILING_PREVIEW_GVL_ENABLED" => "DD_PROFILING_GVL_ENABLED",
419
+ {"DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT" => "DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS",
420
+ "DD_PROFILING_PREVIEW_GVL_ENABLED" => "DD_PROFILING_GVL_ENABLED",
405
421
  "DD_TRACE_EXPERIMENTAL_RUNTIME_ID_ENABLED" => "DD_RUNTIME_METRICS_RUNTIME_ID_ENABLED",
406
422
  "DISABLE_DATADOG_RAILS" => "DD_DISABLE_DATADOG_RAILS",
407
423
  "OTEL_LOG_LEVEL" => "DD_TRACE_DEBUG",
@@ -44,7 +44,11 @@ module Datadog
44
44
  # Reports unhandled exceptions to the crash tracker if available and appropriate.
45
45
  # This is called from the at_exit hook to report unhandled exceptions.
46
46
  def self.report_unhandled_exception(exception)
47
- return unless exception && !exception.is_a?(SystemExit) && !exception.is_a?(NoMemoryError)
47
+ return unless exception &&
48
+ !exception.is_a?(SystemExit) &&
49
+ !exception.is_a?(SignalException) &&
50
+ !exception.is_a?(NoMemoryError) &&
51
+ !exception.is_a?(SystemStackError)
48
52
 
49
53
  begin
50
54
  crashtracker = Datadog.send(:components, allow_initialization: false)&.crashtracker
@@ -75,7 +75,10 @@ module Datadog
75
75
  tags: tags,
76
76
  runtime_metrics_enabled: runtime_metrics_enabled,
77
77
  vm: vm,
78
- health_metrics_enabled: health_metrics_enabled
78
+ health_metrics_enabled: health_metrics_enabled,
79
+ otlp_traces_export_enabled: otlp_traces_export_enabled,
80
+ otlp_metrics_export_enabled: otlp_metrics_export_enabled,
81
+ otlp_logs_export_enabled: otlp_logs_export_enabled,
79
82
  }
80
83
  end
81
84
 
@@ -159,8 +162,40 @@ module Datadog
159
162
  !!Datadog.configuration.health_metrics.enabled
160
163
  end
161
164
 
165
+ # @return [Boolean] whether the tracer exports traces over OTLP.
166
+ # Always false: Ruby exports spans in Datadog's native format and has no OTLP trace exporter.
167
+ def otlp_traces_export_enabled
168
+ false
169
+ end
170
+
171
+ # @return [Boolean] whether the tracer exports metrics over OTLP
172
+ def otlp_metrics_export_enabled
173
+ metrics = opentelemetry_settings&.metrics
174
+ # A "none" exporter skips the OTLP metric reader even when metrics are enabled
175
+ # (mirrors Datadog::OpenTelemetry::Ext::EXPORTER_NONE).
176
+ !!(metrics&.enabled && metrics.exporter != "none")
177
+ end
178
+
179
+ # @return [Boolean] whether the tracer exports logs over OTLP
180
+ def otlp_logs_export_enabled
181
+ logs = opentelemetry_settings&.logs
182
+ # A "none" exporter skips the OTLP log record processor even when logs are enabled
183
+ # (mirrors Datadog::OpenTelemetry::Ext::EXPORTER_NONE).
184
+ !!(logs&.enabled && logs.exporter != "none")
185
+ end
186
+
162
187
  private
163
188
 
189
+ # The `opentelemetry` settings namespace is registered by core configuration, but access it
190
+ # defensively so a missing/unregistered namespace defaults to `false` rather than raising.
191
+ def opentelemetry_settings
192
+ return unless Datadog.configuration.respond_to?(:opentelemetry)
193
+
194
+ Datadog.configuration.opentelemetry
195
+ rescue
196
+ nil
197
+ end
198
+
164
199
  # Outputs "k1:v1,k2:v2,..."
165
200
  def hash_serializer(h)
166
201
  h.map { |k, v| "#{k}:#{v}" }.join(",")
@@ -12,7 +12,7 @@ module Datadog
12
12
  end
13
13
 
14
14
  def available?
15
- defined?(::GC) && ::GC.respond_to?(:stat)
15
+ !!(defined?(::GC) && ::GC.respond_to?(:stat))
16
16
  end
17
17
  end
18
18
  end
@@ -56,7 +56,7 @@ module Datadog
56
56
  end
57
57
 
58
58
  def available?
59
- defined?(::RubyVM) && ::RubyVM.respond_to?(:stat)
59
+ !!(defined?(::RubyVM) && ::RubyVM.respond_to?(:stat))
60
60
  end
61
61
  end
62
62
  end
@@ -59,9 +59,9 @@ module Datadog
59
59
  end
60
60
 
61
61
  def available?
62
- defined?(::RubyVM::YJIT) \
62
+ !!(defined?(::RubyVM::YJIT) \
63
63
  && ::RubyVM::YJIT.enabled? \
64
- && ::RubyVM::YJIT.respond_to?(:runtime_stats)
64
+ && ::RubyVM::YJIT.respond_to?(:runtime_stats))
65
65
  end
66
66
  end
67
67
  end
@@ -10,7 +10,7 @@ module Datadog
10
10
  :distribution,
11
11
  :increment,
12
12
  :gauge,
13
- :time
13
+ :time,
14
14
  ].each do |metric_type|
15
15
  define_method(metric_type) do |name, stat|
16
16
  name = name.to_sym
@@ -16,8 +16,8 @@ module Datadog
16
16
  "#{Ext::TAG_LANG_VERSION}:#{Environment::Identity.lang_version}",
17
17
  # TODO: Technically not accurate, if tracing version diverges from datadog gem version
18
18
  # If we extract tracing to its own gem, this needs to be updated.
19
- "#{Ext::TAG_TRACER_VERSION}:#{Environment::Identity.gem_datadog_version}"
20
- ].freeze
19
+ "#{Ext::TAG_TRACER_VERSION}:#{Environment::Identity.gem_datadog_version}",
20
+ ].freeze,
21
21
  }.freeze
22
22
 
23
23
  def metric_options(options = nil)
@@ -23,7 +23,11 @@ module Datadog
23
23
  metadata = get_metadata(settings)
24
24
 
25
25
  shutdown!
26
- @file_descriptor = _native_store_tracer_metadata(Datadog.logger, **metadata)
26
+ @file_descriptor = _native_store_tracer_metadata(
27
+ Datadog.logger,
28
+ settings.tracing.otel_thread_context_enabled,
29
+ **metadata
30
+ )
27
31
  end
28
32
 
29
33
  def shutdown!
@@ -53,7 +57,7 @@ module Datadog
53
57
  service_version: settings.version || "",
54
58
  # Follows Java: https://github.com/DataDog/dd-trace-java/blob/2ebc964340ac530342cc389ba68ff0f5070d5f9f/dd-trace-core/src/main/java/datadog/trace/core/servicediscovery/ServiceDiscovery.java#L37-L38
55
59
  process_tags: settings.experimental_propagate_process_tags_enabled ? Core::Environment::Process.serialized : "",
56
- container_id: Core::Environment::Container.container_id || ""
60
+ container_id: Core::Environment::Container.container_id || "",
57
61
  }
58
62
  end
59
63
  end
@@ -6,7 +6,6 @@ require_relative "../../../tracing/remote"
6
6
  require_relative "../../../di/remote"
7
7
  require_relative "../../../symbol_database"
8
8
  require_relative "../../../symbol_database/remote"
9
- require_relative "../../../open_feature/remote"
10
9
 
11
10
  module Datadog
12
11
  module Core
@@ -14,33 +13,51 @@ module Datadog
14
13
  class Client
15
14
  # Capabilities
16
15
  class Capabilities
17
- attr_reader :capabilities, :receivers, :base64_capabilities
18
-
19
- def initialize(settings, telemetry)
16
+ def initialize(settings, telemetry:)
20
17
  @capabilities = []
21
18
  @products = []
22
- @products_mutex = Mutex.new
23
19
  @receivers = []
24
20
  @telemetry = telemetry
21
+ @mutex = Mutex.new
25
22
 
26
23
  register(settings)
27
24
 
28
- @base64_capabilities = capabilities_to_base64
25
+ @base64_capabilities = capabilities_to_base64(@capabilities)
26
+ end
27
+
28
+ def capabilities
29
+ @mutex.synchronize { @capabilities.dup }
29
30
  end
30
31
 
31
32
  def products
32
- @products_mutex.synchronize { @products.dup }
33
+ @mutex.synchronize { @products.dup }
33
34
  end
34
35
 
35
- def add_products(*products)
36
- @products_mutex.synchronize do
37
- products.each { |product| @products << product unless @products.include?(product) }
36
+ def receivers
37
+ @mutex.synchronize { @receivers.dup }
38
+ end
39
+
40
+ def base64_capabilities
41
+ @mutex.synchronize { @base64_capabilities }
42
+ end
43
+
44
+ def register_runtime(capabilities:, products:, receivers:)
45
+ @mutex.synchronize do
46
+ register_capabilities(capabilities)
47
+ register_products(products)
48
+ register_receivers(receivers)
49
+ @base64_capabilities = capabilities_to_base64(@capabilities)
38
50
  end
39
51
  nil
40
52
  end
41
53
 
54
+ def add_products(*products)
55
+ @mutex.synchronize { register_products(products) }
56
+ nil
57
+ end
58
+
42
59
  def remove_products(*products)
43
- @products_mutex.synchronize { products.each { |product| @products.delete(product) } }
60
+ @mutex.synchronize { products.each { |product| @products.delete(product) } }
44
61
  nil
45
62
  end
46
63
 
@@ -94,27 +111,21 @@ module Datadog
94
111
  end
95
112
  end
96
113
  end
97
-
98
- if settings.respond_to?(:open_feature) && settings.open_feature.enabled
99
- register_capabilities(Datadog::OpenFeature::Remote.capabilities)
100
- register_products(Datadog::OpenFeature::Remote.products)
101
- register_receivers(Datadog::OpenFeature::Remote.receivers(@telemetry))
102
- end
103
114
  end
104
115
 
105
116
  def register_capabilities(capabilities)
106
- @capabilities.concat(capabilities)
117
+ capabilities.each { |capability| @capabilities << capability unless @capabilities.include?(capability) }
107
118
  end
108
119
 
109
120
  def register_receivers(receivers)
110
- @receivers.concat(receivers)
121
+ receivers.each { |receiver| @receivers << receiver unless @receivers.include?(receiver) }
111
122
  end
112
123
 
113
124
  def register_products(products)
114
- @products.concat(products)
125
+ products.each { |product| @products << product unless @products.include?(product) }
115
126
  end
116
127
 
117
- def capabilities_to_base64
128
+ def capabilities_to_base64(capabilities)
118
129
  return "" if capabilities.empty?
119
130
 
120
131
  cap_to_hexs = capabilities.reduce(:|).to_s(16).tap { |s| s.size.odd? && s.prepend("0") }.scan(/\h\h/)
@@ -16,6 +16,12 @@ module Datadog
16
16
 
17
17
  attr_reader :transport, :repository, :id, :dispatcher, :settings, :logger
18
18
 
19
+ # Whether the initial reconcile is still pending, to run on the first
20
+ # sync whose response contains targets.
21
+ #
22
+ # @return [Boolean]
23
+ attr_reader :pending_initial_reconcile
24
+
19
25
  def initialize(transport, capabilities, settings:, logger:, repository: Configuration::Repository.new)
20
26
  @transport = transport
21
27
  @settings = settings
@@ -25,27 +31,52 @@ module Datadog
25
31
  @id = SecureRandom.uuid
26
32
  @capabilities = capabilities
27
33
  @dispatcher = Dispatcher.new(@capabilities.receivers)
34
+ @pending_initial_reconcile = true
28
35
  end
29
36
 
37
+ # Polls the agent for remote configuration, applies the response to
38
+ # the repository and dispatches the resulting changes to the receivers.
39
+ #
40
+ # The agent sends an empty response when it holds no targets newer
41
+ # than the targets version the client reported. Until the client
42
+ # applies a response that carries targets, it reports the initial
43
+ # targets version, so an empty response then means the agent has not
44
+ # received targets from the backend. The initial reconcile therefore
45
+ # waits for a response that carries targets.
46
+ #
47
+ # @return [void]
48
+ # @raise [TransportError] when the agent reports an internal error
49
+ # @raise [SyncError] when the response cannot be applied to the repository
30
50
  def sync
31
51
  # TODO: Skip sync if no capabilities are registered
32
52
  response = transport.send_config(payload)
33
53
 
34
54
  if response.ok?
35
- process_response(response)
55
+ changes = process_response(response)
56
+ if pending_initial_reconcile && !response.empty?
57
+ dispatcher.reconcile(changes, repository)
58
+ @pending_initial_reconcile = false
59
+ end
36
60
  elsif response.internal_error?
37
61
  raise TransportError, response.to_s
38
62
  end
63
+ nil
39
64
  end
40
65
 
41
66
  private
42
67
 
68
+ # Applies an OK response to the repository and returns the resulting
69
+ # change set, which is empty when the response is empty.
70
+ #
71
+ # @param response [Transport::Config::Response] the response returned by the agent
72
+ # @return [Configuration::Repository::ChangeSet] the changes applied by this response
73
+ # @raise [SyncError] when the response cannot be applied to the repository
43
74
  def process_response(response)
44
75
  # when response is completely empty, do nothing as in: leave as is
45
76
  if response.empty?
46
77
  logger.debug { "remote: empty response => NOOP" }
47
78
 
48
- return
79
+ return Configuration::Repository::ChangeSet.new
49
80
  end
50
81
 
51
82
  begin
@@ -61,7 +92,7 @@ module Datadog
61
92
  end
62
93
 
63
94
  # To make sure steep does not complain
64
- return unless paths && targets && contents
95
+ return Configuration::Repository::ChangeSet.new unless paths && targets && contents
65
96
 
66
97
  # TODO: sometimes it can strangely be so that paths.empty?
67
98
  # TODO: sometimes it can strangely be so that targets.empty?
@@ -69,6 +100,14 @@ module Datadog
69
100
  apply_config(paths, targets, contents)
70
101
  end
71
102
 
103
+ # Applies the response to the repository in a transaction, dispatches the
104
+ # resulting changes to the receivers and returns them.
105
+ #
106
+ # @param paths [Array<Configuration::Path>] ingress paths from the response
107
+ # @param targets [Configuration::TargetMap] targets keyed by path
108
+ # @param contents [Configuration::ContentList] contents from the response
109
+ # @return [Configuration::Repository::ChangeSet] the changes applied by the transaction
110
+ # @raise [SyncError] when a path has no matching target or content
72
111
  def apply_config(paths, targets, contents)
73
112
  changes = repository.transaction do |current, transaction|
74
113
  # paths to be removed: previously applied paths minus ingress paths
@@ -121,6 +160,8 @@ module Datadog
121
160
  else
122
161
  dispatcher.dispatch(changes, repository)
123
162
  end
163
+
164
+ changes
124
165
  end
125
166
 
126
167
  def payload # standard:disable Metrics/MethodLength
@@ -185,7 +226,7 @@ module Datadog
185
226
  is_agent: false,
186
227
  client_tracer: client_tracer,
187
228
  # base64 is needed otherwise the Go agent fails with an unmarshal error
188
- capabilities: @capabilities.base64_capabilities
229
+ capabilities: @capabilities.base64_capabilities,
189
230
  },
190
231
  cached_target_files: state.cached_target_files,
191
232
  }
@@ -15,7 +15,7 @@ module Datadog
15
15
  #
16
16
  # @api private
17
17
  class Component
18
- attr_reader :logger, :client, :healthy, :worker
18
+ attr_reader :logger, :healthy, :worker
19
19
 
20
20
  def initialize(settings, capabilities, agent_settings, logger:)
21
21
  @logger = logger
@@ -28,6 +28,7 @@ module Datadog
28
28
 
29
29
  @barrier = Barrier.new(settings.remote.boot_timeout_seconds)
30
30
 
31
+ @client_mutex = Mutex.new
31
32
  @client = Client.new(@transport, @capabilities, settings: settings, logger: logger)
32
33
  @healthy = false
33
34
  logger.debug { "new remote configuration client: #{@client.id} products: #{@capabilities.products.sort.join(", ")}" }
@@ -40,7 +41,7 @@ module Datadog
40
41
  end
41
42
 
42
43
  begin
43
- @client.sync
44
+ client.sync
44
45
  @healthy ||= true
45
46
  rescue Client::SyncError => e
46
47
  # Transient errors due to network or agent. Logged the error but not via telemetry
@@ -60,9 +61,11 @@ module Datadog
60
61
  end
61
62
 
62
63
  # client state is unknown, state might be corrupted
63
- @client = Client.new(@transport, @capabilities, settings: settings, logger: logger)
64
+ new_client = @client_mutex.synchronize do
65
+ @client = Client.new(@transport, @capabilities, settings: settings, logger: logger)
66
+ end
64
67
  @healthy = false
65
- logger.debug { "new remote configuration client: #{@client.id} products: #{@capabilities.products.sort.join(", ")}" }
68
+ logger.debug { "new remote configuration client: #{new_client.id} products: #{@capabilities.products.sort.join(", ")}" }
66
69
 
67
70
  # TODO: bail out if too many errors?
68
71
  end
@@ -81,6 +84,10 @@ module Datadog
81
84
  @worker.started?
82
85
  end
83
86
 
87
+ def client
88
+ @client_mutex.synchronize { @client }
89
+ end
90
+
84
91
  # If the worker is not initialized, initialize it.
85
92
  #
86
93
  # Then, waits for one client sync to be executed if `kind` is `:once`.
@@ -96,9 +103,13 @@ module Datadog
96
103
  # Recreates the remote configuration client after a fork.
97
104
  # This ensures each forked process has a unique client ID and fresh state.
98
105
  def after_fork
99
- @client = Client.new(@transport, @capabilities, settings: @settings, logger: @logger)
106
+ @worker.after_fork
107
+ @barrier = Barrier.new(@settings.remote.boot_timeout_seconds)
108
+ new_client = @client_mutex.synchronize do
109
+ @client = Client.new(@transport, @capabilities, settings: @settings, logger: @logger)
110
+ end
100
111
  @healthy = false
101
- logger.debug { "remote configuration client recreated after fork: #{@client.id} products: #{@capabilities.products.sort.join(", ")}" }
112
+ logger.debug { "remote configuration client recreated after fork: #{new_client.id} products: #{@capabilities.products.sort.join(", ")}" }
102
113
  end
103
114
 
104
115
  def add_products(*products)
@@ -109,6 +120,17 @@ module Datadog
109
120
  @capabilities.remove_products(*products)
110
121
  end
111
122
 
123
+ def register(capabilities:, products:, receivers:)
124
+ @client_mutex.synchronize do
125
+ @capabilities.register_runtime(
126
+ capabilities: capabilities,
127
+ products: products,
128
+ receivers: receivers,
129
+ )
130
+ @client.dispatcher.add_receivers(*receivers)
131
+ end
132
+ end
133
+
112
134
  # Barrier provides a mechanism to fence execution until a condition happens
113
135
  class Barrier
114
136
  def initialize(timeout = nil)
@@ -190,7 +212,8 @@ module Datadog
190
212
  def build(settings, agent_settings, logger:, telemetry:)
191
213
  return unless settings.remote.enabled
192
214
 
193
- new(settings, Client::Capabilities.new(settings, telemetry), agent_settings, logger: logger)
215
+ capabilities = Client::Capabilities.new(settings, telemetry: telemetry)
216
+ new(settings, capabilities, agent_settings, logger: logger)
194
217
  end
195
218
  end
196
219
  end
@@ -111,9 +111,9 @@ module Datadog
111
111
  hashes: content.hashes.map do |algorithm, hexdigest|
112
112
  {
113
113
  algorithm: algorithm,
114
- hash: hexdigest
114
+ hash: hexdigest,
115
115
  }
116
- end
116
+ end,
117
117
  }
118
118
  end
119
119
  end
@@ -5,24 +5,57 @@ module Datadog
5
5
  module Remote
6
6
  # Repository update dispatcher
7
7
  class Dispatcher
8
- attr_reader :receivers
9
-
10
8
  def initialize(receivers)
11
- @receivers = receivers
9
+ @receivers = receivers.dup
10
+ @mutex = Mutex.new
11
+ end
12
+
13
+ def receivers
14
+ @mutex.synchronize { @receivers.dup }
15
+ end
16
+
17
+ def add_receivers(*receivers)
18
+ @mutex.synchronize do
19
+ receivers.each { |receiver| @receivers << receiver unless @receivers.include?(receiver) }
20
+ end
21
+ nil
12
22
  end
13
23
 
14
24
  def dispatch(changes, repository)
15
25
  receivers.each do |receiver|
16
- matching_changes = changes.select { |c| receiver.match?(c.path) }
26
+ matching = matching_changes(changes, receiver)
27
+
28
+ receiver.call(repository, matching) if matching.any?
29
+ end
30
+ nil
31
+ end
32
+
33
+ # Calls each receiver that declares initial-reconcile participation and has no
34
+ # matching change in `changes`, passing an empty change list.
35
+ def reconcile(changes, repository)
36
+ receivers.each do |receiver|
37
+ next unless receiver.initial_reconcile?
17
38
 
18
- receiver.call(repository, matching_changes) if matching_changes.any?
39
+ receiver.call(repository, []) unless any_matching?(changes, receiver)
19
40
  end
41
+ nil
42
+ end
43
+
44
+ private
45
+
46
+ def matching_changes(changes, receiver)
47
+ changes.select { |change| receiver.match?(change.path) }
48
+ end
49
+
50
+ def any_matching?(changes, receiver)
51
+ changes.any? { |change| receiver.match?(change.path) }
20
52
  end
21
53
 
22
54
  # Store Matcher and block to be executed on a match
23
55
  class Receiver
24
- def initialize(matcher, &block)
56
+ def initialize(matcher, initial_reconcile: false, &block)
25
57
  @block = block
58
+ @initial_reconcile = initial_reconcile
26
59
  @matcher = matcher
27
60
  end
28
61
 
@@ -30,6 +63,14 @@ module Datadog
30
63
  @matcher.match?(path)
31
64
  end
32
65
 
66
+ # Whether #reconcile may call this receiver with an empty change
67
+ # list on the client's first sync. A participating receiver must
68
+ # act on the repository's current contents when the change list is
69
+ # empty.
70
+ def initial_reconcile?
71
+ @initial_reconcile
72
+ end
73
+
33
74
  def call(repository, changes)
34
75
  @block.call(repository, changes)
35
76
  end
@@ -70,6 +70,14 @@ module Datadog
70
70
  @started
71
71
  end
72
72
 
73
+ # Child-only: discard inherited synchronization without starting a thread.
74
+ def after_fork
75
+ @mutex = Mutex.new
76
+ @thr = nil
77
+ @starting = false
78
+ @started = false
79
+ end
80
+
73
81
  private
74
82
 
75
83
  def poll(interval)