datadog 2.28.0 → 2.41.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 (941) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +412 -1
  3. data/bin/ddprofrb +4 -4
  4. data/ext/datadog_profiling_native_extension/clock_id.h +9 -1
  5. data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +66 -0
  6. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -1
  7. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +281 -57
  8. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  9. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +18 -4
  10. data/ext/datadog_profiling_native_extension/collectors_stack.c +245 -160
  11. data/ext/datadog_profiling_native_extension/collectors_stack.h +23 -4
  12. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +725 -432
  13. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +19 -6
  14. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +5 -4
  15. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +44 -19
  16. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +17 -12
  17. data/ext/datadog_profiling_native_extension/extconf.rb +44 -40
  18. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +4 -43
  19. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +15 -47
  20. data/ext/datadog_profiling_native_extension/heap_recorder.c +230 -81
  21. data/ext/datadog_profiling_native_extension/heap_recorder.h +12 -1
  22. data/ext/datadog_profiling_native_extension/http_transport.c +61 -69
  23. data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
  24. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -16
  25. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +300 -108
  26. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +17 -9
  27. data/ext/datadog_profiling_native_extension/profiling.c +44 -5
  28. data/ext/datadog_profiling_native_extension/ruby_helpers.c +40 -34
  29. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +26 -8
  30. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -3
  31. data/ext/datadog_profiling_native_extension/stack_recorder.c +94 -69
  32. data/ext/datadog_profiling_native_extension/stack_recorder.h +3 -1
  33. data/ext/datadog_profiling_native_extension/time_helpers.h +13 -7
  34. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +4 -2
  35. data/ext/libdatadog_api/crashtracker.c +12 -8
  36. data/ext/libdatadog_api/crashtracker_report_exception.c +126 -0
  37. data/ext/libdatadog_api/datadog_ruby_common.c +44 -19
  38. data/ext/libdatadog_api/datadog_ruby_common.h +17 -12
  39. data/ext/libdatadog_api/di.c +203 -0
  40. data/ext/libdatadog_api/extconf.rb +38 -44
  41. data/ext/libdatadog_api/feature_flags.c +26 -0
  42. data/ext/libdatadog_api/init.c +9 -2
  43. data/ext/libdatadog_api/trace_exporter.c +1312 -0
  44. data/ext/libdatadog_api/trace_exporter.h +5 -0
  45. data/ext/libdatadog_extconf_helpers.rb +98 -15
  46. data/lib/datadog/ai_guard/api_client.rb +9 -7
  47. data/lib/datadog/ai_guard/autoload.rb +10 -0
  48. data/lib/datadog/ai_guard/component.rb +11 -9
  49. data/lib/datadog/ai_guard/configuration.rb +106 -2
  50. data/lib/datadog/ai_guard/contrib/auto_instrument.rb +24 -0
  51. data/lib/datadog/ai_guard/contrib/rack/integration.rb +42 -0
  52. data/lib/datadog/ai_guard/contrib/rack/patcher.rb +26 -0
  53. data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +97 -0
  54. data/lib/datadog/ai_guard/contrib/rails/integration.rb +41 -0
  55. data/lib/datadog/ai_guard/contrib/rails/patcher.rb +97 -0
  56. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +41 -3
  57. data/lib/datadog/ai_guard/evaluation/content_builder.rb +31 -0
  58. data/lib/datadog/ai_guard/evaluation/content_part.rb +36 -0
  59. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +3 -1
  60. data/lib/datadog/ai_guard/evaluation/request.rb +22 -17
  61. data/lib/datadog/ai_guard/evaluation/result.rb +3 -1
  62. data/lib/datadog/ai_guard/evaluation.rb +51 -7
  63. data/lib/datadog/ai_guard/ext.rb +15 -0
  64. data/lib/datadog/ai_guard.rb +34 -8
  65. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +22 -43
  66. data/lib/datadog/appsec/actions_handler.rb +6 -6
  67. data/lib/datadog/appsec/anonymizer.rb +1 -1
  68. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +2 -2
  69. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +6 -6
  70. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +1 -1
  71. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +2 -2
  72. data/lib/datadog/appsec/api_security/route_extractor.rb +26 -14
  73. data/lib/datadog/appsec/api_security/sampler.rb +5 -5
  74. data/lib/datadog/appsec/api_security.rb +1 -1
  75. data/lib/datadog/appsec/assets/blocked.html +2 -1
  76. data/lib/datadog/appsec/assets.rb +7 -7
  77. data/lib/datadog/appsec/autoload.rb +4 -4
  78. data/lib/datadog/appsec/component.rb +29 -22
  79. data/lib/datadog/appsec/compressed_json.rb +7 -7
  80. data/lib/datadog/appsec/configuration.rb +436 -1
  81. data/lib/datadog/appsec/context.rb +49 -12
  82. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +6 -6
  83. data/lib/datadog/appsec/contrib/active_record/integration.rb +4 -4
  84. data/lib/datadog/appsec/contrib/active_record/patcher.rb +7 -4
  85. data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +75 -0
  86. data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +39 -0
  87. data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +30 -0
  88. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +146 -0
  89. data/lib/datadog/appsec/contrib/devise/configuration.rb +1 -1
  90. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +3 -3
  91. data/lib/datadog/appsec/contrib/devise/ext.rb +20 -20
  92. data/lib/datadog/appsec/contrib/devise/integration.rb +5 -5
  93. data/lib/datadog/appsec/contrib/devise/patcher.rb +8 -8
  94. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +14 -13
  95. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +8 -8
  96. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +24 -9
  97. data/lib/datadog/appsec/contrib/excon/integration.rb +4 -4
  98. data/lib/datadog/appsec/contrib/excon/patcher.rb +3 -1
  99. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +118 -14
  100. data/lib/datadog/appsec/contrib/faraday/integration.rb +5 -5
  101. data/lib/datadog/appsec/contrib/faraday/patcher.rb +4 -4
  102. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +119 -12
  103. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +4 -4
  104. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +76 -26
  105. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +7 -7
  106. data/lib/datadog/appsec/contrib/graphql/integration.rb +10 -9
  107. data/lib/datadog/appsec/contrib/graphql/patcher.rb +3 -3
  108. data/lib/datadog/appsec/contrib/rack/buffered_input.rb +83 -0
  109. data/lib/datadog/appsec/contrib/rack/ext.rb +29 -29
  110. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +56 -21
  111. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +1 -1
  112. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +46 -30
  113. data/lib/datadog/appsec/contrib/rack/input_peeker.rb +79 -0
  114. data/lib/datadog/appsec/contrib/rack/integration.rb +7 -7
  115. data/lib/datadog/appsec/contrib/rack/patcher.rb +3 -3
  116. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +11 -8
  117. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +63 -52
  118. data/lib/datadog/appsec/contrib/rack/response_body.rb +36 -0
  119. data/lib/datadog/appsec/contrib/rails/gateway/request.rb +43 -4
  120. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +25 -9
  121. data/lib/datadog/appsec/contrib/rails/integration.rb +6 -6
  122. data/lib/datadog/appsec/contrib/rails/patcher.rb +17 -17
  123. data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +3 -1
  124. data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +3 -3
  125. data/lib/datadog/appsec/contrib/rails/request.rb +3 -3
  126. data/lib/datadog/appsec/contrib/rails/request_middleware.rb +2 -1
  127. data/lib/datadog/appsec/contrib/rest_client/integration.rb +5 -5
  128. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +3 -1
  129. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +131 -13
  130. data/lib/datadog/appsec/contrib/sinatra/gateway/request.rb +1 -1
  131. data/lib/datadog/appsec/contrib/sinatra/gateway/route_params.rb +1 -1
  132. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +35 -12
  133. data/lib/datadog/appsec/contrib/sinatra/integration.rb +5 -5
  134. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +11 -11
  135. data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +3 -3
  136. data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
  137. data/lib/datadog/appsec/counter_sampler.rb +25 -0
  138. data/lib/datadog/appsec/default_header_tags.rb +52 -0
  139. data/lib/datadog/appsec/event.rb +15 -31
  140. data/lib/datadog/appsec/ext.rb +11 -10
  141. data/lib/datadog/appsec/extensions.rb +2 -2
  142. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +2 -3
  143. data/lib/datadog/appsec/instrumentation/gateway.rb +3 -16
  144. data/lib/datadog/appsec/metrics/collector.rb +18 -1
  145. data/lib/datadog/appsec/metrics/exporter.rb +17 -11
  146. data/lib/datadog/appsec/metrics/telemetry.rb +15 -3
  147. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +20 -2
  148. data/lib/datadog/appsec/metrics.rb +4 -4
  149. data/lib/datadog/appsec/monitor/gateway/watcher.rb +18 -12
  150. data/lib/datadog/appsec/monitor.rb +1 -1
  151. data/lib/datadog/appsec/processor/rule_loader.rb +32 -32
  152. data/lib/datadog/appsec/rate_limiter.rb +1 -1
  153. data/lib/datadog/appsec/remote.rb +15 -9
  154. data/lib/datadog/appsec/response.rb +22 -22
  155. data/lib/datadog/appsec/route_normalizer/rails_route_pattern.rb +176 -0
  156. data/lib/datadog/appsec/route_normalizer/route_pattern.rb +378 -0
  157. data/lib/datadog/appsec/route_normalizer/route_text.rb +57 -0
  158. data/lib/datadog/appsec/route_normalizer.rb +80 -0
  159. data/lib/datadog/appsec/security_engine/engine.rb +54 -33
  160. data/lib/datadog/appsec/security_engine/runner.rb +3 -3
  161. data/lib/datadog/appsec/security_event.rb +2 -2
  162. data/lib/datadog/appsec/trace_keeper.rb +18 -6
  163. data/lib/datadog/appsec/utils/http/body.rb +41 -0
  164. data/lib/datadog/appsec/utils/http/body_reader.rb +61 -0
  165. data/lib/datadog/appsec/utils/http/media_range.rb +17 -16
  166. data/lib/datadog/appsec/utils/http/media_type.rb +28 -36
  167. data/lib/datadog/appsec/utils/http/url_encoded.rb +107 -0
  168. data/lib/datadog/appsec.rb +21 -24
  169. data/lib/datadog/auto_instrument.rb +2 -2
  170. data/lib/datadog/core/buffer/cruby.rb +1 -1
  171. data/lib/datadog/core/buffer/thread_safe.rb +1 -1
  172. data/lib/datadog/core/configuration/agent_settings.rb +1 -1
  173. data/lib/datadog/core/configuration/agent_settings_resolver.rb +15 -15
  174. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +2 -2
  175. data/lib/datadog/core/configuration/base.rb +19 -7
  176. data/lib/datadog/core/configuration/components.rb +166 -36
  177. data/lib/datadog/core/configuration/components_state.rb +6 -1
  178. data/lib/datadog/core/configuration/config_helper.rb +12 -3
  179. data/lib/datadog/core/configuration/deprecations.rb +6 -6
  180. data/lib/datadog/core/configuration/ext.rb +11 -11
  181. data/lib/datadog/core/configuration/option.rb +48 -22
  182. data/lib/datadog/core/configuration/option_definition.rb +43 -17
  183. data/lib/datadog/core/configuration/options.rb +43 -9
  184. data/lib/datadog/core/configuration/settings.rb +155 -106
  185. data/lib/datadog/core/configuration/stable_config.rb +1 -1
  186. data/lib/datadog/core/configuration/supported_configurations.rb +44 -1
  187. data/lib/datadog/core/configuration.rb +11 -11
  188. data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
  189. data/lib/datadog/core/contrib/rails/utils.rb +7 -3
  190. data/lib/datadog/core/crashtracking/component.rb +78 -26
  191. data/lib/datadog/core/crashtracking/tag_builder.rb +5 -5
  192. data/lib/datadog/core/deprecations.rb +1 -1
  193. data/lib/datadog/core/diagnostics/environment_logger.rb +45 -8
  194. data/lib/datadog/core/diagnostics/health.rb +2 -2
  195. data/lib/datadog/core/encoding.rb +4 -4
  196. data/lib/datadog/core/environment/agent_info.rb +65 -1
  197. data/lib/datadog/core/environment/cgroup.rb +4 -4
  198. data/lib/datadog/core/environment/container.rb +11 -11
  199. data/lib/datadog/core/environment/execution.rb +3 -3
  200. data/lib/datadog/core/environment/ext.rb +21 -15
  201. data/lib/datadog/core/environment/gc.rb +1 -1
  202. data/lib/datadog/core/environment/git.rb +2 -2
  203. data/lib/datadog/core/environment/identity.rb +47 -11
  204. data/lib/datadog/core/environment/platform.rb +8 -8
  205. data/lib/datadog/core/environment/process.rb +54 -19
  206. data/lib/datadog/core/environment/socket.rb +15 -2
  207. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  208. data/lib/datadog/core/environment/vm_cache.rb +1 -1
  209. data/lib/datadog/core/environment/yjit.rb +2 -2
  210. data/lib/datadog/core/error.rb +5 -5
  211. data/lib/datadog/core/evp.rb +11 -0
  212. data/lib/datadog/core/extensions.rb +1 -1
  213. data/lib/datadog/core/feature_flags.rb +3 -3
  214. data/lib/datadog/core/git/ext.rb +4 -4
  215. data/lib/datadog/core/knuth_sampler.rb +3 -1
  216. data/lib/datadog/core/logger.rb +4 -4
  217. data/lib/datadog/core/logging/ext.rb +1 -1
  218. data/lib/datadog/core/metrics/client.rb +26 -26
  219. data/lib/datadog/core/metrics/ext.rb +5 -5
  220. data/lib/datadog/core/metrics/helpers.rb +1 -1
  221. data/lib/datadog/core/metrics/logging.rb +3 -3
  222. data/lib/datadog/core/metrics/options.rb +5 -5
  223. data/lib/datadog/core/pin.rb +1 -1
  224. data/lib/datadog/core/process_discovery.rb +23 -22
  225. data/lib/datadog/core/rate_limiter.rb +3 -1
  226. data/lib/datadog/core/remote/client/capabilities.rb +67 -15
  227. data/lib/datadog/core/remote/client.rb +18 -18
  228. data/lib/datadog/core/remote/component.rb +70 -34
  229. data/lib/datadog/core/remote/configuration/content.rb +3 -3
  230. data/lib/datadog/core/remote/configuration/digest.rb +1 -1
  231. data/lib/datadog/core/remote/configuration/path.rb +9 -9
  232. data/lib/datadog/core/remote/configuration/repository.rb +4 -4
  233. data/lib/datadog/core/remote/configuration/target.rb +9 -9
  234. data/lib/datadog/core/remote/configuration.rb +4 -4
  235. data/lib/datadog/core/remote/ext.rb +3 -3
  236. data/lib/datadog/core/remote/negotiation.rb +1 -1
  237. data/lib/datadog/core/remote/tie/tracing.rb +7 -7
  238. data/lib/datadog/core/remote/transport/config.rb +9 -15
  239. data/lib/datadog/core/remote/transport/http/config.rb +10 -10
  240. data/lib/datadog/core/remote/transport/http/negotiation.rb +4 -4
  241. data/lib/datadog/core/remote/transport/http.rb +10 -10
  242. data/lib/datadog/core/remote/transport/negotiation.rb +3 -3
  243. data/lib/datadog/core/remote/worker.rb +5 -5
  244. data/lib/datadog/core/runtime/ext.rb +22 -22
  245. data/lib/datadog/core/runtime/metrics.rb +11 -12
  246. data/lib/datadog/core/tag_builder.rb +18 -18
  247. data/lib/datadog/core/tag_normalizer.rb +7 -7
  248. data/lib/datadog/core/telemetry/component.rb +16 -26
  249. data/lib/datadog/core/telemetry/configuration_value.rb +38 -0
  250. data/lib/datadog/core/telemetry/emitter.rb +5 -5
  251. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +10 -9
  252. data/lib/datadog/core/telemetry/event/app_closing.rb +2 -2
  253. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +2 -2
  254. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +3 -3
  255. data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
  256. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +2 -2
  257. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +2 -2
  258. data/lib/datadog/core/telemetry/event/app_started.rb +142 -193
  259. data/lib/datadog/core/telemetry/event/base.rb +1 -1
  260. data/lib/datadog/core/telemetry/event/distributions.rb +2 -2
  261. data/lib/datadog/core/telemetry/event/generate_metrics.rb +3 -3
  262. data/lib/datadog/core/telemetry/event/log.rb +6 -6
  263. data/lib/datadog/core/telemetry/event/message_batch.rb +1 -1
  264. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +3 -3
  265. data/lib/datadog/core/telemetry/event.rb +16 -22
  266. data/lib/datadog/core/telemetry/ext.rb +11 -10
  267. data/lib/datadog/core/telemetry/logger.rb +1 -1
  268. data/lib/datadog/core/telemetry/logging.rb +5 -5
  269. data/lib/datadog/core/telemetry/metric.rb +9 -9
  270. data/lib/datadog/core/telemetry/metrics_collection.rb +2 -2
  271. data/lib/datadog/core/telemetry/metrics_manager.rb +1 -1
  272. data/lib/datadog/core/telemetry/request.rb +6 -8
  273. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +16 -11
  274. data/lib/datadog/core/telemetry/transport/http.rb +7 -7
  275. data/lib/datadog/core/telemetry/transport/telemetry.rb +8 -9
  276. data/lib/datadog/core/telemetry/worker.rb +26 -6
  277. data/lib/datadog/core/transport/ext.rb +14 -13
  278. data/lib/datadog/core/transport/http/adapters/net.rb +4 -4
  279. data/lib/datadog/core/transport/http/adapters/test.rb +1 -1
  280. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +4 -4
  281. data/lib/datadog/core/transport/http/api/endpoint.rb +1 -1
  282. data/lib/datadog/core/transport/http/api/map.rb +1 -1
  283. data/lib/datadog/core/transport/http/builder.rb +6 -6
  284. data/lib/datadog/core/transport/http/client.rb +2 -2
  285. data/lib/datadog/core/transport/http/response.rb +5 -1
  286. data/lib/datadog/core/transport/http.rb +9 -7
  287. data/lib/datadog/core/transport/parcel.rb +61 -9
  288. data/lib/datadog/core/transport/response.rb +1 -1
  289. data/lib/datadog/core/transport/transport.rb +2 -2
  290. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +172 -20
  291. data/lib/datadog/core/utils/base64_codec.rb +23 -0
  292. data/lib/datadog/core/utils/duration.rb +1 -1
  293. data/lib/datadog/core/utils/{array.rb → enumerable_compat.rb} +2 -2
  294. data/lib/datadog/core/utils/fnv.rb +26 -0
  295. data/lib/datadog/core/utils/forking.rb +3 -1
  296. data/lib/datadog/core/utils/hash.rb +0 -23
  297. data/lib/datadog/core/utils/lru_cache.rb +3 -3
  298. data/lib/datadog/core/utils/network.rb +11 -11
  299. data/lib/datadog/core/utils/only_once.rb +1 -1
  300. data/lib/datadog/core/utils/only_once_successful.rb +1 -1
  301. data/lib/datadog/core/utils/safe_dup.rb +2 -1
  302. data/lib/datadog/core/utils/sequence.rb +3 -6
  303. data/lib/datadog/core/utils/spawn_monkey_patch.rb +68 -0
  304. data/lib/datadog/core/utils/time.rb +18 -52
  305. data/lib/datadog/core/utils/url.rb +1 -1
  306. data/lib/datadog/core/utils.rb +5 -5
  307. data/lib/datadog/core/workers/async.rb +2 -2
  308. data/lib/datadog/core/workers/interval_loop.rb +13 -6
  309. data/lib/datadog/core/workers/polling.rb +2 -2
  310. data/lib/datadog/core/workers/queue.rb +0 -4
  311. data/lib/datadog/core/workers/runtime_metrics.rb +13 -5
  312. data/lib/datadog/core.rb +13 -6
  313. data/lib/datadog/data_streams/configuration.rb +40 -1
  314. data/lib/datadog/data_streams/ext.rb +1 -1
  315. data/lib/datadog/data_streams/extensions.rb +2 -2
  316. data/lib/datadog/data_streams/pathway_context.rb +8 -8
  317. data/lib/datadog/data_streams/processor.rb +87 -85
  318. data/lib/datadog/data_streams/transport/http/stats.rb +9 -3
  319. data/lib/datadog/data_streams/transport/http.rb +5 -9
  320. data/lib/datadog/data_streams/transport/stats.rb +10 -17
  321. data/lib/datadog/data_streams.rb +5 -5
  322. data/lib/datadog/di/base.rb +16 -8
  323. data/lib/datadog/di/boot.rb +25 -23
  324. data/lib/datadog/di/capture_expression.rb +21 -0
  325. data/lib/datadog/di/capture_expression_evaluator.rb +71 -0
  326. data/lib/datadog/di/capture_limits.rb +41 -0
  327. data/lib/datadog/di/code_tracker.rb +218 -16
  328. data/lib/datadog/di/component.rb +137 -39
  329. data/lib/datadog/di/configuration.rb +241 -2
  330. data/lib/datadog/di/context.rb +15 -3
  331. data/lib/datadog/di/contrib/active_record.rb +6 -2
  332. data/lib/datadog/di/contrib/railtie.rb +1 -1
  333. data/lib/datadog/di/contrib.rb +5 -5
  334. data/lib/datadog/di/el/compiler.rb +114 -38
  335. data/lib/datadog/di/el/evaluator.rb +82 -2
  336. data/lib/datadog/di/el/expression.rb +13 -2
  337. data/lib/datadog/di/el.rb +3 -3
  338. data/lib/datadog/di/error.rb +10 -0
  339. data/lib/datadog/di/fatal_exceptions.rb +26 -0
  340. data/lib/datadog/di/instrumenter.rb +608 -255
  341. data/lib/datadog/di/logger.rb +1 -1
  342. data/lib/datadog/di/preload.rb +1 -1
  343. data/lib/datadog/di/probe.rb +71 -3
  344. data/lib/datadog/di/probe_builder.rb +98 -15
  345. data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
  346. data/lib/datadog/di/probe_file_loader.rb +16 -11
  347. data/lib/datadog/di/probe_manager.rb +153 -73
  348. data/lib/datadog/di/probe_notification_builder.rb +218 -38
  349. data/lib/datadog/di/probe_notifier_worker.rb +111 -35
  350. data/lib/datadog/di/probe_repository.rb +198 -0
  351. data/lib/datadog/di/proc_responder.rb +4 -0
  352. data/lib/datadog/di/redactor.rb +16 -1
  353. data/lib/datadog/di/remote.rb +193 -33
  354. data/lib/datadog/di/serializer.rb +201 -39
  355. data/lib/datadog/di/transport/diagnostics.rb +10 -12
  356. data/lib/datadog/di/transport/http/diagnostics.rb +5 -3
  357. data/lib/datadog/di/transport/http/input.rb +3 -3
  358. data/lib/datadog/di/transport/http.rb +22 -13
  359. data/lib/datadog/di/transport/input.rb +65 -24
  360. data/lib/datadog/di/utils.rb +43 -15
  361. data/lib/datadog/di.rb +147 -3
  362. data/lib/datadog/error_tracking/collector.rb +3 -2
  363. data/lib/datadog/error_tracking/component.rb +12 -12
  364. data/lib/datadog/error_tracking/configuration.rb +55 -2
  365. data/lib/datadog/error_tracking/ext.rb +7 -7
  366. data/lib/datadog/error_tracking/extensions.rb +2 -2
  367. data/lib/datadog/error_tracking/filters.rb +4 -4
  368. data/lib/datadog/error_tracking.rb +6 -6
  369. data/lib/datadog/kit/appsec/events/v2.rb +91 -33
  370. data/lib/datadog/kit/appsec/events.rb +25 -25
  371. data/lib/datadog/kit/enable_core_dumps.rb +3 -3
  372. data/lib/datadog/kit/identity.rb +18 -18
  373. data/lib/datadog/kit/tracing/method_tracer.rb +135 -0
  374. data/lib/datadog/kit.rb +1 -1
  375. data/lib/datadog/open_feature/component.rb +62 -13
  376. data/lib/datadog/open_feature/configuration.rb +24 -1
  377. data/lib/datadog/open_feature/evaluation_engine.rb +9 -9
  378. data/lib/datadog/open_feature/exposures/batch_builder.rb +1 -1
  379. data/lib/datadog/open_feature/exposures/buffer.rb +1 -1
  380. data/lib/datadog/open_feature/exposures/deduplicator.rb +1 -1
  381. data/lib/datadog/open_feature/exposures/event.rb +7 -7
  382. data/lib/datadog/open_feature/exposures/reporter.rb +3 -3
  383. data/lib/datadog/open_feature/exposures/worker.rb +6 -6
  384. data/lib/datadog/open_feature/ext.rb +13 -6
  385. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +286 -0
  386. data/lib/datadog/open_feature/flag_evaluation/writer.rb +433 -0
  387. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +102 -0
  388. data/lib/datadog/open_feature/hooks/flag_eval_metrics_hook.rb +51 -0
  389. data/lib/datadog/open_feature/hooks/span_enrichment_hook/codec.rb +58 -0
  390. data/lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb +96 -0
  391. data/lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state_store.rb +49 -0
  392. data/lib/datadog/open_feature/hooks/span_enrichment_hook.rb +184 -0
  393. data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
  394. data/lib/datadog/open_feature/native_evaluator.rb +23 -1
  395. data/lib/datadog/open_feature/noop_evaluator.rb +3 -3
  396. data/lib/datadog/open_feature/provider.rb +106 -21
  397. data/lib/datadog/open_feature/remote.rb +3 -3
  398. data/lib/datadog/open_feature/resolution_details.rb +4 -2
  399. data/lib/datadog/open_feature/transport.rb +73 -22
  400. data/lib/datadog/open_feature.rb +2 -2
  401. data/lib/datadog/opentelemetry/api/baggage.rb +3 -3
  402. data/lib/datadog/opentelemetry/api/context.rb +4 -4
  403. data/lib/datadog/opentelemetry/configuration/settings.rb +95 -28
  404. data/lib/datadog/opentelemetry/ext.rb +9 -0
  405. data/lib/datadog/opentelemetry/logs.rb +98 -0
  406. data/lib/datadog/opentelemetry/metrics.rb +17 -44
  407. data/lib/datadog/opentelemetry/sdk/configurator.rb +46 -6
  408. data/lib/datadog/opentelemetry/sdk/id_generator.rb +16 -10
  409. data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +30 -0
  410. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +9 -16
  411. data/lib/datadog/opentelemetry/sdk/propagator.rb +16 -10
  412. data/lib/datadog/opentelemetry/sdk/span_processor.rb +18 -15
  413. data/lib/datadog/opentelemetry/sdk/trace/span.rb +32 -32
  414. data/lib/datadog/opentelemetry/sdk.rb +19 -0
  415. data/lib/datadog/opentelemetry/signal_configuration.rb +53 -0
  416. data/lib/datadog/opentelemetry/trace.rb +1 -1
  417. data/lib/datadog/opentelemetry.rb +8 -7
  418. data/lib/datadog/profiling/collectors/code_provenance.rb +36 -11
  419. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +50 -3
  420. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +12 -4
  421. data/lib/datadog/profiling/collectors/info.rb +17 -4
  422. data/lib/datadog/profiling/collectors/thread_context.rb +16 -18
  423. data/lib/datadog/profiling/component.rb +62 -33
  424. data/lib/datadog/profiling/exporter.rb +38 -13
  425. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +6 -5
  426. data/lib/datadog/profiling/ext.rb +0 -2
  427. data/lib/datadog/profiling/flush.rb +21 -12
  428. data/lib/datadog/profiling/http_transport.rb +18 -8
  429. data/lib/datadog/profiling/load_native_extension.rb +2 -2
  430. data/lib/datadog/profiling/profiler.rb +28 -13
  431. data/lib/datadog/profiling/scheduler.rb +2 -2
  432. data/lib/datadog/profiling/sequence_tracker.rb +1 -1
  433. data/lib/datadog/profiling/stack_recorder.rb +0 -8
  434. data/lib/datadog/profiling/tag_builder.rb +19 -19
  435. data/lib/datadog/profiling/tasks/exec.rb +9 -4
  436. data/lib/datadog/profiling/tasks/help.rb +1 -0
  437. data/lib/datadog/profiling/tasks/setup.rb +2 -2
  438. data/lib/datadog/profiling.rb +32 -29
  439. data/lib/datadog/ruby_version.rb +25 -0
  440. data/lib/datadog/single_step_instrument.rb +2 -2
  441. data/lib/datadog/symbol_database/component.rb +734 -0
  442. data/lib/datadog/symbol_database/configuration.rb +73 -0
  443. data/lib/datadog/symbol_database/extensions.rb +19 -0
  444. data/lib/datadog/symbol_database/extractor.rb +1110 -0
  445. data/lib/datadog/symbol_database/file_hash.rb +48 -0
  446. data/lib/datadog/symbol_database/logger.rb +43 -0
  447. data/lib/datadog/symbol_database/remote.rb +195 -0
  448. data/lib/datadog/symbol_database/scope.rb +102 -0
  449. data/lib/datadog/symbol_database/scope_batcher.rb +292 -0
  450. data/lib/datadog/symbol_database/service_version.rb +66 -0
  451. data/lib/datadog/symbol_database/symbol.rb +69 -0
  452. data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
  453. data/lib/datadog/symbol_database/transport/http.rb +45 -0
  454. data/lib/datadog/symbol_database/transport.rb +54 -0
  455. data/lib/datadog/symbol_database/uploader.rb +230 -0
  456. data/lib/datadog/symbol_database.rb +71 -0
  457. data/lib/datadog/tracing/analytics.rb +1 -1
  458. data/lib/datadog/tracing/buffer.rb +8 -8
  459. data/lib/datadog/tracing/client_ip.rb +4 -4
  460. data/lib/datadog/tracing/component.rb +39 -7
  461. data/lib/datadog/tracing/configuration/dynamic/option.rb +4 -0
  462. data/lib/datadog/tracing/configuration/dynamic.rb +13 -11
  463. data/lib/datadog/tracing/configuration/ext.rb +52 -38
  464. data/lib/datadog/tracing/configuration/http.rb +2 -2
  465. data/lib/datadog/tracing/configuration/settings.rb +51 -17
  466. data/lib/datadog/tracing/context.rb +1 -1
  467. data/lib/datadog/tracing/context_provider.rb +2 -2
  468. data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +2 -2
  469. data/lib/datadog/tracing/contrib/action_cable/event.rb +4 -4
  470. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +9 -6
  471. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +8 -5
  472. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +9 -6
  473. data/lib/datadog/tracing/contrib/action_cable/events.rb +5 -5
  474. data/lib/datadog/tracing/contrib/action_cable/ext.rb +18 -18
  475. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -5
  476. data/lib/datadog/tracing/contrib/action_cable/integration.rb +7 -7
  477. data/lib/datadog/tracing/contrib/action_cable/patcher.rb +4 -4
  478. data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +2 -2
  479. data/lib/datadog/tracing/contrib/action_mailer/event.rb +7 -4
  480. data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +8 -8
  481. data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +4 -4
  482. data/lib/datadog/tracing/contrib/action_mailer/events.rb +3 -3
  483. data/lib/datadog/tracing/contrib/action_mailer/ext.rb +18 -18
  484. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +7 -7
  485. data/lib/datadog/tracing/contrib/action_mailer/patcher.rb +3 -3
  486. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -12
  487. data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +2 -2
  488. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +31 -3
  489. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +5 -3
  490. data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +3 -3
  491. data/lib/datadog/tracing/contrib/action_pack/ext.rb +10 -10
  492. data/lib/datadog/tracing/contrib/action_pack/integration.rb +7 -7
  493. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +3 -3
  494. data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -1
  495. data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +3 -3
  496. data/lib/datadog/tracing/contrib/action_view/event.rb +1 -1
  497. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +10 -7
  498. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +11 -8
  499. data/lib/datadog/tracing/contrib/action_view/events.rb +3 -3
  500. data/lib/datadog/tracing/contrib/action_view/ext.rb +10 -10
  501. data/lib/datadog/tracing/contrib/action_view/integration.rb +11 -11
  502. data/lib/datadog/tracing/contrib/action_view/patcher.rb +5 -5
  503. data/lib/datadog/tracing/contrib/action_view/utils.rb +2 -2
  504. data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +2 -2
  505. data/lib/datadog/tracing/contrib/active_job/data_streams.rb +62 -0
  506. data/lib/datadog/tracing/contrib/active_job/event.rb +3 -3
  507. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +10 -7
  508. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +10 -7
  509. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +10 -7
  510. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +10 -7
  511. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +10 -7
  512. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +10 -7
  513. data/lib/datadog/tracing/contrib/active_job/events.rb +6 -6
  514. data/lib/datadog/tracing/contrib/active_job/ext.rb +23 -23
  515. data/lib/datadog/tracing/contrib/active_job/integration.rb +7 -7
  516. data/lib/datadog/tracing/contrib/active_job/patcher.rb +17 -5
  517. data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +2 -2
  518. data/lib/datadog/tracing/contrib/active_model_serializers/event.rb +4 -4
  519. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +7 -7
  520. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +8 -9
  521. data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +3 -3
  522. data/lib/datadog/tracing/contrib/active_model_serializers/ext.rb +10 -10
  523. data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +5 -5
  524. data/lib/datadog/tracing/contrib/active_model_serializers/patcher.rb +3 -3
  525. data/lib/datadog/tracing/contrib/active_record/configuration/makara_resolver.rb +1 -1
  526. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +9 -9
  527. data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +4 -4
  528. data/lib/datadog/tracing/contrib/active_record/event.rb +1 -1
  529. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +9 -9
  530. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +11 -14
  531. data/lib/datadog/tracing/contrib/active_record/events.rb +3 -3
  532. data/lib/datadog/tracing/contrib/active_record/ext.rb +15 -15
  533. data/lib/datadog/tracing/contrib/active_record/integration.rb +11 -11
  534. data/lib/datadog/tracing/contrib/active_record/patcher.rb +2 -2
  535. data/lib/datadog/tracing/contrib/active_record/utils.rb +4 -4
  536. data/lib/datadog/tracing/contrib/active_support/cache/event.rb +1 -1
  537. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +14 -17
  538. data/lib/datadog/tracing/contrib/active_support/cache/events.rb +1 -1
  539. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +5 -8
  540. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +5 -5
  541. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +4 -4
  542. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +3 -3
  543. data/lib/datadog/tracing/contrib/active_support/ext.rb +16 -16
  544. data/lib/datadog/tracing/contrib/active_support/integration.rb +8 -8
  545. data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +1 -1
  546. data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +2 -2
  547. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +3 -3
  548. data/lib/datadog/tracing/contrib/active_support/patcher.rb +2 -2
  549. data/lib/datadog/tracing/contrib/analytics.rb +1 -1
  550. data/lib/datadog/tracing/contrib/auto_instrument.rb +4 -4
  551. data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +3 -3
  552. data/lib/datadog/tracing/contrib/aws/ext.rb +26 -26
  553. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +7 -11
  554. data/lib/datadog/tracing/contrib/aws/integration.rb +9 -9
  555. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +1 -1
  556. data/lib/datadog/tracing/contrib/aws/patcher.rb +5 -5
  557. data/lib/datadog/tracing/contrib/aws/service/dynamodb.rb +2 -2
  558. data/lib/datadog/tracing/contrib/aws/service/eventbridge.rb +2 -2
  559. data/lib/datadog/tracing/contrib/aws/service/kinesis.rb +4 -4
  560. data/lib/datadog/tracing/contrib/aws/service/s3.rb +2 -2
  561. data/lib/datadog/tracing/contrib/aws/service/sns.rb +3 -3
  562. data/lib/datadog/tracing/contrib/aws/service/sqs.rb +3 -3
  563. data/lib/datadog/tracing/contrib/aws/service/states.rb +5 -5
  564. data/lib/datadog/tracing/contrib/aws/services.rb +14 -14
  565. data/lib/datadog/tracing/contrib/component.rb +1 -1
  566. data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +1 -1
  567. data/lib/datadog/tracing/contrib/concurrent_ruby/configuration/settings.rb +2 -2
  568. data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -1
  569. data/lib/datadog/tracing/contrib/concurrent_ruby/ext.rb +2 -2
  570. data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +1 -1
  571. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +6 -6
  572. data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +4 -4
  573. data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +1 -1
  574. data/lib/datadog/tracing/contrib/configurable.rb +20 -5
  575. data/lib/datadog/tracing/contrib/configuration/resolver.rb +14 -4
  576. data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +1 -1
  577. data/lib/datadog/tracing/contrib/configuration/settings.rb +2 -2
  578. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +2 -2
  579. data/lib/datadog/tracing/contrib/dalli/ext.rb +13 -13
  580. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +6 -10
  581. data/lib/datadog/tracing/contrib/dalli/integration.rb +10 -7
  582. data/lib/datadog/tracing/contrib/dalli/patcher.rb +3 -3
  583. data/lib/datadog/tracing/contrib/dalli/quantize.rb +3 -3
  584. data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +2 -2
  585. data/lib/datadog/tracing/contrib/delayed_job/ext.rb +14 -14
  586. data/lib/datadog/tracing/contrib/delayed_job/integration.rb +5 -5
  587. data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +3 -3
  588. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +7 -5
  589. data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +1 -0
  590. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +2 -2
  591. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +15 -15
  592. data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +6 -6
  593. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +12 -16
  594. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +4 -4
  595. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +7 -3
  596. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +9 -13
  597. data/lib/datadog/tracing/contrib/ethon/ext.rb +13 -12
  598. data/lib/datadog/tracing/contrib/ethon/integration.rb +6 -6
  599. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +4 -11
  600. data/lib/datadog/tracing/contrib/ethon/patcher.rb +3 -3
  601. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +10 -7
  602. data/lib/datadog/tracing/contrib/excon/ext.rb +11 -10
  603. data/lib/datadog/tracing/contrib/excon/integration.rb +6 -6
  604. data/lib/datadog/tracing/contrib/excon/middleware.rb +10 -14
  605. data/lib/datadog/tracing/contrib/excon/patcher.rb +2 -2
  606. data/lib/datadog/tracing/contrib/ext.rb +20 -18
  607. data/lib/datadog/tracing/contrib/extensions.rb +11 -2
  608. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +9 -6
  609. data/lib/datadog/tracing/contrib/faraday/ext.rb +11 -10
  610. data/lib/datadog/tracing/contrib/faraday/integration.rb +6 -6
  611. data/lib/datadog/tracing/contrib/faraday/middleware.rb +10 -14
  612. data/lib/datadog/tracing/contrib/faraday/patcher.rb +6 -6
  613. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +4 -4
  614. data/lib/datadog/tracing/contrib/grape/endpoint.rb +30 -27
  615. data/lib/datadog/tracing/contrib/grape/ext.rb +15 -15
  616. data/lib/datadog/tracing/contrib/grape/instrumentation.rb +15 -10
  617. data/lib/datadog/tracing/contrib/grape/integration.rb +5 -5
  618. data/lib/datadog/tracing/contrib/grape/patcher.rb +10 -5
  619. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +1 -1
  620. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +3 -3
  621. data/lib/datadog/tracing/contrib/graphql/ext.rb +9 -9
  622. data/lib/datadog/tracing/contrib/graphql/integration.rb +9 -9
  623. data/lib/datadog/tracing/contrib/graphql/patcher.rb +7 -7
  624. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +38 -37
  625. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +2 -2
  626. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +7 -4
  627. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +11 -15
  628. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +11 -15
  629. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +6 -6
  630. data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +1 -1
  631. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +11 -9
  632. data/lib/datadog/tracing/contrib/grpc/ext.rb +14 -13
  633. data/lib/datadog/tracing/contrib/grpc/formatting.rb +7 -7
  634. data/lib/datadog/tracing/contrib/grpc/integration.rb +5 -5
  635. data/lib/datadog/tracing/contrib/grpc/intercept_with_datadog.rb +1 -1
  636. data/lib/datadog/tracing/contrib/grpc/patcher.rb +3 -3
  637. data/lib/datadog/tracing/contrib/grpc.rb +7 -6
  638. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +4 -3
  639. data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +2 -2
  640. data/lib/datadog/tracing/contrib/hanami/ext.rb +8 -8
  641. data/lib/datadog/tracing/contrib/hanami/integration.rb +6 -6
  642. data/lib/datadog/tracing/contrib/hanami/patcher.rb +5 -5
  643. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +4 -3
  644. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +6 -4
  645. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +1 -1
  646. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +9 -6
  647. data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +3 -3
  648. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +10 -8
  649. data/lib/datadog/tracing/contrib/http/ext.rb +11 -10
  650. data/lib/datadog/tracing/contrib/http/instrumentation.rb +10 -14
  651. data/lib/datadog/tracing/contrib/http/integration.rb +7 -9
  652. data/lib/datadog/tracing/contrib/http/patcher.rb +3 -3
  653. data/lib/datadog/tracing/contrib/http.rb +7 -6
  654. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +9 -6
  655. data/lib/datadog/tracing/contrib/httpclient/ext.rb +11 -10
  656. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +12 -12
  657. data/lib/datadog/tracing/contrib/httpclient/integration.rb +6 -6
  658. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +3 -3
  659. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +9 -6
  660. data/lib/datadog/tracing/contrib/httprb/ext.rb +11 -10
  661. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +10 -14
  662. data/lib/datadog/tracing/contrib/httprb/integration.rb +7 -7
  663. data/lib/datadog/tracing/contrib/httprb/patcher.rb +3 -3
  664. data/lib/datadog/tracing/contrib/integration.rb +3 -3
  665. data/lib/datadog/tracing/contrib/kafka/configuration/settings.rb +2 -2
  666. data/lib/datadog/tracing/contrib/kafka/event.rb +4 -3
  667. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +7 -3
  668. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +4 -4
  669. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +4 -4
  670. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +5 -5
  671. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +5 -5
  672. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +5 -5
  673. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +5 -5
  674. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +10 -5
  675. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +10 -5
  676. data/lib/datadog/tracing/contrib/kafka/events.rb +10 -10
  677. data/lib/datadog/tracing/contrib/kafka/ext.rb +40 -40
  678. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +4 -4
  679. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +6 -6
  680. data/lib/datadog/tracing/contrib/kafka/integration.rb +6 -6
  681. data/lib/datadog/tracing/contrib/kafka/patcher.rb +5 -5
  682. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +7 -3
  683. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +11 -9
  684. data/lib/datadog/tracing/contrib/karafka/ext.rb +13 -12
  685. data/lib/datadog/tracing/contrib/karafka/integration.rb +5 -5
  686. data/lib/datadog/tracing/contrib/karafka/monitor.rb +14 -14
  687. data/lib/datadog/tracing/contrib/karafka/patcher.rb +9 -9
  688. data/lib/datadog/tracing/contrib/karafka.rb +7 -6
  689. data/lib/datadog/tracing/contrib/lograge/configuration/settings.rb +2 -2
  690. data/lib/datadog/tracing/contrib/lograge/ext.rb +1 -1
  691. data/lib/datadog/tracing/contrib/lograge/integration.rb +5 -5
  692. data/lib/datadog/tracing/contrib/lograge/patcher.rb +9 -9
  693. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +2 -2
  694. data/lib/datadog/tracing/contrib/mongodb/ext.rb +18 -18
  695. data/lib/datadog/tracing/contrib/mongodb/instrumentation.rb +3 -3
  696. data/lib/datadog/tracing/contrib/mongodb/integration.rb +7 -7
  697. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +9 -9
  698. data/lib/datadog/tracing/contrib/mongodb/patcher.rb +3 -3
  699. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -21
  700. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +9 -3
  701. data/lib/datadog/tracing/contrib/mysql2/ext.rb +11 -11
  702. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +9 -12
  703. data/lib/datadog/tracing/contrib/mysql2/integration.rb +5 -5
  704. data/lib/datadog/tracing/contrib/mysql2/patcher.rb +2 -2
  705. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +2 -2
  706. data/lib/datadog/tracing/contrib/opensearch/ext.rb +23 -23
  707. data/lib/datadog/tracing/contrib/opensearch/integration.rb +6 -6
  708. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +15 -19
  709. data/lib/datadog/tracing/contrib/opensearch/quantize.rb +5 -5
  710. data/lib/datadog/tracing/contrib/patchable.rb +1 -1
  711. data/lib/datadog/tracing/contrib/patcher.rb +3 -3
  712. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +9 -3
  713. data/lib/datadog/tracing/contrib/pg/ext.rb +19 -19
  714. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +21 -24
  715. data/lib/datadog/tracing/contrib/pg/integration.rb +5 -5
  716. data/lib/datadog/tracing/contrib/pg/patcher.rb +2 -2
  717. data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +2 -2
  718. data/lib/datadog/tracing/contrib/presto/ext.rb +21 -21
  719. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +8 -10
  720. data/lib/datadog/tracing/contrib/presto/integration.rb +6 -6
  721. data/lib/datadog/tracing/contrib/presto/patcher.rb +4 -4
  722. data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +2 -2
  723. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +26 -13
  724. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +7 -3
  725. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +29 -5
  726. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +7 -4
  727. data/lib/datadog/tracing/contrib/que/ext.rb +19 -18
  728. data/lib/datadog/tracing/contrib/que/integration.rb +6 -6
  729. data/lib/datadog/tracing/contrib/que/patcher.rb +1 -1
  730. data/lib/datadog/tracing/contrib/que/tracer.rb +3 -2
  731. data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +3 -3
  732. data/lib/datadog/tracing/contrib/racecar/event.rb +5 -9
  733. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +3 -3
  734. data/lib/datadog/tracing/contrib/racecar/events/consume.rb +3 -3
  735. data/lib/datadog/tracing/contrib/racecar/events/message.rb +3 -3
  736. data/lib/datadog/tracing/contrib/racecar/events.rb +4 -4
  737. data/lib/datadog/tracing/contrib/racecar/ext.rb +18 -18
  738. data/lib/datadog/tracing/contrib/racecar/integration.rb +5 -5
  739. data/lib/datadog/tracing/contrib/racecar/patcher.rb +3 -3
  740. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +14 -4
  741. data/lib/datadog/tracing/contrib/rack/ext.rb +43 -15
  742. data/lib/datadog/tracing/contrib/rack/header_collection.rb +3 -3
  743. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +24 -1
  744. data/lib/datadog/tracing/contrib/rack/integration.rb +6 -6
  745. data/lib/datadog/tracing/contrib/rack/middlewares.rb +28 -25
  746. data/lib/datadog/tracing/contrib/rack/patcher.rb +5 -5
  747. data/lib/datadog/tracing/contrib/rack/request_queue.rb +4 -4
  748. data/lib/datadog/tracing/contrib/rack/route_inference.rb +27 -13
  749. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +124 -6
  750. data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +1 -1
  751. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +8 -5
  752. data/lib/datadog/tracing/contrib/rails/ext.rb +15 -14
  753. data/lib/datadog/tracing/contrib/rails/framework.rb +11 -11
  754. data/lib/datadog/tracing/contrib/rails/integration.rb +5 -5
  755. data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
  756. data/lib/datadog/tracing/contrib/rails/middlewares.rb +1 -1
  757. data/lib/datadog/tracing/contrib/rails/patcher.rb +8 -9
  758. data/lib/datadog/tracing/contrib/rails/railtie.rb +4 -4
  759. data/lib/datadog/tracing/contrib/rails/runner.rb +4 -2
  760. data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +3 -3
  761. data/lib/datadog/tracing/contrib/rake/ext.rb +12 -12
  762. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +9 -7
  763. data/lib/datadog/tracing/contrib/rake/integration.rb +5 -5
  764. data/lib/datadog/tracing/contrib/rake/patcher.rb +3 -3
  765. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +3 -3
  766. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +2 -2
  767. data/lib/datadog/tracing/contrib/redis/ext.rb +16 -16
  768. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +6 -6
  769. data/lib/datadog/tracing/contrib/redis/integration.rb +7 -7
  770. data/lib/datadog/tracing/contrib/redis/patcher.rb +10 -10
  771. data/lib/datadog/tracing/contrib/redis/quantize.rb +40 -6
  772. data/lib/datadog/tracing/contrib/redis/tags.rb +6 -11
  773. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +16 -8
  774. data/lib/datadog/tracing/contrib/registerable.rb +11 -0
  775. data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +2 -2
  776. data/lib/datadog/tracing/contrib/resque/ext.rb +7 -7
  777. data/lib/datadog/tracing/contrib/resque/integration.rb +5 -5
  778. data/lib/datadog/tracing/contrib/resque/patcher.rb +3 -3
  779. data/lib/datadog/tracing/contrib/resque/resque_job.rb +6 -5
  780. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +7 -4
  781. data/lib/datadog/tracing/contrib/rest_client/ext.rb +10 -9
  782. data/lib/datadog/tracing/contrib/rest_client/integration.rb +6 -6
  783. data/lib/datadog/tracing/contrib/rest_client/patcher.rb +2 -2
  784. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +6 -10
  785. data/lib/datadog/tracing/contrib/roda/configuration/settings.rb +2 -2
  786. data/lib/datadog/tracing/contrib/roda/ext.rb +6 -5
  787. data/lib/datadog/tracing/contrib/roda/instrumentation.rb +8 -5
  788. data/lib/datadog/tracing/contrib/roda/integration.rb +6 -6
  789. data/lib/datadog/tracing/contrib/roda/patcher.rb +3 -3
  790. data/lib/datadog/tracing/contrib/semantic_logger/configuration/settings.rb +2 -2
  791. data/lib/datadog/tracing/contrib/semantic_logger/ext.rb +1 -1
  792. data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +5 -5
  793. data/lib/datadog/tracing/contrib/semantic_logger/patcher.rb +2 -2
  794. data/lib/datadog/tracing/contrib/sequel/configuration/settings.rb +2 -2
  795. data/lib/datadog/tracing/contrib/sequel/database.rb +7 -10
  796. data/lib/datadog/tracing/contrib/sequel/dataset.rb +6 -5
  797. data/lib/datadog/tracing/contrib/sequel/ext.rb +12 -8
  798. data/lib/datadog/tracing/contrib/sequel/integration.rb +5 -5
  799. data/lib/datadog/tracing/contrib/sequel/patcher.rb +3 -3
  800. data/lib/datadog/tracing/contrib/sequel/utils.rb +116 -16
  801. data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +2 -2
  802. data/lib/datadog/tracing/contrib/shoryuken/ext.rb +12 -12
  803. data/lib/datadog/tracing/contrib/shoryuken/integration.rb +6 -6
  804. data/lib/datadog/tracing/contrib/shoryuken/patcher.rb +1 -1
  805. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +3 -2
  806. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +9 -8
  807. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +7 -3
  808. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +12 -10
  809. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +30 -29
  810. data/lib/datadog/tracing/contrib/sidekiq/integration.rb +7 -7
  811. data/lib/datadog/tracing/contrib/sidekiq/patcher.rb +8 -8
  812. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +2 -0
  813. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +1 -0
  814. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/redis_info.rb +1 -0
  815. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +2 -0
  816. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/stop.rb +1 -0
  817. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +15 -14
  818. data/lib/datadog/tracing/contrib/sidekiq/utils.rb +10 -10
  819. data/lib/datadog/tracing/contrib/sidekiq.rb +7 -6
  820. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +8 -4
  821. data/lib/datadog/tracing/contrib/sinatra/env.rb +6 -6
  822. data/lib/datadog/tracing/contrib/sinatra/ext.rb +17 -16
  823. data/lib/datadog/tracing/contrib/sinatra/framework.rb +2 -2
  824. data/lib/datadog/tracing/contrib/sinatra/integration.rb +5 -5
  825. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +5 -5
  826. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +11 -10
  827. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +9 -8
  828. data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +1 -1
  829. data/lib/datadog/tracing/contrib/sneakers/ext.rb +12 -12
  830. data/lib/datadog/tracing/contrib/sneakers/integration.rb +19 -8
  831. data/lib/datadog/tracing/contrib/sneakers/patcher.rb +2 -2
  832. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +5 -4
  833. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +2 -2
  834. data/lib/datadog/tracing/contrib/status_range_env_parser.rb +2 -2
  835. data/lib/datadog/tracing/contrib/status_range_matcher.rb +4 -0
  836. data/lib/datadog/tracing/contrib/stripe/configuration/settings.rb +2 -2
  837. data/lib/datadog/tracing/contrib/stripe/ext.rb +12 -12
  838. data/lib/datadog/tracing/contrib/stripe/integration.rb +5 -5
  839. data/lib/datadog/tracing/contrib/stripe/patcher.rb +2 -2
  840. data/lib/datadog/tracing/contrib/stripe/request.rb +4 -4
  841. data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +2 -2
  842. data/lib/datadog/tracing/contrib/sucker_punch/exception_handler.rb +1 -1
  843. data/lib/datadog/tracing/contrib/sucker_punch/ext.rb +13 -13
  844. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +5 -4
  845. data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +5 -5
  846. data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +4 -4
  847. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +9 -3
  848. data/lib/datadog/tracing/contrib/trilogy/ext.rb +11 -11
  849. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +10 -12
  850. data/lib/datadog/tracing/contrib/trilogy/integration.rb +5 -5
  851. data/lib/datadog/tracing/contrib/trilogy/patcher.rb +2 -2
  852. data/lib/datadog/tracing/contrib/utils/database.rb +5 -5
  853. data/lib/datadog/tracing/contrib/utils/quantization/{hash.rb → hash_formatter.rb} +3 -3
  854. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +10 -10
  855. data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +7 -3
  856. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +11 -9
  857. data/lib/datadog/tracing/contrib/waterdrop/ext.rb +4 -3
  858. data/lib/datadog/tracing/contrib/waterdrop/integration.rb +5 -5
  859. data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +2 -2
  860. data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +7 -7
  861. data/lib/datadog/tracing/contrib/waterdrop/producer.rb +3 -3
  862. data/lib/datadog/tracing/contrib/waterdrop.rb +7 -6
  863. data/lib/datadog/tracing/contrib.rb +62 -54
  864. data/lib/datadog/tracing/correlation.rb +12 -12
  865. data/lib/datadog/tracing/diagnostics/environment_logger.rb +14 -12
  866. data/lib/datadog/tracing/diagnostics/ext.rb +19 -19
  867. data/lib/datadog/tracing/diagnostics/health.rb +1 -1
  868. data/lib/datadog/tracing/distributed/b3_multi.rb +8 -8
  869. data/lib/datadog/tracing/distributed/b3_single.rb +4 -4
  870. data/lib/datadog/tracing/distributed/baggage.rb +82 -28
  871. data/lib/datadog/tracing/distributed/datadog.rb +32 -30
  872. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +4 -17
  873. data/lib/datadog/tracing/distributed/fetcher.rb +1 -1
  874. data/lib/datadog/tracing/distributed/helpers.rb +3 -3
  875. data/lib/datadog/tracing/distributed/propagation.rb +43 -11
  876. data/lib/datadog/tracing/distributed/propagation_policy.rb +5 -0
  877. data/lib/datadog/tracing/distributed/trace_context.rb +108 -85
  878. data/lib/datadog/tracing/event.rb +2 -2
  879. data/lib/datadog/tracing/ext.rb +9 -0
  880. data/lib/datadog/tracing/metadata/analytics.rb +2 -2
  881. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  882. data/lib/datadog/tracing/metadata/ext.rb +79 -65
  883. data/lib/datadog/tracing/metadata/metastruct.rb +1 -1
  884. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +1 -1
  885. data/lib/datadog/tracing/metadata/tagging.rb +5 -5
  886. data/lib/datadog/tracing/metadata.rb +4 -4
  887. data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
  888. data/lib/datadog/tracing/pipeline.rb +3 -3
  889. data/lib/datadog/tracing/remote.rb +48 -10
  890. data/lib/datadog/tracing/sampling/all_sampler.rb +1 -1
  891. data/lib/datadog/tracing/sampling/ext.rb +9 -7
  892. data/lib/datadog/tracing/sampling/matcher.rb +4 -4
  893. data/lib/datadog/tracing/sampling/priority_sampler.rb +17 -4
  894. data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +3 -3
  895. data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +2 -2
  896. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -2
  897. data/lib/datadog/tracing/sampling/rule.rb +5 -5
  898. data/lib/datadog/tracing/sampling/rule_sampler.rb +66 -37
  899. data/lib/datadog/tracing/sampling/sampler.rb +2 -2
  900. data/lib/datadog/tracing/sampling/span/ext.rb +3 -3
  901. data/lib/datadog/tracing/sampling/span/matcher.rb +2 -2
  902. data/lib/datadog/tracing/sampling/span/rule.rb +1 -1
  903. data/lib/datadog/tracing/sampling/span/rule_parser.rb +10 -10
  904. data/lib/datadog/tracing/span.rb +9 -9
  905. data/lib/datadog/tracing/span_event.rb +5 -5
  906. data/lib/datadog/tracing/span_operation.rb +39 -26
  907. data/lib/datadog/tracing/sync_writer.rb +12 -8
  908. data/lib/datadog/tracing/trace_digest.rb +7 -0
  909. data/lib/datadog/tracing/trace_operation.rb +90 -21
  910. data/lib/datadog/tracing/trace_segment.rb +10 -10
  911. data/lib/datadog/tracing/tracer.rb +63 -22
  912. data/lib/datadog/tracing/transport/http/client.rb +4 -4
  913. data/lib/datadog/tracing/transport/http/statistics.rb +2 -2
  914. data/lib/datadog/tracing/transport/http/traces.rb +8 -8
  915. data/lib/datadog/tracing/transport/http.rb +10 -10
  916. data/lib/datadog/tracing/transport/io/client.rb +8 -11
  917. data/lib/datadog/tracing/transport/io/response.rb +1 -1
  918. data/lib/datadog/tracing/transport/io/traces.rb +33 -39
  919. data/lib/datadog/tracing/transport/io.rb +3 -3
  920. data/lib/datadog/tracing/transport/native/response.rb +71 -0
  921. data/lib/datadog/tracing/transport/native.rb +387 -0
  922. data/lib/datadog/tracing/transport/serializable_trace.rb +19 -19
  923. data/lib/datadog/tracing/transport/statistics.rb +2 -2
  924. data/lib/datadog/tracing/transport/trace_formatter.rb +20 -9
  925. data/lib/datadog/tracing/transport/traces.rb +13 -19
  926. data/lib/datadog/tracing/utils.rb +2 -2
  927. data/lib/datadog/tracing/workers.rb +4 -3
  928. data/lib/datadog/tracing/writer.rb +22 -10
  929. data/lib/datadog/tracing.rb +3 -3
  930. data/lib/datadog/version.rb +4 -4
  931. data/lib/datadog.rb +15 -11
  932. metadata +91 -23
  933. data/ext/datadog_profiling_native_extension/clock_id_noop.c +0 -21
  934. data/lib/datadog/ai_guard/configuration/settings.rb +0 -110
  935. data/lib/datadog/appsec/configuration/settings.rb +0 -409
  936. data/lib/datadog/appsec/contrib/rails/ext.rb +0 -13
  937. data/lib/datadog/core/utils/base64.rb +0 -22
  938. data/lib/datadog/data_streams/configuration/settings.rb +0 -49
  939. data/lib/datadog/di/configuration/settings.rb +0 -234
  940. data/lib/datadog/error_tracking/configuration/settings.rb +0 -63
  941. data/lib/datadog/tracing/workers/trace_writer.rb +0 -204
