datadog 2.30.0 → 2.45.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 (966) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +450 -1
  3. data/README.md +3 -0
  4. data/bin/ddprofrb +4 -4
  5. data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +12 -24
  6. data/ext/datadog_profiling_native_extension/clock_id.h +9 -1
  7. data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +66 -0
  8. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -1
  9. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +368 -151
  10. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +2 -6
  11. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +0 -2
  12. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +29 -16
  13. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.h +5 -1
  14. data/ext/datadog_profiling_native_extension/collectors_stack.c +263 -170
  15. data/ext/datadog_profiling_native_extension/collectors_stack.h +24 -5
  16. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +909 -552
  17. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +25 -9
  18. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +5 -4
  19. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +44 -19
  20. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -12
  21. data/ext/datadog_profiling_native_extension/extconf.rb +86 -104
  22. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +4 -43
  23. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +15 -47
  24. data/ext/datadog_profiling_native_extension/heap_recorder.c +393 -279
  25. data/ext/datadog_profiling_native_extension/heap_recorder.h +50 -31
  26. data/ext/datadog_profiling_native_extension/http_transport.c +10 -5
  27. data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
  28. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -27
  29. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +847 -510
  30. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +38 -14
  31. data/ext/datadog_profiling_native_extension/profiling.c +65 -27
  32. data/ext/datadog_profiling_native_extension/ruby_helpers.c +37 -107
  33. data/ext/datadog_profiling_native_extension/ruby_helpers.h +4 -7
  34. data/ext/datadog_profiling_native_extension/stack_recorder.c +130 -93
  35. data/ext/datadog_profiling_native_extension/stack_recorder.h +12 -4
  36. data/ext/datadog_profiling_native_extension/time_helpers.c +2 -4
  37. data/ext/datadog_profiling_native_extension/time_helpers.h +25 -19
  38. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +4 -2
  39. data/ext/libdatadog_api/crashtracker.c +7 -8
  40. data/ext/libdatadog_api/datadog_ruby_common.c +44 -19
  41. data/ext/libdatadog_api/datadog_ruby_common.h +7 -12
  42. data/ext/libdatadog_api/di.c +218 -0
  43. data/ext/libdatadog_api/extconf.rb +40 -26
  44. data/ext/libdatadog_api/feature_flags.c +34 -0
  45. data/ext/libdatadog_api/init.c +13 -2
  46. data/ext/libdatadog_api/otel_thread_context.c +268 -0
  47. data/ext/libdatadog_api/otel_thread_context.h +5 -0
  48. data/ext/libdatadog_api/trace_exporter.c +1998 -0
  49. data/ext/libdatadog_api/trace_exporter.h +5 -0
  50. data/ext/libdatadog_extconf_helpers.rb +63 -13
  51. data/lib/datadog/ai_guard/autoload.rb +10 -0
  52. data/lib/datadog/ai_guard/component.rb +24 -13
  53. data/lib/datadog/ai_guard/configuration/ext.rb +2 -0
  54. data/lib/datadog/ai_guard/configuration.rb +119 -2
  55. data/lib/datadog/ai_guard/contrib/auto_instrument.rb +24 -0
  56. data/lib/datadog/ai_guard/contrib/rack/integration.rb +42 -0
  57. data/lib/datadog/ai_guard/contrib/rack/patcher.rb +26 -0
  58. data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +97 -0
  59. data/lib/datadog/ai_guard/contrib/rails/integration.rb +41 -0
  60. data/lib/datadog/ai_guard/contrib/rails/patcher.rb +97 -0
  61. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +54 -23
  62. data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +1 -1
  63. data/lib/datadog/ai_guard/contrib/ruby_llm/message_adapter.rb +76 -0
  64. data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +1 -0
  65. data/lib/datadog/ai_guard/contrib/ruby_llm/redaction_change_set.rb +135 -0
  66. data/lib/datadog/ai_guard/evaluation/client.rb +50 -0
  67. data/lib/datadog/ai_guard/evaluation/content_part.rb +48 -0
  68. data/lib/datadog/ai_guard/evaluation/message.rb +25 -7
  69. data/lib/datadog/ai_guard/evaluation/message_builder.rb +31 -0
  70. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +8 -6
  71. data/lib/datadog/ai_guard/evaluation/outcome.rb +24 -0
  72. data/lib/datadog/ai_guard/evaluation/request.rb +8 -59
  73. data/lib/datadog/ai_guard/evaluation/response.rb +33 -0
  74. data/lib/datadog/ai_guard/evaluation/result.rb +11 -16
  75. data/lib/datadog/ai_guard/evaluation/tool_call.rb +15 -2
  76. data/lib/datadog/ai_guard/evaluation.rb +75 -17
  77. data/lib/datadog/ai_guard/ext.rb +16 -0
  78. data/lib/datadog/ai_guard/{api_client.rb → http_client.rb} +15 -11
  79. data/lib/datadog/ai_guard/metrics/telemetry.rb +43 -0
  80. data/lib/datadog/ai_guard/redaction/replacements.rb +97 -0
  81. data/lib/datadog/ai_guard/redaction/result.rb +29 -0
  82. data/lib/datadog/ai_guard/redaction.rb +80 -0
  83. data/lib/datadog/ai_guard.rb +70 -43
  84. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +22 -43
  85. data/lib/datadog/appsec/actions_handler.rb +6 -6
  86. data/lib/datadog/appsec/anonymizer.rb +1 -1
  87. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +2 -2
  88. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +6 -6
  89. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +1 -1
  90. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +2 -2
  91. data/lib/datadog/appsec/api_security/route_extractor.rb +26 -14
  92. data/lib/datadog/appsec/api_security/sampler.rb +5 -5
  93. data/lib/datadog/appsec/api_security.rb +1 -1
  94. data/lib/datadog/appsec/assets/blocked.html +1 -108
  95. data/lib/datadog/appsec/assets.rb +7 -7
  96. data/lib/datadog/appsec/autoload.rb +4 -4
  97. data/lib/datadog/appsec/component.rb +29 -22
  98. data/lib/datadog/appsec/compressed_json.rb +7 -7
  99. data/lib/datadog/appsec/configuration.rb +436 -1
  100. data/lib/datadog/appsec/context.rb +10 -8
  101. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +6 -6
  102. data/lib/datadog/appsec/contrib/active_record/integration.rb +4 -4
  103. data/lib/datadog/appsec/contrib/active_record/patcher.rb +4 -4
  104. data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +75 -0
  105. data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +39 -0
  106. data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +30 -0
  107. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +146 -0
  108. data/lib/datadog/appsec/contrib/devise/configuration.rb +1 -1
  109. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +3 -3
  110. data/lib/datadog/appsec/contrib/devise/ext.rb +20 -20
  111. data/lib/datadog/appsec/contrib/devise/integration.rb +4 -4
  112. data/lib/datadog/appsec/contrib/devise/patcher.rb +8 -8
  113. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +14 -13
  114. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +8 -8
  115. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +24 -9
  116. data/lib/datadog/appsec/contrib/excon/integration.rb +4 -4
  117. data/lib/datadog/appsec/contrib/excon/patcher.rb +1 -1
  118. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +76 -21
  119. data/lib/datadog/appsec/contrib/faraday/integration.rb +4 -4
  120. data/lib/datadog/appsec/contrib/faraday/patcher.rb +4 -4
  121. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +72 -18
  122. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +4 -4
  123. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +66 -21
  124. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +7 -7
  125. data/lib/datadog/appsec/contrib/graphql/integration.rb +9 -8
  126. data/lib/datadog/appsec/contrib/graphql/patcher.rb +3 -3
  127. data/lib/datadog/appsec/contrib/rack/buffered_input.rb +83 -0
  128. data/lib/datadog/appsec/contrib/rack/ext.rb +29 -29
  129. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +56 -17
  130. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +1 -1
  131. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +46 -30
  132. data/lib/datadog/appsec/contrib/rack/input_peeker.rb +79 -0
  133. data/lib/datadog/appsec/contrib/rack/integration.rb +6 -6
  134. data/lib/datadog/appsec/contrib/rack/patcher.rb +3 -3
  135. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +11 -8
  136. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +51 -61
  137. data/lib/datadog/appsec/contrib/rack/response_body.rb +1 -1
  138. data/lib/datadog/appsec/contrib/rails/gateway/request.rb +43 -4
  139. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +25 -9
  140. data/lib/datadog/appsec/contrib/rails/integration.rb +5 -5
  141. data/lib/datadog/appsec/contrib/rails/patcher.rb +17 -17
  142. data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +2 -2
  143. data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +3 -3
  144. data/lib/datadog/appsec/contrib/rails/request.rb +3 -3
  145. data/lib/datadog/appsec/contrib/rails/request_middleware.rb +2 -1
  146. data/lib/datadog/appsec/contrib/rest_client/integration.rb +5 -5
  147. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +1 -1
  148. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +74 -21
  149. data/lib/datadog/appsec/contrib/sinatra/gateway/request.rb +1 -1
  150. data/lib/datadog/appsec/contrib/sinatra/gateway/route_params.rb +1 -1
  151. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +34 -13
  152. data/lib/datadog/appsec/contrib/sinatra/integration.rb +5 -5
  153. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +11 -11
  154. data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +3 -3
  155. data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
  156. data/lib/datadog/appsec/counter_sampler.rb +1 -1
  157. data/lib/datadog/appsec/default_header_tags.rb +52 -0
  158. data/lib/datadog/appsec/event.rb +14 -14
  159. data/lib/datadog/appsec/ext.rb +11 -10
  160. data/lib/datadog/appsec/extensions.rb +2 -2
  161. data/lib/datadog/appsec/instrumentation/gateway.rb +1 -14
  162. data/lib/datadog/appsec/metrics/collector.rb +18 -1
  163. data/lib/datadog/appsec/metrics/exporter.rb +17 -11
  164. data/lib/datadog/appsec/metrics/telemetry.rb +15 -3
  165. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +4 -4
  166. data/lib/datadog/appsec/metrics.rb +4 -4
  167. data/lib/datadog/appsec/monitor/gateway/watcher.rb +18 -12
  168. data/lib/datadog/appsec/monitor.rb +1 -1
  169. data/lib/datadog/appsec/processor/rule_loader.rb +32 -32
  170. data/lib/datadog/appsec/rate_limiter.rb +1 -1
  171. data/lib/datadog/appsec/remote.rb +15 -9
  172. data/lib/datadog/appsec/response.rb +22 -22
  173. data/lib/datadog/appsec/route_normalizer/rails_route_pattern.rb +176 -0
  174. data/lib/datadog/appsec/route_normalizer/route_pattern.rb +378 -0
  175. data/lib/datadog/appsec/route_normalizer/route_text.rb +57 -0
  176. data/lib/datadog/appsec/route_normalizer.rb +80 -0
  177. data/lib/datadog/appsec/security_engine/engine.rb +40 -40
  178. data/lib/datadog/appsec/security_engine/runner.rb +3 -3
  179. data/lib/datadog/appsec/security_event.rb +2 -2
  180. data/lib/datadog/appsec/trace_keeper.rb +18 -6
  181. data/lib/datadog/appsec/utils/http/body.rb +11 -8
  182. data/lib/datadog/appsec/utils/http/body_reader.rb +61 -0
  183. data/lib/datadog/appsec/utils/http/media_range.rb +15 -15
  184. data/lib/datadog/appsec/utils/http/media_type.rb +5 -6
  185. data/lib/datadog/appsec/utils/http/url_encoded.rb +79 -24
  186. data/lib/datadog/appsec.rb +21 -24
  187. data/lib/datadog/auto_instrument.rb +2 -2
  188. data/lib/datadog/core/buffer/cruby.rb +1 -1
  189. data/lib/datadog/core/buffer/thread_safe.rb +1 -1
  190. data/lib/datadog/core/configuration/agent_settings.rb +1 -1
  191. data/lib/datadog/core/configuration/agent_settings_resolver.rb +15 -15
  192. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +2 -2
  193. data/lib/datadog/core/configuration/base.rb +19 -7
  194. data/lib/datadog/core/configuration/components.rb +151 -37
  195. data/lib/datadog/core/configuration/components_state.rb +6 -1
  196. data/lib/datadog/core/configuration/config_helper.rb +12 -3
  197. data/lib/datadog/core/configuration/deprecations.rb +6 -6
  198. data/lib/datadog/core/configuration/ext.rb +11 -11
  199. data/lib/datadog/core/configuration/option.rb +46 -21
  200. data/lib/datadog/core/configuration/option_definition.rb +43 -17
  201. data/lib/datadog/core/configuration/options.rb +42 -8
  202. data/lib/datadog/core/configuration/settings.rb +133 -105
  203. data/lib/datadog/core/configuration/stable_config.rb +1 -1
  204. data/lib/datadog/core/configuration/supported_configurations.rb +33 -1
  205. data/lib/datadog/core/configuration.rb +9 -9
  206. data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
  207. data/lib/datadog/core/contrib/rails/utils.rb +7 -3
  208. data/lib/datadog/core/crashtracking/component.rb +17 -13
  209. data/lib/datadog/core/crashtracking/tag_builder.rb +5 -5
  210. data/lib/datadog/core/deprecations.rb +1 -1
  211. data/lib/datadog/core/diagnostics/environment_logger.rb +45 -8
  212. data/lib/datadog/core/diagnostics/health.rb +2 -2
  213. data/lib/datadog/core/encoding.rb +4 -4
  214. data/lib/datadog/core/environment/agent_info.rb +2 -2
  215. data/lib/datadog/core/environment/cgroup.rb +4 -4
  216. data/lib/datadog/core/environment/container.rb +11 -11
  217. data/lib/datadog/core/environment/execution.rb +3 -3
  218. data/lib/datadog/core/environment/ext.rb +21 -15
  219. data/lib/datadog/core/environment/gc.rb +1 -1
  220. data/lib/datadog/core/environment/git.rb +2 -2
  221. data/lib/datadog/core/environment/identity.rb +47 -11
  222. data/lib/datadog/core/environment/platform.rb +8 -8
  223. data/lib/datadog/core/environment/process.rb +54 -19
  224. data/lib/datadog/core/environment/socket.rb +15 -2
  225. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  226. data/lib/datadog/core/environment/vm_cache.rb +1 -1
  227. data/lib/datadog/core/environment/yjit.rb +2 -2
  228. data/lib/datadog/core/error.rb +5 -5
  229. data/lib/datadog/core/evp.rb +11 -0
  230. data/lib/datadog/core/extensions.rb +1 -1
  231. data/lib/datadog/core/feature_flags.rb +3 -3
  232. data/lib/datadog/core/git/ext.rb +4 -4
  233. data/lib/datadog/core/knuth_sampler.rb +3 -1
  234. data/lib/datadog/core/logger.rb +3 -3
  235. data/lib/datadog/core/logging/ext.rb +1 -1
  236. data/lib/datadog/core/metrics/client.rb +26 -26
  237. data/lib/datadog/core/metrics/ext.rb +5 -5
  238. data/lib/datadog/core/metrics/helpers.rb +1 -1
  239. data/lib/datadog/core/metrics/logging.rb +2 -2
  240. data/lib/datadog/core/metrics/options.rb +5 -5
  241. data/lib/datadog/core/pin.rb +1 -1
  242. data/lib/datadog/core/process_discovery.rb +8 -8
  243. data/lib/datadog/core/rate_limiter.rb +1 -1
  244. data/lib/datadog/core/remote/client/capabilities.rb +77 -19
  245. data/lib/datadog/core/remote/client.rb +18 -18
  246. data/lib/datadog/core/remote/component.rb +66 -34
  247. data/lib/datadog/core/remote/configuration/content.rb +3 -3
  248. data/lib/datadog/core/remote/configuration/digest.rb +1 -1
  249. data/lib/datadog/core/remote/configuration/path.rb +9 -9
  250. data/lib/datadog/core/remote/configuration/repository.rb +4 -4
  251. data/lib/datadog/core/remote/configuration/target.rb +9 -9
  252. data/lib/datadog/core/remote/configuration.rb +4 -4
  253. data/lib/datadog/core/remote/ext.rb +3 -3
  254. data/lib/datadog/core/remote/negotiation.rb +1 -1
  255. data/lib/datadog/core/remote/tie/tracing.rb +7 -7
  256. data/lib/datadog/core/remote/transport/config.rb +4 -4
  257. data/lib/datadog/core/remote/transport/http/config.rb +10 -10
  258. data/lib/datadog/core/remote/transport/http/negotiation.rb +4 -4
  259. data/lib/datadog/core/remote/transport/http.rb +10 -10
  260. data/lib/datadog/core/remote/transport/negotiation.rb +3 -3
  261. data/lib/datadog/core/remote/worker.rb +13 -5
  262. data/lib/datadog/core/runtime/ext.rb +22 -22
  263. data/lib/datadog/core/runtime/metrics.rb +10 -10
  264. data/lib/datadog/core/tag_builder.rb +18 -18
  265. data/lib/datadog/core/tag_normalizer.rb +7 -7
  266. data/lib/datadog/core/telemetry/component.rb +16 -13
  267. data/lib/datadog/core/telemetry/configuration_value.rb +38 -0
  268. data/lib/datadog/core/telemetry/emitter.rb +5 -5
  269. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +10 -9
  270. data/lib/datadog/core/telemetry/event/app_closing.rb +2 -2
  271. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +2 -2
  272. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +3 -3
  273. data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
  274. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +2 -2
  275. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +2 -2
  276. data/lib/datadog/core/telemetry/event/app_started.rb +142 -193
  277. data/lib/datadog/core/telemetry/event/base.rb +1 -1
  278. data/lib/datadog/core/telemetry/event/distributions.rb +2 -2
  279. data/lib/datadog/core/telemetry/event/generate_metrics.rb +3 -3
  280. data/lib/datadog/core/telemetry/event/log.rb +6 -6
  281. data/lib/datadog/core/telemetry/event/message_batch.rb +1 -1
  282. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +3 -3
  283. data/lib/datadog/core/telemetry/event.rb +16 -22
  284. data/lib/datadog/core/telemetry/ext.rb +11 -10
  285. data/lib/datadog/core/telemetry/logger.rb +1 -1
  286. data/lib/datadog/core/telemetry/logging.rb +5 -5
  287. data/lib/datadog/core/telemetry/metric.rb +9 -9
  288. data/lib/datadog/core/telemetry/metrics_collection.rb +2 -2
  289. data/lib/datadog/core/telemetry/metrics_manager.rb +1 -1
  290. data/lib/datadog/core/telemetry/request.rb +6 -8
  291. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +16 -11
  292. data/lib/datadog/core/telemetry/transport/http.rb +7 -7
  293. data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -3
  294. data/lib/datadog/core/telemetry/worker.rb +26 -6
  295. data/lib/datadog/core/transport/ext.rb +14 -14
  296. data/lib/datadog/core/transport/http/adapters/net.rb +4 -4
  297. data/lib/datadog/core/transport/http/adapters/test.rb +1 -1
  298. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +4 -4
  299. data/lib/datadog/core/transport/http/api/endpoint.rb +1 -1
  300. data/lib/datadog/core/transport/http/api/map.rb +1 -1
  301. data/lib/datadog/core/transport/http/builder.rb +6 -6
  302. data/lib/datadog/core/transport/http/client.rb +2 -2
  303. data/lib/datadog/core/transport/http/response.rb +1 -1
  304. data/lib/datadog/core/transport/http.rb +9 -7
  305. data/lib/datadog/core/transport/response.rb +1 -1
  306. data/lib/datadog/core/transport/transport.rb +2 -2
  307. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +172 -20
  308. data/lib/datadog/core/utils/base64_codec.rb +23 -0
  309. data/lib/datadog/core/utils/duration.rb +1 -1
  310. data/lib/datadog/core/utils/{array.rb → enumerable_compat.rb} +2 -2
  311. data/lib/datadog/core/utils/forking.rb +3 -1
  312. data/lib/datadog/core/utils/hash.rb +0 -23
  313. data/lib/datadog/core/utils/lru_cache.rb +3 -3
  314. data/lib/datadog/core/utils/network.rb +11 -11
  315. data/lib/datadog/core/utils/only_once.rb +1 -1
  316. data/lib/datadog/core/utils/only_once_successful.rb +1 -1
  317. data/lib/datadog/core/utils/safe_dup.rb +2 -1
  318. data/lib/datadog/core/utils/sequence.rb +3 -6
  319. data/lib/datadog/core/utils/spawn_monkey_patch.rb +68 -0
  320. data/lib/datadog/core/utils/time.rb +18 -52
  321. data/lib/datadog/core/utils/url.rb +1 -1
  322. data/lib/datadog/core/utils.rb +5 -5
  323. data/lib/datadog/core/workers/async.rb +2 -2
  324. data/lib/datadog/core/workers/polling.rb +2 -2
  325. data/lib/datadog/core/workers/runtime_metrics.rb +4 -4
  326. data/lib/datadog/core.rb +7 -5
  327. data/lib/datadog/data_streams/configuration.rb +40 -1
  328. data/lib/datadog/data_streams/ext.rb +1 -1
  329. data/lib/datadog/data_streams/extensions.rb +2 -2
  330. data/lib/datadog/data_streams/pathway_context.rb +28 -30
  331. data/lib/datadog/data_streams/processor.rb +93 -62
  332. data/lib/datadog/data_streams/transport/http/stats.rb +5 -5
  333. data/lib/datadog/data_streams/transport/http.rb +5 -5
  334. data/lib/datadog/data_streams/transport/stats.rb +7 -7
  335. data/lib/datadog/data_streams.rb +5 -5
  336. data/lib/datadog/di/base.rb +16 -8
  337. data/lib/datadog/di/boot.rb +25 -24
  338. data/lib/datadog/di/capture_expression.rb +21 -0
  339. data/lib/datadog/di/capture_expression_evaluator.rb +71 -0
  340. data/lib/datadog/di/capture_limits.rb +41 -0
  341. data/lib/datadog/di/code_tracker.rb +218 -16
  342. data/lib/datadog/di/component.rb +123 -37
  343. data/lib/datadog/di/configuration.rb +241 -2
  344. data/lib/datadog/di/context.rb +9 -3
  345. data/lib/datadog/di/contrib/active_record.rb +6 -2
  346. data/lib/datadog/di/contrib/railtie.rb +1 -1
  347. data/lib/datadog/di/contrib.rb +5 -5
  348. data/lib/datadog/di/el/compiler.rb +114 -38
  349. data/lib/datadog/di/el/evaluator.rb +82 -2
  350. data/lib/datadog/di/el/expression.rb +13 -2
  351. data/lib/datadog/di/el.rb +3 -3
  352. data/lib/datadog/di/error.rb +10 -0
  353. data/lib/datadog/di/fatal_exceptions.rb +26 -0
  354. data/lib/datadog/di/instrumenter.rb +528 -184
  355. data/lib/datadog/di/logger.rb +3 -3
  356. data/lib/datadog/di/preload.rb +1 -1
  357. data/lib/datadog/di/probe.rb +69 -2
  358. data/lib/datadog/di/probe_builder.rb +98 -15
  359. data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
  360. data/lib/datadog/di/probe_file_loader.rb +14 -9
  361. data/lib/datadog/di/probe_manager.rb +83 -20
  362. data/lib/datadog/di/probe_notification_builder.rb +178 -25
  363. data/lib/datadog/di/probe_notifier_worker.rb +57 -37
  364. data/lib/datadog/di/probe_repository.rb +1 -1
  365. data/lib/datadog/di/proc_responder.rb +1 -1
  366. data/lib/datadog/di/redactor.rb +16 -1
  367. data/lib/datadog/di/remote.rb +187 -26
  368. data/lib/datadog/di/serializer.rb +79 -35
  369. data/lib/datadog/di/transport/diagnostics.rb +5 -5
  370. data/lib/datadog/di/transport/http/diagnostics.rb +3 -3
  371. data/lib/datadog/di/transport/http/input.rb +2 -2
  372. data/lib/datadog/di/transport/http.rb +10 -10
  373. data/lib/datadog/di/transport/input.rb +18 -14
  374. data/lib/datadog/di/utils.rb +43 -15
  375. data/lib/datadog/di.rb +147 -3
  376. data/lib/datadog/error_tracking/collector.rb +3 -2
  377. data/lib/datadog/error_tracking/component.rb +12 -12
  378. data/lib/datadog/error_tracking/configuration.rb +55 -2
  379. data/lib/datadog/error_tracking/ext.rb +7 -7
  380. data/lib/datadog/error_tracking/extensions.rb +2 -2
  381. data/lib/datadog/error_tracking/filters.rb +4 -4
  382. data/lib/datadog/error_tracking.rb +6 -6
  383. data/lib/datadog/kit/appsec/events/v2.rb +91 -33
  384. data/lib/datadog/kit/appsec/events.rb +25 -25
  385. data/lib/datadog/kit/enable_core_dumps.rb +3 -3
  386. data/lib/datadog/kit/identity.rb +18 -18
  387. data/lib/datadog/kit/tracing/method_tracer.rb +9 -6
  388. data/lib/datadog/kit.rb +1 -1
  389. data/lib/datadog/open_feature/agentless/configuration_source.rb +246 -0
  390. data/lib/datadog/open_feature/agentless/parser.rb +43 -0
  391. data/lib/datadog/open_feature/agentless/response.rb +19 -0
  392. data/lib/datadog/open_feature/agentless/transport.rb +103 -0
  393. data/lib/datadog/open_feature/component.rb +118 -13
  394. data/lib/datadog/open_feature/configuration/agentless_endpoint.rb +90 -0
  395. data/lib/datadog/open_feature/configuration/source/resolution.rb +22 -0
  396. data/lib/datadog/open_feature/configuration/source.rb +43 -0
  397. data/lib/datadog/open_feature/configuration.rb +140 -1
  398. data/lib/datadog/open_feature/evaluation_engine.rb +38 -12
  399. data/lib/datadog/open_feature/exposures/batch_builder.rb +1 -1
  400. data/lib/datadog/open_feature/exposures/buffer.rb +1 -1
  401. data/lib/datadog/open_feature/exposures/deduplicator.rb +1 -1
  402. data/lib/datadog/open_feature/exposures/event.rb +17 -10
  403. data/lib/datadog/open_feature/exposures/reporter.rb +3 -3
  404. data/lib/datadog/open_feature/exposures/worker.rb +6 -6
  405. data/lib/datadog/open_feature/ext.rb +32 -6
  406. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +442 -0
  407. data/lib/datadog/open_feature/flag_evaluation/writer.rb +544 -0
  408. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +105 -0
  409. data/lib/datadog/open_feature/hooks/flag_eval_metrics_hook.rb +51 -0
  410. data/lib/datadog/open_feature/hooks/span_enrichment_hook/codec.rb +58 -0
  411. data/lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb +96 -0
  412. data/lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state_store.rb +49 -0
  413. data/lib/datadog/open_feature/hooks/span_enrichment_hook.rb +184 -0
  414. data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
  415. data/lib/datadog/open_feature/native_evaluator.rb +43 -7
  416. data/lib/datadog/open_feature/noop_evaluator.rb +8 -3
  417. data/lib/datadog/open_feature/provider.rb +115 -21
  418. data/lib/datadog/open_feature/remote.rb +8 -8
  419. data/lib/datadog/open_feature/resolution_details.rb +4 -2
  420. data/lib/datadog/open_feature/transport.rb +71 -12
  421. data/lib/datadog/open_feature.rb +2 -2
  422. data/lib/datadog/opentelemetry/api/baggage.rb +3 -3
  423. data/lib/datadog/opentelemetry/api/context.rb +4 -4
  424. data/lib/datadog/opentelemetry/configuration/settings.rb +95 -28
  425. data/lib/datadog/opentelemetry/ext.rb +9 -0
  426. data/lib/datadog/opentelemetry/logs.rb +98 -0
  427. data/lib/datadog/opentelemetry/metrics.rb +17 -44
  428. data/lib/datadog/opentelemetry/sdk/configurator.rb +46 -6
  429. data/lib/datadog/opentelemetry/sdk/id_generator.rb +16 -10
  430. data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +30 -0
  431. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +9 -16
  432. data/lib/datadog/opentelemetry/sdk/propagator.rb +17 -11
  433. data/lib/datadog/opentelemetry/sdk/span_processor.rb +18 -15
  434. data/lib/datadog/opentelemetry/sdk/trace/span.rb +32 -32
  435. data/lib/datadog/opentelemetry/sdk.rb +19 -0
  436. data/lib/datadog/opentelemetry/signal_configuration.rb +57 -0
  437. data/lib/datadog/opentelemetry/trace.rb +4 -1
  438. data/lib/datadog/opentelemetry.rb +8 -7
  439. data/lib/datadog/profiling/collectors/code_provenance.rb +36 -11
  440. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +45 -3
  441. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +10 -4
  442. data/lib/datadog/profiling/collectors/info.rb +19 -10
  443. data/lib/datadog/profiling/collectors/thread_context.rb +16 -22
  444. data/lib/datadog/profiling/component.rb +43 -37
  445. data/lib/datadog/profiling/exporter.rb +43 -16
  446. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +6 -5
  447. data/lib/datadog/profiling/ext.rb +0 -2
  448. data/lib/datadog/profiling/flush.rb +21 -12
  449. data/lib/datadog/profiling/http_transport.rb +13 -2
  450. data/lib/datadog/profiling/load_native_extension.rb +2 -2
  451. data/lib/datadog/profiling/profiler.rb +13 -5
  452. data/lib/datadog/profiling/scheduler.rb +2 -2
  453. data/lib/datadog/profiling/sequence_tracker.rb +1 -1
  454. data/lib/datadog/profiling/stack_recorder.rb +0 -8
  455. data/lib/datadog/profiling/tag_builder.rb +19 -19
  456. data/lib/datadog/profiling/tasks/exec.rb +9 -4
  457. data/lib/datadog/profiling/tasks/help.rb +1 -0
  458. data/lib/datadog/profiling/tasks/setup.rb +2 -2
  459. data/lib/datadog/profiling.rb +32 -29
  460. data/lib/datadog/ruby_version.rb +25 -0
  461. data/lib/datadog/single_step_instrument.rb +2 -2
  462. data/lib/datadog/symbol_database/component.rb +734 -0
  463. data/lib/datadog/symbol_database/configuration.rb +73 -0
  464. data/lib/datadog/symbol_database/extensions.rb +19 -0
  465. data/lib/datadog/symbol_database/extractor.rb +1092 -0
  466. data/lib/datadog/symbol_database/file_hash.rb +48 -0
  467. data/lib/datadog/symbol_database/logger.rb +43 -0
  468. data/lib/datadog/symbol_database/remote.rb +195 -0
  469. data/lib/datadog/symbol_database/scope.rb +102 -0
  470. data/lib/datadog/symbol_database/scope_batcher.rb +292 -0
  471. data/lib/datadog/symbol_database/service_version.rb +66 -0
  472. data/lib/datadog/symbol_database/symbol.rb +69 -0
  473. data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
  474. data/lib/datadog/symbol_database/transport/http.rb +45 -0
  475. data/lib/datadog/symbol_database/transport.rb +54 -0
  476. data/lib/datadog/symbol_database/uploader.rb +230 -0
  477. data/lib/datadog/symbol_database.rb +71 -0
  478. data/lib/datadog/tracing/analytics.rb +1 -1
  479. data/lib/datadog/tracing/buffer.rb +8 -8
  480. data/lib/datadog/tracing/client_ip.rb +4 -4
  481. data/lib/datadog/tracing/component.rb +41 -7
  482. data/lib/datadog/tracing/configuration/dynamic/option.rb +4 -0
  483. data/lib/datadog/tracing/configuration/dynamic.rb +13 -11
  484. data/lib/datadog/tracing/configuration/ext.rb +53 -38
  485. data/lib/datadog/tracing/configuration/http.rb +2 -2
  486. data/lib/datadog/tracing/configuration/settings.rb +58 -17
  487. data/lib/datadog/tracing/context.rb +25 -3
  488. data/lib/datadog/tracing/context_provider.rb +11 -7
  489. data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +2 -2
  490. data/lib/datadog/tracing/contrib/action_cable/event.rb +4 -4
  491. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +9 -6
  492. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +8 -5
  493. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +9 -6
  494. data/lib/datadog/tracing/contrib/action_cable/events.rb +5 -5
  495. data/lib/datadog/tracing/contrib/action_cable/ext.rb +18 -18
  496. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -5
  497. data/lib/datadog/tracing/contrib/action_cable/integration.rb +7 -7
  498. data/lib/datadog/tracing/contrib/action_cable/patcher.rb +4 -4
  499. data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +2 -2
  500. data/lib/datadog/tracing/contrib/action_mailer/event.rb +7 -4
  501. data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +8 -8
  502. data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +4 -4
  503. data/lib/datadog/tracing/contrib/action_mailer/events.rb +3 -3
  504. data/lib/datadog/tracing/contrib/action_mailer/ext.rb +18 -18
  505. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +7 -7
  506. data/lib/datadog/tracing/contrib/action_mailer/patcher.rb +3 -3
  507. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -12
  508. data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +2 -2
  509. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +31 -3
  510. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +5 -3
  511. data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +3 -3
  512. data/lib/datadog/tracing/contrib/action_pack/ext.rb +10 -10
  513. data/lib/datadog/tracing/contrib/action_pack/integration.rb +7 -7
  514. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +3 -3
  515. data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -1
  516. data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +3 -3
  517. data/lib/datadog/tracing/contrib/action_view/event.rb +1 -1
  518. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +10 -7
  519. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +11 -8
  520. data/lib/datadog/tracing/contrib/action_view/events.rb +3 -3
  521. data/lib/datadog/tracing/contrib/action_view/ext.rb +10 -10
  522. data/lib/datadog/tracing/contrib/action_view/integration.rb +11 -11
  523. data/lib/datadog/tracing/contrib/action_view/patcher.rb +5 -5
  524. data/lib/datadog/tracing/contrib/action_view/utils.rb +2 -2
  525. data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +2 -2
  526. data/lib/datadog/tracing/contrib/active_job/data_streams.rb +62 -0
  527. data/lib/datadog/tracing/contrib/active_job/event.rb +3 -3
  528. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +10 -7
  529. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +10 -7
  530. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +10 -7
  531. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +10 -7
  532. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +10 -7
  533. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +10 -7
  534. data/lib/datadog/tracing/contrib/active_job/events.rb +6 -6
  535. data/lib/datadog/tracing/contrib/active_job/ext.rb +23 -23
  536. data/lib/datadog/tracing/contrib/active_job/integration.rb +7 -7
  537. data/lib/datadog/tracing/contrib/active_job/patcher.rb +17 -5
  538. data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +2 -2
  539. data/lib/datadog/tracing/contrib/active_model_serializers/event.rb +4 -4
  540. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +7 -7
  541. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +8 -9
  542. data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +3 -3
  543. data/lib/datadog/tracing/contrib/active_model_serializers/ext.rb +10 -10
  544. data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +5 -5
  545. data/lib/datadog/tracing/contrib/active_model_serializers/patcher.rb +3 -3
  546. data/lib/datadog/tracing/contrib/active_record/configuration/makara_resolver.rb +1 -1
  547. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +9 -9
  548. data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +4 -4
  549. data/lib/datadog/tracing/contrib/active_record/event.rb +1 -1
  550. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +9 -9
  551. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +12 -14
  552. data/lib/datadog/tracing/contrib/active_record/events.rb +3 -3
  553. data/lib/datadog/tracing/contrib/active_record/ext.rb +15 -15
  554. data/lib/datadog/tracing/contrib/active_record/integration.rb +11 -11
  555. data/lib/datadog/tracing/contrib/active_record/patcher.rb +2 -2
  556. data/lib/datadog/tracing/contrib/active_record/utils.rb +4 -4
  557. data/lib/datadog/tracing/contrib/active_support/cache/event.rb +1 -1
  558. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +14 -17
  559. data/lib/datadog/tracing/contrib/active_support/cache/events.rb +1 -1
  560. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +5 -8
  561. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +5 -5
  562. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +4 -4
  563. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +3 -3
  564. data/lib/datadog/tracing/contrib/active_support/ext.rb +16 -16
  565. data/lib/datadog/tracing/contrib/active_support/integration.rb +8 -8
  566. data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +1 -1
  567. data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +2 -2
  568. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +3 -3
  569. data/lib/datadog/tracing/contrib/active_support/patcher.rb +2 -2
  570. data/lib/datadog/tracing/contrib/analytics.rb +1 -1
  571. data/lib/datadog/tracing/contrib/auto_instrument.rb +4 -4
  572. data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +3 -3
  573. data/lib/datadog/tracing/contrib/aws/ext.rb +26 -26
  574. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +7 -11
  575. data/lib/datadog/tracing/contrib/aws/integration.rb +9 -9
  576. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +1 -1
  577. data/lib/datadog/tracing/contrib/aws/patcher.rb +5 -5
  578. data/lib/datadog/tracing/contrib/aws/service/dynamodb.rb +2 -2
  579. data/lib/datadog/tracing/contrib/aws/service/eventbridge.rb +2 -2
  580. data/lib/datadog/tracing/contrib/aws/service/kinesis.rb +4 -4
  581. data/lib/datadog/tracing/contrib/aws/service/s3.rb +2 -2
  582. data/lib/datadog/tracing/contrib/aws/service/sns.rb +3 -3
  583. data/lib/datadog/tracing/contrib/aws/service/sqs.rb +3 -3
  584. data/lib/datadog/tracing/contrib/aws/service/states.rb +5 -5
  585. data/lib/datadog/tracing/contrib/aws/services.rb +14 -14
  586. data/lib/datadog/tracing/contrib/component.rb +1 -1
  587. data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +1 -1
  588. data/lib/datadog/tracing/contrib/concurrent_ruby/configuration/settings.rb +2 -2
  589. data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -1
  590. data/lib/datadog/tracing/contrib/concurrent_ruby/ext.rb +2 -2
  591. data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +1 -1
  592. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +6 -6
  593. data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +4 -4
  594. data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +1 -1
  595. data/lib/datadog/tracing/contrib/configurable.rb +20 -5
  596. data/lib/datadog/tracing/contrib/configuration/resolver.rb +14 -4
  597. data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +1 -1
  598. data/lib/datadog/tracing/contrib/configuration/settings.rb +2 -2
  599. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +2 -2
  600. data/lib/datadog/tracing/contrib/dalli/ext.rb +13 -13
  601. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +6 -10
  602. data/lib/datadog/tracing/contrib/dalli/integration.rb +7 -7
  603. data/lib/datadog/tracing/contrib/dalli/patcher.rb +3 -3
  604. data/lib/datadog/tracing/contrib/dalli/quantize.rb +3 -3
  605. data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +2 -2
  606. data/lib/datadog/tracing/contrib/delayed_job/ext.rb +14 -14
  607. data/lib/datadog/tracing/contrib/delayed_job/integration.rb +5 -5
  608. data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +3 -3
  609. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +7 -5
  610. data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +1 -0
  611. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +2 -2
  612. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +15 -15
  613. data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +6 -6
  614. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +12 -16
  615. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +4 -4
  616. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +2 -2
  617. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +9 -13
  618. data/lib/datadog/tracing/contrib/ethon/ext.rb +13 -13
  619. data/lib/datadog/tracing/contrib/ethon/integration.rb +6 -6
  620. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +4 -11
  621. data/lib/datadog/tracing/contrib/ethon/patcher.rb +3 -3
  622. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +5 -5
  623. data/lib/datadog/tracing/contrib/excon/ext.rb +11 -11
  624. data/lib/datadog/tracing/contrib/excon/integration.rb +6 -6
  625. data/lib/datadog/tracing/contrib/excon/middleware.rb +10 -14
  626. data/lib/datadog/tracing/contrib/excon/patcher.rb +2 -2
  627. data/lib/datadog/tracing/contrib/ext.rb +20 -18
  628. data/lib/datadog/tracing/contrib/extensions.rb +11 -2
  629. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +4 -4
  630. data/lib/datadog/tracing/contrib/faraday/ext.rb +11 -11
  631. data/lib/datadog/tracing/contrib/faraday/integration.rb +6 -6
  632. data/lib/datadog/tracing/contrib/faraday/middleware.rb +10 -14
  633. data/lib/datadog/tracing/contrib/faraday/patcher.rb +6 -6
  634. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +4 -4
  635. data/lib/datadog/tracing/contrib/grape/endpoint.rb +59 -29
  636. data/lib/datadog/tracing/contrib/grape/ext.rb +15 -15
  637. data/lib/datadog/tracing/contrib/grape/instrumentation.rb +3 -3
  638. data/lib/datadog/tracing/contrib/grape/integration.rb +5 -5
  639. data/lib/datadog/tracing/contrib/grape/patcher.rb +5 -5
  640. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +1 -1
  641. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +3 -3
  642. data/lib/datadog/tracing/contrib/graphql/ext.rb +9 -9
  643. data/lib/datadog/tracing/contrib/graphql/integration.rb +9 -9
  644. data/lib/datadog/tracing/contrib/graphql/patcher.rb +7 -7
  645. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +38 -37
  646. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +2 -2
  647. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +2 -2
  648. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +11 -15
  649. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +11 -15
  650. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +6 -6
  651. data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +1 -1
  652. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +11 -9
  653. data/lib/datadog/tracing/contrib/grpc/ext.rb +14 -14
  654. data/lib/datadog/tracing/contrib/grpc/formatting.rb +7 -7
  655. data/lib/datadog/tracing/contrib/grpc/integration.rb +5 -5
  656. data/lib/datadog/tracing/contrib/grpc/intercept_with_datadog.rb +1 -1
  657. data/lib/datadog/tracing/contrib/grpc/patcher.rb +3 -3
  658. data/lib/datadog/tracing/contrib/grpc.rb +7 -6
  659. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +4 -3
  660. data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +2 -2
  661. data/lib/datadog/tracing/contrib/hanami/ext.rb +8 -8
  662. data/lib/datadog/tracing/contrib/hanami/integration.rb +6 -6
  663. data/lib/datadog/tracing/contrib/hanami/patcher.rb +5 -5
  664. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +4 -3
  665. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +6 -4
  666. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +1 -1
  667. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +4 -4
  668. data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +3 -3
  669. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +10 -8
  670. data/lib/datadog/tracing/contrib/http/ext.rb +11 -11
  671. data/lib/datadog/tracing/contrib/http/instrumentation.rb +10 -14
  672. data/lib/datadog/tracing/contrib/http/integration.rb +7 -7
  673. data/lib/datadog/tracing/contrib/http/patcher.rb +3 -3
  674. data/lib/datadog/tracing/contrib/http.rb +7 -6
  675. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +4 -4
  676. data/lib/datadog/tracing/contrib/httpclient/ext.rb +11 -11
  677. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +12 -12
  678. data/lib/datadog/tracing/contrib/httpclient/integration.rb +6 -6
  679. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +3 -3
  680. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +4 -4
  681. data/lib/datadog/tracing/contrib/httprb/ext.rb +11 -11
  682. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +10 -14
  683. data/lib/datadog/tracing/contrib/httprb/integration.rb +7 -7
  684. data/lib/datadog/tracing/contrib/httprb/patcher.rb +3 -3
  685. data/lib/datadog/tracing/contrib/integration.rb +3 -3
  686. data/lib/datadog/tracing/contrib/kafka/configuration/settings.rb +2 -2
  687. data/lib/datadog/tracing/contrib/kafka/event.rb +4 -3
  688. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +7 -3
  689. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +4 -4
  690. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +4 -4
  691. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +5 -5
  692. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +5 -5
  693. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +5 -5
  694. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +5 -5
  695. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +10 -5
  696. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +10 -5
  697. data/lib/datadog/tracing/contrib/kafka/events.rb +10 -10
  698. data/lib/datadog/tracing/contrib/kafka/ext.rb +40 -40
  699. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +4 -4
  700. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +6 -6
  701. data/lib/datadog/tracing/contrib/kafka/integration.rb +6 -6
  702. data/lib/datadog/tracing/contrib/kafka/patcher.rb +5 -5
  703. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +2 -2
  704. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +11 -9
  705. data/lib/datadog/tracing/contrib/karafka/ext.rb +13 -13
  706. data/lib/datadog/tracing/contrib/karafka/integration.rb +5 -5
  707. data/lib/datadog/tracing/contrib/karafka/monitor.rb +14 -14
  708. data/lib/datadog/tracing/contrib/karafka/patcher.rb +9 -9
  709. data/lib/datadog/tracing/contrib/karafka.rb +7 -6
  710. data/lib/datadog/tracing/contrib/lograge/configuration/settings.rb +2 -2
  711. data/lib/datadog/tracing/contrib/lograge/ext.rb +1 -1
  712. data/lib/datadog/tracing/contrib/lograge/integration.rb +5 -5
  713. data/lib/datadog/tracing/contrib/lograge/patcher.rb +9 -9
  714. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +2 -2
  715. data/lib/datadog/tracing/contrib/mongodb/ext.rb +18 -18
  716. data/lib/datadog/tracing/contrib/mongodb/instrumentation.rb +3 -3
  717. data/lib/datadog/tracing/contrib/mongodb/integration.rb +7 -7
  718. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +9 -9
  719. data/lib/datadog/tracing/contrib/mongodb/patcher.rb +3 -3
  720. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -21
  721. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +3 -3
  722. data/lib/datadog/tracing/contrib/mysql2/ext.rb +11 -11
  723. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +7 -11
  724. data/lib/datadog/tracing/contrib/mysql2/integration.rb +5 -5
  725. data/lib/datadog/tracing/contrib/mysql2/patcher.rb +2 -2
  726. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +2 -2
  727. data/lib/datadog/tracing/contrib/opensearch/ext.rb +23 -23
  728. data/lib/datadog/tracing/contrib/opensearch/integration.rb +6 -6
  729. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +15 -19
  730. data/lib/datadog/tracing/contrib/opensearch/quantize.rb +5 -5
  731. data/lib/datadog/tracing/contrib/patchable.rb +1 -1
  732. data/lib/datadog/tracing/contrib/patcher.rb +3 -3
  733. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +3 -3
  734. data/lib/datadog/tracing/contrib/pg/ext.rb +19 -19
  735. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +19 -23
  736. data/lib/datadog/tracing/contrib/pg/integration.rb +5 -5
  737. data/lib/datadog/tracing/contrib/pg/patcher.rb +2 -2
  738. data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +2 -2
  739. data/lib/datadog/tracing/contrib/presto/ext.rb +21 -21
  740. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +8 -10
  741. data/lib/datadog/tracing/contrib/presto/integration.rb +6 -6
  742. data/lib/datadog/tracing/contrib/presto/patcher.rb +4 -4
  743. data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +2 -2
  744. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +19 -16
  745. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +3 -3
  746. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +5 -5
  747. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +2 -2
  748. data/lib/datadog/tracing/contrib/que/ext.rb +19 -19
  749. data/lib/datadog/tracing/contrib/que/integration.rb +6 -6
  750. data/lib/datadog/tracing/contrib/que/patcher.rb +1 -1
  751. data/lib/datadog/tracing/contrib/que/tracer.rb +3 -2
  752. data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +3 -3
  753. data/lib/datadog/tracing/contrib/racecar/event.rb +5 -9
  754. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +3 -3
  755. data/lib/datadog/tracing/contrib/racecar/events/consume.rb +3 -3
  756. data/lib/datadog/tracing/contrib/racecar/events/message.rb +3 -3
  757. data/lib/datadog/tracing/contrib/racecar/events.rb +4 -4
  758. data/lib/datadog/tracing/contrib/racecar/ext.rb +18 -18
  759. data/lib/datadog/tracing/contrib/racecar/integration.rb +5 -5
  760. data/lib/datadog/tracing/contrib/racecar/patcher.rb +3 -3
  761. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +9 -3
  762. data/lib/datadog/tracing/contrib/rack/ext.rb +43 -16
  763. data/lib/datadog/tracing/contrib/rack/header_collection.rb +3 -3
  764. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +24 -1
  765. data/lib/datadog/tracing/contrib/rack/integration.rb +6 -6
  766. data/lib/datadog/tracing/contrib/rack/middlewares.rb +28 -25
  767. data/lib/datadog/tracing/contrib/rack/patcher.rb +5 -5
  768. data/lib/datadog/tracing/contrib/rack/request_queue.rb +4 -4
  769. data/lib/datadog/tracing/contrib/rack/route_inference.rb +12 -10
  770. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +124 -6
  771. data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +1 -1
  772. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +3 -3
  773. data/lib/datadog/tracing/contrib/rails/ext.rb +15 -15
  774. data/lib/datadog/tracing/contrib/rails/framework.rb +11 -11
  775. data/lib/datadog/tracing/contrib/rails/integration.rb +5 -5
  776. data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
  777. data/lib/datadog/tracing/contrib/rails/middlewares.rb +1 -1
  778. data/lib/datadog/tracing/contrib/rails/patcher.rb +8 -9
  779. data/lib/datadog/tracing/contrib/rails/railtie.rb +4 -4
  780. data/lib/datadog/tracing/contrib/rails/runner.rb +4 -2
  781. data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +3 -3
  782. data/lib/datadog/tracing/contrib/rake/ext.rb +12 -12
  783. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +9 -7
  784. data/lib/datadog/tracing/contrib/rake/integration.rb +5 -5
  785. data/lib/datadog/tracing/contrib/rake/patcher.rb +3 -3
  786. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +3 -3
  787. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +2 -2
  788. data/lib/datadog/tracing/contrib/redis/ext.rb +16 -16
  789. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +6 -6
  790. data/lib/datadog/tracing/contrib/redis/integration.rb +7 -7
  791. data/lib/datadog/tracing/contrib/redis/patcher.rb +10 -10
  792. data/lib/datadog/tracing/contrib/redis/quantize.rb +40 -6
  793. data/lib/datadog/tracing/contrib/redis/tags.rb +6 -11
  794. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +16 -8
  795. data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +2 -2
  796. data/lib/datadog/tracing/contrib/resque/ext.rb +7 -7
  797. data/lib/datadog/tracing/contrib/resque/integration.rb +5 -5
  798. data/lib/datadog/tracing/contrib/resque/patcher.rb +3 -3
  799. data/lib/datadog/tracing/contrib/resque/resque_job.rb +6 -5
  800. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +2 -2
  801. data/lib/datadog/tracing/contrib/rest_client/ext.rb +10 -10
  802. data/lib/datadog/tracing/contrib/rest_client/integration.rb +6 -6
  803. data/lib/datadog/tracing/contrib/rest_client/patcher.rb +2 -2
  804. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +6 -10
  805. data/lib/datadog/tracing/contrib/roda/configuration/settings.rb +2 -2
  806. data/lib/datadog/tracing/contrib/roda/ext.rb +6 -5
  807. data/lib/datadog/tracing/contrib/roda/instrumentation.rb +8 -5
  808. data/lib/datadog/tracing/contrib/roda/integration.rb +6 -6
  809. data/lib/datadog/tracing/contrib/roda/patcher.rb +3 -3
  810. data/lib/datadog/tracing/contrib/semantic_logger/configuration/settings.rb +2 -2
  811. data/lib/datadog/tracing/contrib/semantic_logger/ext.rb +1 -1
  812. data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +5 -5
  813. data/lib/datadog/tracing/contrib/semantic_logger/patcher.rb +2 -2
  814. data/lib/datadog/tracing/contrib/sequel/configuration/settings.rb +2 -2
  815. data/lib/datadog/tracing/contrib/sequel/database.rb +7 -10
  816. data/lib/datadog/tracing/contrib/sequel/dataset.rb +6 -5
  817. data/lib/datadog/tracing/contrib/sequel/ext.rb +12 -8
  818. data/lib/datadog/tracing/contrib/sequel/integration.rb +5 -5
  819. data/lib/datadog/tracing/contrib/sequel/jdbc_connection_string.rb +140 -0
  820. data/lib/datadog/tracing/contrib/sequel/patcher.rb +3 -3
  821. data/lib/datadog/tracing/contrib/sequel/utils.rb +103 -16
  822. data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +2 -2
  823. data/lib/datadog/tracing/contrib/shoryuken/ext.rb +12 -12
  824. data/lib/datadog/tracing/contrib/shoryuken/integration.rb +6 -6
  825. data/lib/datadog/tracing/contrib/shoryuken/patcher.rb +1 -1
  826. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +3 -2
  827. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +9 -8
  828. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +2 -2
  829. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +12 -10
  830. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +30 -30
  831. data/lib/datadog/tracing/contrib/sidekiq/integration.rb +7 -7
  832. data/lib/datadog/tracing/contrib/sidekiq/patcher.rb +8 -8
  833. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +2 -0
  834. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +1 -0
  835. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/redis_info.rb +1 -0
  836. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +2 -0
  837. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/stop.rb +1 -0
  838. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +15 -14
  839. data/lib/datadog/tracing/contrib/sidekiq/utils.rb +10 -10
  840. data/lib/datadog/tracing/contrib/sidekiq.rb +7 -6
  841. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +3 -3
  842. data/lib/datadog/tracing/contrib/sinatra/env.rb +6 -6
  843. data/lib/datadog/tracing/contrib/sinatra/ext.rb +17 -17
  844. data/lib/datadog/tracing/contrib/sinatra/framework.rb +2 -2
  845. data/lib/datadog/tracing/contrib/sinatra/integration.rb +5 -5
  846. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +5 -5
  847. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +11 -10
  848. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +9 -8
  849. data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +1 -1
  850. data/lib/datadog/tracing/contrib/sneakers/ext.rb +12 -12
  851. data/lib/datadog/tracing/contrib/sneakers/integration.rb +7 -7
  852. data/lib/datadog/tracing/contrib/sneakers/patcher.rb +2 -2
  853. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +5 -4
  854. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +2 -2
  855. data/lib/datadog/tracing/contrib/status_range_env_parser.rb +2 -2
  856. data/lib/datadog/tracing/contrib/status_range_matcher.rb +4 -0
  857. data/lib/datadog/tracing/contrib/stripe/configuration/settings.rb +2 -2
  858. data/lib/datadog/tracing/contrib/stripe/ext.rb +12 -12
  859. data/lib/datadog/tracing/contrib/stripe/integration.rb +5 -5
  860. data/lib/datadog/tracing/contrib/stripe/patcher.rb +2 -2
  861. data/lib/datadog/tracing/contrib/stripe/request.rb +4 -4
  862. data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +2 -2
  863. data/lib/datadog/tracing/contrib/sucker_punch/exception_handler.rb +1 -1
  864. data/lib/datadog/tracing/contrib/sucker_punch/ext.rb +13 -13
  865. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +5 -4
  866. data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +5 -5
  867. data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +4 -4
  868. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +3 -3
  869. data/lib/datadog/tracing/contrib/trilogy/ext.rb +11 -11
  870. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +7 -11
  871. data/lib/datadog/tracing/contrib/trilogy/integration.rb +5 -5
  872. data/lib/datadog/tracing/contrib/trilogy/patcher.rb +2 -2
  873. data/lib/datadog/tracing/contrib/utils/database.rb +5 -5
  874. data/lib/datadog/tracing/contrib/utils/quantization/{hash.rb → hash_formatter.rb} +3 -3
  875. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +16 -13
  876. data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +2 -2
  877. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +11 -9
  878. data/lib/datadog/tracing/contrib/waterdrop/ext.rb +4 -4
  879. data/lib/datadog/tracing/contrib/waterdrop/integration.rb +5 -5
  880. data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +2 -2
  881. data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +7 -7
  882. data/lib/datadog/tracing/contrib/waterdrop/producer.rb +3 -3
  883. data/lib/datadog/tracing/contrib/waterdrop.rb +7 -6
  884. data/lib/datadog/tracing/contrib.rb +62 -54
  885. data/lib/datadog/tracing/correlation.rb +12 -12
  886. data/lib/datadog/tracing/diagnostics/environment_logger.rb +15 -12
  887. data/lib/datadog/tracing/diagnostics/ext.rb +19 -19
  888. data/lib/datadog/tracing/diagnostics/health.rb +1 -1
  889. data/lib/datadog/tracing/distributed/b3_multi.rb +8 -8
  890. data/lib/datadog/tracing/distributed/b3_single.rb +4 -4
  891. data/lib/datadog/tracing/distributed/baggage.rb +81 -28
  892. data/lib/datadog/tracing/distributed/datadog.rb +34 -32
  893. data/lib/datadog/tracing/distributed/fetcher.rb +1 -1
  894. data/lib/datadog/tracing/distributed/helpers.rb +3 -3
  895. data/lib/datadog/tracing/distributed/propagation.rb +46 -11
  896. data/lib/datadog/tracing/distributed/propagation_policy.rb +5 -0
  897. data/lib/datadog/tracing/distributed/trace_context.rb +29 -263
  898. data/lib/datadog/tracing/distributed/trace_state/datadog.rb +233 -0
  899. data/lib/datadog/tracing/distributed/trace_state/ext.rb +44 -0
  900. data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +156 -0
  901. data/lib/datadog/tracing/distributed/trace_state.rb +121 -0
  902. data/lib/datadog/tracing/event.rb +2 -2
  903. data/lib/datadog/tracing/ext.rb +9 -0
  904. data/lib/datadog/tracing/metadata/analytics.rb +2 -2
  905. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  906. data/lib/datadog/tracing/metadata/ext.rb +79 -66
  907. data/lib/datadog/tracing/metadata/metastruct.rb +1 -1
  908. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +1 -1
  909. data/lib/datadog/tracing/metadata/tagging.rb +5 -5
  910. data/lib/datadog/tracing/metadata.rb +4 -4
  911. data/lib/datadog/tracing/otel_thread_context.rb +99 -0
  912. data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
  913. data/lib/datadog/tracing/pipeline.rb +3 -3
  914. data/lib/datadog/tracing/remote.rb +227 -21
  915. data/lib/datadog/tracing/sampling/all_sampler.rb +1 -1
  916. data/lib/datadog/tracing/sampling/ext.rb +9 -7
  917. data/lib/datadog/tracing/sampling/matcher.rb +4 -4
  918. data/lib/datadog/tracing/sampling/priority_sampler.rb +17 -4
  919. data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +3 -3
  920. data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +2 -2
  921. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -2
  922. data/lib/datadog/tracing/sampling/rule.rb +5 -5
  923. data/lib/datadog/tracing/sampling/rule_sampler.rb +68 -37
  924. data/lib/datadog/tracing/sampling/sampler.rb +2 -2
  925. data/lib/datadog/tracing/sampling/span/ext.rb +3 -3
  926. data/lib/datadog/tracing/sampling/span/matcher.rb +2 -2
  927. data/lib/datadog/tracing/sampling/span/rule.rb +1 -1
  928. data/lib/datadog/tracing/sampling/span/rule_parser.rb +10 -10
  929. data/lib/datadog/tracing/span.rb +9 -9
  930. data/lib/datadog/tracing/span_event.rb +5 -5
  931. data/lib/datadog/tracing/span_operation.rb +39 -26
  932. data/lib/datadog/tracing/sync_writer.rb +12 -7
  933. data/lib/datadog/tracing/trace_digest.rb +29 -4
  934. data/lib/datadog/tracing/trace_operation.rb +112 -31
  935. data/lib/datadog/tracing/trace_segment.rb +10 -10
  936. data/lib/datadog/tracing/tracer.rb +83 -29
  937. data/lib/datadog/tracing/transport/http/client.rb +4 -4
  938. data/lib/datadog/tracing/transport/http/statistics.rb +2 -2
  939. data/lib/datadog/tracing/transport/http/traces.rb +8 -8
  940. data/lib/datadog/tracing/transport/http.rb +10 -10
  941. data/lib/datadog/tracing/transport/io/client.rb +3 -3
  942. data/lib/datadog/tracing/transport/io/response.rb +1 -1
  943. data/lib/datadog/tracing/transport/io/traces.rb +5 -5
  944. data/lib/datadog/tracing/transport/io.rb +3 -3
  945. data/lib/datadog/tracing/transport/native/response.rb +71 -0
  946. data/lib/datadog/tracing/transport/native.rb +380 -0
  947. data/lib/datadog/tracing/transport/serializable_trace.rb +19 -19
  948. data/lib/datadog/tracing/transport/span_events_negotiation.rb +41 -0
  949. data/lib/datadog/tracing/transport/statistics.rb +2 -2
  950. data/lib/datadog/tracing/transport/trace_formatter.rb +23 -13
  951. data/lib/datadog/tracing/transport/traces.rb +12 -32
  952. data/lib/datadog/tracing/utils.rb +2 -2
  953. data/lib/datadog/tracing/workers.rb +4 -3
  954. data/lib/datadog/tracing/writer.rb +22 -9
  955. data/lib/datadog/tracing.rb +3 -3
  956. data/lib/datadog/version.rb +4 -4
  957. data/lib/datadog.rb +15 -11
  958. metadata +109 -23
  959. data/ext/datadog_profiling_native_extension/clock_id_noop.c +0 -21
  960. data/lib/datadog/ai_guard/configuration/settings.rb +0 -113
  961. data/lib/datadog/appsec/configuration/settings.rb +0 -423
  962. data/lib/datadog/core/utils/base64.rb +0 -22
  963. data/lib/datadog/data_streams/configuration/settings.rb +0 -49
  964. data/lib/datadog/di/configuration/settings.rb +0 -243
  965. data/lib/datadog/error_tracking/configuration/settings.rb +0 -63
  966. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -82
