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
@@ -24,7 +24,7 @@ end
24
24
  if ENV["DD_NO_EXTENSION"].to_s.strip.downcase == "true"
25
25
  skip_building_extension!("the `DD_NO_EXTENSION` environment variable is/was set to `true` during installation")
26
26
  end
27
- skip_building_extension!("current Ruby VM is not supported") if RUBY_ENGINE != "ruby"
27
+ skip_building_extension!("current Ruby VM is not supported") unless %w[ruby truffleruby].include?(RUBY_ENGINE)
28
28
  skip_building_extension!("Microsoft Windows is not supported") if Gem.win_platform?
29
29
 
30
30
  libdatadog_issue = Datadog::LibdatadogExtconfHelpers.load_libdatadog_or_get_issue
@@ -98,6 +98,11 @@ EXTENSION_NAME = "libdatadog_api.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}".fr
98
98
 
99
99
  have_func("rb_iseq_type")
100
100
 
101
+ $defs << "-DHAVE_RB_IMEMO_NAME" if RUBY_VERSION >= "3.0"
102
+ $defs << "-DHAVE_SHIFTED_IMEMO_MASK" if RUBY_VERSION >= "4.1"
103
+ $defs << "-DHAVE_RUBY_THREAD_STORAGE_API" if RUBY_VERSION >= "3.3"
104
+ $defs << "-DHAVE_RUBY_THREAD_HAS_GVL_P" if have_func("ruby_thread_has_gvl_p")
105
+
101
106
  create_makefile(EXTENSION_NAME)
102
107
 
103
108
  # rubocop:enable Style/GlobalVars
@@ -13,6 +13,7 @@
13
13
  // Forward declarations
14
14
  static VALUE configuration_new(VALUE klass, VALUE json_str);
15
15
  static void configuration_free(void *ptr);
16
+ static VALUE configuration_get_observe_full_evaluation_data(VALUE self);
16
17
  static VALUE configuration_get_assignment(
17
18
  VALUE self, VALUE flag_key, VALUE expected_type, VALUE context);
18
19
 