@@ -17,6 +17,10 @@
17
17
  #include "setup_signal_handler.h"
18
18
  #include "time_helpers.h"
19
19
 
20
+ #ifdef __APPLE__
21
+ #include "macos_sampler_thread.h"
22
+ #endif
23
+
20
24
  // Used to trigger the execution of Collectors::ThreadContext, which implements all of the sampling logic
21
25
  // itself; this class only implements the "when to do it" part.
22
26
  //
@@ -87,6 +91,7 @@ unsigned int MAX_ALLOC_WEIGHT = 10000;
87
91
  static rb_postponed_job_handle_t sample_from_postponed_job_handle;
88
92
  static rb_postponed_job_handle_t after_gc_from_postponed_job_handle;
89
93
  static rb_postponed_job_handle_t after_gvl_running_from_postponed_job_handle;
94
+ static rb_postponed_job_handle_t after_allocation_from_postponed_job_handle;
90
95
  #endif
91
96
 
92
97
  // Contains state for a single CpuAndWallTimeWorker instance
@@ -101,6 +106,7 @@ typedef struct {
101
106
  bool gvl_profiling_enabled;
102
107
  bool skip_idle_samples_for_testing;
103
108
  bool sighandler_sampling_enabled;
109
+ uint32_t cpu_sampling_interval_ms;
104
110
  VALUE self_instance;
105
111
  VALUE thread_context_collector_instance;
106
112
  VALUE idle_sampling_helper_instance;
@@ -138,6 +144,8 @@ typedef struct {
138
144
  // # Generic stats
139
145
  // How many times we tried to trigger a sample
140
146
  unsigned int trigger_sample_attempts;
147
+ // How many times extra sleep was triggered by dynamic sampling rate
148
+ unsigned int trigger_sample_extra_sleep;
141
149
  // How many times we tried to simulate signal delivery
142
150
  unsigned int trigger_simulated_signal_delivery_attempts;
143
151
  // How many times we actually simulated signal delivery
@@ -146,8 +154,6 @@ typedef struct {
146
154
  unsigned int signal_handler_enqueued_sample;
147
155
  // How many times we prepared a sample (sampled directly) from the signal handler
148
156
  unsigned int signal_handler_prepared_sample;
149
- // How many times the signal handler was called from the wrong thread
150
- unsigned int signal_handler_wrong_thread;
151
157
  // How many times we actually tried to interrupt a thread for sampling
152
158
  unsigned int interrupt_thread_attempts;
153
159
 
@@ -174,6 +180,11 @@ typedef struct {
174
180
  unsigned int allocations_during_sample;
175
181
 
176
182
  // # GVL profiling stats
183
+ // Note that this tracks two kind of samples from RESUMED:
184
+ // * samples when Waiting for GVL for more than the threshold
185
+ // * samples for the skip-samples-while-without-GVL optimization,
186
+ // which are needed to attribute the time without GVL to the correct Ruby stack
187
+
177
188
  // How many times we triggered the after_gvl_running sampling
178
189
  unsigned int after_gvl_running;
179
190
  // How many times we skipped the after_gvl_running sampling
@@ -182,6 +193,11 @@ typedef struct {
182
193
  uint64_t gvl_sampling_time_ns_min;
183
194
  uint64_t gvl_sampling_time_ns_max;
184
195
  uint64_t gvl_sampling_time_ns_total;
196
+
197
+ struct vm_metrics {
198
+ // Total time spent waiting for the GVL
199
+ uint64_t gvl_waiting_time_ns_total;
200
+ } vm_metrics;
185
201
  } stats;
186
202
  } cpu_and_wall_time_worker_state;
187
203
 
@@ -204,6 +220,7 @@ static VALUE _native_failure_exception_during_operation(DDTRACE_UNUSED VALUE sel
204
220
  static void testing_signal_handler(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext);
205
221
  static VALUE _native_install_testing_signal_handler(DDTRACE_UNUSED VALUE self);
206
222
  static VALUE _native_remove_testing_signal_handler(DDTRACE_UNUSED VALUE self);
223
+ static VALUE _native_install_sigprof_handler_on_altstack(DDTRACE_UNUSED VALUE self);
207
224
  static VALUE _native_trigger_sample(DDTRACE_UNUSED VALUE self);
208
225
  static VALUE _native_gc_tracepoint(DDTRACE_UNUSED VALUE self, VALUE instance);
209
226
  static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused);
@@ -229,23 +246,26 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
229
246
  static void disable_tracepoints(cpu_and_wall_time_worker_state *state);
230
247
  static VALUE _native_with_blocked_sigprof(DDTRACE_UNUSED VALUE self);
231
248
  static VALUE rescued_sample_allocation(VALUE tracepoint_data);
249
+ static VALUE rescued_after_allocation(VALUE self_instance);
232
250
  static void delayed_error(cpu_and_wall_time_worker_state *state, const char *error);
233
251
  static void delayed_error_clock_failure(cpu_and_wall_time_worker_state *state);
234
252
  static VALUE _native_delayed_error(DDTRACE_UNUSED VALUE self, VALUE instance, VALUE error_msg);
235
253
  static VALUE _native_hold_signals(DDTRACE_UNUSED VALUE self);
236
254
  static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self);
237
255
  #ifndef NO_GVL_INSTRUMENTATION
238
- static void on_gvl_event(rb_event_flag_t event_id, const rb_internal_thread_event_data_t *event_data, DDTRACE_UNUSED void *_unused);
239
- static void after_gvl_running_from_postponed_job(DDTRACE_UNUSED void *_unused);
256
+ static void on_gvl_event(rb_event_flag_t event_id, const rb_internal_thread_event_data_t *event_data, DDTRACE_UNUSED void *_unused);
257
+ static void after_gvl_running_from_postponed_job(DDTRACE_UNUSED void *_unused);
258
+ static VALUE rescued_after_gvl_running_from_postponed_job(VALUE self_instance);
259
+ static VALUE handle_sampling_failure_rescued_after_gvl_running_from_postponed_job(VALUE self_instance, VALUE exception);
240
260
  #endif
241
- static VALUE rescued_after_gvl_running_from_postponed_job(VALUE self_instance);
242
261
  static VALUE _native_gvl_profiling_hook_active(DDTRACE_UNUSED VALUE self, VALUE instance);
243
262
  static VALUE handle_sampling_failure_rescued_sample_from_postponed_job(VALUE self_instance, VALUE exception);
244
263
  static VALUE handle_sampling_failure_thread_context_collector_sample_after_gc(VALUE self_instance, VALUE exception);
245
264
  static VALUE handle_sampling_failure_rescued_sample_allocation(VALUE self_instance, VALUE exception);
246
- static VALUE handle_sampling_failure_rescued_after_gvl_running_from_postponed_job(VALUE self_instance, VALUE exception);
265
+ static VALUE handle_sampling_failure_rescued_after_allocation(VALUE self_instance, VALUE exception);
247
266
  static inline void during_sample_enter(cpu_and_wall_time_worker_state* state);
248
267
  static inline void during_sample_exit(cpu_and_wall_time_worker_state* state);
268
+ static void after_allocation_from_postponed_job(DDTRACE_UNUSED void *_unused);
249
269
 
250
270
  // We're using `on_newobj_event` function with `rb_add_event_hook2`, which requires in its public signature a function
251
271
  // with signature `rb_event_hook_func_t` which doesn't match `on_newobj_event`.
@@ -273,6 +293,15 @@ static VALUE active_sampler_instance = Qnil;
273
293
  static cpu_and_wall_time_worker_state *active_sampler_instance_state = NULL;
274
294
  static VALUE clock_failure_exception_class = Qnil;
275
295
 
296
+ // Stats that live outside of any particular `cpu_and_wall_time_worker_state`, so that they can always be safely
297
+ // touched, even when we're not sure it's safe to touch the state (e.g. signal handler, no GVL, etc).
298
+ typedef struct {
299
+ // How many times we skipped sampling because we were running on the alternate signal stack (e.g. nested inside
300
+ // another signal handler, presumably GC compaction).
301
+ unsigned int signal_handler_skipped_sample_on_altstack;
302
+ } global_stats_t;
303
+ static global_stats_t global_stats;
304
+
276
305
  // See handle_sampling_signal for details on what this does
277
306
  #ifdef NO_POSTPONED_TRIGGER
278
307
  static void *gc_finalize_deferred_workaround;
@@ -293,11 +322,13 @@ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
293
322
  sample_from_postponed_job_handle = rb_postponed_job_preregister(unused_flags, sample_from_postponed_job, NULL);
294
323
  after_gc_from_postponed_job_handle = rb_postponed_job_preregister(unused_flags, after_gc_from_postponed_job, NULL);
295
324
  after_gvl_running_from_postponed_job_handle = rb_postponed_job_preregister(unused_flags, after_gvl_running_from_postponed_job, NULL);
325
+ after_allocation_from_postponed_job_handle = rb_postponed_job_preregister(unused_flags, after_allocation_from_postponed_job, NULL);
296
326
 
297
327
  if (
298
328
  sample_from_postponed_job_handle == POSTPONED_JOB_HANDLE_INVALID ||
299
329
  after_gc_from_postponed_job_handle == POSTPONED_JOB_HANDLE_INVALID ||
300
- after_gvl_running_from_postponed_job_handle == POSTPONED_JOB_HANDLE_INVALID
330
+ after_gvl_running_from_postponed_job_handle == POSTPONED_JOB_HANDLE_INVALID ||
331
+ after_allocation_from_postponed_job_handle == POSTPONED_JOB_HANDLE_INVALID
301
332
  ) {
302
333
  raise_error(rb_eRuntimeError, "Failed to register profiler postponed jobs (got POSTPONED_JOB_HANDLE_INVALID)");
303
334
  }
@@ -336,6 +367,7 @@ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
336
367
  rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_resume_signals", _native_resume_signals, 0);
337
368
  rb_define_singleton_method(testing_module, "_native_install_testing_signal_handler", _native_install_testing_signal_handler, 0);
338
369
  rb_define_singleton_method(testing_module, "_native_remove_testing_signal_handler", _native_remove_testing_signal_handler, 0);
370
+ rb_define_singleton_method(testing_module, "_native_install_sigprof_handler_on_altstack", _native_install_sigprof_handler_on_altstack, 0);
339
371
  rb_define_singleton_method(testing_module, "_native_trigger_sample", _native_trigger_sample, 0);
340
372
  rb_define_singleton_method(testing_module, "_native_gc_tracepoint", _native_gc_tracepoint, 1);
341
373
  rb_define_singleton_method(testing_module, "_native_simulate_handle_sampling_signal", _native_simulate_handle_sampling_signal, 0);
@@ -375,6 +407,7 @@ static VALUE _native_new(VALUE klass) {
375
407
  state->gvl_profiling_enabled = false;
376
408
  state->skip_idle_samples_for_testing = false;
377
409
  state->sighandler_sampling_enabled = false;
410
+ state->cpu_sampling_interval_ms = 10;
378
411
  state->thread_context_collector_instance = Qnil;
379
412
  state->idle_sampling_helper_instance = Qnil;
380
413
  state->owner_thread = Qnil;
@@ -419,6 +452,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
419
452
  VALUE gvl_profiling_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("gvl_profiling_enabled")));
420
453
  VALUE skip_idle_samples_for_testing = rb_hash_fetch(options, ID2SYM(rb_intern("skip_idle_samples_for_testing")));
421
454
  VALUE sighandler_sampling_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("sighandler_sampling_enabled")));