@@ -3,9 +3,10 @@
3
3
  #include "ruby_helpers.h"
4
4
  #include "collectors_stack.h"
5
5
  #include "libdatadog_helpers.h"
6
+ #include "private_vm_api_access.h"
6
7
  #include "time_helpers.h"
7
8
 
8
- // Note on calloc vs ruby_xcalloc use:
9
+ // note on calloc vs ruby_xcalloc use:
9
10
  // * Whenever we're allocating memory after being called by the Ruby VM in a "regular" situation (e.g. initializer)
10
11
  // we should use `ruby_xcalloc` to give the VM visibility into what we're doing + give it a chance to manage GC
11
12
  // * BUT, when we're being called during a sample, being in the middle of an object allocation is a very special
@@ -58,7 +59,7 @@ typedef struct {
58
59
  heap_frame frames[];
59
60
  } heap_record;
60
61
  static heap_record* heap_record_new(heap_recorder*, ddog_prof_Slice_Location);
61
- static void heap_record_free(heap_recorder*, heap_record*);
62
+ static void heap_record_free(heap_recorder*, heap_record*, bool should_unintern);
62
63
 
63
64
  #if MAX_FRAMES_LIMIT > UINT16_MAX
64
65
  #error Frames len type not compatible with MAX_FRAMES_LIMIT