@@ -94,6 +95,7 @@ void feature_flags_init(VALUE core_module) {
94
95
  rb_undef_alloc_func(configuration_class);
95
96
  rb_define_singleton_method(configuration_class, "new", configuration_new, 1);
96
97
  rb_define_method(configuration_class, "get_assignment", configuration_get_assignment, 3);
98
+ rb_define_method(configuration_class, "observe_full_evaluation_data", configuration_get_observe_full_evaluation_data, 0);
97
99
 
98
100
  rb_gc_register_address(&resolution_details_class);
99
101
  resolution_details_class = rb_define_class_under(feature_flags_module, "ResolutionDetails", rb_cObject);
@@ -137,6 +139,12 @@ static VALUE configuration_new(VALUE klass, VALUE json_str) {
137
139
  return TypedData_Wrap_Struct(klass, &configuration_data_type, result.ok);
138
140
  }
139
141
 
142
+ static VALUE configuration_get_observe_full_evaluation_data(VALUE self) {
143
+ ddog_ffe_Handle_Configuration configuration =
144
+ (ddog_ffe_Handle_Configuration)rb_check_typeddata(self, &configuration_data_type);
145
+ return ddog_ffe_configuration_get_observe_full_evaluation_data(configuration) ? Qtrue : Qfalse;
146
+ }
147
+
140
148
  static void configuration_free(void *ptr) {
141
149
  ddog_ffe_Handle_Configuration config = (ddog_ffe_Handle_Configuration)ptr;
142
150
  ddog_ffe_configuration_drop(&config);
@@ -5,7 +5,9 @@
5
5
  #include "crashtracker.h"
6
6
  #include "feature_flags.h"
7
7
  #include "library_config.h"
8
+ #include "otel_thread_context.h"
8
9
  #include "process_discovery.h"
10
+ #include "trace_exporter.h"
9
11
 
10
12
  void ddsketch_init(VALUE core_module);
11
13
  void di_init(VALUE datadog_module);
@@ -23,5 +25,11 @@ void DDTRACE_EXPORT Init_libdatadog_api(void) {
23
25
  library_config_init(core_module);
24
26
  ddsketch_init(core_module);
25
27
  feature_flags_init(core_module);
26
- di_init(datadog_module);
28
+ #ifndef TRUFFLERUBY
29
+ di_init(datadog_module);
30
+ #endif
31
+
32
+ VALUE tracing_module = rb_define_module_under(datadog_module, "Tracing");
33
+ trace_exporter_init(tracing_module);
34
+ otel_thread_context_init(tracing_module);
27
35
  }
@@ -0,0 +1,274 @@
1
+ #include <ruby.h>
2
+ #include <ruby/thread.h>
3
+
4
+ #include "datadog_ruby_common.h"
5
+ #include "otel_thread_context.h"
6
+
7
+ // Relies on a :fiber_switch TracePoint that TruffleRuby does not support yet
8
+ #if defined(__linux__) && !defined(TRUFFLERUBY)
9
+ #define OTEL_THREAD_CONTEXT_SUPPORTED
10
+ #endif
11
+
12
+ #ifdef OTEL_THREAD_CONTEXT_SUPPORTED
13
+ #include <datadog/otel-thread-ctx.h>
14
+ extern __thread const uint8_t *otel_thread_ctx_v1;
15
+
16
+ static void otel_ctx_handle_free(void *handle) {
17
+ ddog_otel_thread_ctx_free((ddog_ThreadContextHandle *) handle);
18
+ }
19
+
20
+ static const rb_data_type_t otel_ctx_handle_t = {
21
+ .wrap_struct_name = "Datadog::Tracing::OTelThreadContext handle",
22
+ .function = {.dfree = otel_ctx_handle_free},
23
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
24
+ };
25
+ #endif
26
+
27
+ static ID fiber_context_slot;
28
+
29
+ DDTRACE_UNUSED static bool otel_context_enabled = false;
30
+
31
+ static VALUE native_set(VALUE _self, VALUE trace_id, VALUE span_id, VALUE local_root_span_id);
32
+ static VALUE native_clear(VALUE _self);
33
+ static VALUE native_enable(VALUE _self);
34
+ static VALUE native_read(VALUE _self);
35
+
36
+ void otel_thread_context_init(VALUE tracing_module) {
37
+ fiber_context_slot = rb_intern("__dd_otel_fiber_context");
38
+
39
+ VALUE otel_thread_context_class = rb_define_class_under(tracing_module, "OTelThreadContext", rb_cObject);
40
+
41
+ rb_define_method(otel_thread_context_class, "_native_enable", native_enable, 0);
42
+ rb_define_method(otel_thread_context_class, "_native_set", native_set, 3);
43
+ rb_define_method(otel_thread_context_class, "_native_clear", native_clear, 0);
44
+
45
+ VALUE testing_module = rb_define_module_under(otel_thread_context_class, "Testing");
46
+ rb_define_singleton_method(testing_module, "_native_read", native_read, 0);
47
+ }
48
+
49
+ #ifdef OTEL_THREAD_CONTEXT_SUPPORTED
50
+ static ddog_ThreadContextHandle *get_fiber_handle_for(VALUE thread) {
51
+ VALUE obj = rb_thread_local_aref(thread, fiber_context_slot);
52
+
53
+ if (!rb_typeddata_is_kind_of(obj, &otel_ctx_handle_t)) return NULL;
54
+
55
+ return RTYPEDDATA_DATA(obj);
56
+ }
57
+
58
+ static ddog_ThreadContextHandle *get_current_fiber_handle(void) {
59
+ return get_fiber_handle_for(rb_thread_current());
60
+ }
61
+
62
+ static void pack_span_id(VALUE id, uint8_t bytes[8]) {
63
+ // Tracing::Utils.next_id caps generated span IDs at (1 << 62) - 1, which fits
64
+ // in a Fixnum on 64-bit Ruby. Packing them directly avoids rb_integer_pack's
65
+ // generic conversion and format checks on each context update.
66
+ // https://github.com/DataDog/dd-trace-rb/blob/0b10368e0a2940c1f4d50c9739b9973b4f8bc32a/lib/datadog/tracing/utils.rb#L20-L37
67
+ if (FIXNUM_P(id)) {
68
+ uint64_t number = (uint64_t) FIX2LONG(id);
69
+ for (int i = 7; i >= 0; i--) {
70
+ bytes[i] = (uint8_t) number;
71
+ number >>= 8;
72
+ }
73
+ } else {
74
+ rb_integer_pack(id, bytes, 1, sizeof(uint64_t), 0, INTEGER_PACK_BIG_ENDIAN);
75
+ }
76
+ }
77
+
78
+ static void store_current_fiber_handle(ddog_ThreadContextHandle *handle) {
79
+ VALUE obj = TypedData_Wrap_Struct(rb_cObject, &otel_ctx_handle_t, handle);
80
+ rb_thread_local_aset(rb_thread_current(), fiber_context_slot, obj);
81
+ }
82
+
83
+ #ifdef RUBY_INTERNAL_THREAD_EVENT_EXITED
84
+ static void on_thread_exited(
85
+ DDTRACE_UNUSED rb_event_flag_t event,
86
+ DDTRACE_UNUSED const rb_internal_thread_event_data_t *event_data,
87
+ DDTRACE_UNUSED void *user_data
88
+ ) {
89
+ ddog_otel_thread_ctx_detach();
90
+ }
91
+ #else
92
+ static void on_thread_end(
93
+ DDTRACE_UNUSED rb_event_flag_t evflag,
94
+ DDTRACE_UNUSED VALUE data,
95
+ DDTRACE_UNUSED VALUE self,
96
+ DDTRACE_UNUSED ID mid,
97
+ DDTRACE_UNUSED VALUE klass
98
+ ) {
99
+ ddog_otel_thread_ctx_detach();
100
+ }
101
+
102
+ // CRuby fires RUBY_EVENT_THREAD_END only after the thread body returns,
103
+ // and Thread#kill unwinds the body via EC_JUMP_TAG(TAG_FATAL):
104
+ // https://github.com/ruby/ruby/blob/v3_1_4/thread.c#L744-L775
105
+ static void on_thread_begin(
106
+ DDTRACE_UNUSED rb_event_flag_t evflag,
107
+ DDTRACE_UNUSED VALUE data,
108
+ DDTRACE_UNUSED VALUE self,
109
+ DDTRACE_UNUSED ID mid,
110
+ DDTRACE_UNUSED VALUE klass
111
+ ) {
112
+ ddog_otel_thread_ctx_detach();
113
+ }
114
+ #endif
115
+
116
+ #ifdef HAVE_RUBY_THREAD_STORAGE_API
117
+ // This function is declared in internal/thread.h.
118
+ // It returns 0 when the current thread sits in a blocking region.
119
+ int ruby_thread_has_gvl_p(void);
120
+
121
+ static bool in_blocking_region(void) {
122
+ #ifdef HAVE_RUBY_THREAD_HAS_GVL_P
123
+ return ruby_thread_has_gvl_p() == 0;
124
+ #else
125
+ return false;
126
+ #endif
127
+ }
128
+
129
+ // Under M:N a Ruby thread can migrate between native threads,
130
+ // so we need to detach the context when the Ruby thread gets suspended.
131
+ static void on_thread_suspended(
132
+ DDTRACE_UNUSED rb_event_flag_t event,
133
+ DDTRACE_UNUSED const rb_internal_thread_event_data_t *event_data,
134
+ DDTRACE_UNUSED void *user_data
135
+ ) {
136
+ // Ruby pins threads that release GVL to call into a native extension,
137
+ // so we know the thread will not migrate.
138
+ if (in_blocking_region()) return;
139
+
140
+ ddog_otel_thread_ctx_detach();
141
+ }
142
+
143
+ static void on_thread_resumed(
144
+ DDTRACE_UNUSED rb_event_flag_t event,
145
+ const rb_internal_thread_event_data_t *event_data,
146
+ DDTRACE_UNUSED void *user_data
147
+ ) {
148
+ ddog_ThreadContextHandle *handle = get_fiber_handle_for(event_data->thread);
149
+
150
+ if (handle != NULL) ddog_otel_thread_ctx_attach(handle);
151
+ }
152
+ #endif
153
+
154
+ static void on_fiber_switch(
155
+ DDTRACE_UNUSED rb_event_flag_t evflag,
156
+ DDTRACE_UNUSED VALUE data,
157
+ DDTRACE_UNUSED VALUE self,
158
+ DDTRACE_UNUSED ID mid,
159
+ DDTRACE_UNUSED VALUE klass
160
+ ) {
161
+ ddog_ThreadContextHandle *handle = get_current_fiber_handle();
162
+
163
+ if (handle != NULL) {
164
+ ddog_otel_thread_ctx_attach(handle);
165
+ } else {
166
+ ddog_otel_thread_ctx_detach();
167
+ }
168
+ }
169
+ #endif
170
+
171
+ static VALUE native_enable(DDTRACE_UNUSED VALUE _self) {
172
+ #ifdef OTEL_THREAD_CONTEXT_SUPPORTED
173
+ if (otel_context_enabled) return Qtrue;
174
+ otel_context_enabled = true;
175
+
176
+ #ifdef RUBY_INTERNAL_THREAD_EVENT_EXITED
177
+ rb_internal_thread_add_event_hook(on_thread_exited, RUBY_INTERNAL_THREAD_EVENT_EXITED, NULL);
178
+ #else
179
+ rb_add_event_hook(on_thread_end, RUBY_EVENT_THREAD_END, Qnil);
180
+ // RUBY_EVENT_THREAD_END does not fire for threads terminated via Thread#kill
181
+ // on Ruby < 3.2, so a killed thread's otel_thread_ctx_v1 TLS stays attached
182
+ // on a native thread CRuby may recycle for a later Ruby thread. Detach on
183
+ // thread begin to drop that stale record before the new thread runs.
184
+ rb_add_event_hook(on_thread_begin, RUBY_EVENT_THREAD_BEGIN, Qnil);
185
+ #endif
186
+
187
+ // These hooks only matter under the M:N thread scheduler (Ruby 3.3+),
188
+ // where a Ruby thread can migrate between native threads.
189
+ #ifdef HAVE_RUBY_THREAD_STORAGE_API
190
+ rb_internal_thread_add_event_hook(on_thread_suspended, RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, NULL);
191
+ rb_internal_thread_add_event_hook(on_thread_resumed, RUBY_INTERNAL_THREAD_EVENT_RESUMED, NULL);
192
+ #endif
193
+
194
+ rb_add_event_hook(on_fiber_switch, RUBY_EVENT_FIBER_SWITCH, Qnil);
195
+
196
+ return Qtrue;
197
+ #else
198
+ raise_error(rb_eRuntimeError, "OTel thread context is not supported on this platform");
199
+ #endif
200
+ }
201
+
202
+ static VALUE native_set(
203
+ DDTRACE_UNUSED VALUE _self,
204
+ DDTRACE_UNUSED VALUE trace_id,
205
+ DDTRACE_UNUSED VALUE span_id,
206
+ DDTRACE_UNUSED VALUE local_root_span_id
207
+ ) {
208
+ #ifdef OTEL_THREAD_CONTEXT_SUPPORTED
209
+ if (!otel_context_enabled) return Qfalse;
210
+
211
+ uint8_t trace_id_bytes[16];
212
+ uint8_t span_id_bytes[8];
213
+ uint8_t local_root_span_id_bytes[8];
214
+
215
+ // Note: We use 2 words of size 8, as `rb_integer_pack` has a fast path for it (vs 16 bytes of size 1)
216
+ rb_integer_pack(trace_id, trace_id_bytes, 2, sizeof(uint64_t), 0, INTEGER_PACK_BIG_ENDIAN);
217
+ pack_span_id(span_id, span_id_bytes);
218
+ pack_span_id(local_root_span_id, local_root_span_id_bytes);
219
+
220
+ ddog_ThreadContextHandle *handle = get_current_fiber_handle();
221
+
222
+ if (handle == NULL) {
223
+ handle = ddog_otel_thread_ctx_new(&trace_id_bytes, &span_id_bytes, 0, &local_root_span_id_bytes);
224
+ store_current_fiber_handle(handle);
225
+ ddog_otel_thread_ctx_attach(handle);
226
+ } else {
227
+ ddog_otel_thread_ctx_update_and_attach(handle, &trace_id_bytes, &span_id_bytes, 0, &local_root_span_id_bytes);
228
+ }
229
+
230
+ return Qtrue;
231
+ #else
232
+ return Qfalse;
233
+ #endif
234
+ }
235
+
236
+ static VALUE native_clear(DDTRACE_UNUSED VALUE _self) {
237
+ #ifdef OTEL_THREAD_CONTEXT_SUPPORTED
238
+ if (!otel_context_enabled) return Qfalse;
239
+
240
+ ddog_ThreadContextHandle *detached = ddog_otel_thread_ctx_detach();
241
+ rb_thread_local_aset(rb_thread_current(), fiber_context_slot, Qnil);
242
+
243
+ return detached == NULL ? Qfalse : Qtrue;
244
+ #else
245
+ return Qfalse;
246
+ #endif
247
+ }
248
+
249
+ static VALUE native_read(DDTRACE_UNUSED VALUE _self) {
250
+ #ifdef OTEL_THREAD_CONTEXT_SUPPORTED
251
+ const uint8_t *raw = otel_thread_ctx_v1;
252
+ if (!raw) return Qnil;
253
+
254
+ uint16_t attrs_data_size = (uint16_t) raw[26] | ((uint16_t) raw[27] << 8);
255
+
256
+ if (attrs_data_size > ddog_MAX_ATTRS_DATA_SIZE) {
257
+ raise_error(
258
+ rb_eRuntimeError,
259
+ "Invalid OTel thread context record: attrs_data_size (%d) exceeds maximum (%d)",
260
+ attrs_data_size, ddog_MAX_ATTRS_DATA_SIZE
261
+ );
262
+ }
263
+
264
+ VALUE result = rb_hash_new();
265
+ rb_hash_aset(result, ID2SYM(rb_intern("trace_id")), rb_str_new((const char *) raw, 16));
266
+ rb_hash_aset(result, ID2SYM(rb_intern("span_id")), rb_str_new((const char *) (raw + 16), 8));
267
+ rb_hash_aset(result, ID2SYM(rb_intern("valid")), rb_str_new((const char *) (raw + 24), 1));
268
+ rb_hash_aset(result, ID2SYM(rb_intern("attrs")), rb_str_new((const char *) (raw + 28), attrs_data_size));
269
+
270
+ return result;
271
+ #else
272
+ return Qnil;
273
+ #endif
274
+ }
@@ -0,0 +1,5 @@
1
+ #pragma once
2
+
3
+ #include <ruby.h>
4
+
5
+ void otel_thread_context_init(VALUE tracing_module);
@@ -4,6 +4,7 @@
4
4
  #include <datadog/library-config.h>
5
5
 
6
6
  #include "datadog_ruby_common.h"
7
+ #include "helpers.h"
7
8
 
8
9
  static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
9
10
  static VALUE _native_to_rb_int(DDTRACE_UNUSED VALUE _self, VALUE tracer_memfd);
@@ -38,8 +39,9 @@ void process_discovery_init(VALUE core_module) {
38
39
 
39
40
  static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
40
41
  VALUE logger;
42
+ VALUE otel_thread_context_enabled;
41
43
  VALUE options;
42
- rb_scan_args(argc, argv, "1:", &logger, &options);
44
+ rb_scan_args(argc, argv, "2:", &logger, &otel_thread_context_enabled, &options);
43
45
  if (options == Qnil) options = rb_hash_new();
44
46
 
45
47
  VALUE runtime_id = rb_hash_fetch(options, ID2SYM(rb_intern("runtime_id")));
@@ -61,6 +63,7 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
61
63
  ENFORCE_TYPE(service_version, T_STRING);
62
64
  ENFORCE_TYPE(process_tags, T_STRING);
63
65
  ENFORCE_TYPE(container_id, T_STRING);
66
+ ENFORCE_BOOLEAN(otel_thread_context_enabled);
64
67
 
65
68
  void* builder = ddog_tracer_metadata_new();
66
69
 
@@ -74,6 +77,16 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
74
77
  ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_PROCESS_TAGS, StringValueCStr(process_tags));
75
78
  ddog_tracer_metadata_set(builder, DDOG_METADATA_KIND_CONTAINER_ID, StringValueCStr(container_id));
76
79
 
80
+ if (RTEST(otel_thread_context_enabled)) {
81
+ ddog_VoidResult include_result = ddog_tracer_metadata_include_otel_thread_context(builder);
82
+
83
+ if (include_result.tag == DDOG_VOID_RESULT_ERR) {
84
+ ddog_tracer_metadata_free(builder);
85
+ }
86
+
87
+ CHECK_VOID_RESULT("Failed to include OTel thread context metadata", include_result);
88
+ }
89
+
77
90
  ddog_Result_TracerMemfdHandle result = ddog_tracer_metadata_store(builder);
78
91
  ddog_tracer_metadata_free(builder);
79
92
 
@@ -89,6 +102,7 @@ static VALUE _native_store_tracer_metadata(int argc, VALUE *argv, VALUE self) {
89
102
  *fd = result.ok.fd;
90
103
  VALUE tracer_memfd_class = rb_const_get(self, rb_intern("TracerMemfd"));
91
104
  VALUE tracer_memfd = TypedData_Wrap_Struct(tracer_memfd_class, &tracer_memfd_type, fd);
105
+
92
106
  return tracer_memfd;
93
107
  }
94
108