455
+ VALUE cpu_sampling_interval_ms = rb_hash_fetch(options, ID2SYM(rb_intern("cpu_sampling_interval_ms")));
422
456
 
423
457
  ENFORCE_BOOLEAN(gc_profiling_enabled);
424
458
  ENFORCE_BOOLEAN(no_signals_workaround_enabled);
@@ -429,6 +463,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
429
463
  ENFORCE_BOOLEAN(gvl_profiling_enabled);
430
464
  ENFORCE_BOOLEAN(skip_idle_samples_for_testing)
431
465
  ENFORCE_BOOLEAN(sighandler_sampling_enabled)
466
+ ENFORCE_TYPE(cpu_sampling_interval_ms, T_FIXNUM);
432
467
 
433
468
  cpu_and_wall_time_worker_state *state;
434
469
  TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
@@ -441,6 +476,7 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
441
476
  state->gvl_profiling_enabled = (gvl_profiling_enabled == Qtrue);
442
477
  state->skip_idle_samples_for_testing = (skip_idle_samples_for_testing == Qtrue);
443
478
  state->sighandler_sampling_enabled = (sighandler_sampling_enabled == Qtrue);
479
+ state->cpu_sampling_interval_ms = NUM2INT(cpu_sampling_interval_ms);
444
480
 