@@ -68,24 +69,24 @@ static int heap_record_cmp_st(st_data_t, st_data_t);
68
69
  static st_index_t heap_record_hash_st(st_data_t);
69
70
  static const struct st_hash_type st_hash_type_heap_record = { .compare = heap_record_cmp_st, .hash = heap_record_hash_st };
70
71
 
71
- // An object record is used for storing data about currently tracked live objects
72
+ // A pending recording is used to defer adding the object to the `weak_objects` map: doing so is a Ruby method
73
+ // call that allocates, and neither of those is safe to do during on_newobj_event
72
74
  typedef struct {
73
- long obj_id;
75
+ VALUE object_ref;
76
+ long record_id; // Always in Fixnum range
74
77
  heap_record *heap_record;
75
78
  live_object_data object_data;
76
- } object_record;
77
- static object_record* object_record_new(long, heap_record*, live_object_data);
78
- static void object_record_free(heap_recorder*, object_record*);
79
- static VALUE object_record_inspect(heap_recorder*, object_record*);
80
- static object_record SKIPPED_RECORD = {0};
79
+ } pending_recording;
81
80
 
82
- // A pending recording is used to defer the object_id call on Ruby 4+
83
- // where calling rb_obj_id during on_newobj_event is unsafe.
81
+ // An object record is used for storing data about currently tracked live objects
84
82
  typedef struct {
85
- VALUE object_ref;
83
+ long record_id;
86
84
  heap_record *heap_record;
87
85
  live_object_data object_data;
88
- } pending_recording;
86
+ } object_record;
87
+ static object_record* object_record_new(pending_recording pending);
88
+ static void object_record_free(heap_recorder*, object_record*, bool should_unintern);
89
+ static VALUE object_record_inspect(heap_recorder*, object_record*);
89
90
 
90
91
  #define MAX_PENDING_RECORDINGS 256
91
92
 
@@ -106,7 +107,7 @@ struct heap_recorder {
106
107
  // entire stacks for us, then we wouldn't need to do it on the Ruby side.
107
108
  st_table *heap_records;
108
109
 
109
- // Map[obj_id: long, record: object_record*]
110
+ // Map[record_id: long, record: object_record*]
110
111
  // NOTE: This table is currently only protected by the GVL since we never interact with it
111
112
  // outside the GVL.
112
113
  // NOTE: This table has ownership of its object_records. The keys are longs and so are
@@ -114,18 +115,17 @@ struct heap_recorder {
114
115
  //
115
116
  // TODO: @ivoanjo We've evolved to actually never need to look up on object_records (we only insert and iterate),
116
117
  // so right now this seems to be just a really really fancy self-resizing list/set.
117
- // If we replace this with a list, we could record the latest id and compare it when inserting to make sure our
118
- // assumption of ids never reused + always increasing always holds. (This as an alternative to checking for duplicates)
118
+ // Tests do use it for lookup currently though.
119
119
  st_table *object_records;
120
120
 
121
- // Map[obj_id: long, record: object_record*]
121
+ // Map[record_id: long, record: object_record*]
122
122
  // NOTE: This is a snapshot of object_records built ahead of a iteration. Outside of an
123
123
  // iteration context, this table will be NULL. During an iteration, there will be no
124
124
  // mutation of the data so iteration can occur without acquiring a lock.
125
125
  // NOTE: Contrary to object_records, this table has no ownership of its data.
126
126
  st_table *object_records_snapshot;
127
- // Are we currently updating or not?
128
- bool updating;
127
+ // "Lock" protecting the heap recorder bookkeeping; see "note on locking" below
128
+ uint8_t lock;
129
129
  // The GC gen/epoch/count in which we are updating (or last updated if not currently updating).
130
130
  //
131
131
  // This enables us to calculate the age of objects considered in the update by comparing it
@@ -137,16 +137,18 @@ struct heap_recorder {
137
137
  // When did we do the last update of heap recorder?
138
138
  long last_update_ns;
139
139
 
140
- // Data for a heap recording that was started but not yet ended
141
- object_record *active_recording;
142
-
143
- // Pending recordings that need to be finalized after on_newobj_event completes.
144
- // On Ruby 4+, we can't call rb_obj_id during the newobj event, so we store the
145
- // VALUE reference here and finalize it via a postponed job.
140
+ // ObjectSpace::WeakMap[record_id: Integer (Fixnum) => object]
141
+ // Weak references to every object we're tracking.
142
+ // Looking a record_id up returns the object while it's alive, and nil once it's been garbage collected, which
143
+ // is how we determine liveness. See `ruby_weak_map_new` for details on why this gives us a weak reference.
144
+ VALUE weak_objects;
145
+ // Source for the ids used as keys in `object_records` and `weak_objects`. Ids are never reused.
146
+ long next_record_id;
147
+
148
+ // Recordings that are waiting to be committed after on_newobj_event completes.
149
+ // We can't add the object to `weak_objects` during the newobj event, so we store the
150
+ // VALUE reference here and commit it via a postponed job.
146
151
  pending_recording pending_recordings[MAX_PENDING_RECORDINGS];
147
- // Temporary storage for the recording in progress, used between start and end
148
- VALUE active_deferred_object;
149
- live_object_data active_deferred_object_data;
150
152
  uint16_t pending_recordings_count;
151
153
 
152
154
  // Reusable arrays, implementing a flyweight pattern for things like iteration
@@ -184,33 +186,144 @@ struct heap_recorder {
184
186
  double ewma_objects_skipped;
185
187
 
186
188
  unsigned long deferred_recordings_skipped_buffer_full;
187
- unsigned long deferred_recordings_finalized;
189
+ unsigned long deferred_recordings_committed;
188
190
  } stats_lifetime;
189
191
  };
190
192
 
193
+ // note on locking:
194
+ //
195
+ // The state of the heap profiler (`pending_recordings`, `object_records`, `heap_records`, `weak_objects`) gets mutated from a
196
+ // few different places and, unlike most of the profiler, some of those operations lose the GVL while they work.
197
+ // Thus, unlike most of the profiler, relying only on knowing "we get called with the GVL" is not enough to keep them
198
+ // from stepping on each other, hence this extra "uint8_t lock".
199
+ //
200
+ // Yet, because we only ever touch while holding the GVL, and never lose the GVL between checking it and setting it, a
201
+ // plain field is enough -- no atomics needed. (Hence the "lock" and not a full actual lock)
202
+ //
203
+ // Operations that can be skipped use `heap_recorder_try_lock` and walk away when it's taken (which is almost all of them).
204
+ // The one operation that can't be skipped -- the full update that runs before serialization -- uses
205
+ // `heap_recorder_lock`, which waits.
206
+ //
207
+ // `heap_recorder_lock` is expected to be bounded because once `LOCK_WANTED` gets set, no `try_lock` will succeed, so
208
+ // the `heap_recorder_lock` will only need to wait for the previous user of the lock to finish it's work + Ruby to
209
+ // switch back to is thread.
210
+ #define HEAP_RECORDER_LOCK_HELD 0x1
211
+ #define HEAP_RECORDER_LOCK_WANTED 0x2
212
+
213
+ // Is someone in the middle of a locked operation? (Which, because they may lose the GVL, may be true even though we're
214
+ // the ones currently holding the GVL.)
215
+ static inline bool heap_recorder_is_locked(heap_recorder *heap_recorder) {
216
+ return (heap_recorder->lock & HEAP_RECORDER_LOCK_HELD) != 0;
217
+ }
218
+
219
+ // Takes the lock, unless it's held or someone is waiting for it. Returns whether it was taken.
220
+ __attribute__((warn_unused_result))
221
+ static inline bool heap_recorder_try_lock(heap_recorder *heap_recorder) {
222
+ if (heap_recorder->lock != 0) return false;
223
+
224
+ heap_recorder->lock = HEAP_RECORDER_LOCK_HELD;
225
+ return true;
226
+ }
227
+
228
+ // Takes the lock, waiting for the current holder to finish if needed. See "note on locking" above for why this wait is
229
+ // expected to be bounded.
230
+ //
231
+ // WARN: Do not call this while already holding the lock -- it would wait forever.
232
+ static void heap_recorder_lock(heap_recorder *heap_recorder) {
233
+ while (heap_recorder_is_locked(heap_recorder)) {
234
+ heap_recorder->lock |= HEAP_RECORDER_LOCK_WANTED;
235
+ rb_thread_schedule();
236
+ }
237
+
238
+ // Note that we go from observing the lock as free to taking it without ever losing the GVL, and thus without giving
239
+ // anyone else a chance to take it from under us
240
+ heap_recorder->lock = HEAP_RECORDER_LOCK_HELD;
241
+ }
242
+
243
+ static inline void heap_recorder_unlock(heap_recorder *heap_recorder) {
244
+ // Deliberately preserves `HEAP_RECORDER_LOCK_WANTED` (rather than just zero-ing the lock)
245
+ heap_recorder->lock &= ~HEAP_RECORDER_LOCK_HELD;
246
+ }
247
+
248
+ // Same as the above, in the shape `rb_ensure` wants
249
+ static VALUE heap_recorder_unlock_ensure(VALUE heap_recorder_as_value) {
250
+ heap_recorder_unlock((heap_recorder *) heap_recorder_as_value);
251
+ return Qnil;
252
+ }
253
+
191
254
  typedef struct {
192
255
  heap_recorder *heap_recorder;
193
- ddog_prof_Slice_Location locations;
194
- } end_heap_allocation_args;
256
+ bool full_update;
257
+ } heap_recorder_update_locked_args;
195
258
 
196
259
  static heap_record* get_or_create_heap_record(heap_recorder*, ddog_prof_Slice_Location);
197
260
  static void cleanup_heap_record_if_unused(heap_recorder*, heap_record*);
198
261
  static void on_committed_object_record_cleanup(heap_recorder *heap_recorder, object_record *record);
199
- static int st_heap_record_entry_free(st_data_t, st_data_t, st_data_t);
200
- static int st_object_record_entry_free(st_data_t, st_data_t, st_data_t);
262
+ static int st_heap_record_entry_free_no_unintern(st_data_t, st_data_t, st_data_t);
263
+ static int st_object_record_entry_free_no_unintern(st_data_t, st_data_t, st_data_t);
201
264
  static int st_object_record_update(st_data_t, st_data_t, st_data_t);
202
265
  static int st_object_records_iterate(st_data_t, st_data_t, st_data_t);
203
266
  static int st_object_records_debug(st_data_t key, st_data_t value, st_data_t extra);
204
- static int update_object_record_entry(st_data_t*, st_data_t*, st_data_t, int);
205
267
  static void inc_tracked_objects_or_fail(heap_record *heap_record);
206
- static void commit_recording(heap_recorder *, heap_record *, object_record *active_recording);
207
- static VALUE end_heap_allocation_recording(VALUE end_heap_allocation_args);
268
+ static void commit_recording(heap_recorder *, pending_recording);
208
269
  static void heap_recorder_update(heap_recorder *heap_recorder, bool full_update);
270
+ static VALUE heap_recorder_update_locked(VALUE heap_recorder_update_locked_args_as_value);
271
+ static VALUE heap_recorder_commit_recordings_may_lose_gvl_locked(VALUE heap_recorder_as_value);
209
272
  static inline double ewma_stat(double previous, double current);
210
273
  static void unintern_or_raise(heap_recorder *, ddog_prof_ManagedStringId);
211
274
  static void unintern_all_or_raise(heap_recorder *recorder, ddog_prof_Slice_ManagedStringId ids);
212
275
  static VALUE get_ruby_string_or_raise(heap_recorder*, ddog_prof_ManagedStringId);
213
- static long obj_id_or_fail(VALUE obj);
276
+
277
+ // The following global variables are initialized at startup to save expensive lookups later.
278
+ // They are not expected to be mutated outside of init.
279
+ static VALUE class_weak_map = Qnil;
280
+ static ID aref_id = Qnil;
281
+ static ID aset_id = Qnil;
282
+
283
+ void collectors_heap_recorder_init(void) {
284
+ rb_global_variable(&class_weak_map);
285
+
286
+ VALUE module_object_space = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
287
+ class_weak_map = rb_const_get(module_object_space, rb_intern("WeakMap"));
288
+ aref_id = rb_intern("[]");
289
+ aset_id = rb_intern("[]=");
290
+ }
291
+
292
+ // Native wrapper to create a new `ObjectSpace::WeakMap`.
293
+ //
294
+ // Because an `ObjectSpace::WeakMap` entry is dropped as soon as *either* its key or its value is garbage
295
+ // collected, pairing a key that can never be collected (such as a fixnum) with the object of interest as the
296
+ // value gives us a weak reference: reading the key back returns the object while it's alive, and nothing once
297
+ // it's been collected.
298
+ static VALUE ruby_weak_map_new(void) {
299
+ return rb_class_new_instance(0, NULL, class_weak_map);
300
+ }
301
+
302
+ // Native wrapper to get an object from an `ObjectSpace::WeakMap`.
303
+ // Returns the object on success and nil if the entry is gone, meaning
304
+ // the object has been garbage collected.
305
+ // We never store nil as a value, see ruby_weak_map_set_may_lose_gvl_and_allocate_objects(), so nil unambiguously
306
+ // means "the value was garbage collected".
307
+ //
308
+ // Note: GVL can be released and other threads may get to run before this method returns
309
+ static VALUE ruby_weak_map_get_may_lose_gvl(VALUE weak_map, VALUE key) {
310
+ return rb_funcall(weak_map, aref_id, 1, key);
311
+ }
312
+
313
+ // Native wrapper to add an entry to an `ObjectSpace::WeakMap`.
314
+ // Raises RuntimeError if passed nil as a value.
315
+ //
316
+ // Note: GVL can be released and other threads may get to run before this method returns.
317
+ //
318
+ // On Ruby < 3.3 this allocates Ruby objects (because underneath the weak map registers
319
+ // finalizers for the objects, which requires allocations). Later Rubies improved WeakMap to not need this.
320
+ // This we need to be careful not to recurse on the profiler (e.g. NEWOBJ tracepoint).
321
+ static void ruby_weak_map_set_may_lose_gvl_and_allocate_objects(VALUE weak_map, VALUE key, VALUE value) {
322
+ if (value == Qnil) {
323
+ raise_error(rb_eRuntimeError, "Can't use nil as the value in the WeakMap, otherwise #[] can't differentiate alive vs nil value");
324
+ }
325
+ rb_funcall(weak_map, aset_id, 2, key, value);
326
+ }
214
327
 
215
328
  // ==========================
216
329
  // Heap Recorder External API
@@ -230,11 +343,12 @@ heap_recorder* heap_recorder_new(ddog_prof_ManagedStringStorage string_storage)
230
343
  recorder->reusable_locations = ruby_xcalloc(REUSABLE_LOCATIONS_SIZE, sizeof(ddog_prof_Location));
231
344
  recorder->reusable_ids = ruby_xcalloc(REUSABLE_FRAME_DETAILS_SIZE, sizeof(ddog_prof_ManagedStringId));
232
345
  recorder->reusable_char_slices = ruby_xcalloc(REUSABLE_FRAME_DETAILS_SIZE, sizeof(ddog_CharSlice));
233
- recorder->active_recording = NULL;
234
346
  recorder->size_enabled = true;
235
347
  recorder->sample_rate = 1; // By default do no sampling on top of what allocation profiling already does
236
348
  recorder->string_storage = string_storage;
237
- recorder->active_deferred_object = Qnil;
349
+ // Note: This allocates, and thus can trigger a GC. That's fine: our caller only publishes the heap recorder on the
350
+ // stack recorder state after we return, so `heap_recorder_mark` will not observe a half-initialized recorder.
351
+ recorder->weak_objects = ruby_weak_map_new();
238
352
 
239
353
  return recorder;
240
354
  }