445
481
  double total_overhead_target_percentage = NUM2DBL(dynamic_sampling_rate_overhead_target_percentage);
446
482
  if (!state->allocation_profiling_enabled) {
@@ -503,11 +539,20 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
503
539
  // situation we stop immediately and never even start the sampling trigger loop.
504
540
  if (state->stop_thread == rb_thread_current()) return Qnil;
505
541
 
542
+ thread_context_collector_profiler_internal_thread_started();
543
+
506
544
  // Reset the dynamic sampling rate state, if any (reminder: the monotonic clock reference may change after a fork)
507
545
  dynamic_sampling_rate_reset(&state->cpu_dynamic_sampling_rate);
508
546
  long now = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
509
547
  discrete_dynamic_sampler_reset(&state->allocation_sampler, now);
510
548
 
549
+ // Reset per-thread state, if any. This ensures there's no leftover state from a previous profiler run that would
550
+ // affect or be included in samples taken by this profiler about to run.
551
+ //
552
+ // NOTE: This needs to be called before we enable any tracepoints or anything that could trigger samples (e.g.
553
+ // reset cannot be concurrent with any sampling activity)
554
+ thread_context_collector_reset_all_per_thread_contexts(state->thread_context_collector_instance);
555
+
511
556
  // This write to a global is thread-safe BECAUSE we're still holding on to the global VM lock at this point
512
557
  active_sampler_instance_state = state;
513
558
  active_sampler_instance = instance;
@@ -517,6 +562,14 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
517
562
 
518
563
  block_sigprof_signal_handler_from_running_in_current_thread(); // We want to interrupt the thread with the global VM lock, never this one
519
564
 
565
+ #ifdef __APPLE__
566
+ // Promote the native thread that will run the sampling loop to a realtime scheduling policy so
567
+ // its periodic wake-ups are not subject to the default ~1-2ms timeshare wake latency. The matching
568
+ // demote happens below in this same function, alongside the SIGPROF unblock dance, so both per-thread
569
+ // policy changes are reverted before Ruby reuses this native thread for an unrelated Ruby thread.
570
+ promote_sampler_thread_to_realtime(MILLIS_AS_NS(state->cpu_sampling_interval_ms));
571
+ #endif
572
+
520
573
  // Release GVL, get to the actual work!
521
574
  int exception_state;
522
575
  rb_protect(release_gvl_and_run_sampling_trigger_loop, instance, &exception_state);
@@ -538,6 +591,14 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
538
591
  // had SIGPROF delivery blocked. :hide_the_pain_harold:
539
592
  unblock_sigprof_signal_handler_from_running_in_current_thread();
540
593
 
594
+ #ifdef __APPLE__
595
+ // Pairs with promote_sampler_thread_to_realtime above. Same reasoning as the SIGPROF unblock:
596
+ // Ruby may reuse this native thread for an unrelated Ruby thread that would otherwise inherit
597
+ // our scheduler policy. Doing it here also covers the exception path, since grab_gvl_and_sample
598
+ // can raise and unwind out of the sampling loop.
599
+ demote_sampler_thread_from_realtime();
600
+ #endif
601
+
541
602
  // Why replace and not use remove the signal handler? We do this because when a process receives a SIGPROF without
542
603
  // having an explicit signal handler set up, the process will instantly terminate with a confusing
543
604
  // "Profiling timer expired" message left behind. (This message doesn't come from us -- it's the default message for
@@ -548,8 +609,9 @@ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
548
609
  // @ivoanjo: I suspect this will never happen, but the cost of getting it wrong is really high (VM terminates) so this
549
610
  // is a just-in-case situation.
550
611
  //
551
- // Note 2: This can raise exceptions as well, so make sure that all cleanups are done by the time we get here.
552
- replace_sigprof_signal_handler_with_empty_handler(handle_sampling_signal);
612
+ // Note 2: If exception_state is set, we have a pending exception that we'll re-raise below.
613
+ // In that case, we don't want replace_sigprof_signal_handler_with_empty_handler to raise another exception.
614
+ replace_sigprof_signal_handler_with_empty_handler(handle_sampling_signal, !exception_state);
553
615
 
554
616
  // Ensure that instance is not garbage collected while the native sampling loop is running; this is probably not needed, but just in case
555
617
  RB_GC_GUARD(instance);
@@ -587,23 +649,63 @@ static VALUE stop(VALUE self_instance, VALUE optional_exception, const char *opt
587
649
  return Qtrue;
588
650
  }
589
651
 
652
+ // Our SIGPROF handler is not installed with SA_ONSTACK (see `install_sigprof_signal_handler`).
653
+ // If we detect our signal handler is running on the alt stack, it means we interrupted another signal handler
654
+ // that IS running on the alt stack -- in practice, Ruby's GC compaction read-barrier handler.
655
+ #ifdef __APPLE__
656
+ // On macOS, `ucontext->uc_stack.ss_sp` reports the (live) stack pointer near the top of the alt stack rather than the
657
+ // alt-stack base like Linux does, and `ss_size` is the full alt-stack size. Thus the linux version of the check
658
+ // didn't work for macOS.
659
+ // As an alternative, we query `sigaltstack()`; we save/restore errno since `sigaltstack()` may clobber it.
660
+ static bool is_running_on_alternate_signal_stack(DDTRACE_UNUSED void *ucontext) {
661
+ int old_errno = errno;
662
+ stack_t current_alt_stack;
663
+ bool on_alt_stack = sigaltstack(NULL, &current_alt_stack) == 0 && (current_alt_stack.ss_flags & SS_ONSTACK) != 0;
664
+ errno = old_errno;
665
+ return on_alt_stack;
666
+ }
667
+ #else
668
+ // NOTE: On Linux we use the alt-stack bounds from the `ucontext` rather than `sigaltstack()`, allowing us to avoid one syscall.
669
+ static bool is_running_on_alternate_signal_stack(void *ucontext) {
670
+ if (ucontext == NULL) return false;
671
+
672
+ stack_t alt_stack = ((ucontext_t *) ucontext)->uc_stack;
673
+ if (alt_stack.ss_size == 0) return false; // No alternate signal stack registered on this thread
674
+
675
+ char stack_local;
676
+ uintptr_t current_sp = (uintptr_t) &stack_local;
677
+ uintptr_t alt_stack_start = (uintptr_t) alt_stack.ss_sp;
678
+
679
+ return current_sp >= alt_stack_start && current_sp < alt_stack_start + alt_stack.ss_size;
680
+ }
681
+ #endif
682
+
590
683
  // NOTE: Remember that this will run in the thread and within the scope of user code, including user C code.
591
684
  // We need to be careful not to change any state that may be observed OR to restore it if we do. For instance, if anything
592
685
  // we do here can set `errno`, then we must be careful to restore the old `errno` after the fact.
593
- static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) {
594
- cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
595
-
596
- // This can potentially happen if the CpuAndWallTimeWorker was stopped while the signal delivery was happening; nothing to do
597
- if (state == NULL) return;
686
+ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, void *ucontext) {
687
+ // If we're running on the alternate signal stack, we've interrupted another signal handler that's running
688
+ // there -- in practice, Ruby's GC compaction read-barrier handler.
689
+ // During GC compaction, Ruby protects pages containing Ruby objects, so many of the checks we do below are unsafe
690
+ // since they can touch those pages, and thus we just bail out here in this situation to avoid crashes.
691
+ if (is_running_on_alternate_signal_stack(ucontext)) {
692
+ global_stats.signal_handler_skipped_sample_on_altstack++;
693
+ return;
694
+ }
598
695
 
696
+ // We must first check that we landed on the correct thread and can proceed.
697
+ // We must never touch the state before we confirm that we have landed on the thread that is holding the GVL on the main
698
+ // ractor as otherwise we may be concurrent with the profiler shutting down and removing its state.
599
699
  if (
600
700
  !ruby_native_thread_p() || // Not a Ruby thread
601
701
  !is_current_thread_holding_the_gvl() || // Not safe to enqueue a sample from this thread
602
702
  !ddtrace_rb_ractor_main_p() // We're not on the main Ractor; we currently don't support profiling non-main Ractors
603
- ) {
604
- state->stats.signal_handler_wrong_thread++;
605
- return;
606
- }
703
+ ) return;
704
+
705
+ cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
706
+
707
+ // This can potentially happen if the CpuAndWallTimeWorker was stopped while the signal delivery was happening; nothing to do
708
+ if (state == NULL) return;
607
709
 