@@ -250,19 +364,21 @@ void heap_recorder_free(heap_recorder *heap_recorder) {
250
364
  heap_recorder_finish_iteration(heap_recorder);
251
365
  }
252
366
 
367
+ // NOTE: We don't unintern the strings referenced by the records we're about to free, thus we use
368
+ // `..._no_unintern` and `should_unintern: false`. This is intentional: `heap_recorder_free` is only ever called as part of
369
+ // tearing down the entire stack recorder, and the caller drops the whole managed string storage right after
370
+ // (see `stack_recorder_typed_data_free`), so there's no need to spend effort updating the managed string table.
371
+ // Crucially, this also keeps us from crashing: this code runs from the stack recorder's GC free callback, and
372
+ // because uninterning can fail, we can't raise exceptions in the middle of a dfree.
373
+
253
374
  // Clean-up all object records
254
- st_foreach(heap_recorder->object_records, st_object_record_entry_free, (st_data_t) heap_recorder);
375
+ st_foreach(heap_recorder->object_records, st_object_record_entry_free_no_unintern, (st_data_t) heap_recorder);
255
376
  st_free_table(heap_recorder->object_records);
256
377
 
257
378
  // Clean-up all heap records (this includes those only referred to by queued_samples)
258
- st_foreach(heap_recorder->heap_records, st_heap_record_entry_free, (st_data_t) heap_recorder);
379
+ st_foreach(heap_recorder->heap_records, st_heap_record_entry_free_no_unintern, (st_data_t) heap_recorder);
259
380
  st_free_table(heap_recorder->heap_records);
260
381
 
261
- if (heap_recorder->active_recording != NULL && heap_recorder->active_recording != &SKIPPED_RECORD) {
262
- // If there's a partial object record, clean it up as well
263
- object_record_free(heap_recorder, heap_recorder->active_recording);
264
- }
265
-
266
382
  ruby_xfree(heap_recorder->reusable_locations);
267
383
  ruby_xfree(heap_recorder->reusable_ids);
268
384
  ruby_xfree(heap_recorder->reusable_char_slices);
@@ -306,7 +422,7 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder) {
306
422
  // simply be noticed on next heap_recorder_prepare_iteration.
307
423
  //
308
424
  // There is one small caveat though: fork only preserves one thread and in a Ruby app, that
309
- // will be the thread holding on to the GVL. Since we support iteration on the heap recorder
425
+ // will be the thread holding the GVL. Since we support iteration on the heap recorder
310
426
  // outside of the GVL, any state specific to that interaction may be inconsistent after fork
311
427
  // (e.g. an acquired lock for thread safety). Iteration operates on object_records_snapshot
312
428
  // though and that one will be updated on next heap_recorder_prepare_iteration so we really
@@ -315,150 +431,95 @@ void heap_recorder_after_fork(heap_recorder *heap_recorder) {
315
431
  heap_recorder_finish_iteration(heap_recorder);
316
432
  }
317
433
 
434
+ // This could also be left over if fork happens in the middle of a locked operation
435
+ heap_recorder->lock = 0;
436
+
318
437
  // Clear lifetime stats since this is essentially a new heap recorder
319
438
  heap_recorder->stats_lifetime = (struct stats_lifetime) {0};
320
439
  }
321
440
 