608
710
  // We assume there can be no concurrent nor nested calls to handle_sampling_signal because
609
711
  // a) we get triggered using SIGPROF, and the docs state a second SIGPROF will not interrupt an existing one (see sigaction docs on sa_mask)
@@ -620,7 +722,7 @@ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED si
620
722
  if (sample_from_signal_handler) {
621
723
  // Buffer current stack trace. Note that this will not actually record the sample, for that we still need to wait
622
724
  // until the postponed job below gets run.
623
- bool prepared = thread_context_collector_prepare_sample_inside_signal_handler(state->thread_context_collector_instance);
725
+ bool prepared = thread_context_collector_prepare_sample_inside_signal_handler();
624
726
 
625
727
  if (prepared) state->stats.signal_handler_prepared_sample++;
626
728
  }
@@ -660,7 +762,7 @@ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED si
660
762
  static void *run_sampling_trigger_loop(void *state_ptr) {
661
763
  cpu_and_wall_time_worker_state *state = (cpu_and_wall_time_worker_state *) state_ptr;
662
764
 
663
- uint64_t minimum_time_between_signals = MILLIS_AS_NS(10);
765
+ uint64_t minimum_time_between_signals = MILLIS_AS_NS(state->cpu_sampling_interval_ms);
664
766
 
665
767
  while (atomic_load(&state->should_run)) {
666
768
  state->stats.trigger_sample_attempts++;
@@ -713,7 +815,10 @@ static void *run_sampling_trigger_loop(void *state_ptr) {
713
815
  // `dynamic_sampling_rate_get_sleep` may have changed while the above sleep was ongoing.
714
816
  uint64_t extra_sleep =
715
817
  dynamic_sampling_rate_get_sleep(&state->cpu_dynamic_sampling_rate, monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE));
716
- if (state->dynamic_sampling_rate_enabled && extra_sleep > 0) sleep_for(extra_sleep);
818
+ if (state->dynamic_sampling_rate_enabled && extra_sleep > 0) {
819
+ state->stats.trigger_sample_extra_sleep++;
820
+ sleep_for(extra_sleep);
821
+ }
717
822
  }
718
823
 
719
824
  return NULL; // Unused
@@ -766,8 +871,7 @@ static VALUE rescued_sample_from_postponed_job(VALUE self_instance) {
766
871
 
767
872
  state->stats.cpu_sampled++;
768
873
 
769
- VALUE profiler_overhead_stack_thread = state->owner_thread; // Used to attribute profiler overhead to a different stack
770
- thread_context_collector_sample(state->thread_context_collector_instance, wall_time_ns_before_sample, profiler_overhead_stack_thread);
874
+ thread_context_collector_sample(state->thread_context_collector_instance, wall_time_ns_before_sample);
771
875
 
772
876
  long wall_time_ns_after_sample = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
773
877
  long delta_ns = wall_time_ns_after_sample - wall_time_ns_before_sample;
@@ -823,15 +927,12 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
823
927
 
824
928
  if (state->gvl_profiling_enabled) {
825
929
  #ifndef NO_GVL_INSTRUMENTATION
826
- #ifdef USE_GVL_PROFILING_3_2_WORKAROUNDS
827
- gvl_profiling_state_thread_tracking_workaround();
828
- #endif
829
-
830
930
  state->gvl_profiling_hook = rb_internal_thread_add_event_hook(
831
931
  on_gvl_event,
832
932
  (
833
933
  // For now we're only asking for these events, even though there's more
834
934
  // (e.g. check docs or gvl-tracing gem)
935
+ RUBY_INTERNAL_THREAD_EVENT_SUSPENDED | /* released gvl */
835
936
  RUBY_INTERNAL_THREAD_EVENT_READY /* waiting for gvl */ |
836
937
  RUBY_INTERNAL_THREAD_EVENT_RESUMED /* running/runnable */
837
938
  ),
@@ -850,6 +951,8 @@ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
850
951
  // If we stopped sampling due to an exception, re-raise it (now in the worker thread)
851
952
  if (state->failure_exception != Qnil) rb_exc_raise(state->failure_exception);
852
953
 
954
+ thread_context_collector_profiler_internal_thread_done(state->thread_context_collector_instance);
955
+
853
956
  return Qnil;
854
957
  }
855
958
 
@@ -888,6 +991,28 @@ static VALUE _native_remove_testing_signal_handler(DDTRACE_UNUSED VALUE self) {
888
991
  return Qtrue;
889
992
  }
890
993
 
994
+ // Reproduces a profiler sample being taken in the middle of GC compaction: during compaction a SIGPROF can be
995
+ // delivered while nested inside Ruby's read-barrier signal handler, which runs on the alternate signal stack. We
996
+ // simulate that here by re-installing the production `handle_sampling_signal` with the `SA_ONSTACK` flag, so it runs
997
+ // on the alternate signal stack just like it would in that scenario.
998
+ //
999
+ // The `SA_ONSTACK` will be undone by any next `replace_sigprof_signal_handler_with_empty_handler` /
1000
+ // `install_sigprof_signal_handler_internal` / `remove_sigprof_signal_handle` so this doesn't need a specific, symmetric
1001
+ // `uninstall` to undo this.
1002
+ static VALUE _native_install_sigprof_handler_on_altstack(DDTRACE_UNUSED VALUE self) {
1003
+ struct sigaction signal_handler_config = {
1004
+ .sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK,
1005
+ .sa_sigaction = handle_sampling_signal,
1006
+ };
1007
+ sigemptyset(&signal_handler_config.sa_mask);
1008
+
1009
+ if (sigaction(SIGPROF, &signal_handler_config, NULL) != 0) {
1010
+ rb_sys_fail("Failed to install SA_ONSTACK SIGPROF signal handler for testing");
1011
+ }
1012
+
1013
+ return Qtrue;
1014
+ }
1015
+
891
1016
  // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
892
1017
  // It SHOULD NOT be used for other purposes.
893
1018
  static VALUE _native_trigger_sample(DDTRACE_UNUSED VALUE self) {
@@ -1013,6 +1138,9 @@ static VALUE _native_simulate_sample_from_postponed_job(DDTRACE_UNUSED VALUE sel
1013
1138
  //
1014
1139
  // In the future, if we add more other components with tracepoints, we will need to coordinate stopping all such
1015
1140
  // tracepoints before doing the other cleaning steps.
1141
+ //
1142
+ // Note that tests call this method directly in the same process without forking,
1143
+ // and in such a case non-current Threads keep running.
1016
1144
  static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE instance) {
1017
1145
  cpu_and_wall_time_worker_state *state;
1018
1146
  TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
@@ -1049,11 +1177,12 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) {
1049
1177
  VALUE stats_as_hash = rb_hash_new();
1050
1178
  VALUE arguments[] = {
1051
1179
  ID2SYM(rb_intern("trigger_sample_attempts")), /* => */ UINT2NUM(state->stats.trigger_sample_attempts),
1180
+ ID2SYM(rb_intern("trigger_sample_extra_sleep")), /* => */ UINT2NUM(state->stats.trigger_sample_extra_sleep),
1052
1181
  ID2SYM(rb_intern("trigger_simulated_signal_delivery_attempts")), /* => */ UINT2NUM(state->stats.trigger_simulated_signal_delivery_attempts),
1053
1182
  ID2SYM(rb_intern("simulated_signal_delivery")), /* => */ UINT2NUM(state->stats.simulated_signal_delivery),
1054
1183
  ID2SYM(rb_intern("signal_handler_enqueued_sample")), /* => */ UINT2NUM(state->stats.signal_handler_enqueued_sample),
1055
1184
  ID2SYM(rb_intern("signal_handler_prepared_sample")), /* => */ UINT2NUM(state->stats.signal_handler_prepared_sample),
1056
- ID2SYM(rb_intern("signal_handler_wrong_thread")), /* => */ UINT2NUM(state->stats.signal_handler_wrong_thread),
1185
+ ID2SYM(rb_intern("signal_handler_skipped_sample_on_altstack")), /* => */ UINT2NUM(global_stats.signal_handler_skipped_sample_on_altstack),
1057
1186
  ID2SYM(rb_intern("interrupt_thread_attempts")), /* => */ UINT2NUM(state->stats.interrupt_thread_attempts),
1058
1187
 
1059
1188
  // CPU Stats
@@ -1083,8 +1212,12 @@ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) {
1083
1212
  ID2SYM(rb_intern("gvl_sampling_time_ns_max")), /* => */ RUBY_NUM_OR_NIL(state->stats.gvl_sampling_time_ns_max, > 0, ULL2NUM),
1084
1213
  ID2SYM(rb_intern("gvl_sampling_time_ns_total")), /* => */ RUBY_NUM_OR_NIL(state->stats.gvl_sampling_time_ns_total, > 0, ULL2NUM),
1085
1214
  ID2SYM(rb_intern("gvl_sampling_time_ns_avg")), /* => */ RUBY_AVG_OR_NIL(state->stats.gvl_sampling_time_ns_total, state->stats.after_gvl_running),
1215
+ ID2SYM(rb_intern("gvl_waiting_time_ns_total")), /* => */ state->gvl_profiling_enabled ? ULL2NUM(state->stats.vm_metrics.gvl_waiting_time_ns_total) : Qnil,
1086
1216
  };
1087
1217
  for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(stats_as_hash, arguments[i], arguments[i+1]);
1218
+
1219
+ thread_context_collector_stats(state->thread_context_collector_instance, stats_as_hash);
1220
+
1088
1221
  return stats_as_hash;
1089
1222
  }
1090
1223
 
@@ -1092,6 +1225,7 @@ static VALUE _native_stats_reset_not_thread_safe(DDTRACE_UNUSED VALUE self, VALU
1092
1225
  cpu_and_wall_time_worker_state *state;
1093
1226
  TypedData_Get_Struct(instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
1094
1227
  reset_stats_not_thread_safe(state);
1228
+ thread_context_collector_stats_reset_not_thread_safe(state->thread_context_collector_instance);
1095
1229
  return Qnil;
1096
1230
  }
1097
1231
 
@@ -1118,12 +1252,15 @@ static void reset_stats_not_thread_safe(cpu_and_wall_time_worker_state *state) {
1118
1252
  // * Included in the following stats window (writes after stats retrieval and reset).
1119
1253
  // Given the expected infrequency of resetting (~once per 60s profile) and the auxiliary/non-critical nature of these stats
1120
1254
  // this momentary loss of accuracy is deemed acceptable to keep overhead to a minimum.
1255
+
1121
1256
  state->stats = (struct stats) {
1122
1257
  // All these values are initialized to their highest value possible since we always take the min between existing and latest sample
1123
1258
  .cpu_sampling_time_ns_min = UINT64_MAX,
1124
1259
  .allocation_sampling_time_ns_min = UINT64_MAX,
1125
1260
  .gvl_sampling_time_ns_min = UINT64_MAX,
1261
+ // Other fields are reset to 0
1126
1262
  };
1263
+ global_stats = (global_stats_t) {0};
1127
1264
  }
1128
1265
 
1129
1266
  static void sleep_for(uint64_t time_ns) {
@@ -1200,13 +1337,22 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
1200
1337
  return;
1201
1338
  }
1202
1339
 
1340
+ VALUE current_thread = rb_thread_current();
1341
+
1203
1342
  // If Ruby is in the middle of raising an exception, we don't want to try to sample. This is because if we accidentally
1204
1343
  // trigger an exception inside the profiler code, bad things will happen (specifically, Ruby will try to kill off the
1205
1344
  // thread even though we may try to catch the exception).
1206
1345
  //
1207
1346
  // Note that "in the middle of raising an exception" means the exception itself has already been allocated.
1208
1347
  // What's getting allocated now is probably the backtrace objects (@ivoanjo or at least that's what I've observed)
1209
- if (is_raised_flag_set(rb_thread_current())) {
1348
+ if (is_raised_flag_set(current_thread)) {
1349
+ return;
1350
+ }
1351
+
1352
+ per_thread_context *thread_context = get_per_thread_context(current_thread);
1353
+ if (!thread_context) {
1354
+ // Context is created eagerly via on_thread_begin_event, so this should not normally be NULL.
1355
+ // We keep the guard since we can't allocate here (inside on_newobj_event).
1210
1356
  return;
1211
1357
  }
1212
1358
 
@@ -1241,7 +1387,7 @@ static void on_newobj_event(DDTRACE_UNUSED VALUE unused1, DDTRACE_UNUSED void *u
1241
1387
  // Rescue against any exceptions that happen during sampling
1242
1388
  safely_call(
1243
1389
  rescued_sample_allocation,
1244
- Qnil,
1390
+ (VALUE) thread_context,
1245
1391
  state->self_instance,
1246
1392
  handle_sampling_failure_rescued_sample_allocation
1247
1393
  );
@@ -1293,7 +1439,8 @@ static VALUE _native_with_blocked_sigprof(DDTRACE_UNUSED VALUE self) {
1293
1439
  }
1294
1440
  }
1295
1441
 
1296
- static VALUE rescued_sample_allocation(DDTRACE_UNUSED VALUE unused) {
1442
+ static VALUE rescued_sample_allocation(VALUE arg) {
1443
+ per_thread_context *thread_context = (per_thread_context*) arg;
1297
1444
  cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
1298
1445
 
1299
1446
  // This should not happen in a normal situation because on_newobj_event already checked for this, but just in case...
@@ -1312,13 +1459,21 @@ static VALUE rescued_sample_allocation(DDTRACE_UNUSED VALUE unused) {
1312
1459
  // To control bias from sampling, we clamp the maximum weight attributed to a single allocation sample. This avoids
1313
1460
  // assigning a very large number to a sample, if for instance the dynamic sampling mechanism chose a really big interval.
1314
1461
  unsigned int weight = allocations_since_last_sample > MAX_ALLOC_WEIGHT ? MAX_ALLOC_WEIGHT : (unsigned int) allocations_since_last_sample;
1315
- thread_context_collector_sample_allocation(state->thread_context_collector_instance, weight, new_object);
1462
+ bool needs_after_allocation = thread_context_collector_sample_allocation(state->thread_context_collector_instance, thread_context, weight, new_object);
1316
1463
  // ...but we still represent the skipped samples in the profile, thus the data will account for all allocations.
1317
1464
  if (weight < allocations_since_last_sample) {
1318
1465
  uint32_t skipped_samples = (uint32_t) uint64_min_of(allocations_since_last_sample - weight, UINT32_MAX);
1319
1466
  thread_context_collector_sample_skipped_allocation_samples(state->thread_context_collector_instance, skipped_samples);
1320
1467
  }
1321
1468
 
1469
+ if (needs_after_allocation) {
1470
+ #ifndef NO_POSTPONED_TRIGGER
1471
+ rb_postponed_job_trigger(after_allocation_from_postponed_job_handle);
1472
+ #else
1473
+ // Not needed on legacy rubies
1474
+ #endif
1475
+ }
1476
+
1322
1477
  // Return a dummy VALUE because we're called from rb_rescue2 which requires it
1323
1478
  return Qnil;
1324
1479
  }
@@ -1361,44 +1516,69 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) {
1361
1516
  #ifndef NO_GVL_INSTRUMENTATION
1362
1517
  static void on_gvl_event(rb_event_flag_t event_id, const rb_internal_thread_event_data_t *event_data, DDTRACE_UNUSED void *_unused) {
1363
1518
  // Be very careful about touching the `state` here or doing anything at all:
1364
- // This function gets called without the GVL, and potentially from background Ractors!
1519
+ // This function gets called without the GVL, and potentially from non-main Ractors!
1365
1520
  //
1366
- // In fact, the `target_thread` that this event is about may not even be the current thread. (So be careful with thread locals that
1367
- // are not directly tied to the `target_thread` object and the like)
1368
- gvl_profiling_thread target_thread = thread_from_event(event_data);
1521
+ // Note, even though these events can get called without the GVL, they synchronize-with enabling/disabling of
1522
+ // the hook that calls us using a read-write lock. Thus, disabling the hook cannot be concurrent with calling this function,
1523
+ // and once the disable finishes there can't be "late" calls into this function.
1524
+
1525
+ // The thread that this event is about may not be the current thread
1526
+ // (as documented on rb_internal_thread_add_event_hook(), and this is notably the case for READY on Ruby 4.0),
1527
+ // so be careful with native thread locals that are not directly tied to the thread object and the like.
1528
+
1529
+ #ifdef HAVE_RUBY_THREAD_STORAGE_API
1530
+ VALUE target_thread = event_data->thread;
1531
+ #else
1532
+ // On Ruby 3.2 the event does not carry the thread, but all events fire on the thread itself.
1533
+ // However, during early thread startup rb_thread_current() can crash because the execution context (Fiber) isn't
1534
+ // stored in TLS yet; ruby_native_thread_p() guards against this.
1535
+ if (!ruby_native_thread_p()) return;
1536
+ VALUE target_thread = rb_thread_current();
1537
+ #endif
1538
+
1539
+ per_thread_context* thread_context = get_per_thread_context(target_thread);
1540
+ if (!thread_context) return;
1541
+ // If non-NULL the thread is profiled and from the main Ractor
1369
1542
 
1370
- if (event_id == RUBY_INTERNAL_THREAD_EVENT_READY) { /* waiting for gvl */
1371
- thread_context_collector_on_gvl_waiting(target_thread);
1543
+ if (event_id == RUBY_INTERNAL_THREAD_EVENT_SUSPENDED) { /* released gvl */
1544
+ thread_context_collector_on_gvl_released(thread_context);
1545
+ } else if (event_id == RUBY_INTERNAL_THREAD_EVENT_READY) { /* waiting for gvl */
1546
+ thread_context_collector_on_gvl_waiting(thread_context);
1372
1547
  } else if (event_id == RUBY_INTERNAL_THREAD_EVENT_RESUMED) { /* running/runnable */
1373
- // Interesting note: A RUBY_INTERNAL_THREAD_EVENT_RESUMED is guaranteed to be called with the GVL being acquired.
1374
- // (And... I think target_thread will be == rb_thread_current()?)
1548
+ // Interesting note: A RUBY_INTERNAL_THREAD_EVENT_RESUMED is guaranteed to be called with the GVL being acquired
1549
+ // and on the event thread.
1550
+ // However, on_gvl_event() is called while holding the scheduler lock, so we do as little work as possible here,
1551
+ // and perform the sample in a postponed_job.
1552
+ cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
1553
+ if (state == NULL) return; // This should not happen, but just in case...
1554
+
1555
+ // on_gvl_running prepares a stack sample so we need to gate it with `during_sample_enter` to avoid a
1556
+ // SIGPROF signal coming in during that function and potentially causing a corrupted final state.
1375
1557
  //
1376
- // But we're not sure if we're on the main Ractor yet. The thread context collector actually can actually help here:
1377
- // it tags threads it's tracking, so if a thread is tagged then by definition we know that thread belongs to the main
1378
- // Ractor. Thus, if we get a ON_GVL_RUNNING_UNKNOWN result we shouldn't touch any state, but otherwise we're good to go.
1558
+ // TODO: Currently, the sample prepared in on_gvl_running can still be clobbered if the signal handler runs
1559
+ // after `during_sample_exit` but before `after_gvl_running_from_postponed_job` gets to run. We'll need to fix
1560
+ // that next.
1561
+ during_sample_enter(state);
1379
1562
 
1380
- #ifdef USE_GVL_PROFILING_3_2_WORKAROUNDS
1381
- target_thread = gvl_profiling_state_maybe_initialize();
1382
- #endif
1563
+ on_gvl_running_result result = thread_context_collector_on_gvl_running(state->thread_context_collector_instance, target_thread, thread_context);
1564
+
1565
+ during_sample_exit(state);
1383
1566
 
1384
- on_gvl_running_result result = thread_context_collector_on_gvl_running(target_thread);
1567
+ if (result.waiting_for_gvl_duration_ns > 0) {
1568
+ state->stats.vm_metrics.gvl_waiting_time_ns_total += (uint64_t) result.waiting_for_gvl_duration_ns;
1569
+ }
1385
1570
 
1386
- if (result == ON_GVL_RUNNING_SAMPLE) {
1571
+ if (result.action == ON_GVL_RUNNING_SAMPLE) {
1387
1572
  #ifndef NO_POSTPONED_TRIGGER
1388
1573
  rb_postponed_job_trigger(after_gvl_running_from_postponed_job_handle);
1389
1574
  #else
1390
1575
  rb_postponed_job_register_one(0, after_gvl_running_from_postponed_job, NULL);
1391
1576
  #endif
1392
- } else if (result == ON_GVL_RUNNING_DONT_SAMPLE) {
1393
- cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
1394
-
1395
- if (state == NULL) return; // This should not happen, but just in case...
1396
-
1577
+ } else if (result.action == ON_GVL_RUNNING_DONT_SAMPLE) {
1397
1578
  state->stats.gvl_dont_sample++;
1398
1579
  }
1399
1580
  } else {
1400
- // This is a very delicate time and it's hard for us to raise an exception so let's at least complain to stderr
1401
- fprintf(stderr, "[ddtrace] Unexpected value in on_gvl_event (%d)\n", event_id);
1581
+ rb_bug("[ddtrace] Unexpected value in on_gvl_event (%d)\n", event_id);
1402
1582
  }
1403
1583
  }
1404
1584
 
@@ -1449,6 +1629,11 @@ static VALUE _native_resume_signals(DDTRACE_UNUSED VALUE self) {
1449
1629
 
1450
1630
  return state->gvl_profiling_hook != NULL ? Qtrue : Qfalse;
1451
1631
  }
1632
+
1633
+ static VALUE handle_sampling_failure_rescued_after_gvl_running_from_postponed_job(VALUE self_instance, VALUE exception) {
1634
+ stop(self_instance, exception, "rescued_after_gvl_running_from_postponed_job");
1635
+ return Qnil;
1636
+ }
1452
1637
  #else
1453
1638
  static VALUE _native_gvl_profiling_hook_active(DDTRACE_UNUSED VALUE self, DDTRACE_UNUSED VALUE instance) {
1454
1639
  return Qfalse;
@@ -1470,11 +1655,50 @@ static VALUE handle_sampling_failure_rescued_sample_allocation(VALUE self_instan
1470
1655
  return Qnil;
1471
1656
  }
1472
1657
 
1473
- static VALUE handle_sampling_failure_rescued_after_gvl_running_from_postponed_job(VALUE self_instance, VALUE exception) {
1474
- stop(self_instance, exception, "rescued_after_gvl_running_from_postponed_job");
1658
+ static VALUE handle_sampling_failure_rescued_after_allocation(VALUE self_instance, VALUE exception) {
1659
+ stop(self_instance, exception, "rescued_after_allocation");
1475
1660
  return Qnil;
1476
1661
  }
1477
1662
 
1663
+ static VALUE rescued_after_allocation(VALUE self_instance) {
1664
+ cpu_and_wall_time_worker_state *state;
1665
+ TypedData_Get_Struct(self_instance, cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
1666
+
1667
+ thread_context_collector_after_allocation(state->thread_context_collector_instance);
1668
+
1669
+ // Return a dummy VALUE because we're called from rb_rescue2 which requires it
1670
+ return Qnil;
1671
+ }
1672
+
1673
+ // This postponed job callback is used to finalize heap allocation recordings on Ruby 4+.
1674
+ // During on_newobj_event, calling rb_obj_id() is unsafe because it mutates the object.
1675
+ // So we defer getting the object_id until after the event completes.
1676
+ #pragma GCC diagnostic push
1677
+ #pragma GCC diagnostic ignored "-Wunused-function" // This is only used for some Rubies, but we want to build on all to make it easier to dev
1678
+ static void after_allocation_from_postponed_job(DDTRACE_UNUSED void *_unused) {
1679
+ cpu_and_wall_time_worker_state *state = active_sampler_instance_state;
1680
+
1681
+ if (state == NULL || !ddtrace_rb_ractor_main_p()) return;
1682
+
1683
+ // Protect against nested operations
1684
+ if (state->during_sample) return;
1685
+
1686
+ during_sample_enter(state);
1687
+
1688
+ // NOTE: We're not updating the allocation_sampler here.
1689
+ // This means work done in this function isn't accounted for as profiler overhead.
1690
+ // This is acceptable as the amount of work done here is expected to be small.
1691
+ safely_call(
1692
+ rescued_after_allocation,
1693
+ state->self_instance,
1694
+ state->self_instance,
1695
+ handle_sampling_failure_rescued_after_allocation
1696
+ );
1697
+
1698
+ during_sample_exit(state);
1699
+ }
1700
+ #pragma GCC diagnostic pop
1701
+
1478
1702
  static inline void during_sample_enter(cpu_and_wall_time_worker_state* state) {
1479
1703
  // Tell the compiler it's not allowed to reorder the `during_sample` flag with anything that happens after.
1480
1704
  //