322
- bool start_heap_allocation_recording(heap_recorder *heap_recorder, VALUE new_obj, unsigned int weight, ddog_CharSlice alloc_class) {
441
+ // This method gets called from inside the RUBY_INTERNAL_EVENT_NEWOBJ tracepoint so it should neither allocate in the
442
+ // Ruby heap nor release the GVL (https://github.com/DataDog/dd-trace-rb/pull/4240).
443
+ //
444
+ // See the header for details on the arguments and on `needs_commit`.
445
+ void heap_recorder_record_allocation(
446
+ heap_recorder *heap_recorder,
447
+ VALUE new_object,
448
+ unsigned int weight,
449
+ ddog_CharSlice alloc_class,
450
+ ddog_prof_Slice_Location locations,
451
+ bool *needs_commit
452
+ ) {
323
453
  if (heap_recorder == NULL) {
324
- return false;
325
- }
326
-
327
- if (heap_recorder->active_recording != NULL) {
328
- raise_error(rb_eRuntimeError, "Detected consecutive heap allocation recording starts without end.");
454
+ *needs_commit = false;
455
+ return;
329
456
  }
330
457
 
331
- if (++heap_recorder->num_recordings_skipped < heap_recorder->sample_rate ||
332
- #ifdef NO_IMEMO_OBJECT_ID
333
- // On Ruby 4, we can't ask the object_id from IMEMOs (https://github.com/ruby/ruby/pull/13347)
334
- RB_BUILTIN_TYPE(new_obj) == RUBY_T_IMEMO
335
- #else
336
- false
337
- #endif
338
- // If we got really unlucky and an allocation showed up during an update (because it triggered an allocation
339
- // directly OR because the GVL got released in the middle of an update), let's skip this sample as well.
340
- // See notes on `heap_recorder_update` for details.
341
- || heap_recorder->updating
342
- ) {
343
- heap_recorder->active_recording = &SKIPPED_RECORD;
344
- return false;
458
+ // We always report `needs_commit` when there's anything pending, even if it's from a previous allocation.
459
+ //
460
+ // This can mean we "spam" a bit the postponed jobs mechanism (e.g. perhaps our postponed job hasn't run
461
+ // because there's a native extension doing Ruby object allocations in a row without giving Ruby the chance to
462
+ // run interrupts.
463
+ // That shouldn't be a problem because the allocation profiler has the dynamic sampling rate mechanism +
464
+ // triggering postponed jobs is cheap on current Rubies.
465
+ // (Note that asking for the same job multiple times de-duplicates -- Ruby will only run it once when it gets the chance)
466
+ *needs_commit = heap_recorder->pending_recordings_count > 0;
467
+
468
+ if (++heap_recorder->num_recordings_skipped < heap_recorder->sample_rate) return;
469
+
470
+ if (heap_recorder_is_locked(heap_recorder)) {
471
+ // If we got unlucky and an allocation showed up in the middle of a locked operation (because it triggered
472
+ // an allocation directly OR because that operation lost the GVL), let's skip this sample as well.
473
+ // (Note we don't take the lock ourselves: the current function never loses the GVL, and is thus already atomic.)
474
+ return;
345
475
  }
346
476
 
347
- bool needs_after_allocation = false;
477
+ // Do not sample internal objects in the heap profiler because they are added to a ObjectSpace::WeakMap, which would not be safe.
478
+ // This means we ignore internal VM objects samples for the heap profiler,
479
+ // which is a trade-off discussed in https://github.com/DataDog/dd-trace-rb/pull/6176#discussion_r3819776251
480
+ //
481
+ // Note this is checked after the sample rate above, as the sample rate is in number of allocation profiler samples,
482
+ // not in number of non-internal samples. Like the skips above, num_recordings_skipped is not reset here, so the
483
+ // next allocation sample still gets a chance to be tracked.
484
+ if (ddtrace_is_internal_object_p(new_object)) return;
348
485
 
349
- #ifdef USE_DEFERRED_HEAP_ALLOCATION_RECORDING
350
- // Skip if we've hit the pending recordings limit or if there's already a deferred object being recorded
486
+ // Skip if we've hit the pending recordings limit
351
487
  if (heap_recorder->pending_recordings_count >= MAX_PENDING_RECORDINGS) {
352
488
  heap_recorder->stats_lifetime.deferred_recordings_skipped_buffer_full++;
353
- heap_recorder->active_recording = &SKIPPED_RECORD;
354
- return true; // If the buffer is full, we keep asking for a callback (see `needs_after_allocation` below)
355
- } else {
356
- // The intuition here is: We start by asking for an `after_allocation` callback when the buffer is about to go
357
- // from empty -> non-empty, because this is going to be mapped onto a postponed job, so after it gets queued once
358
- // it doesn't seem worth it to keep spamming requests.
359
- //
360
- // Yet, if for some reason the postponed job doesn't flush the pending list (or if e.g. it ran with `during_sample == true` and thus
361
- // was skipped) we need to have some mechanism to recover -- and so if the buffer starts accumulating too much we
362
- // start always requesting the callback to happen so that we eventually flush the buffer.
363
- needs_after_allocation =
364
- heap_recorder->pending_recordings_count == 0 || heap_recorder->pending_recordings_count >= (MAX_PENDING_RECORDINGS / 2);
489
+ return; // `needs_commit` is already true: a full buffer definitely has something to commit
365
490
  }
366
- #endif
367
491
 
368
492
  heap_recorder->num_recordings_skipped = 0;
369
493
 
370
- live_object_data object_data = (live_object_data) {
494
+ // Note: Everything that can raise happens before we add the recording to `pending_recordings` below, so that a
495
+ // failure never leaves a half-built entry behind
496
+ live_object_data object_data = {
371
497
  .weight = weight * heap_recorder->sample_rate,
372
498
  .class = intern_or_raise(heap_recorder->string_storage, alloc_class),
373
499
  .alloc_gen = rb_gc_count(),
374
500
  };
375
501
 
376
- #ifdef USE_DEFERRED_HEAP_ALLOCATION_RECORDING
377
- // On Ruby 4+, we can't call rb_obj_id during on_newobj_event as it mutates the object.
378
- // Instead, we store the VALUE reference and will get the object_id later via a postponed job.
379
- // active_deferred_object != Qnil indicates we're in deferred mode.
380
- heap_recorder->active_deferred_object = new_obj;
381
- heap_recorder->active_deferred_object_data = object_data;
382
- #else
383
- heap_recorder->active_recording = object_record_new(obj_id_or_fail(new_obj), NULL, object_data);
384
- #endif
385
-
386
- return needs_after_allocation;
387
- }
388
-
389
- // end_heap_allocation_recording_with_rb_protect gets called while the stack_recorder is holding one of the profile
390
- // locks. To enable us to correctly unlock the profile on exception, we wrap the call to end_heap_allocation_recording
391
- // with an rb_protect.
392
- __attribute__((warn_unused_result))
393
- int end_heap_allocation_recording_with_rb_protect(heap_recorder *heap_recorder, ddog_prof_Slice_Location locations) {
394
- if (heap_recorder == NULL) {
395
- return 0;
396
- }
397
- if (heap_recorder->active_recording == &SKIPPED_RECORD) {
398
- // Short circuit, in this case there's nothing to be done
399
- heap_recorder->active_recording = NULL;
400
- return 0;
502
+ long record_id = ++heap_recorder->next_record_id;
503
+ if (record_id > RUBY_FIXNUM_MAX) {
504
+ // We rely on record_id always fitting in a FIXNUM to avoid extra overhead and
505
+ // allocation here. If we exhaust the record_id, we stop profiling.
506
+ // We don't expect this to happen in practice, as we don't heap sample every object, and RUBY_FIXNUM_MAX is (2**62 - 1)
507
+ raise_error(rb_eRuntimeError, "Heap profiling: Exhausted usable record_ids");
401
508
  }
402
509
 
403
- int exception_state;
404
- end_heap_allocation_args args = {
405
- .heap_recorder = heap_recorder,
406
- .locations = locations,
407
- };
408
- rb_protect(end_heap_allocation_recording, (VALUE) &args, &exception_state);
409
- return exception_state;
410
- }
411
-
412
- static VALUE end_heap_allocation_recording(VALUE protect_args) {
413
- end_heap_allocation_args *args = (end_heap_allocation_args *) protect_args;
414
-
415
- heap_recorder *heap_recorder = args->heap_recorder;
416
- ddog_prof_Slice_Location locations = args->locations;
417
-
418
- #ifdef USE_DEFERRED_HEAP_ALLOCATION_RECORDING
419
- if (heap_recorder->active_deferred_object == Qnil) {
420
- // Recording ended without having been started?
421
- raise_error(rb_eRuntimeError, "Ended a heap recording that was not started");
422
- }
423
- #else
424
- object_record *active_recording = heap_recorder->active_recording;
425
-
426
- if (active_recording == NULL) {
427
- // Recording ended without having been started?
428
- raise_error(rb_eRuntimeError, "Ended a heap recording that was not started");
429
- }
430
- // From now on, mark the global active recording as invalid so we can short-circuit at any point
431
- // and not end up with a still active recording. the local active_recording still holds the
432
- // data required for committing though.
433
- heap_recorder->active_recording = NULL;
434
-
435
- if (active_recording == &SKIPPED_RECORD) {
436
- raise_error(
437
- rb_eRuntimeError,
438
- "BUG: end_heap_allocation_recording should never observe SKIPPED_RECORDING because " \
439
- "end_heap_allocation_recording_with_rb_protect is supposed to test for it directly"
440
- );
441
- }
442
- #endif
443
-
444
510
  heap_record *heap_record = get_or_create_heap_record(heap_recorder, locations);
445
511
  inc_tracked_objects_or_fail(heap_record);
446
512
 
447
- #ifdef USE_DEFERRED_HEAP_ALLOCATION_RECORDING
448
- // Commit is delayed, so we need to record all we'll need for it
449
- pending_recording *pending = &heap_recorder->pending_recordings[heap_recorder->pending_recordings_count++];
450
- pending->object_ref = heap_recorder->active_deferred_object;
451
- pending->heap_record = heap_record;
452
- pending->object_data = heap_recorder->active_deferred_object_data;
453
-
454
- heap_recorder->active_deferred_object = Qnil;
455
- heap_recorder->active_deferred_object_data = (live_object_data) {0};
456
- #else
457
- // And then commit the new allocation
458
- commit_recording(heap_recorder, heap_record, active_recording);
459
- #endif
513
+ // We can't add the object to `weak_objects` from inside the NEWOBJ tracepoint, so the recording stays pending until
514
+ // `heap_recorder_commit_recordings_may_lose_gvl` gets to it
515
+ heap_recorder->pending_recordings[heap_recorder->pending_recordings_count++] = (pending_recording) {
516
+ .object_ref = new_object,
517
+ .record_id = record_id,
518
+ .heap_record = heap_record,
519
+ .object_data = object_data,
520
+ };
460
521
 
461
- return Qnil;
522
+ *needs_commit = true; // We just added a recording
462
523
  }
463
524
 
464
525
  void heap_recorder_update_young_objects(heap_recorder *heap_recorder) {
@@ -469,46 +530,68 @@ void heap_recorder_update_young_objects(heap_recorder *heap_recorder) {
469
530
  heap_recorder_update(heap_recorder, /* full_update: */ false);
470
531
  }
471
532
 
472
- void heap_recorder_finalize_pending_recordings(heap_recorder *heap_recorder) {
533
+ void heap_recorder_commit_recordings_may_lose_gvl(heap_recorder *heap_recorder) {
473
534
  if (heap_recorder == NULL) {
474
535
  return; // Nothing to do
475
536
  }
476
537
 
477
- uint count = heap_recorder->pending_recordings_count;
478
- if (count == 0) {
479
- return; // Nothing to do
538
+ if (!heap_recorder_try_lock(heap_recorder)) {
539
+ // Something else is busy; `heap_recorder_record_allocation` will ask for us to be called again later
540
+ return;
480
541
  }
481
542
 
482
- heap_recorder->stats_lifetime.deferred_recordings_finalized += count;
543
+ rb_ensure(
544
+ heap_recorder_commit_recordings_may_lose_gvl_locked,
545
+ (VALUE) heap_recorder,
546
+ heap_recorder_unlock_ensure,
547
+ (VALUE) heap_recorder
548
+ );
549
+ }
483
550
 
484
- for (uint i = 0; i < count; i++) {
485
- pending_recording *pending = &heap_recorder->pending_recordings[i];
551
+ static VALUE heap_recorder_commit_recordings_may_lose_gvl_locked(VALUE heap_recorder_as_value) {
552
+ heap_recorder *heap_recorder = (struct heap_recorder *) heap_recorder_as_value;
486
553
 
487
- // This is the step we couldn't do during the original sample call -- we're now expected to be called in a context
488
- // where it's finally safe to call this
489
- long obj_id = obj_id_or_fail(pending->object_ref);
554
+ // Note: We consume the buffer back-to-front, and only drop each entry once it's fully committed. That makes the
555
+ // "can lose the GVL" bit below safe to retry: if anything raises, or another thread unwinds us, the entry stays
556
+ // pending and a later commit picks it up -- and setting the same entry on the weak map again is harmless. It also
557
+ // means the entry we're working on stays marked (see `heap_recorder_mark`) across any GC that happens while we don't
558
+ // have the GVL.
559
+ //
560
+ // Note as well that `ruby_weak_map_set_may_lose_gvl_and_allocate_objects` below can lose the GVL (and, on older
561
+ // Rubies, allocate). This function gets called while holding the heap recorder lock so that no other heap recorder
562
+ // operation can concurrently execute with us in that window (including recording more allocations, which on older Rubies
563
+ // would otherwise add entries to the very buffer we're draining).
564
+ while (heap_recorder->pending_recordings_count > 0) {
565
+ pending_recording pending = heap_recorder->pending_recordings[heap_recorder->pending_recordings_count - 1];
566
+
567
+ ruby_weak_map_set_may_lose_gvl_and_allocate_objects(heap_recorder->weak_objects, LONG2FIX(pending.record_id), pending.object_ref);
490
568
 
491
- // Create the object record now that we have the object_id
492
- object_record *record = object_record_new(obj_id, pending->heap_record, pending->object_data);
569
+ // After here, we can no longer lose the GVL until we loop around again, so these steps are "atomic"
493
570
 
494
- commit_recording(heap_recorder, pending->heap_record, record);
571
+ commit_recording(heap_recorder, pending);
572
+ heap_recorder->pending_recordings_count--;
573
+ heap_recorder->stats_lifetime.deferred_recordings_committed++;
495
574
  }
496
575
 
497
- heap_recorder->pending_recordings_count = 0;
576
+ return Qnil;
498
577
  }
499
578
 
500
- // Mark pending recordings to prevent GC from collecting the objects
501
- // while they're waiting to be finalized
502
- void heap_recorder_mark_pending_recordings(heap_recorder *heap_recorder) {
579
+ // Mark the Ruby objects the heap recorder holds on to.
580
+ //
581
+ // Note that the objects we track are deliberately **not** marked here: `weak_objects` holds only weak references
582
+ // to them, which is exactly what lets us detect that they've been garbage collected.
583
+ void heap_recorder_mark(heap_recorder *heap_recorder) {
503
584
  if (heap_recorder == NULL) {
504
585
  return;
505
586
  }
506
587
 
588
+ // Mark pending recordings while they're waiting to be committed, otherwise it won't be safe to read them later.
589
+ // We would not mind if they are GC'd, but we would need to know that reliably and we can't.
507
590
  for (uint i = 0; i < heap_recorder->pending_recordings_count; i++) {
508
591
  rb_gc_mark(heap_recorder->pending_recordings[i].object_ref);
509
592
  }
510
593
 
511
- rb_gc_mark(heap_recorder->active_deferred_object);
594
+ rb_gc_mark(heap_recorder->weak_objects);
512
595
  }
513
596
 
514
597
  // NOTE: This function needs and assumes it gets called with the GVL being held.
@@ -516,36 +599,35 @@ void heap_recorder_mark_pending_recordings(heap_recorder *heap_recorder) {
516
599
  // so we can't assume a single update happens in a single "atomic" step -- other threads may get some running time
517
600
  // in the meanwhile.
518
601
  static void heap_recorder_update(heap_recorder *heap_recorder, bool full_update) {
519
- if (heap_recorder->updating) {
520
- if (full_update) {
521
- // There's another thread that's already doing an update :(
522
- //
523
- // Because there's a lock on the `StackRecorder` (see @no_concurrent_serialize_mutex) then it's not possible that
524
- // the other update is a full update.
525
- // Thus we expect is happening is that the GVL got released by the other thread in the middle of a non-full update
526
- // and the scheduler thread decided now was a great time to serialize the profile.
527
- //
528
- // So, let's yield the time on the current thread until Ruby goes back to the other thread doing the update and
529
- // it finishes cleanly.
530
- while (heap_recorder->updating) { rb_thread_schedule(); }
531
- } else {
532
- // Non-full updates are optional, so let's walk away
533
- heap_recorder->stats_lifetime.updates_skipped_concurrent++;
534
- return;
535
- }
602
+ if (full_update) {
603
+ // A full update runs as part of serialization and can't be skipped, so we wait for our turn if needed
604
+ heap_recorder_lock(heap_recorder);
605
+ } else if (!heap_recorder_try_lock(heap_recorder)) {
606
+ // Non-full updates are optional, so let's walk away
607
+ heap_recorder->stats_lifetime.updates_skipped_concurrent++;
608
+ return;
536
609
  }
537
610
 
611
+ heap_recorder_update_locked_args args = {.heap_recorder = heap_recorder, .full_update = full_update};
612
+ rb_ensure(heap_recorder_update_locked, (VALUE) &args, heap_recorder_unlock_ensure, (VALUE) heap_recorder);
613
+ }
614
+
615
+ static VALUE heap_recorder_update_locked(VALUE heap_recorder_update_locked_args_as_value) {
616
+ heap_recorder_update_locked_args *args = (heap_recorder_update_locked_args *) heap_recorder_update_locked_args_as_value;
617
+ heap_recorder *heap_recorder = args->heap_recorder;
618
+ bool full_update = args->full_update;
619
+
538
620
  if (heap_recorder->object_records_snapshot != NULL) {
539
621
  // While serialization is happening, it runs without the GVL and uses the object_records_snapshot.
540
622
  // Although we iterate on a snapshot of object_records, these records point to other data that has not been
541
623
  // snapshotted for efficiency reasons (e.g. heap_records). Since updating may invalidate
542
624
  // some of that non-snapshotted data, let's refrain from doing updates during iteration. This also enforces the
543
625
  // semantic that iteration will operate as a point-in-time snapshot.
544
- return;
626
+ return Qnil;
545
627
  }
546
628
 
547
629
  size_t current_gc_gen = rb_gc_count();
548
- long now_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
630
+ long now_ns = monotonic_wall_time_now_ns();
549
631
 
550
632
  if (!full_update) {
551
633
  if (current_gc_gen == heap_recorder->update_gen) {
@@ -556,17 +638,16 @@ static void heap_recorder_update(heap_recorder *heap_recorder, bool full_update)
556
638
  // object records to do an update, let's wait until all steps for a particular GC generation
557
639
  // have finished to do so. We may revisit this once we have a better liveness checking mechanism.
558
640
  heap_recorder->stats_lifetime.updates_skipped_gcgen++;
559
- return;
641
+ return Qnil;
560
642
  }
561
643
 
562
- if (now_ns > 0 && (now_ns - heap_recorder->last_update_ns) < MIN_TIME_BETWEEN_HEAP_RECORDER_UPDATES_NS) {
644
+ if ((now_ns - heap_recorder->last_update_ns) < MIN_TIME_BETWEEN_HEAP_RECORDER_UPDATES_NS) {
563
645
  // We did an update not too long ago. Let's skip this one to avoid over-taxing the system.
564
646
  heap_recorder->stats_lifetime.updates_skipped_time++;
565
- return;
647
+ return Qnil;
566
648
  }
567
649
  }
568
650
 
569
- heap_recorder->updating = true;
570
651
  // Reset last update stats, we'll be building them from scratch during the st_foreach call below
571
652
  heap_recorder->stats_last_update = (struct stats_last_update) {0};
572
653
 
@@ -589,7 +670,7 @@ static void heap_recorder_update(heap_recorder *heap_recorder, bool full_update)
589
670
  heap_recorder->stats_lifetime.ewma_objects_skipped = ewma_stat(heap_recorder->stats_lifetime.ewma_objects_skipped, heap_recorder->stats_last_update.objects_skipped);
590
671
  }
591
672
 
592
- heap_recorder->updating = false;
673
+ return Qnil;
593
674
  }
594
675
 
595
676
  void heap_recorder_prepare_iteration(heap_recorder *heap_recorder) {
@@ -683,7 +764,7 @@ VALUE heap_recorder_state_snapshot(heap_recorder *heap_recorder) {
683
764
  ID2SYM(rb_intern("lifetime_ewma_objects_skipped")), /* => */ DBL2NUM(heap_recorder->stats_lifetime.ewma_objects_skipped),
684
765
 
685
766
  ID2SYM(rb_intern("lifetime_deferred_recordings_skipped_buffer_full")), /* => */ ULONG2NUM(heap_recorder->stats_lifetime.deferred_recordings_skipped_buffer_full),
686
- ID2SYM(rb_intern("lifetime_deferred_recordings_finalized")), /* => */ ULONG2NUM(heap_recorder->stats_lifetime.deferred_recordings_finalized),
767
+ ID2SYM(rb_intern("lifetime_deferred_recordings_committed")), /* => */ ULONG2NUM(heap_recorder->stats_lifetime.deferred_recordings_committed),
687
768
  };
688
769
  VALUE hash = rb_hash_new();
689
770
  for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(hash, arguments[i], arguments[i+1]);
@@ -714,26 +795,26 @@ VALUE heap_recorder_testonly_debug(heap_recorder *heap_recorder) {
714
795
  // ==========================
715
796
  // Heap Recorder Internal API
716
797
  // ==========================
717
- static int st_heap_record_entry_free(st_data_t key, DDTRACE_UNUSED st_data_t value, st_data_t extra_arg) {
798
+ // NOTE: Only expected to be used from heap_recorder_free, which will separately destroy the string table
799
+ static int st_heap_record_entry_free_no_unintern(st_data_t key, DDTRACE_UNUSED st_data_t value, st_data_t extra_arg) {
718
800
  heap_recorder *recorder = (heap_recorder *) extra_arg;
719
- heap_record_free(recorder, (heap_record *) key);
801
+ heap_record_free(recorder, (heap_record *) key, false);
720
802
  return ST_DELETE;
721
803
  }
722
804
 
723
- static int st_object_record_entry_free(DDTRACE_UNUSED st_data_t key, st_data_t value, st_data_t extra_arg) {
805
+ // NOTE: Only expected to be used from heap_recorder_free, which will separately destroy the string table
806
+ static int st_object_record_entry_free_no_unintern(DDTRACE_UNUSED st_data_t key, st_data_t value, st_data_t extra_arg) {
724
807
  heap_recorder *recorder = (heap_recorder *) extra_arg;
725
- object_record_free(recorder, (object_record *) value);
808
+ object_record_free(recorder, (object_record *) value, false);
726
809
  return ST_DELETE;
727
810
  }
728
811
 
729
812
  // NOTE: Some operations inside this function can cause the GVL to be released! Plan accordingly.
730
813
  static int st_object_record_update(st_data_t key, st_data_t value, st_data_t extra_arg) {
731
- long obj_id = (long) key;
814
+ long record_id = (long) key;
732
815
  object_record *record = (object_record*) value;
733
816
  heap_recorder *recorder = (heap_recorder*) extra_arg;
734
817
 
735
- VALUE ref;
736
-
737
818
  size_t update_gen = recorder->update_gen;
738
819
  size_t alloc_gen = record->object_data.alloc_gen;
739
820
  // Guard against potential overflows given unsigned types here.
@@ -752,8 +833,10 @@ static int st_object_record_update(st_data_t key, st_data_t value, st_data_t ext
752
833
  return ST_CONTINUE;
753
834
  }
754
835
 
755
- if (!ruby_ref_from_id(LONG2NUM(obj_id), &ref)) { // Note: This function call can cause the GVL to be released
756
- // Id no longer associated with a valid ref. Need to delete this object record!
836
+ // Note: This function call can cause the GVL to be released
837
+ VALUE ref = ruby_weak_map_get_may_lose_gvl(recorder->weak_objects, LONG2FIX(record_id));
838
+ if (ref == Qnil) {
839
+ // The weak reference is gone, meaning the object was garbage collected. Need to delete this object record!
757
840
  on_committed_object_record_cleanup(recorder, record);
758
841
  recorder->stats_last_update.objects_dead++;
759
842
  return ST_DELETE;
@@ -836,15 +919,6 @@ static int st_object_records_debug(DDTRACE_UNUSED st_data_t key, st_data_t value
836
919
  return ST_CONTINUE;
837
920
  }
838
921
 
839
- static int update_object_record_entry(DDTRACE_UNUSED st_data_t *key, st_data_t *value, st_data_t new_object_record, int existing) {
840
- if (!existing) {
841
- (*value) = (st_data_t) new_object_record; // Expected to be a `object_record *`
842
- } else {
843
- // If key already existed, we don't touch the existing value, so it can be used for diagnostics
844
- }
845
- return ST_CONTINUE;
846
- }
847
-
848
922
  static void inc_tracked_objects_or_fail(heap_record *heap_record) {
849
923
  if (heap_record->num_tracked_objects == UINT32_MAX) {
850
924
  raise_error(rb_eRuntimeError, "Reached maximum number of tracked objects for heap record");
@@ -852,21 +926,12 @@ static void inc_tracked_objects_or_fail(heap_record *heap_record) {
852
926
  heap_record->num_tracked_objects++;
853
927
  }
854
928
 
855
- static void commit_recording(heap_recorder *heap_recorder, heap_record *heap_record, object_record *active_recording) {
856
- // Link the object record with the corresponding heap record. This was the last remaining thing we
857
- // needed to fully build the object_record.
858
- active_recording->heap_record = heap_record;
859
-
860
- int existing_error = st_update(heap_recorder->object_records, active_recording->obj_id, update_object_record_entry, (st_data_t) active_recording);
861
- if (existing_error) {
862
- object_record *existing_record = NULL;
863
- st_lookup(heap_recorder->object_records, active_recording->obj_id, (st_data_t *) &existing_record);
864
- if (existing_record == NULL) raise_error(rb_eRuntimeError, "Unexpected NULL when reading existing record");
865
-
866
- VALUE existing_inspect = object_record_inspect(heap_recorder, existing_record);
867
- VALUE new_inspect = object_record_inspect(heap_recorder, active_recording);
868
- raise_error(rb_eRuntimeError, "Object ids are supposed to be unique. We got 2 allocation recordings with "
869
- "the same id. previous={%"PRIsVALUE"} new={%"PRIsVALUE"}", existing_inspect, new_inspect);
929
+ static void commit_recording(heap_recorder *heap_recorder, pending_recording pending) {
930
+ object_record *new_record = object_record_new(pending);
931
+
932
+ int existing = st_insert(heap_recorder->object_records, new_record->record_id, (st_data_t) new_record);
933
+ if (existing) {
934
+ raise_error(rb_eRuntimeError, "Unexpected record with the same record_id in heap_recorder->object_records");
870
935
  }
871
936
  }
872
937
 
@@ -886,9 +951,9 @@ static heap_record* get_or_create_heap_record(heap_recorder *heap_recorder, ddog
886
951
  heap_record *stack = heap_record_new(heap_recorder, locations);
887
952
 
888
953
  heap_record *new_or_existing_record = NULL; // Will be set inside update_heap_record_entry_with_new_allocation
889
- bool existing = st_update(heap_recorder->heap_records, (st_data_t) stack, update_heap_record_entry_with_new_allocation, (st_data_t) &new_or_existing_record);
954
+ int existing = st_update(heap_recorder->heap_records, (st_data_t) stack, update_heap_record_entry_with_new_allocation, (st_data_t) &new_or_existing_record);
890
955
  if (existing) {
891
- heap_record_free(heap_recorder, stack);
956
+ heap_record_free(heap_recorder, stack, true);
892
957
  }
893
958
 
894
959
  return new_or_existing_record;
@@ -903,7 +968,7 @@ static void cleanup_heap_record_if_unused(heap_recorder *heap_recorder, heap_rec
903
968
  if (!st_delete(heap_recorder->heap_records, (st_data_t*) &heap_record, NULL)) {
904
969
  raise_error(rb_eRuntimeError, "Attempted to cleanup an untracked heap_record");
905
970
  };
906
- heap_record_free(heap_recorder, heap_record);
971
+ heap_record_free(heap_recorder, heap_record, true);
907
972
  }
908
973
 
909
974
  static void on_committed_object_record_cleanup(heap_recorder *heap_recorder, object_record *record) {
@@ -925,32 +990,37 @@ static void on_committed_object_record_cleanup(heap_recorder *heap_recorder, obj
925
990
  // One less object using this heap record, it may have become unused...
926
991
  cleanup_heap_record_if_unused(heap_recorder, heap_record);
927
992
 
928
- object_record_free(heap_recorder, record);
993
+ object_record_free(heap_recorder, record, true);
929
994
  }
930
995
 
931
996
  // =================
932
997
  // Object Record API
933
998
  // =================
934
- object_record* object_record_new(long obj_id, heap_record *heap_record, live_object_data object_data) {
999
+ static object_record* object_record_new(pending_recording pending) {
935
1000
  object_record *record = calloc(1, sizeof(object_record)); // See "note on calloc vs ruby_xcalloc use" above
936
- record->obj_id = obj_id;
937
- record->heap_record = heap_record;
938
- record->object_data = object_data;
1001
+ record->record_id = pending.record_id;
1002
+ // Link the object record with the corresponding heap record
1003
+ record->heap_record = pending.heap_record;
1004
+ record->object_data = pending.object_data;
939
1005
  return record;
940
1006
  }
941
1007
 
942
- void object_record_free(heap_recorder *recorder, object_record *record) {
943
- unintern_or_raise(recorder, record->object_data.class);
1008
+ static void object_record_free(heap_recorder *recorder, object_record *record, bool should_unintern) {
1009
+ // When tearing down the whole recorder state, we skip uninterning as it's not needed (the managed
1010
+ // string table is going to be destroyed anyway) and if there's any failures we can't raise
1011
+ // in the middle of a dfree callback.
1012
+ if (should_unintern) unintern_or_raise(recorder, record->object_data.class);
1013
+
944
1014
  free(record); // See "note on calloc vs ruby_xcalloc use" above
945
1015
  }
946
1016
 
947
- VALUE object_record_inspect(heap_recorder *recorder, object_record *record) {
1017
+ static VALUE object_record_inspect(heap_recorder *recorder, object_record *record) {
948
1018
  heap_frame top_frame = record->heap_record->frames[0];
949
1019
  VALUE filename = get_ruby_string_or_raise(recorder, top_frame.filename);
950
1020
  live_object_data object_data = record->object_data;
951
1021
 
952
- VALUE inspect = rb_sprintf("obj_id=%ld weight=%d size=%zu location=%"PRIsVALUE":%d alloc_gen=%zu gen_age=%zu frozen=%d ",
953
- record->obj_id, object_data.weight, object_data.size, filename,
1022
+ VALUE inspect = rb_sprintf("record_id=%ld weight=%d size=%zu location=%"PRIsVALUE":%d alloc_gen=%zu gen_age=%zu frozen=%d ",
1023
+ record->record_id, object_data.weight, object_data.size, filename,
954
1024
  (int) top_frame.line, object_data.alloc_gen, object_data.gen_age, object_data.is_frozen);
955
1025
 
956
1026
  if (record->object_data.class.value > 0) {
@@ -958,9 +1028,9 @@ VALUE object_record_inspect(heap_recorder *recorder, object_record *record) {
958
1028
 
959
1029
  rb_str_catf(inspect, "class=%"PRIsVALUE" ", class);
960
1030
  }
961
- VALUE ref;
962
1031
 
963
- if (!ruby_ref_from_id(LONG2NUM(record->obj_id), &ref)) {
1032
+ VALUE ref = ruby_weak_map_get_may_lose_gvl(recorder->weak_objects, LONG2FIX(record->record_id));
1033
+ if (ref == Qnil) {
964
1034
  rb_str_catf(inspect, "object=<invalid>");
965
1035
  } else {
966
1036
  rb_str_catf(inspect, "value=%p ", (void *) ref);
@@ -978,7 +1048,7 @@ VALUE object_record_inspect(heap_recorder *recorder, object_record *record) {
978
1048
  // ==============
979
1049
  // Heap Record API
980
1050
  // ==============
981
- heap_record* heap_record_new(heap_recorder *recorder, ddog_prof_Slice_Location locations) {
1051
+ static heap_record* heap_record_new(heap_recorder *recorder, ddog_prof_Slice_Location locations) {
982
1052
  uint16_t frames_len = locations.len;
983
1053
  if (frames_len > MAX_FRAMES_LIMIT) {
984
1054
  // This is not expected as MAX_FRAMES_LIMIT is shared with the stacktrace construction mechanism
@@ -1012,22 +1082,27 @@ heap_record* heap_record_new(heap_recorder *recorder, ddog_prof_Slice_Location l
1012
1082
  return stack;
1013
1083
  }
1014
1084
 
1015
- void heap_record_free(heap_recorder *recorder, heap_record *stack) {
1016
- ddog_prof_ManagedStringId *ids = recorder->reusable_ids;
1017
-
1018
- // Put all the ids in the same array; doesn't really matter the order
1019
- for (u_int16_t i = 0; i < stack->frames_len; i++) {
1020
- ids[i] = stack->frames[i].filename;
1021
- ids[i + stack->frames_len] = stack->frames[i].name;
1085
+ static void heap_record_free(heap_recorder *recorder, heap_record *stack, bool should_unintern) {
1086
+ // When tearing down the whole recorder state, we skip uninterning as it's not needed (the managed
1087
+ // string table is going to be destroyed anyway) and if there's any failures we can't raise
1088
+ // in the middle of a dfree callback.
1089
+ if (should_unintern) {
1090
+ ddog_prof_ManagedStringId *ids = recorder->reusable_ids;
1091
+
1092
+ // Put all the ids in the same array; doesn't really matter the order
1093
+ for (u_int16_t i = 0; i < stack->frames_len; i++) {
1094
+ ids[i] = stack->frames[i].filename;
1095
+ ids[i + stack->frames_len] = stack->frames[i].name;
1096
+ }
1097
+ unintern_all_or_raise(recorder, (ddog_prof_Slice_ManagedStringId) { .ptr = ids, .len = stack->frames_len * 2 });
1022
1098
  }
1023
- unintern_all_or_raise(recorder, (ddog_prof_Slice_ManagedStringId) { .ptr = ids, .len = stack->frames_len * 2 });
1024
1099
 
1025
1100
  free(stack); // See "note on calloc vs ruby_xcalloc use" above
1026
1101
  }
1027
1102
 
1028
1103
  // The entire stack is represented by ids (name, filename) and lines (integers) so we can treat is as just
1029
1104
  // a big string of bytes and compare it all in one go.
1030
- int heap_record_cmp_st(st_data_t key1, st_data_t key2) {
1105
+ static int heap_record_cmp_st(st_data_t key1, st_data_t key2) {
1031
1106
  heap_record *stack1 = (heap_record*) key1;
1032
1107
  heap_record *stack2 = (heap_record*) key2;
1033
1108
 
@@ -1043,7 +1118,7 @@ int heap_record_cmp_st(st_data_t key1, st_data_t key2) {
1043
1118
 
1044
1119
  // The entire stack is represented by ids (name, filename) and lines (integers) so we can treat is as just
1045
1120
  // a big string of bytes and hash it all in one go.
1046
- st_index_t heap_record_hash_st(st_data_t key) {
1121
+ static st_index_t heap_record_hash_st(st_data_t key) {
1047
1122
  heap_record *stack = (heap_record*) key;
1048
1123
  return st_hash(stack->frames, stack->frames_len * sizeof(heap_frame), FNV1_32A_INIT);
1049
1124
  }
@@ -1075,29 +1150,68 @@ static VALUE get_ruby_string_or_raise(heap_recorder *recorder, ddog_prof_Managed
1075
1150
  return ruby_string;
1076
1151
  }
1077
1152
 
1078
- static long obj_id_or_fail(VALUE obj) {
1079
- VALUE ruby_obj_id = rb_obj_id(obj);
1080
- if (!FIXNUM_P(ruby_obj_id)) {
1081
- // Bignum object ids indicate the fixnum range is exhausted - all future IDs will also be bignums.
1082
- // Heap profiling cannot continue.
1083
- raise_error(rb_eRuntimeError, "Heap profiling: bignum object id detected. Heap profiling cannot continue.");
1153
+ static inline double ewma_stat(double previous, double current) {
1154
+ double alpha = 0.3;
1155
+ return (1 - alpha) * previous + alpha * current;
1156
+ }
1157
+
1158
+ VALUE heap_recorder_testonly_is_object_recorded(heap_recorder *heap_recorder, long record_id) {
1159
+ if (heap_recorder == NULL) {
1160
+ raise_error(rb_eArgError, "heap_recorder is NULL");
1084
1161
  }
1085
1162
 
1086
- return FIX2LONG(ruby_obj_id);
1163
+ // Check if object records contains an object with this record_id
1164
+ return st_is_member(heap_recorder->object_records, record_id) ? Qtrue : Qfalse;
1087
1165
  }
1088
1166
 
1089
- static inline double ewma_stat(double previous, double current) {
1090
- double alpha = 0.3;
1091
- return (1 - alpha) * previous + alpha * current;
1167
+ typedef struct {
1168
+ heap_recorder *recorder;
1169
+ VALUE target;
1170
+ VALUE result;
1171
+ } record_id_for_context;
1172
+
1173
+ static int st_object_record_id_for(st_data_t key, DDTRACE_UNUSED st_data_t value, st_data_t extra) {
1174
+ record_id_for_context *context = (record_id_for_context*) extra;
1175
+ long record_id = (long) key;
1176
+
1177
+ VALUE ref = ruby_weak_map_get_may_lose_gvl(context->recorder->weak_objects, LONG2FIX(record_id));
1178
+ if (ref != Qnil && ref == context->target) {
1179
+ context->result = LONG2FIX(record_id);
1180
+ return ST_STOP;
1181
+ }
1182
+
1183
+ return ST_CONTINUE;
1184
+ }
1185
+
1186
+ VALUE heap_recorder_testonly_record_id_for(heap_recorder *heap_recorder, VALUE obj) {
1187
+ // Heap profiling is disabled, so nothing is being tracked
1188
+ if (heap_recorder == NULL) return Qnil;
1189
+
1190
+ record_id_for_context context = (record_id_for_context) {.recorder = heap_recorder, .target = obj, .result = Qnil};
1191
+ st_foreach(heap_recorder->object_records, st_object_record_id_for, (st_data_t) &context);
1192
+
1193
+ return context.result;
1194
+ }
1195
+
1196
+ void heap_recorder_testonly_set_object_alloc_gen(heap_recorder *heap_recorder, long record_id, size_t alloc_gen) {
1197
+ if (heap_recorder == NULL) {
1198
+ raise_error(rb_eArgError, "heap_recorder is NULL");
1199
+ }
1200
+
1201
+ object_record *record = NULL;
1202
+ if (!st_lookup(heap_recorder->object_records, (st_data_t) record_id, (st_data_t *) &record)) {
1203
+ raise_error(rb_eArgError, "record_id %ld is not being tracked", record_id);
1204
+ }
1205
+
1206
+ record->object_data.alloc_gen = alloc_gen;
1092
1207
  }
1093
1208
 
1094
- VALUE heap_recorder_testonly_is_object_recorded(heap_recorder *heap_recorder, VALUE obj_id) {
1209
+ void heap_recorder_testonly_exhaust_record_ids(heap_recorder *heap_recorder) {
1095
1210
  if (heap_recorder == NULL) {
1096
1211
  raise_error(rb_eArgError, "heap_recorder is NULL");
1097
1212
  }
1098
1213
 
1099
- // Check if object records contains an object with this object_id
1100
- return st_is_member(heap_recorder->object_records, FIX2LONG(obj_id)) ? Qtrue : Qfalse;
1214
+ heap_recorder->next_record_id = RUBY_FIXNUM_MAX;
1101
1215
  }
1102
1216
 
1103
1217
  void heap_recorder_testonly_reset_last_update(heap_recorder *heap_recorder) {