datadog 2.4.0 → 2.44.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 (1070) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1261 -1
  3. data/README.md +3 -1
  4. data/bin/ddprofrb +4 -4
  5. data/ext/LIBDATADOG_DEVELOPMENT.md +3 -0
  6. data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +12 -24
  7. data/ext/datadog_profiling_native_extension/clock_id.h +11 -3
  8. data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +66 -0
  9. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +3 -2
  10. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +653 -212
  11. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +5 -5
  12. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
  13. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +3 -2
  14. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +33 -20
  15. data/ext/datadog_profiling_native_extension/collectors_stack.c +409 -113
  16. data/ext/datadog_profiling_native_extension/collectors_stack.h +41 -5
  17. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +1208 -623
  18. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +33 -8
  19. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +240 -0
  20. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +85 -16
  21. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +47 -1
  22. data/ext/datadog_profiling_native_extension/encoded_profile.c +80 -0
  23. data/ext/datadog_profiling_native_extension/encoded_profile.h +8 -0
  24. data/ext/datadog_profiling_native_extension/extconf.rb +99 -120
  25. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +6 -43
  26. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +15 -55
  27. data/ext/datadog_profiling_native_extension/heap_recorder.c +762 -608
  28. data/ext/datadog_profiling_native_extension/heap_recorder.h +67 -28
  29. data/ext/datadog_profiling_native_extension/http_transport.c +108 -144
  30. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +18 -15
  31. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -10
  32. data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
  33. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -40
  34. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +796 -417
  35. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +48 -12
  36. data/ext/datadog_profiling_native_extension/profiling.c +93 -27
  37. data/ext/datadog_profiling_native_extension/ruby_helpers.c +77 -137
  38. data/ext/datadog_profiling_native_extension/ruby_helpers.h +21 -20
  39. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +34 -10
  40. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +2 -1
  41. data/ext/datadog_profiling_native_extension/stack_recorder.c +458 -302
  42. data/ext/datadog_profiling_native_extension/stack_recorder.h +14 -3
  43. data/ext/datadog_profiling_native_extension/time_helpers.h +18 -11
  44. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +48 -0
  45. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +36 -0
  46. data/ext/libdatadog_api/crashtracker.c +33 -30
  47. data/ext/libdatadog_api/crashtracker.h +5 -0
  48. data/ext/libdatadog_api/crashtracker_report_exception.c +126 -0
  49. data/ext/libdatadog_api/datadog_ruby_common.c +85 -16
  50. data/ext/libdatadog_api/datadog_ruby_common.h +47 -1
  51. data/ext/libdatadog_api/ddsketch.c +102 -0
  52. data/ext/libdatadog_api/di.c +218 -0
  53. data/ext/libdatadog_api/extconf.rb +44 -45
  54. data/ext/libdatadog_api/feature_flags.c +588 -0
  55. data/ext/libdatadog_api/feature_flags.h +5 -0
  56. data/ext/libdatadog_api/helpers.h +27 -0
  57. data/ext/libdatadog_api/init.c +35 -0
  58. data/ext/libdatadog_api/library_config.c +173 -0
  59. data/ext/libdatadog_api/library_config.h +25 -0
  60. data/ext/libdatadog_api/otel_thread_context.c +268 -0
  61. data/ext/libdatadog_api/otel_thread_context.h +5 -0
  62. data/ext/libdatadog_api/process_discovery.c +118 -0
  63. data/ext/libdatadog_api/process_discovery.h +5 -0
  64. data/ext/libdatadog_api/trace_exporter.c +1932 -0
  65. data/ext/libdatadog_api/trace_exporter.h +5 -0
  66. data/ext/libdatadog_extconf_helpers.rb +116 -18
  67. data/lib/datadog/ai_guard/autoload.rb +10 -0
  68. data/lib/datadog/ai_guard/component.rb +53 -0
  69. data/lib/datadog/ai_guard/configuration/ext.rb +19 -0
  70. data/lib/datadog/ai_guard/configuration.rb +128 -0
  71. data/lib/datadog/ai_guard/contrib/auto_instrument.rb +24 -0
  72. data/lib/datadog/ai_guard/contrib/integration.rb +37 -0
  73. data/lib/datadog/ai_guard/contrib/rack/integration.rb +42 -0
  74. data/lib/datadog/ai_guard/contrib/rack/patcher.rb +26 -0
  75. data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +97 -0
  76. data/lib/datadog/ai_guard/contrib/rails/integration.rb +41 -0
  77. data/lib/datadog/ai_guard/contrib/rails/patcher.rb +97 -0
  78. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +73 -0
  79. data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +41 -0
  80. data/lib/datadog/ai_guard/contrib/ruby_llm/message_adapter.rb +76 -0
  81. data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +31 -0
  82. data/lib/datadog/ai_guard/contrib/ruby_llm/redaction_change_set.rb +135 -0
  83. data/lib/datadog/ai_guard/evaluation/client.rb +50 -0
  84. data/lib/datadog/ai_guard/evaluation/content_part.rb +48 -0
  85. data/lib/datadog/ai_guard/evaluation/message.rb +43 -0
  86. data/lib/datadog/ai_guard/evaluation/message_builder.rb +31 -0
  87. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +36 -0
  88. data/lib/datadog/ai_guard/evaluation/outcome.rb +24 -0
  89. data/lib/datadog/ai_guard/evaluation/request.rb +30 -0
  90. data/lib/datadog/ai_guard/evaluation/response.rb +33 -0
  91. data/lib/datadog/ai_guard/evaluation/result.rb +38 -0
  92. data/lib/datadog/ai_guard/evaluation/tool_call.rb +31 -0
  93. data/lib/datadog/ai_guard/evaluation.rb +130 -0
  94. data/lib/datadog/ai_guard/ext.rb +32 -0
  95. data/lib/datadog/ai_guard/http_client.rb +86 -0
  96. data/lib/datadog/ai_guard/metrics/telemetry.rb +43 -0
  97. data/lib/datadog/ai_guard/redaction/replacements.rb +97 -0
  98. data/lib/datadog/ai_guard/redaction/result.rb +29 -0
  99. data/lib/datadog/ai_guard/redaction.rb +80 -0
  100. data/lib/datadog/ai_guard.rb +182 -0
  101. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +68 -0
  102. data/lib/datadog/appsec/actions_handler.rb +49 -0
  103. data/lib/datadog/appsec/anonymizer.rb +16 -0
  104. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
  105. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +66 -0
  106. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +36 -0
  107. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
  108. data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
  109. data/lib/datadog/appsec/api_security/route_extractor.rb +104 -0
  110. data/lib/datadog/appsec/api_security/sampler.rb +62 -0
  111. data/lib/datadog/appsec/api_security.rb +23 -0
  112. data/lib/datadog/appsec/assets/blocked.html +1 -99
  113. data/lib/datadog/appsec/assets/blocked.json +1 -1
  114. data/lib/datadog/appsec/assets/blocked.text +3 -1
  115. data/lib/datadog/appsec/assets/waf_rules/README.md +44 -5
  116. data/lib/datadog/appsec/assets/waf_rules/recommended.json +954 -229
  117. data/lib/datadog/appsec/assets/waf_rules/strict.json +109 -106
  118. data/lib/datadog/appsec/assets.rb +8 -8
  119. data/lib/datadog/appsec/autoload.rb +5 -5
  120. data/lib/datadog/appsec/component.rb +56 -75
  121. data/lib/datadog/appsec/compressed_json.rb +40 -0
  122. data/lib/datadog/appsec/configuration.rb +436 -1
  123. data/lib/datadog/appsec/context.rb +135 -0
  124. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +94 -0
  125. data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
  126. data/lib/datadog/appsec/contrib/active_record/patcher.rb +104 -0
  127. data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
  128. data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +75 -0
  129. data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +39 -0
  130. data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +30 -0
  131. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +146 -0
  132. data/lib/datadog/appsec/contrib/devise/configuration.rb +52 -0
  133. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +78 -0
  134. data/lib/datadog/appsec/contrib/devise/ext.rb +22 -0
  135. data/lib/datadog/appsec/contrib/devise/integration.rb +5 -6
  136. data/lib/datadog/appsec/contrib/devise/patcher.rb +34 -26
  137. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +104 -0
  138. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +70 -0
  139. data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +3 -3
  140. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +121 -0
  141. data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
  142. data/lib/datadog/appsec/contrib/excon/patcher.rb +30 -0
  143. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +181 -0
  144. data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
  145. data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
  146. data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
  147. data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
  148. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +166 -0
  149. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +4 -10
  150. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +76 -26
  151. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +21 -36
  152. data/lib/datadog/appsec/contrib/graphql/integration.rb +10 -9
  153. data/lib/datadog/appsec/contrib/graphql/patcher.rb +3 -6
  154. data/lib/datadog/appsec/contrib/rack/buffered_input.rb +83 -0
  155. data/lib/datadog/appsec/contrib/rack/ext.rb +34 -0
  156. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +56 -21
  157. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +4 -4
  158. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +101 -106
  159. data/lib/datadog/appsec/contrib/rack/input_peeker.rb +79 -0
  160. data/lib/datadog/appsec/contrib/rack/integration.rb +7 -7
  161. data/lib/datadog/appsec/contrib/rack/patcher.rb +3 -6
  162. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +17 -15
  163. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +118 -114
  164. data/lib/datadog/appsec/contrib/rack/response_body.rb +36 -0
  165. data/lib/datadog/appsec/contrib/rails/gateway/request.rb +43 -4
  166. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +58 -35
  167. data/lib/datadog/appsec/contrib/rails/integration.rb +6 -6
  168. data/lib/datadog/appsec/contrib/rails/patcher.rb +82 -69
  169. data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +29 -0
  170. data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +33 -0
  171. data/lib/datadog/appsec/contrib/rails/request.rb +3 -3
  172. data/lib/datadog/appsec/contrib/rails/request_middleware.rb +2 -1
  173. data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
  174. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +30 -0
  175. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +193 -0
  176. data/lib/datadog/appsec/contrib/sinatra/gateway/request.rb +1 -1
  177. data/lib/datadog/appsec/contrib/sinatra/gateway/route_params.rb +1 -1
  178. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +83 -71
  179. data/lib/datadog/appsec/contrib/sinatra/integration.rb +6 -6
  180. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +25 -61
  181. data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +31 -0
  182. data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
  183. data/lib/datadog/appsec/counter_sampler.rb +25 -0
  184. data/lib/datadog/appsec/default_header_tags.rb +52 -0
  185. data/lib/datadog/appsec/event.rb +80 -128
  186. data/lib/datadog/appsec/ext.rb +17 -1
  187. data/lib/datadog/appsec/extensions.rb +2 -2
  188. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +23 -2
  189. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +23 -0
  190. data/lib/datadog/appsec/instrumentation/gateway.rb +6 -24
  191. data/lib/datadog/appsec/metrics/collector.rb +80 -0
  192. data/lib/datadog/appsec/metrics/exporter.rb +48 -0
  193. data/lib/datadog/appsec/metrics/telemetry.rb +40 -0
  194. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +47 -0
  195. data/lib/datadog/appsec/metrics.rb +14 -0
  196. data/lib/datadog/appsec/monitor/gateway/watcher.rb +60 -36
  197. data/lib/datadog/appsec/monitor.rb +1 -1
  198. data/lib/datadog/appsec/processor/rule_loader.rb +54 -60
  199. data/lib/datadog/appsec/rate_limiter.rb +1 -1
  200. data/lib/datadog/appsec/remote.rb +59 -70
  201. data/lib/datadog/appsec/response.rb +42 -94
  202. data/lib/datadog/appsec/route_normalizer/rails_route_pattern.rb +176 -0
  203. data/lib/datadog/appsec/route_normalizer/route_pattern.rb +378 -0
  204. data/lib/datadog/appsec/route_normalizer/route_text.rb +57 -0
  205. data/lib/datadog/appsec/route_normalizer.rb +80 -0
  206. data/lib/datadog/appsec/security_engine/engine.rb +197 -0
  207. data/lib/datadog/appsec/security_engine/result.rb +103 -0
  208. data/lib/datadog/appsec/security_engine/runner.rb +111 -0
  209. data/lib/datadog/appsec/security_engine.rb +9 -0
  210. data/lib/datadog/appsec/security_event.rb +37 -0
  211. data/lib/datadog/appsec/thread_safe_ref.rb +61 -0
  212. data/lib/datadog/appsec/trace_keeper.rb +36 -0
  213. data/lib/datadog/appsec/utils/hash_coercion.rb +23 -0
  214. data/lib/datadog/appsec/utils/http/body.rb +41 -0
  215. data/lib/datadog/appsec/utils/http/body_reader.rb +61 -0
  216. data/lib/datadog/appsec/utils/http/media_range.rb +17 -16
  217. data/lib/datadog/appsec/utils/http/media_type.rb +33 -27
  218. data/lib/datadog/appsec/utils/http/url_encoded.rb +107 -0
  219. data/lib/datadog/appsec.rb +35 -28
  220. data/lib/datadog/auto_instrument.rb +5 -2
  221. data/lib/datadog/auto_instrument_base.rb +2 -1
  222. data/lib/datadog/core/buffer/cruby.rb +1 -1
  223. data/lib/datadog/core/buffer/random.rb +18 -2
  224. data/lib/datadog/core/buffer/thread_safe.rb +1 -1
  225. data/lib/datadog/core/configuration/agent_settings.rb +52 -0
  226. data/lib/datadog/core/configuration/agent_settings_resolver.rb +46 -59
  227. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  228. data/lib/datadog/core/configuration/base.rb +19 -7
  229. data/lib/datadog/core/configuration/components.rb +283 -54
  230. data/lib/datadog/core/configuration/components_state.rb +28 -0
  231. data/lib/datadog/core/configuration/config_helper.rb +109 -0
  232. data/lib/datadog/core/configuration/deprecations.rb +36 -0
  233. data/lib/datadog/core/configuration/ext.rb +15 -12
  234. data/lib/datadog/core/configuration/option.rb +150 -84
  235. data/lib/datadog/core/configuration/option_definition.rb +51 -30
  236. data/lib/datadog/core/configuration/options.rb +58 -19
  237. data/lib/datadog/core/configuration/settings.rb +341 -140
  238. data/lib/datadog/core/configuration/stable_config.rb +32 -0
  239. data/lib/datadog/core/configuration/supported_configurations.rb +426 -0
  240. data/lib/datadog/core/configuration.rb +51 -21
  241. data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
  242. data/lib/datadog/core/contrib/rails/utils.rb +28 -0
  243. data/lib/datadog/core/crashtracking/component.rb +89 -39
  244. data/lib/datadog/core/crashtracking/tag_builder.rb +11 -23
  245. data/lib/datadog/core/ddsketch.rb +19 -0
  246. data/lib/datadog/core/deprecations.rb +3 -3
  247. data/lib/datadog/core/diagnostics/environment_logger.rb +46 -9
  248. data/lib/datadog/core/diagnostics/health.rb +2 -2
  249. data/lib/datadog/core/encoding.rb +21 -5
  250. data/lib/datadog/core/environment/agent_info.rb +142 -0
  251. data/lib/datadog/core/environment/cgroup.rb +53 -28
  252. data/lib/datadog/core/environment/container.rb +143 -51
  253. data/lib/datadog/core/environment/execution.rb +3 -3
  254. data/lib/datadog/core/environment/ext.rb +32 -21
  255. data/lib/datadog/core/environment/gc.rb +1 -1
  256. data/lib/datadog/core/environment/git.rb +5 -4
  257. data/lib/datadog/core/environment/identity.rb +50 -14
  258. data/lib/datadog/core/environment/platform.rb +8 -8
  259. data/lib/datadog/core/environment/process.rb +122 -0
  260. data/lib/datadog/core/environment/socket.rb +15 -2
  261. data/lib/datadog/core/environment/variable_helpers.rb +4 -4
  262. data/lib/datadog/core/environment/vm_cache.rb +1 -1
  263. data/lib/datadog/core/environment/yjit.rb +8 -2
  264. data/lib/datadog/core/error.rb +15 -13
  265. data/lib/datadog/core/evp.rb +11 -0
  266. data/lib/datadog/core/extensions.rb +1 -1
  267. data/lib/datadog/core/feature_flags.rb +61 -0
  268. data/lib/datadog/core/git/ext.rb +4 -4
  269. data/lib/datadog/core/knuth_sampler.rb +59 -0
  270. data/lib/datadog/core/logger.rb +5 -5
  271. data/lib/datadog/core/logging/ext.rb +1 -1
  272. data/lib/datadog/core/metrics/client.rb +49 -49
  273. data/lib/datadog/core/metrics/ext.rb +5 -5
  274. data/lib/datadog/core/metrics/helpers.rb +1 -1
  275. data/lib/datadog/core/metrics/logging.rb +8 -8
  276. data/lib/datadog/core/metrics/options.rb +5 -5
  277. data/lib/datadog/core/pin.rb +9 -9
  278. data/lib/datadog/core/process_discovery/tracer_memfd.rb +13 -0
  279. data/lib/datadog/core/process_discovery.rb +62 -0
  280. data/lib/datadog/core/rate_limiter.rb +16 -4
  281. data/lib/datadog/core/remote/client/capabilities.rb +82 -11
  282. data/lib/datadog/core/remote/client.rb +130 -107
  283. data/lib/datadog/core/remote/component.rb +97 -55
  284. data/lib/datadog/core/remote/configuration/content.rb +17 -4
  285. data/lib/datadog/core/remote/configuration/digest.rb +22 -15
  286. data/lib/datadog/core/remote/configuration/path.rb +9 -9
  287. data/lib/datadog/core/remote/configuration/repository.rb +19 -6
  288. data/lib/datadog/core/remote/configuration/target.rb +15 -8
  289. data/lib/datadog/core/remote/configuration.rb +4 -4
  290. data/lib/datadog/core/remote/ext.rb +3 -3
  291. data/lib/datadog/core/remote/negotiation.rb +10 -10
  292. data/lib/datadog/core/remote/tie/tracing.rb +7 -7
  293. data/lib/datadog/core/remote/transport/config.rb +11 -37
  294. data/lib/datadog/core/remote/transport/http/config.rb +39 -107
  295. data/lib/datadog/core/remote/transport/http/negotiation.rb +19 -92
  296. data/lib/datadog/core/remote/transport/http.rb +33 -106
  297. data/lib/datadog/core/remote/transport/negotiation.rb +9 -21
  298. data/lib/datadog/core/remote/worker.rb +40 -41
  299. data/lib/datadog/core/runtime/ext.rb +22 -22
  300. data/lib/datadog/core/runtime/metrics.rb +34 -14
  301. data/lib/datadog/core/semaphore.rb +32 -0
  302. data/lib/datadog/core/tag_builder.rb +52 -0
  303. data/lib/datadog/core/tag_normalizer.rb +84 -0
  304. data/lib/datadog/core/telemetry/component.rb +143 -60
  305. data/lib/datadog/core/telemetry/configuration_value.rb +38 -0
  306. data/lib/datadog/core/telemetry/emitter.rb +26 -14
  307. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +67 -0
  308. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  309. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  310. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
  311. data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
  312. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  313. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  314. data/lib/datadog/core/telemetry/event/app_started.rb +274 -0
  315. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  316. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  317. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  318. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  319. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  320. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +66 -0
  321. data/lib/datadog/core/telemetry/event.rb +21 -392
  322. data/lib/datadog/core/telemetry/ext.rb +11 -9
  323. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  324. data/lib/datadog/core/telemetry/logger.rb +6 -3
  325. data/lib/datadog/core/telemetry/logging.rb +35 -17
  326. data/lib/datadog/core/telemetry/metric.rb +37 -15
  327. data/lib/datadog/core/telemetry/metrics_collection.rb +2 -2
  328. data/lib/datadog/core/telemetry/metrics_manager.rb +10 -1
  329. data/lib/datadog/core/telemetry/request.rb +23 -11
  330. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +66 -0
  331. data/lib/datadog/core/telemetry/transport/http.rb +68 -0
  332. data/lib/datadog/core/telemetry/transport/telemetry.rb +42 -0
  333. data/lib/datadog/core/telemetry/worker.rb +214 -35
  334. data/lib/datadog/core/transport/ext.rb +14 -10
  335. data/lib/datadog/core/transport/http/adapters/net.rb +19 -4
  336. data/lib/datadog/core/transport/http/adapters/test.rb +3 -2
  337. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +5 -5
  338. data/lib/datadog/core/transport/http/api/endpoint.rb +10 -5
  339. data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +5 -5
  340. data/lib/datadog/core/transport/http/api/map.rb +1 -1
  341. data/lib/datadog/{tracing → core}/transport/http/builder.rb +62 -36
  342. data/lib/datadog/core/transport/http/client.rb +80 -0
  343. data/lib/datadog/core/transport/http/env.rb +8 -0
  344. data/lib/datadog/core/transport/http/response.rb +5 -1
  345. data/lib/datadog/core/transport/http.rb +80 -0
  346. data/lib/datadog/core/transport/parcel.rb +61 -9
  347. data/lib/datadog/core/transport/response.rb +19 -1
  348. data/lib/datadog/core/transport/transport.rb +90 -0
  349. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +181 -29
  350. data/lib/datadog/core/utils/base64_codec.rb +23 -0
  351. data/lib/datadog/core/utils/duration.rb +33 -33
  352. data/lib/datadog/core/utils/enumerable_compat.rb +29 -0
  353. data/lib/datadog/core/utils/fnv.rb +26 -0
  354. data/lib/datadog/core/utils/forking.rb +5 -3
  355. data/lib/datadog/core/utils/hash.rb +0 -23
  356. data/lib/datadog/core/utils/lru_cache.rb +45 -0
  357. data/lib/datadog/core/utils/network.rb +34 -13
  358. data/lib/datadog/core/utils/only_once.rb +1 -1
  359. data/lib/datadog/core/utils/only_once_successful.rb +25 -8
  360. data/lib/datadog/core/utils/safe_dup.rb +4 -3
  361. data/lib/datadog/core/utils/sequence.rb +3 -4
  362. data/lib/datadog/core/utils/spawn_monkey_patch.rb +68 -0
  363. data/lib/datadog/core/utils/time.rb +19 -33
  364. data/lib/datadog/core/utils/truncation.rb +21 -0
  365. data/lib/datadog/core/utils/url.rb +1 -1
  366. data/lib/datadog/core/utils.rb +14 -5
  367. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  368. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  369. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  370. data/lib/datadog/core/worker.rb +1 -1
  371. data/lib/datadog/core/workers/async.rb +41 -15
  372. data/lib/datadog/core/workers/interval_loop.rb +63 -4
  373. data/lib/datadog/core/workers/polling.rb +4 -2
  374. data/lib/datadog/core/workers/queue.rb +96 -1
  375. data/lib/datadog/core/workers/runtime_metrics.rb +14 -6
  376. data/lib/datadog/core.rb +20 -3
  377. data/lib/datadog/data_streams/configuration.rb +50 -0
  378. data/lib/datadog/data_streams/ext.rb +11 -0
  379. data/lib/datadog/data_streams/extensions.rb +16 -0
  380. data/lib/datadog/data_streams/pathway_context.rb +167 -0
  381. data/lib/datadog/data_streams/processor.rb +542 -0
  382. data/lib/datadog/data_streams/transport/http/stats.rb +58 -0
  383. data/lib/datadog/data_streams/transport/http.rb +36 -0
  384. data/lib/datadog/data_streams/transport/stats.rb +39 -0
  385. data/lib/datadog/data_streams.rb +100 -0
  386. data/lib/datadog/di/base.rb +123 -0
  387. data/lib/datadog/di/boot.rb +47 -0
  388. data/lib/datadog/di/capture_expression.rb +21 -0
  389. data/lib/datadog/di/capture_expression_evaluator.rb +71 -0
  390. data/lib/datadog/di/capture_limits.rb +41 -0
  391. data/lib/datadog/di/code_tracker.rb +256 -18
  392. data/lib/datadog/di/component.rb +220 -0
  393. data/lib/datadog/di/configuration.rb +241 -2
  394. data/lib/datadog/di/context.rb +82 -0
  395. data/lib/datadog/di/contrib/active_record.rb +41 -0
  396. data/lib/datadog/di/contrib/railtie.rb +15 -0
  397. data/lib/datadog/di/contrib.rb +28 -0
  398. data/lib/datadog/di/el/compiler.rb +244 -0
  399. data/lib/datadog/di/el/evaluator.rb +239 -0
  400. data/lib/datadog/di/el/expression.rb +53 -0
  401. data/lib/datadog/di/el.rb +5 -0
  402. data/lib/datadog/di/error.rb +66 -0
  403. data/lib/datadog/di/fatal_exceptions.rb +26 -0
  404. data/lib/datadog/di/instrumenter.rb +978 -0
  405. data/lib/datadog/di/logger.rb +30 -0
  406. data/lib/datadog/di/preload.rb +18 -0
  407. data/lib/datadog/di/probe.rb +188 -14
  408. data/lib/datadog/di/probe_builder.rb +132 -3
  409. data/lib/datadog/di/probe_file_loader/railtie.rb +15 -0
  410. data/lib/datadog/di/probe_file_loader.rb +87 -0
  411. data/lib/datadog/di/probe_manager.rb +352 -0
  412. data/lib/datadog/di/probe_notification_builder.rb +452 -0
  413. data/lib/datadog/di/probe_notifier_worker.rb +381 -0
  414. data/lib/datadog/di/probe_repository.rb +198 -0
  415. data/lib/datadog/di/proc_responder.rb +36 -0
  416. data/lib/datadog/di/redactor.rb +24 -3
  417. data/lib/datadog/di/remote.rb +310 -0
  418. data/lib/datadog/di/serializer.rb +487 -96
  419. data/lib/datadog/di/transport/diagnostics.rb +32 -0
  420. data/lib/datadog/di/transport/http/diagnostics.rb +35 -0
  421. data/lib/datadog/di/transport/http/input.rb +45 -0
  422. data/lib/datadog/di/transport/http.rb +81 -0
  423. data/lib/datadog/di/transport/input.rb +144 -0
  424. data/lib/datadog/di/utils.rb +170 -0
  425. data/lib/datadog/di.rb +224 -2
  426. data/lib/datadog/error_tracking/collector.rb +88 -0
  427. data/lib/datadog/error_tracking/component.rb +167 -0
  428. data/lib/datadog/error_tracking/configuration.rb +64 -0
  429. data/lib/datadog/error_tracking/ext.rb +18 -0
  430. data/lib/datadog/error_tracking/extensions.rb +16 -0
  431. data/lib/datadog/error_tracking/filters.rb +77 -0
  432. data/lib/datadog/error_tracking.rb +18 -0
  433. data/lib/datadog/kit/appsec/events/v2.rb +253 -0
  434. data/lib/datadog/kit/appsec/events.rb +39 -26
  435. data/lib/datadog/kit/enable_core_dumps.rb +3 -3
  436. data/lib/datadog/kit/identity.rb +34 -24
  437. data/lib/datadog/kit/tracing/method_tracer.rb +135 -0
  438. data/lib/datadog/kit.rb +1 -1
  439. data/lib/datadog/open_feature/agentless/configuration_source.rb +246 -0
  440. data/lib/datadog/open_feature/agentless/parser.rb +43 -0
  441. data/lib/datadog/open_feature/agentless/response.rb +19 -0
  442. data/lib/datadog/open_feature/agentless/transport.rb +103 -0
  443. data/lib/datadog/open_feature/component.rb +165 -0
  444. data/lib/datadog/open_feature/configuration/agentless_endpoint.rb +90 -0
  445. data/lib/datadog/open_feature/configuration/source/resolution.rb +22 -0
  446. data/lib/datadog/open_feature/configuration/source.rb +43 -0
  447. data/lib/datadog/open_feature/configuration.rb +168 -0
  448. data/lib/datadog/open_feature/evaluation_engine.rb +96 -0
  449. data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
  450. data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
  451. data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
  452. data/lib/datadog/open_feature/exposures/event.rb +67 -0
  453. data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
  454. data/lib/datadog/open_feature/exposures/worker.rb +116 -0
  455. data/lib/datadog/open_feature/ext.rb +40 -0
  456. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +442 -0
  457. data/lib/datadog/open_feature/flag_evaluation/writer.rb +544 -0
  458. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +105 -0
  459. data/lib/datadog/open_feature/hooks/flag_eval_metrics_hook.rb +51 -0
  460. data/lib/datadog/open_feature/hooks/span_enrichment_hook/codec.rb +58 -0
  461. data/lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state.rb +96 -0
  462. data/lib/datadog/open_feature/hooks/span_enrichment_hook/span_enrichment_state_store.rb +49 -0
  463. data/lib/datadog/open_feature/hooks/span_enrichment_hook.rb +184 -0
  464. data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
  465. data/lib/datadog/open_feature/native_evaluator.rb +74 -0
  466. data/lib/datadog/open_feature/noop_evaluator.rb +31 -0
  467. data/lib/datadog/open_feature/provider.rb +235 -0
  468. data/lib/datadog/open_feature/remote.rb +67 -0
  469. data/lib/datadog/open_feature/resolution_details.rb +37 -0
  470. data/lib/datadog/open_feature/transport.rb +126 -0
  471. data/lib/datadog/open_feature.rb +19 -0
  472. data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
  473. data/lib/datadog/opentelemetry/api/context.rb +25 -10
  474. data/lib/datadog/opentelemetry/configuration/settings.rb +226 -0
  475. data/lib/datadog/opentelemetry/ext.rb +9 -0
  476. data/lib/datadog/opentelemetry/logs.rb +98 -0
  477. data/lib/datadog/opentelemetry/metrics.rb +90 -0
  478. data/lib/datadog/opentelemetry/sdk/configurator.rb +69 -5
  479. data/lib/datadog/opentelemetry/sdk/id_generator.rb +16 -10
  480. data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +30 -0
  481. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +28 -0
  482. data/lib/datadog/opentelemetry/sdk/propagator.rb +21 -15
  483. data/lib/datadog/opentelemetry/sdk/span_processor.rb +24 -21
  484. data/lib/datadog/opentelemetry/sdk/trace/span.rb +43 -39
  485. data/lib/datadog/opentelemetry/sdk.rb +19 -0
  486. data/lib/datadog/opentelemetry/signal_configuration.rb +57 -0
  487. data/lib/datadog/opentelemetry/trace.rb +8 -5
  488. data/lib/datadog/opentelemetry.rb +11 -6
  489. data/lib/datadog/profiling/collectors/code_provenance.rb +84 -16
  490. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +60 -3
  491. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -4
  492. data/lib/datadog/profiling/collectors/info.rb +62 -8
  493. data/lib/datadog/profiling/collectors/thread_context.rb +25 -18
  494. data/lib/datadog/profiling/component.rb +123 -104
  495. data/lib/datadog/profiling/encoded_profile.rb +11 -0
  496. data/lib/datadog/profiling/exporter.rb +51 -17
  497. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +24 -5
  498. data/lib/datadog/profiling/ext/exec_monkey_patch.rb +32 -0
  499. data/lib/datadog/profiling/ext.rb +2 -17
  500. data/lib/datadog/profiling/flush.rb +26 -17
  501. data/lib/datadog/profiling/http_transport.rb +30 -96
  502. data/lib/datadog/profiling/load_native_extension.rb +3 -35
  503. data/lib/datadog/profiling/profiler.rb +31 -12
  504. data/lib/datadog/profiling/scheduler.rb +19 -10
  505. data/lib/datadog/profiling/sequence_tracker.rb +44 -0
  506. data/lib/datadog/profiling/stack_recorder.rb +38 -18
  507. data/lib/datadog/profiling/tag_builder.rb +41 -41
  508. data/lib/datadog/profiling/tasks/exec.rb +11 -6
  509. data/lib/datadog/profiling/tasks/help.rb +1 -0
  510. data/lib/datadog/profiling/tasks/setup.rb +4 -2
  511. data/lib/datadog/profiling.rb +42 -37
  512. data/lib/datadog/ruby_version.rb +25 -0
  513. data/lib/datadog/single_step_instrument.rb +11 -2
  514. data/lib/datadog/symbol_database/component.rb +734 -0
  515. data/lib/datadog/symbol_database/configuration.rb +73 -0
  516. data/lib/datadog/symbol_database/extensions.rb +19 -0
  517. data/lib/datadog/symbol_database/extractor.rb +1092 -0
  518. data/lib/datadog/symbol_database/file_hash.rb +48 -0
  519. data/lib/datadog/symbol_database/logger.rb +43 -0
  520. data/lib/datadog/symbol_database/remote.rb +195 -0
  521. data/lib/datadog/symbol_database/scope.rb +102 -0
  522. data/lib/datadog/symbol_database/scope_batcher.rb +292 -0
  523. data/lib/datadog/symbol_database/service_version.rb +66 -0
  524. data/lib/datadog/symbol_database/symbol.rb +69 -0
  525. data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
  526. data/lib/datadog/symbol_database/transport/http.rb +45 -0
  527. data/lib/datadog/symbol_database/transport.rb +54 -0
  528. data/lib/datadog/symbol_database/uploader.rb +230 -0
  529. data/lib/datadog/symbol_database.rb +71 -0
  530. data/lib/datadog/tracing/analytics.rb +2 -2
  531. data/lib/datadog/tracing/buffer.rb +15 -15
  532. data/lib/datadog/tracing/client_ip.rb +4 -4
  533. data/lib/datadog/tracing/component.rb +63 -23
  534. data/lib/datadog/tracing/configuration/dynamic/option.rb +4 -0
  535. data/lib/datadog/tracing/configuration/dynamic.rb +16 -16
  536. data/lib/datadog/tracing/configuration/ext.rb +62 -33
  537. data/lib/datadog/tracing/configuration/http.rb +2 -2
  538. data/lib/datadog/tracing/configuration/settings.rb +182 -34
  539. data/lib/datadog/tracing/context.rb +27 -5
  540. data/lib/datadog/tracing/context_provider.rb +12 -8
  541. data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +2 -2
  542. data/lib/datadog/tracing/contrib/action_cable/event.rb +5 -5
  543. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +9 -6
  544. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +8 -5
  545. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +9 -6
  546. data/lib/datadog/tracing/contrib/action_cable/events.rb +5 -5
  547. data/lib/datadog/tracing/contrib/action_cable/ext.rb +18 -18
  548. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -5
  549. data/lib/datadog/tracing/contrib/action_cable/integration.rb +10 -7
  550. data/lib/datadog/tracing/contrib/action_cable/patcher.rb +4 -4
  551. data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +2 -2
  552. data/lib/datadog/tracing/contrib/action_mailer/event.rb +7 -4
  553. data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +8 -8
  554. data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +4 -4
  555. data/lib/datadog/tracing/contrib/action_mailer/events.rb +3 -3
  556. data/lib/datadog/tracing/contrib/action_mailer/ext.rb +18 -18
  557. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +11 -7
  558. data/lib/datadog/tracing/contrib/action_mailer/patcher.rb +3 -3
  559. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +38 -20
  560. data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +2 -2
  561. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +48 -13
  562. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +5 -3
  563. data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +3 -3
  564. data/lib/datadog/tracing/contrib/action_pack/ext.rb +10 -8
  565. data/lib/datadog/tracing/contrib/action_pack/integration.rb +10 -7
  566. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +3 -3
  567. data/lib/datadog/tracing/contrib/action_pack/utils.rb +2 -3
  568. data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +3 -3
  569. data/lib/datadog/tracing/contrib/action_view/event.rb +1 -1
  570. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +10 -7
  571. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +12 -9
  572. data/lib/datadog/tracing/contrib/action_view/events.rb +3 -3
  573. data/lib/datadog/tracing/contrib/action_view/ext.rb +10 -10
  574. data/lib/datadog/tracing/contrib/action_view/integration.rb +14 -11
  575. data/lib/datadog/tracing/contrib/action_view/patcher.rb +5 -5
  576. data/lib/datadog/tracing/contrib/action_view/utils.rb +2 -2
  577. data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +2 -2
  578. data/lib/datadog/tracing/contrib/active_job/data_streams.rb +62 -0
  579. data/lib/datadog/tracing/contrib/active_job/event.rb +11 -11
  580. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +11 -8
  581. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +11 -8
  582. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +11 -8
  583. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +11 -8
  584. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +11 -8
  585. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +11 -8
  586. data/lib/datadog/tracing/contrib/active_job/events.rb +6 -6
  587. data/lib/datadog/tracing/contrib/active_job/ext.rb +23 -23
  588. data/lib/datadog/tracing/contrib/active_job/integration.rb +10 -7
  589. data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
  590. data/lib/datadog/tracing/contrib/active_job/patcher.rb +21 -5
  591. data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +2 -2
  592. data/lib/datadog/tracing/contrib/active_model_serializers/event.rb +4 -4
  593. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +8 -8
  594. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +9 -10
  595. data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +3 -3
  596. data/lib/datadog/tracing/contrib/active_model_serializers/ext.rb +10 -10
  597. data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +5 -6
  598. data/lib/datadog/tracing/contrib/active_model_serializers/patcher.rb +3 -3
  599. data/lib/datadog/tracing/contrib/active_record/configuration/makara_resolver.rb +1 -1
  600. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +9 -9
  601. data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +4 -4
  602. data/lib/datadog/tracing/contrib/active_record/event.rb +1 -1
  603. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +10 -10
  604. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +17 -19
  605. data/lib/datadog/tracing/contrib/active_record/events.rb +3 -3
  606. data/lib/datadog/tracing/contrib/active_record/ext.rb +15 -15
  607. data/lib/datadog/tracing/contrib/active_record/integration.rb +16 -12
  608. data/lib/datadog/tracing/contrib/active_record/patcher.rb +2 -2
  609. data/lib/datadog/tracing/contrib/active_record/utils.rb +19 -19
  610. data/lib/datadog/tracing/contrib/active_support/cache/event.rb +1 -1
  611. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +29 -21
  612. data/lib/datadog/tracing/contrib/active_support/cache/events.rb +1 -1
  613. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +40 -8
  614. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +8 -4
  615. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +16 -6
  616. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +26 -3
  617. data/lib/datadog/tracing/contrib/active_support/ext.rb +16 -16
  618. data/lib/datadog/tracing/contrib/active_support/integration.rb +11 -8
  619. data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +3 -2
  620. data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +2 -2
  621. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +9 -11
  622. data/lib/datadog/tracing/contrib/active_support/patcher.rb +2 -2
  623. data/lib/datadog/tracing/contrib/analytics.rb +1 -1
  624. data/lib/datadog/tracing/contrib/auto_instrument.rb +5 -5
  625. data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +3 -3
  626. data/lib/datadog/tracing/contrib/aws/ext.rb +27 -27
  627. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +21 -13
  628. data/lib/datadog/tracing/contrib/aws/integration.rb +11 -8
  629. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +9 -3
  630. data/lib/datadog/tracing/contrib/aws/patcher.rb +10 -6
  631. data/lib/datadog/tracing/contrib/aws/service/base.rb +2 -1
  632. data/lib/datadog/tracing/contrib/aws/service/dynamodb.rb +2 -2
  633. data/lib/datadog/tracing/contrib/aws/service/eventbridge.rb +2 -2
  634. data/lib/datadog/tracing/contrib/aws/service/kinesis.rb +4 -4
  635. data/lib/datadog/tracing/contrib/aws/service/s3.rb +2 -2
  636. data/lib/datadog/tracing/contrib/aws/service/sns.rb +3 -3
  637. data/lib/datadog/tracing/contrib/aws/service/sqs.rb +3 -3
  638. data/lib/datadog/tracing/contrib/aws/service/states.rb +5 -5
  639. data/lib/datadog/tracing/contrib/aws/services.rb +14 -14
  640. data/lib/datadog/tracing/contrib/component.rb +3 -3
  641. data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +2 -2
  642. data/lib/datadog/tracing/contrib/concurrent_ruby/configuration/settings.rb +2 -2
  643. data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +2 -2
  644. data/lib/datadog/tracing/contrib/concurrent_ruby/ext.rb +2 -2
  645. data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +2 -2
  646. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +8 -5
  647. data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +4 -4
  648. data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +2 -2
  649. data/lib/datadog/tracing/contrib/configurable.rb +24 -9
  650. data/lib/datadog/tracing/contrib/configuration/resolver.rb +14 -4
  651. data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +5 -5
  652. data/lib/datadog/tracing/contrib/configuration/settings.rb +3 -3
  653. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +2 -2
  654. data/lib/datadog/tracing/contrib/dalli/ext.rb +16 -15
  655. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +6 -10
  656. data/lib/datadog/tracing/contrib/dalli/integration.rb +10 -7
  657. data/lib/datadog/tracing/contrib/dalli/patcher.rb +3 -3
  658. data/lib/datadog/tracing/contrib/dalli/quantize.rb +3 -3
  659. data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +2 -2
  660. data/lib/datadog/tracing/contrib/delayed_job/ext.rb +14 -14
  661. data/lib/datadog/tracing/contrib/delayed_job/integration.rb +5 -5
  662. data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +3 -3
  663. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +7 -5
  664. data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +1 -0
  665. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +6 -2
  666. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +18 -17
  667. data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +8 -8
  668. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +63 -64
  669. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +9 -9
  670. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +7 -3
  671. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +19 -17
  672. data/lib/datadog/tracing/contrib/ethon/ext.rb +16 -14
  673. data/lib/datadog/tracing/contrib/ethon/integration.rb +6 -6
  674. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +4 -11
  675. data/lib/datadog/tracing/contrib/ethon/patcher.rb +3 -3
  676. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +21 -10
  677. data/lib/datadog/tracing/contrib/excon/ext.rb +14 -12
  678. data/lib/datadog/tracing/contrib/excon/integration.rb +6 -6
  679. data/lib/datadog/tracing/contrib/excon/middleware.rb +18 -17
  680. data/lib/datadog/tracing/contrib/excon/patcher.rb +2 -2
  681. data/lib/datadog/tracing/contrib/ext.rb +23 -20
  682. data/lib/datadog/tracing/contrib/extensions.rb +57 -14
  683. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +20 -13
  684. data/lib/datadog/tracing/contrib/faraday/ext.rb +14 -12
  685. data/lib/datadog/tracing/contrib/faraday/integration.rb +6 -6
  686. data/lib/datadog/tracing/contrib/faraday/middleware.rb +20 -17
  687. data/lib/datadog/tracing/contrib/faraday/patcher.rb +6 -6
  688. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +11 -7
  689. data/lib/datadog/tracing/contrib/grape/endpoint.rb +69 -36
  690. data/lib/datadog/tracing/contrib/grape/ext.rb +15 -15
  691. data/lib/datadog/tracing/contrib/grape/instrumentation.rb +15 -10
  692. data/lib/datadog/tracing/contrib/grape/integration.rb +5 -5
  693. data/lib/datadog/tracing/contrib/grape/patcher.rb +10 -5
  694. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
  695. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +20 -2
  696. data/lib/datadog/tracing/contrib/graphql/ext.rb +11 -5
  697. data/lib/datadog/tracing/contrib/graphql/integration.rb +9 -9
  698. data/lib/datadog/tracing/contrib/graphql/patcher.rb +8 -8
  699. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +174 -41
  700. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +2 -2
  701. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +7 -4
  702. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +26 -24
  703. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +14 -18
  704. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +6 -6
  705. data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +2 -2
  706. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +13 -8
  707. data/lib/datadog/tracing/contrib/grpc/ext.rb +14 -13
  708. data/lib/datadog/tracing/contrib/grpc/formatting.rb +7 -7
  709. data/lib/datadog/tracing/contrib/grpc/integration.rb +5 -5
  710. data/lib/datadog/tracing/contrib/grpc/intercept_with_datadog.rb +1 -1
  711. data/lib/datadog/tracing/contrib/grpc/patcher.rb +3 -3
  712. data/lib/datadog/tracing/contrib/grpc.rb +7 -6
  713. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +4 -3
  714. data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +2 -2
  715. data/lib/datadog/tracing/contrib/hanami/ext.rb +8 -8
  716. data/lib/datadog/tracing/contrib/hanami/integration.rb +6 -6
  717. data/lib/datadog/tracing/contrib/hanami/patcher.rb +5 -5
  718. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +5 -4
  719. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +14 -14
  720. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +1 -7
  721. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +20 -9
  722. data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +6 -6
  723. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +13 -8
  724. data/lib/datadog/tracing/contrib/http/ext.rb +14 -12
  725. data/lib/datadog/tracing/contrib/http/instrumentation.rb +20 -24
  726. data/lib/datadog/tracing/contrib/http/integration.rb +9 -8
  727. data/lib/datadog/tracing/contrib/http/patcher.rb +3 -3
  728. data/lib/datadog/tracing/contrib/http.rb +7 -6
  729. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +20 -9
  730. data/lib/datadog/tracing/contrib/httpclient/ext.rb +14 -12
  731. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +21 -27
  732. data/lib/datadog/tracing/contrib/httpclient/integration.rb +6 -6
  733. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +3 -3
  734. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +20 -9
  735. data/lib/datadog/tracing/contrib/httprb/ext.rb +14 -12
  736. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +21 -29
  737. data/lib/datadog/tracing/contrib/httprb/integration.rb +9 -6
  738. data/lib/datadog/tracing/contrib/httprb/patcher.rb +3 -3
  739. data/lib/datadog/tracing/contrib/integration.rb +3 -3
  740. data/lib/datadog/tracing/contrib/kafka/configuration/settings.rb +2 -2
  741. data/lib/datadog/tracing/contrib/kafka/event.rb +5 -4
  742. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +8 -4
  743. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +5 -5
  744. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +5 -5
  745. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +6 -6
  746. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +6 -6
  747. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +6 -6
  748. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +6 -6
  749. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +11 -6
  750. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +11 -6
  751. data/lib/datadog/tracing/contrib/kafka/events.rb +10 -10
  752. data/lib/datadog/tracing/contrib/kafka/ext.rb +40 -40
  753. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
  754. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
  755. data/lib/datadog/tracing/contrib/kafka/integration.rb +8 -5
  756. data/lib/datadog/tracing/contrib/kafka/patcher.rb +17 -3
  757. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +31 -0
  758. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +50 -0
  759. data/lib/datadog/tracing/contrib/karafka/ext.rb +28 -0
  760. data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
  761. data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
  762. data/lib/datadog/tracing/contrib/karafka/monitor.rb +77 -0
  763. data/lib/datadog/tracing/contrib/karafka/patcher.rb +102 -0
  764. data/lib/datadog/tracing/contrib/karafka.rb +38 -0
  765. data/lib/datadog/tracing/contrib/lograge/configuration/settings.rb +2 -2
  766. data/lib/datadog/tracing/contrib/lograge/ext.rb +1 -1
  767. data/lib/datadog/tracing/contrib/lograge/instrumentation.rb +1 -1
  768. data/lib/datadog/tracing/contrib/lograge/integration.rb +5 -5
  769. data/lib/datadog/tracing/contrib/lograge/patcher.rb +13 -11
  770. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +11 -3
  771. data/lib/datadog/tracing/contrib/mongodb/ext.rb +19 -18
  772. data/lib/datadog/tracing/contrib/mongodb/instrumentation.rb +3 -3
  773. data/lib/datadog/tracing/contrib/mongodb/integration.rb +9 -6
  774. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +10 -10
  775. data/lib/datadog/tracing/contrib/mongodb/patcher.rb +3 -3
  776. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +38 -24
  777. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +9 -3
  778. data/lib/datadog/tracing/contrib/mysql2/ext.rb +12 -12
  779. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +25 -18
  780. data/lib/datadog/tracing/contrib/mysql2/integration.rb +5 -5
  781. data/lib/datadog/tracing/contrib/mysql2/patcher.rb +2 -2
  782. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +19 -2
  783. data/lib/datadog/tracing/contrib/opensearch/ext.rb +31 -21
  784. data/lib/datadog/tracing/contrib/opensearch/integration.rb +8 -6
  785. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +75 -77
  786. data/lib/datadog/tracing/contrib/opensearch/quantize.rb +10 -10
  787. data/lib/datadog/tracing/contrib/patchable.rb +1 -1
  788. data/lib/datadog/tracing/contrib/patcher.rb +15 -14
  789. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +9 -3
  790. data/lib/datadog/tracing/contrib/pg/ext.rb +19 -19
  791. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +21 -24
  792. data/lib/datadog/tracing/contrib/pg/integration.rb +5 -5
  793. data/lib/datadog/tracing/contrib/pg/patcher.rb +2 -2
  794. data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +2 -2
  795. data/lib/datadog/tracing/contrib/presto/ext.rb +22 -22
  796. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +11 -13
  797. data/lib/datadog/tracing/contrib/presto/integration.rb +8 -5
  798. data/lib/datadog/tracing/contrib/presto/patcher.rb +4 -4
  799. data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +2 -2
  800. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +26 -13
  801. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +7 -3
  802. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +29 -5
  803. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +7 -4
  804. data/lib/datadog/tracing/contrib/que/ext.rb +19 -18
  805. data/lib/datadog/tracing/contrib/que/integration.rb +6 -6
  806. data/lib/datadog/tracing/contrib/que/patcher.rb +1 -1
  807. data/lib/datadog/tracing/contrib/que/tracer.rb +3 -2
  808. data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +3 -3
  809. data/lib/datadog/tracing/contrib/racecar/event.rb +6 -10
  810. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +5 -5
  811. data/lib/datadog/tracing/contrib/racecar/events/consume.rb +4 -4
  812. data/lib/datadog/tracing/contrib/racecar/events/message.rb +5 -5
  813. data/lib/datadog/tracing/contrib/racecar/events.rb +4 -4
  814. data/lib/datadog/tracing/contrib/racecar/ext.rb +18 -18
  815. data/lib/datadog/tracing/contrib/racecar/integration.rb +5 -5
  816. data/lib/datadog/tracing/contrib/racecar/patcher.rb +3 -3
  817. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +14 -4
  818. data/lib/datadog/tracing/contrib/rack/ext.rb +43 -15
  819. data/lib/datadog/tracing/contrib/rack/header_collection.rb +13 -3
  820. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +55 -32
  821. data/lib/datadog/tracing/contrib/rack/integration.rb +7 -7
  822. data/lib/datadog/tracing/contrib/rack/middlewares.rb +102 -63
  823. data/lib/datadog/tracing/contrib/rack/patcher.rb +6 -6
  824. data/lib/datadog/tracing/contrib/rack/request_queue.rb +8 -7
  825. data/lib/datadog/tracing/contrib/rack/route_inference.rb +67 -0
  826. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +131 -7
  827. data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +1 -1
  828. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +9 -6
  829. data/lib/datadog/tracing/contrib/rails/ext.rb +16 -14
  830. data/lib/datadog/tracing/contrib/rails/framework.rb +12 -12
  831. data/lib/datadog/tracing/contrib/rails/integration.rb +6 -6
  832. data/lib/datadog/tracing/contrib/rails/log_injection.rb +2 -2
  833. data/lib/datadog/tracing/contrib/rails/middlewares.rb +4 -4
  834. data/lib/datadog/tracing/contrib/rails/patcher.rb +11 -9
  835. data/lib/datadog/tracing/contrib/rails/railtie.rb +4 -4
  836. data/lib/datadog/tracing/contrib/rails/runner.rb +64 -40
  837. data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +3 -3
  838. data/lib/datadog/tracing/contrib/rake/ext.rb +12 -12
  839. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +13 -11
  840. data/lib/datadog/tracing/contrib/rake/integration.rb +5 -5
  841. data/lib/datadog/tracing/contrib/rake/patcher.rb +3 -3
  842. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +5 -5
  843. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +2 -2
  844. data/lib/datadog/tracing/contrib/redis/ext.rb +19 -18
  845. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +6 -6
  846. data/lib/datadog/tracing/contrib/redis/integration.rb +7 -7
  847. data/lib/datadog/tracing/contrib/redis/patcher.rb +12 -12
  848. data/lib/datadog/tracing/contrib/redis/quantize.rb +41 -7
  849. data/lib/datadog/tracing/contrib/redis/tags.rb +7 -12
  850. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +20 -12
  851. data/lib/datadog/tracing/contrib/registerable.rb +11 -0
  852. data/lib/datadog/tracing/contrib/registry.rb +1 -1
  853. data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +2 -2
  854. data/lib/datadog/tracing/contrib/resque/ext.rb +7 -7
  855. data/lib/datadog/tracing/contrib/resque/integration.rb +5 -5
  856. data/lib/datadog/tracing/contrib/resque/patcher.rb +3 -3
  857. data/lib/datadog/tracing/contrib/resque/resque_job.rb +7 -6
  858. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +7 -4
  859. data/lib/datadog/tracing/contrib/rest_client/ext.rb +13 -11
  860. data/lib/datadog/tracing/contrib/rest_client/integration.rb +8 -5
  861. data/lib/datadog/tracing/contrib/rest_client/patcher.rb +2 -2
  862. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +19 -15
  863. data/lib/datadog/tracing/contrib/roda/configuration/settings.rb +2 -2
  864. data/lib/datadog/tracing/contrib/roda/ext.rb +6 -5
  865. data/lib/datadog/tracing/contrib/roda/instrumentation.rb +12 -7
  866. data/lib/datadog/tracing/contrib/roda/integration.rb +6 -6
  867. data/lib/datadog/tracing/contrib/roda/patcher.rb +3 -3
  868. data/lib/datadog/tracing/contrib/semantic_logger/configuration/settings.rb +2 -2
  869. data/lib/datadog/tracing/contrib/semantic_logger/ext.rb +1 -1
  870. data/lib/datadog/tracing/contrib/semantic_logger/instrumentation.rb +1 -1
  871. data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +5 -5
  872. data/lib/datadog/tracing/contrib/semantic_logger/patcher.rb +2 -2
  873. data/lib/datadog/tracing/contrib/sequel/configuration/settings.rb +2 -2
  874. data/lib/datadog/tracing/contrib/sequel/database.rb +8 -11
  875. data/lib/datadog/tracing/contrib/sequel/dataset.rb +7 -6
  876. data/lib/datadog/tracing/contrib/sequel/ext.rb +12 -8
  877. data/lib/datadog/tracing/contrib/sequel/integration.rb +5 -5
  878. data/lib/datadog/tracing/contrib/sequel/jdbc_connection_string.rb +140 -0
  879. data/lib/datadog/tracing/contrib/sequel/patcher.rb +3 -3
  880. data/lib/datadog/tracing/contrib/sequel/utils.rb +103 -16
  881. data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +2 -2
  882. data/lib/datadog/tracing/contrib/shoryuken/ext.rb +12 -12
  883. data/lib/datadog/tracing/contrib/shoryuken/integration.rb +6 -6
  884. data/lib/datadog/tracing/contrib/shoryuken/patcher.rb +1 -1
  885. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +3 -2
  886. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +15 -9
  887. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +7 -3
  888. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +14 -9
  889. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +31 -29
  890. data/lib/datadog/tracing/contrib/sidekiq/integration.rb +7 -7
  891. data/lib/datadog/tracing/contrib/sidekiq/patcher.rb +8 -8
  892. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +2 -0
  893. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +1 -0
  894. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/redis_info.rb +1 -0
  895. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +2 -0
  896. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/stop.rb +1 -0
  897. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +19 -15
  898. data/lib/datadog/tracing/contrib/sidekiq/utils.rb +10 -10
  899. data/lib/datadog/tracing/contrib/sidekiq.rb +7 -6
  900. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +8 -4
  901. data/lib/datadog/tracing/contrib/sinatra/env.rb +6 -6
  902. data/lib/datadog/tracing/contrib/sinatra/ext.rb +17 -16
  903. data/lib/datadog/tracing/contrib/sinatra/framework.rb +2 -2
  904. data/lib/datadog/tracing/contrib/sinatra/integration.rb +5 -5
  905. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +5 -5
  906. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +11 -10
  907. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +46 -45
  908. data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +1 -1
  909. data/lib/datadog/tracing/contrib/sneakers/ext.rb +12 -12
  910. data/lib/datadog/tracing/contrib/sneakers/integration.rb +19 -8
  911. data/lib/datadog/tracing/contrib/sneakers/patcher.rb +2 -2
  912. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +5 -4
  913. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +9 -4
  914. data/lib/datadog/tracing/contrib/status_range_env_parser.rb +2 -2
  915. data/lib/datadog/tracing/contrib/status_range_matcher.rb +13 -1
  916. data/lib/datadog/tracing/contrib/stripe/configuration/settings.rb +2 -2
  917. data/lib/datadog/tracing/contrib/stripe/ext.rb +12 -12
  918. data/lib/datadog/tracing/contrib/stripe/integration.rb +5 -5
  919. data/lib/datadog/tracing/contrib/stripe/patcher.rb +2 -2
  920. data/lib/datadog/tracing/contrib/stripe/request.rb +5 -5
  921. data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +2 -2
  922. data/lib/datadog/tracing/contrib/sucker_punch/exception_handler.rb +1 -1
  923. data/lib/datadog/tracing/contrib/sucker_punch/ext.rb +13 -13
  924. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +5 -4
  925. data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +5 -5
  926. data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +4 -4
  927. data/lib/datadog/tracing/contrib/support.rb +28 -0
  928. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +9 -3
  929. data/lib/datadog/tracing/contrib/trilogy/ext.rb +12 -12
  930. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +10 -12
  931. data/lib/datadog/tracing/contrib/trilogy/integration.rb +5 -5
  932. data/lib/datadog/tracing/contrib/trilogy/patcher.rb +2 -2
  933. data/lib/datadog/tracing/contrib/utils/database.rb +5 -5
  934. data/lib/datadog/tracing/contrib/utils/quantization/{hash.rb → hash_formatter.rb} +17 -15
  935. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +16 -16
  936. data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +31 -0
  937. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +50 -0
  938. data/lib/datadog/tracing/contrib/waterdrop/ext.rb +18 -0
  939. data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
  940. data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
  941. data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +49 -0
  942. data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
  943. data/lib/datadog/tracing/contrib/waterdrop.rb +42 -0
  944. data/lib/datadog/tracing/contrib.rb +62 -52
  945. data/lib/datadog/tracing/correlation.rb +21 -14
  946. data/lib/datadog/tracing/diagnostics/environment_logger.rb +23 -15
  947. data/lib/datadog/tracing/diagnostics/ext.rb +19 -19
  948. data/lib/datadog/tracing/diagnostics/health.rb +1 -1
  949. data/lib/datadog/tracing/distributed/b3_multi.rb +9 -9
  950. data/lib/datadog/tracing/distributed/b3_single.rb +6 -6
  951. data/lib/datadog/tracing/distributed/baggage.rb +250 -0
  952. data/lib/datadog/tracing/distributed/datadog.rb +41 -38
  953. data/lib/datadog/tracing/distributed/fetcher.rb +1 -1
  954. data/lib/datadog/tracing/distributed/helpers.rb +4 -4
  955. data/lib/datadog/tracing/distributed/none.rb +4 -2
  956. data/lib/datadog/tracing/distributed/propagation.rb +73 -14
  957. data/lib/datadog/tracing/distributed/propagation_policy.rb +47 -0
  958. data/lib/datadog/tracing/distributed/trace_context.rb +31 -259
  959. data/lib/datadog/tracing/distributed/trace_state/datadog.rb +233 -0
  960. data/lib/datadog/tracing/distributed/trace_state/ext.rb +44 -0
  961. data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +156 -0
  962. data/lib/datadog/tracing/distributed/trace_state.rb +121 -0
  963. data/lib/datadog/tracing/event.rb +6 -8
  964. data/lib/datadog/tracing/ext.rb +9 -0
  965. data/lib/datadog/tracing/flush.rb +1 -1
  966. data/lib/datadog/tracing/metadata/analytics.rb +3 -3
  967. data/lib/datadog/tracing/metadata/errors.rb +8 -8
  968. data/lib/datadog/tracing/metadata/ext.rb +89 -59
  969. data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
  970. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
  971. data/lib/datadog/tracing/metadata/tagging.rb +9 -9
  972. data/lib/datadog/tracing/metadata.rb +5 -3
  973. data/lib/datadog/tracing/otel_thread_context.rb +99 -0
  974. data/lib/datadog/tracing/pipeline/span_filter.rb +5 -3
  975. data/lib/datadog/tracing/pipeline/span_processor.rb +3 -1
  976. data/lib/datadog/tracing/pipeline.rb +4 -4
  977. data/lib/datadog/tracing/remote.rb +228 -30
  978. data/lib/datadog/tracing/sampling/all_sampler.rb +1 -1
  979. data/lib/datadog/tracing/sampling/ext.rb +9 -9
  980. data/lib/datadog/tracing/sampling/matcher.rb +4 -4
  981. data/lib/datadog/tracing/sampling/priority_sampler.rb +20 -5
  982. data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +3 -3
  983. data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +2 -2
  984. data/lib/datadog/tracing/sampling/rate_sampler.rb +9 -19
  985. data/lib/datadog/tracing/sampling/rule.rb +5 -5
  986. data/lib/datadog/tracing/sampling/rule_sampler.rb +91 -58
  987. data/lib/datadog/tracing/sampling/sampler.rb +2 -2
  988. data/lib/datadog/tracing/sampling/span/ext.rb +3 -3
  989. data/lib/datadog/tracing/sampling/span/matcher.rb +2 -2
  990. data/lib/datadog/tracing/sampling/span/rule.rb +1 -2
  991. data/lib/datadog/tracing/sampling/span/rule_parser.rb +11 -11
  992. data/lib/datadog/tracing/sampling/span/sampler.rb +0 -7
  993. data/lib/datadog/tracing/span.rb +29 -12
  994. data/lib/datadog/tracing/span_event.rb +125 -5
  995. data/lib/datadog/tracing/span_link.rb +12 -12
  996. data/lib/datadog/tracing/span_operation.rb +120 -40
  997. data/lib/datadog/tracing/sync_writer.rb +22 -14
  998. data/lib/datadog/tracing/trace_digest.rb +58 -28
  999. data/lib/datadog/tracing/trace_operation.rb +263 -120
  1000. data/lib/datadog/tracing/trace_segment.rb +18 -16
  1001. data/lib/datadog/tracing/tracer.rb +208 -73
  1002. data/lib/datadog/tracing/transport/http/client.rb +17 -30
  1003. data/lib/datadog/tracing/transport/http/statistics.rb +2 -2
  1004. data/lib/datadog/tracing/transport/http/traces.rb +11 -90
  1005. data/lib/datadog/tracing/transport/http.rb +26 -73
  1006. data/lib/datadog/tracing/transport/io/client.rb +13 -16
  1007. data/lib/datadog/tracing/transport/io/response.rb +1 -1
  1008. data/lib/datadog/tracing/transport/io/traces.rb +33 -39
  1009. data/lib/datadog/tracing/transport/io.rb +3 -3
  1010. data/lib/datadog/tracing/transport/native/response.rb +71 -0
  1011. data/lib/datadog/tracing/transport/native.rb +379 -0
  1012. data/lib/datadog/tracing/transport/serializable_trace.rb +47 -23
  1013. data/lib/datadog/tracing/transport/span_events_negotiation.rb +41 -0
  1014. data/lib/datadog/tracing/transport/statistics.rb +3 -3
  1015. data/lib/datadog/tracing/transport/trace_formatter.rb +49 -10
  1016. data/lib/datadog/tracing/transport/traces.rb +45 -99
  1017. data/lib/datadog/tracing/utils.rb +3 -3
  1018. data/lib/datadog/tracing/workers.rb +12 -10
  1019. data/lib/datadog/tracing/writer.rb +54 -39
  1020. data/lib/datadog/tracing.rb +19 -6
  1021. data/lib/datadog/version.rb +4 -4
  1022. data/lib/datadog.rb +21 -5
  1023. metadata +372 -70
  1024. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
  1025. data/ext/datadog_profiling_loader/extconf.rb +0 -60
  1026. data/ext/datadog_profiling_native_extension/clock_id_noop.c +0 -21
  1027. data/ext/libdatadog_api/macos_development.md +0 -26
  1028. data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -92
  1029. data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -114
  1030. data/lib/datadog/appsec/configuration/settings.rb +0 -207
  1031. data/lib/datadog/appsec/contrib/devise/event.rb +0 -57
  1032. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -77
  1033. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -54
  1034. data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
  1035. data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
  1036. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -59
  1037. data/lib/datadog/appsec/contrib/patcher.rb +0 -12
  1038. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -81
  1039. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -60
  1040. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -66
  1041. data/lib/datadog/appsec/contrib/rails/ext.rb +0 -13
  1042. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -66
  1043. data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
  1044. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -61
  1045. data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -58
  1046. data/lib/datadog/appsec/processor/actions.rb +0 -49
  1047. data/lib/datadog/appsec/processor/rule_merger.rb +0 -170
  1048. data/lib/datadog/appsec/processor.rb +0 -170
  1049. data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
  1050. data/lib/datadog/appsec/reactive/engine.rb +0 -47
  1051. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  1052. data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
  1053. data/lib/datadog/appsec/scope.rb +0 -61
  1054. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
  1055. data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
  1056. data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
  1057. data/lib/datadog/core/remote/transport/http/api.rb +0 -58
  1058. data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
  1059. data/lib/datadog/core/remote/transport/http/client.rb +0 -48
  1060. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  1061. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  1062. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  1063. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
  1064. data/lib/datadog/core/utils/base64.rb +0 -22
  1065. data/lib/datadog/di/configuration/settings.rb +0 -163
  1066. data/lib/datadog/tracing/contrib/rails/utils.rb +0 -26
  1067. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -84
  1068. data/lib/datadog/tracing/transport/http/api/spec.rb +0 -19
  1069. data/lib/datadog/tracing/transport/http/api.rb +0 -43
  1070. data/lib/datadog/tracing/workers/trace_writer.rb +0 -196
@@ -2,47 +2,60 @@
2
2
 
3
3
  // This file exports functions used to access private Ruby VM APIs and internals.
4
4
  // To do this, it imports a few VM internal (private) headers.
5
+ // We rely on the datadog-ruby_core_source gem to get access to private VM headers; see
6
+ // https://github.com/DataDog/datadog-ruby_core_source for details.
5
7
  //
6
8
  // **Important Note**: Our medium/long-term plan is to stop relying on all private Ruby headers, and instead request and
7
9
  // contribute upstream changes so that they become official public VM APIs.
8
10
  //
9
11
  // In the meanwhile, be very careful when changing things here :)
10
12
 
11
- #ifdef RUBY_MJIT_HEADER
12
- // Pick up internal structures from the private Ruby MJIT header file
13
- #include RUBY_MJIT_HEADER
14
- #else
15
- // The MJIT header was introduced on 2.6 and removed on 3.3; for other Rubies we rely on
16
- // the debase-ruby_core_source gem to get access to private VM headers.
13
+ #include <ruby/defines.h>
14
+
15
+ // We can't do anything about warnings in VM headers, so we just use this technique to suppress them.
16
+ // See https://nelkinda.com/blog/suppress-warnings-in-gcc-and-clang/#d11e364 for details.
17
+ #pragma GCC diagnostic push
18
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
19
+ #pragma GCC diagnostic ignored "-Wattributes"
20
+ #pragma GCC diagnostic ignored "-Wpragmas"
21
+ #pragma GCC diagnostic ignored "-Wexpansion-to-defined"
22
+ #include <vm_core.h>
23
+ #pragma GCC diagnostic pop
24
+
25
+ #pragma GCC diagnostic push
26
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
27
+ #include <iseq.h>
28
+ #pragma GCC diagnostic pop
17
29
 
18
- // We can't do anything about warnings in VM headers, so we just use this technique to suppress them.
19
- // See https://nelkinda.com/blog/suppress-warnings-in-gcc-and-clang/#d11e364 for details.
30
+ #ifndef NO_INTERNAL_CLASS_HEADER_INCLUDE
20
31
  #pragma GCC diagnostic push
21
32
  #pragma GCC diagnostic ignored "-Wunused-parameter"
22
- #pragma GCC diagnostic ignored "-Wattributes"
23
- #pragma GCC diagnostic ignored "-Wpragmas"
24
- #pragma GCC diagnostic ignored "-Wexpansion-to-defined"
25
- #include <vm_core.h>
33
+ #include <internal/class.h>
26
34
  #pragma GCC diagnostic pop
35
+ #endif
36
+
37
+ #include <ruby.h>
27
38
 
39
+ #ifndef NO_RACTOR_HEADER_INCLUDE
28
40
  #pragma GCC diagnostic push
29
41
  #pragma GCC diagnostic ignored "-Wunused-parameter"
30
- #include <iseq.h>
42
+ #include <ractor_core.h>
31
43
  #pragma GCC diagnostic pop
44
+ #endif
32
45
 
33
- #include <ruby.h>
34
-
35
- #ifndef NO_RACTOR_HEADER_INCLUDE
36
- #pragma GCC diagnostic push
37
- #pragma GCC diagnostic ignored "-Wunused-parameter"
38
- #include <ractor_core.h>
39
- #pragma GCC diagnostic pop
40
- #endif
46
+ // This file can't include datadog_ruby_common.h so we replicate this here
47
+ #ifdef __GNUC__
48
+ #define DDTRACE_UNUSED __attribute__((unused))
49
+ #else
50
+ #define DDTRACE_UNUSED
41
51
  #endif
42
52
 
43
53
  #define PRIVATE_VM_API_ACCESS_SKIP_RUBY_INCLUDES
44
54
  #include "private_vm_api_access.h"
45
55
 
56
+ static inline const rb_callable_method_entry_t* get_cfunc_method_entry(const rb_control_frame_t *cfp);
57
+ static const rb_callable_method_entry_t* safe_vm_frame_method_entry(const rb_control_frame_t *cfp);
58
+
46
59
  // MRI has a similar rb_thread_ptr() function which we can't call it directly
47
60
  // because Ruby does not expose the thread_data_type publicly.
48
61
  // Instead, we have our own version of that function, and we lazily initialize the thread_data_type pointer
@@ -52,7 +65,9 @@
52
65
  // if the argument passed in is not actually a `Thread` instance.
53
66
  static inline rb_thread_t *thread_struct_from_object(VALUE thread) {
54
67
  static const rb_data_type_t *thread_data_type = NULL;
55
- if (UNLIKELY(thread_data_type == NULL)) thread_data_type = RTYPEDDATA_TYPE(rb_thread_current());
68
+ if (UNLIKELY(thread_data_type == NULL)) {
69
+ thread_data_type = RTYPEDDATA_TYPE(rb_thread_current());
70
+ }
56
71
 
57
72
  return (rb_thread_t *) rb_check_typeddata(thread, thread_data_type);
58
73
  }
@@ -62,7 +77,9 @@ rb_nativethread_id_t pthread_id_for(VALUE thread) {
62
77
  #ifndef NO_RB_NATIVE_THREAD
63
78
  struct rb_native_thread* native_thread = thread_struct_from_object(thread)->nt;
64
79
  // This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
65
- if (native_thread == NULL) return 0;
80
+ if (native_thread == NULL) {
81
+ return 0;
82
+ }
66
83
  return native_thread->thread_id;
67
84
  #else
68
85
  return thread_struct_from_object(thread)->thread_id;
@@ -86,87 +103,93 @@ bool is_current_thread_holding_the_gvl(void) {
86
103
  }
87
104
 
88
105
  #ifdef HAVE_RUBY_RACTOR_H
89
- static inline rb_ractor_t *ddtrace_get_ractor(void) {
90
- #ifndef USE_RACTOR_INTERNAL_APIS_DIRECTLY // Ruby >= 3.3
91
- return thread_struct_from_object(rb_thread_current())->ractor;
92
- #else
93
- return GET_RACTOR();
94
- #endif
95
- }
106
+ static inline rb_ractor_t *ddtrace_get_ractor(void) {
107
+ #ifndef USE_RACTOR_INTERNAL_APIS_DIRECTLY // Ruby >= 3.3
108
+ return thread_struct_from_object(rb_thread_current())->ractor;
109
+ #else
110
+ return GET_RACTOR();
111
+ #endif
112
+ }
96
113
  #endif
97
114
 
98
115
  #ifndef NO_GVL_OWNER // Ruby < 2.6 doesn't have the owner/running field
99
- // NOTE: Reading the owner in this is a racy read, because we're not grabbing the lock that Ruby uses to protect it.
100
- //
101
- // While we could potentially grab this lock, I (@ivoanjo) think we actually don't need it because:
102
- // * In the case where a thread owns the GVL and calls `gvl_owner`, it will always see the correct value. That's
103
- // because every thread sets itself as the owner when it grabs the GVL and unsets itself at the end.
104
- // That means that `is_current_thread_holding_the_gvl` is always accurate.
105
- // * In a case where we observe a different thread, then this may change by the time we do something with this value
106
- // anyway. So unless we want to prevent the Ruby scheduler from switching threads, we need to deal with races here.
107
- current_gvl_owner gvl_owner(void) {
108
- const rb_thread_t *current_owner =
109
- #ifndef NO_RB_THREAD_SCHED // Introduced in Ruby 3.2 as a replacement for struct rb_global_vm_lock_struct
110
- ddtrace_get_ractor()->threads.sched.running;
111
- #elif HAVE_RUBY_RACTOR_H
112
- ddtrace_get_ractor()->threads.gvl.owner;
113
- #else
114
- GET_VM()->gvl.owner;
115
- #endif
116
-
117
- if (current_owner == NULL) return (current_gvl_owner) {.valid = false};
118
-
119
- #ifndef NO_RB_NATIVE_THREAD
120
- struct rb_native_thread* current_owner_native_thread = current_owner->nt;
121
-
122
- // This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
123
- if (current_owner_native_thread == NULL) return (current_gvl_owner) {.valid = false};
124
-
125
- return (current_gvl_owner) {.valid = true, .owner = current_owner_native_thread->thread_id};
116
+ // NOTE: Reading the owner in this is a racy read, because we're not grabbing the lock that Ruby uses to protect it.
117
+ //
118
+ // While we could potentially grab this lock, I (@ivoanjo) think we actually don't need it because:
119
+ // * In the case where a thread owns the GVL and calls `gvl_owner`, it will always see the correct value. That's
120
+ // because every thread sets itself as the owner when it grabs the GVL and unsets itself at the end.
121
+ // That means that `is_current_thread_holding_the_gvl` is always accurate.
122
+ // * In a case where we observe a different thread, then this may change by the time we do something with this value
123
+ // anyway. So unless we want to prevent the Ruby scheduler from switching threads, we need to deal with races here.
124
+ current_gvl_owner gvl_owner(void) {
125
+ const rb_thread_t *current_owner =
126
+ #ifndef NO_RB_THREAD_SCHED // Introduced in Ruby 3.2 as a replacement for struct rb_global_vm_lock_struct
127
+ ddtrace_get_ractor()->threads.sched.running;
128
+ #elif HAVE_RUBY_RACTOR_H
129
+ ddtrace_get_ractor()->threads.gvl.owner;
126
130
  #else
127
- return (current_gvl_owner) {.valid = true, .owner = current_owner->thread_id};
131
+ GET_VM()->gvl.owner;
128
132
  #endif
133
+
134
+ if (current_owner == NULL) {
135
+ return (current_gvl_owner) {.valid = false};
129
136
  }
130
- #else
131
- current_gvl_owner gvl_owner(void) {
132
- rb_vm_t *vm = GET_VM();
133
137
 
134
- // BIG Issue: Ruby < 2.6 did not have the owner field. The really nice thing about the owner field is that it's
135
- // "atomic" -- when a thread sets it, it "declares" two things in a single step
136
- // * Declaration 1: Someone has the GVL
137
- // * Declaration 2: That someone is the specific thread
138
- //
139
- // Observation 1: On older versions of Ruby, this ownership concept is actually split. Specifically, `gvl.acquired`
140
- // is a boolean that represents declaration 1 above, and `vm->running_thread` (or `ruby_current_thread`/
141
- // `ruby_current_execution_context_ptr`) represents declaration 2.
142
- //
143
- // Observation 2: In addition, when a thread releases the GVL, it only sets `gvl.acquired` back to 0 **BUT CRUCIALLY
144
- // DOES NOT CHANGE THE OTHER global variables**.
145
- //
146
- // Observation 1+2 above lead to the following possible race:
147
- // * Thread A grabs the GVL (`gvl.acquired == 1`)
148
- // * Thread A sets `running_thread` (`gvl.acquired == 1` + `running_thread == Thread A`)
149
- // * Thread A releases the GVL (`gvl.acquired == 0` + `running_thread == Thread A`)
150
- // * Thread B grabs the GVL (`gvl.acquired == 1` + `running_thread == Thread A`)
151
- // * Thread A calls gvl_owner. Due to the current state (`gvl.acquired == 1` + `running_thread == Thread A`), this
152
- // function returns an incorrect result.
153
- // * Thread B finally sets `running_thread` (`gvl.acquired == 1` + `running_thread == Thread B`)
154
- //
155
- // This is especially problematic because we use `gvl_owner` to implement `is_current_thread_holding_the_gvl` which
156
- // is called in a signal handler to decide "is it safe for me to call `rb_postponed_job_register_one` or not".
157
- // (See constraints in `collectors_cpu_and_wall_time_worker.c` comments for why).
158
- //
159
- // Thus an incorrect `is_current_thread_holding_the_gvl` result may lead to issues inside `rb_postponed_job_register_one`.
160
- //
161
- // For this reason we currently do not enable the new Ruby profiler on Ruby 2.5 by default, and we print a
162
- // warning when customers force-enable it.
163
- bool gvl_acquired = vm->gvl.acquired != 0;
164
- rb_thread_t *current_owner = vm->running_thread;
138
+ #ifndef NO_RB_NATIVE_THREAD
139
+ struct rb_native_thread* current_owner_native_thread = current_owner->nt;
165
140
 
166
- if (!gvl_acquired || current_owner == NULL) return (current_gvl_owner) {.valid = false};
141
+ // This can be NULL on Ruby 3.3 with MN threads (RUBY_MN_THREADS=1)
142
+ if (current_owner_native_thread == NULL) {
143
+ return (current_gvl_owner) {.valid = false};
144
+ }
167
145
 
146
+ return (current_gvl_owner) {.valid = true, .owner = current_owner_native_thread->thread_id};
147
+ #else
168
148
  return (current_gvl_owner) {.valid = true, .owner = current_owner->thread_id};
149
+ #endif
150
+ }
151
+ #else
152
+ current_gvl_owner gvl_owner(void) {
153
+ rb_vm_t *vm = GET_VM();
154
+
155
+ // BIG Issue: Ruby < 2.6 did not have the owner field. The really nice thing about the owner field is that it's
156
+ // "atomic" -- when a thread sets it, it "declares" two things in a single step
157
+ // * Declaration 1: Someone has the GVL
158
+ // * Declaration 2: That someone is the specific thread
159
+ //
160
+ // Observation 1: On older versions of Ruby, this ownership concept is actually split. Specifically, `gvl.acquired`
161
+ // is a boolean that represents declaration 1 above, and `vm->running_thread` (or `ruby_current_thread`/
162
+ // `ruby_current_execution_context_ptr`) represents declaration 2.
163
+ //
164
+ // Observation 2: In addition, when a thread releases the GVL, it only sets `gvl.acquired` back to 0 **BUT CRUCIALLY
165
+ // DOES NOT CHANGE THE OTHER global variables**.
166
+ //
167
+ // Observation 1+2 above lead to the following possible race:
168
+ // * Thread A grabs the GVL (`gvl.acquired == 1`)
169
+ // * Thread A sets `running_thread` (`gvl.acquired == 1` + `running_thread == Thread A`)
170
+ // * Thread A releases the GVL (`gvl.acquired == 0` + `running_thread == Thread A`)
171
+ // * Thread B grabs the GVL (`gvl.acquired == 1` + `running_thread == Thread A`)
172
+ // * Thread A calls gvl_owner. Due to the current state (`gvl.acquired == 1` + `running_thread == Thread A`), this
173
+ // function returns an incorrect result.
174
+ // * Thread B finally sets `running_thread` (`gvl.acquired == 1` + `running_thread == Thread B`)
175
+ //
176
+ // This is especially problematic because we use `gvl_owner` to implement `is_current_thread_holding_the_gvl` which
177
+ // is called in a signal handler to decide "is it safe for me to call `rb_postponed_job_register_one` or not".
178
+ // (See constraints in `collectors_cpu_and_wall_time_worker.c` comments for why).
179
+ //
180
+ // Thus an incorrect `is_current_thread_holding_the_gvl` result may lead to issues inside `rb_postponed_job_register_one`.
181
+ //
182
+ // For this reason we default to use the "no signals workaround" on Ruby 2.5 by default, and we print a
183
+ // warning when customers force-enable it.
184
+ bool gvl_acquired = vm->gvl.acquired != 0;
185
+ rb_thread_t *current_owner = vm->running_thread;
186
+
187
+ if (!gvl_acquired || current_owner == NULL) {
188
+ return (current_gvl_owner) {.valid = false};
169
189
  }
190
+
191
+ return (current_gvl_owner) {.valid = true, .owner = current_owner->thread_id};
192
+ }
170
193
  #endif // NO_GVL_OWNER
171
194
 
172
195
  // Taken from upstream vm_core.h at commit d9cf0388599a3234b9f3c06ddd006cd59a58ab8b (November 2022, Ruby 3.2 trunk)
@@ -174,7 +197,7 @@ bool is_current_thread_holding_the_gvl(void) {
174
197
  // to support tid_for (see below)
175
198
  // Modifications: None
176
199
  #if defined(__linux__) || defined(__FreeBSD__)
177
- # define RB_THREAD_T_HAS_NATIVE_ID
200
+ #define RB_THREAD_T_HAS_NATIVE_ID
178
201
  #endif
179
202
 
180
203
  uint64_t native_thread_id_for(VALUE thread) {
@@ -182,7 +205,9 @@ uint64_t native_thread_id_for(VALUE thread) {
182
205
  #if !defined(NO_THREAD_TID) && defined(RB_THREAD_T_HAS_NATIVE_ID)
183
206
  #ifndef NO_RB_NATIVE_THREAD
184
207
  struct rb_native_thread* native_thread = thread_struct_from_object(thread)->nt;
185
- if (native_thread == NULL) return 0;
208
+ if (native_thread == NULL) {
209
+ return 0;
210
+ }
186
211
  return native_thread->tid;
187
212
  #else
188
213
  return thread_struct_from_object(thread)->tid;
@@ -194,7 +219,9 @@ uint64_t native_thread_id_for(VALUE thread) {
194
219
  uint64_t result;
195
220
  // On macOS, this gives us the same identifier that shows up in activity monitor
196
221
  int error = pthread_threadid_np(pthread_id, &result);
197
- if (error) rb_syserr_fail(error, "Unexpected failure in pthread_threadid_np");
222
+ if (error) {
223
+ rb_syserr_fail(error, "Unexpected failure in pthread_threadid_np");
224
+ }
198
225
  return result;
199
226
  #else
200
227
  // Fallback, when we have nothing better (e.g. on Ruby < 3.1 on Linux)
@@ -205,21 +232,6 @@ uint64_t native_thread_id_for(VALUE thread) {
205
232
  #endif
206
233
  }
207
234
 
208
- // Returns the stack depth by using the same approach as rb_profile_frames and backtrace_each: get the positions
209
- // of the end and current frame pointers and subtracting them.
210
- ptrdiff_t stack_depth_for(VALUE thread) {
211
- const rb_execution_context_t *ec = thread_struct_from_object(thread)->ec;
212
- const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
213
-
214
- if (end_cfp == NULL) return 0;
215
-
216
- // Skip dummy frame, as seen in `backtrace_each` (`vm_backtrace.c`) and our custom rb_profile_frames
217
- // ( https://github.com/ruby/ruby/blob/4bd38e8120f2fdfdd47a34211720e048502377f1/vm_backtrace.c#L890-L914 )
218
- end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
219
-
220
- return end_cfp <= cfp ? 0 : end_cfp - cfp - 1;
221
- }
222
-
223
235
  // This was renamed in Ruby 3.2
224
236
  #if !defined(ccan_list_for_each) && defined(list_for_each)
225
237
  #define ccan_list_for_each list_for_each
@@ -241,11 +253,12 @@ void ddtrace_thread_list(VALUE result_array) {
241
253
  // called from a different Ractor, but I'm not sure...
242
254
  #ifdef HAVE_RUBY_RACTOR_H
243
255
  rb_ractor_t *current_ractor = ddtrace_get_ractor();
244
- ccan_list_for_each(&current_ractor->threads.set, thread, lt_node) {
256
+ ccan_list_for_each(&current_ractor->threads.set, thread, lt_node)
245
257
  #else
246
258
  rb_vm_t *vm = GET_VM();
247
- list_for_each(&vm->living_threads, thread, vmlt_node) {
259
+ list_for_each(&vm->living_threads, thread, vmlt_node)
248
260
  #endif
261
+ {
249
262
  switch (thread->status) {
250
263
  case THREAD_RUNNABLE:
251
264
  case THREAD_STOPPED:
@@ -265,6 +278,23 @@ VALUE thread_name_for(VALUE thread) {
265
278
  return thread_struct_from_object(thread)->name;
266
279
  }
267
280
 
281
+ // This test doubles as a validation for the layout of the rb_thread_t structure. Because the `name` is almost at
282
+ // the end of the structure, if somehow we can't read the name, this probably means we're getting the structure wrong
283
+ // and we should stop immediately (this includes covering the use of `stat_insn_usage` on Ruby <= 3.2).
284
+ //
285
+ // One example where this happens is in patches such as
286
+ // https://github.com/gitlabhq/omnibus-gitlab/blob/master/config/patches/ruby/thread-memory-allocations-3.2.patch
287
+ // that add items to the structure and thus shift its position from where we expect.
288
+ void self_test_thread_name_for(void) {
289
+ VALUE thread = rb_eval_string("Thread.new { Thread.current.name = 'dd-prof-test' }.join");
290
+ VALUE expected_name = rb_funcall(thread, rb_intern("name"), 0);
291
+ if (thread_name_for(thread) != expected_name) {
292
+ rb_raise(rb_eRuntimeError,
293
+ "thread_name_for() self-test failed; this usually means the `rb_thread_t` on this Ruby doesn't match what the profiler expects"
294
+ );
295
+ }
296
+ }
297
+
268
298
  // -----------------------------------------------------------------------------
269
299
  // The sources below are modified versions of code extracted from the Ruby project.
270
300
  // Each function is annotated with its origin, why we imported it, and the changes made.
@@ -305,6 +335,7 @@ VALUE thread_name_for(VALUE thread) {
305
335
  // to support our custom rb_profile_frames (see below)
306
336
  // Modifications:
307
337
  // * Support int first_lineno for Ruby 3.2.0+ (https://github.com/ruby/ruby/pull/6430)
338
+ // * Validate iseq and pos before calling `rb_iseq_line_no` as a safety measure (see comment below for details)
308
339
  //
309
340
  // `node_id` gets used depending on Ruby VM compilation settings (USE_ISEQ_NODE_ID being defined).
310
341
  // To avoid getting false "unused argument" warnings in setups where it's not used, we need to do this weird dance
@@ -312,51 +343,72 @@ VALUE thread_name_for(VALUE thread) {
312
343
  #pragma GCC diagnostic push
313
344
  #pragma GCC diagnostic ignored "-Wunused-parameter"
314
345
  static inline int
315
- calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
316
- {
317
- VM_ASSERT(iseq);
318
- VM_ASSERT(ISEQ_BODY(iseq));
319
- VM_ASSERT(ISEQ_BODY(iseq)->iseq_encoded);
320
- VM_ASSERT(ISEQ_BODY(iseq)->iseq_size);
321
- if (! pc) {
322
- if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_TOP) {
323
- VM_ASSERT(! ISEQ_BODY(iseq)->local_table);
324
- VM_ASSERT(! ISEQ_BODY(iseq)->local_table_size);
325
- return 0;
326
- }
327
- # ifndef NO_INT_FIRST_LINENO // Ruby 3.2+
328
- if (lineno) *lineno = ISEQ_BODY(iseq)->location.first_lineno;
329
- # else
330
- if (lineno) *lineno = FIX2INT(ISEQ_BODY(iseq)->location.first_lineno);
331
- #endif
346
+ calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id) {
347
+ VM_ASSERT(iseq);
348
+ VM_ASSERT(ISEQ_BODY(iseq));
349
+ VM_ASSERT(ISEQ_BODY(iseq)->iseq_encoded);
350
+ VM_ASSERT(ISEQ_BODY(iseq)->iseq_size);
351
+ if (pc == NULL) {
352
+ if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_TOP) {
353
+ VM_ASSERT(! ISEQ_BODY(iseq)->local_table);
354
+ VM_ASSERT(! ISEQ_BODY(iseq)->local_table_size);
355
+ return 0;
356
+ }
357
+ #ifndef NO_INT_FIRST_LINENO // Ruby 3.2+
358
+ if (lineno) {
359
+ *lineno = ISEQ_BODY(iseq)->location.first_lineno;
360
+ }
361
+ #else
362
+ if (lineno) {
363
+ *lineno = FIX2INT(ISEQ_BODY(iseq)->location.first_lineno);
364
+ }
365
+ #endif
332
366
  #ifdef USE_ISEQ_NODE_ID
333
- if (node_id) *node_id = -1;
334
- #endif
335
- return 1;
367
+ if (node_id) {
368
+ *node_id = -1;
336
369
  }
337
- else {
338
- ptrdiff_t n = pc - ISEQ_BODY(iseq)->iseq_encoded;
339
- VM_ASSERT(n <= ISEQ_BODY(iseq)->iseq_size);
340
- VM_ASSERT(n >= 0);
341
- ASSUME(n >= 0);
342
- size_t pos = n; /* no overflow */
343
- if (LIKELY(pos)) {
344
- /* use pos-1 because PC points next instruction at the beginning of instruction */
345
- pos--;
346
- }
370
+ #endif
371
+ return 1;
372
+ } else {
373
+ ptrdiff_t n = pc - ISEQ_BODY(iseq)->iseq_encoded;
374
+ VM_ASSERT(n <= ISEQ_BODY(iseq)->iseq_size);
375
+ VM_ASSERT(n >= 0);
376
+ ASSUME(n >= 0);
377
+ size_t pos = n; /* no overflow */
378
+ if (LIKELY(pos)) {
379
+ /* use pos-1 because PC points next instruction at the beginning of instruction */
380
+ pos--;
381
+ } else {
347
382
  #if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
348
- else {
349
- /* SDR() is not possible; that causes infinite loop. */
350
- rb_print_backtrace();
351
- __builtin_trap();
352
- }
383
+ /* SDR() is not possible; that causes infinite loop. */
384
+ rb_print_backtrace();
385
+ __builtin_trap();
353
386
  #endif
354
- if (lineno) *lineno = rb_iseq_line_no(iseq, pos);
387
+ }
388
+
389
+ // In PROF-11475 we spotted a crash when calling `rb_iseq_line_no` from this method.
390
+ // We were only able to reproduce this issue on Ruby 2.6 and 2.7, not 2.5 or the 3.x series (tried 3.0, 3.2 and 3.4).
391
+ // Note that going out of bounds doesn't crash every time, as usual with C we may just read garbage or get lucky.
392
+ //
393
+ // For those problematic Rubies, we observed that when we try to take a sample in the middle of processing the
394
+ // VM `LEAVE` instruction, the value of `n` can violate the documented assumptions above and be
395
+ // `n > ISEQ_BODY(iseq)->iseq_size)`.
396
+ //
397
+ // To work around this and any other potential issues, we validate here that the bytecode position is sane.
398
+ if (RB_UNLIKELY(n < 0 || n > ISEQ_BODY(iseq)->iseq_size)) {
399
+ return 0;
400
+ }
401
+
402
+ if (lineno) {
403
+ *lineno = rb_iseq_line_no(iseq, pos);
404
+ }
355
405
  #ifdef USE_ISEQ_NODE_ID
356
- if (node_id) *node_id = rb_iseq_node_id(iseq, pos);
357
- #endif
358
- return 1;
406
+ if (node_id) {
407
+ *node_id = rb_iseq_node_id(iseq, pos);
359
408
  }
409
+ #endif
410
+ return 1;
411
+ }
360
412
  }
361
413
  #pragma GCC diagnostic pop
362
414
 
@@ -365,11 +417,12 @@ calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
365
417
  // to support our custom rb_profile_frames (see below)
366
418
  // Modifications: None
367
419
  static inline int
368
- calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
369
- {
370
- int lineno;
371
- if (calc_pos(iseq, pc, &lineno, NULL)) return lineno;
372
- return 0;
420
+ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc) {
421
+ int lineno;
422
+ if (calc_pos(iseq, pc, &lineno, NULL)) {
423
+ return lineno;
424
+ }
425
+ return 0;
373
426
  }
374
427
 
375
428
  // Taken from upstream vm_backtrace.c at commit 5f10bd634fb6ae8f74a4ea730176233b0ca96954 (March 2022, Ruby 3.2 trunk)
@@ -395,6 +448,9 @@ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
395
448
  // * Add frame_flags.same_frame and logic to skip redoing work if the buffer already contains the same data we're collecting
396
449
  // * Skipped use of rb_callable_method_entry_t (cme) for Ruby frames as it doesn't impact us.
397
450
  // * Imported fix from https://github.com/ruby/ruby/pull/8280 to keep us closer to upstream
451
+ // * Added potential fix for https://github.com/ruby/ruby/pull/13643 (this one is a just-in-case, unclear if it happens
452
+ // for ddtrace)
453
+ // * Reversed order of iteration to better enable caching
398
454
  //
399
455
  // What is rb_profile_frames?
400
456
  // `rb_profile_frames` is a Ruby VM debug API added for use by profilers for sampling the stack trace of a Ruby thread.
@@ -425,257 +481,293 @@ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
425
481
  // disagree, and quite a few of them seem oversights/bugs (speculation from my part) rather than deliberate
426
482
  // decisions.
427
483
  int ddtrace_rb_profile_frames(VALUE thread, int start, int limit, frame_info *stack_buffer) {
428
- int i;
429
- // Modified from upstream: Instead of using `GET_EC` to collect info from the current thread,
430
- // support sampling any thread (including the current) passed as an argument
431
- rb_thread_t *th = thread_struct_from_object(thread);
432
- const rb_execution_context_t *ec = th->ec;
433
- const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
434
- #ifndef NO_JIT_RETURN
435
- const rb_control_frame_t *top = cfp;
436
- #endif
437
- const rb_callable_method_entry_t *cme;
484
+ int i;
485
+ // Modified from upstream: Instead of using `GET_EC` to collect info from the current thread,
486
+ // support sampling any thread (including the current) passed as an argument
487
+ rb_thread_t *th = thread_struct_from_object(thread);
488
+ const rb_execution_context_t *ec = th->ec;
489
+
490
+ // As of this writing, we don't support profiling with MN enabled, and this only happens in that mode, but as we
491
+ // probably want to experiment with it in the future, I've decided to import https://github.com/ruby/ruby/pull/9310
492
+ // here.
493
+ if (ec == NULL) {
494
+ return 0;
495
+ }
438
496
 
439
- // Avoid sampling dead threads
440
- if (th->status == THREAD_KILLED) return 0;
497
+ // Avoid sampling dead threads
498
+ if (th->status == THREAD_KILLED) {
499
+ return 0;
500
+ }
441
501
 
442
- // `vm_backtrace.c` includes this check in several methods. This happens on newly-created threads, and may
443
- // also (not entirely sure) happen on dead threads
444
- if (end_cfp == NULL) return PLACEHOLDER_STACK_IN_NATIVE_CODE;
502
+ const rb_control_frame_t *cfp = ec->cfp;
445
503
 
446
- // This should not happen for ddtrace (it can only happen when a thread is still being created), but I've imported
447
- // it from https://github.com/ruby/ruby/pull/7116 in a "just in case" kind of mindset.
448
- if (cfp == NULL) return 0;
504
+ // This happens on newly-created threads (we even had a flaky test because of it)
505
+ if (cfp == NULL) {
506
+ return PLACEHOLDER_STACK_IN_NATIVE_CODE;
507
+ }
449
508
 
450
- // As of this writing, we don't support profiling with MN enabled, and this only happens in that mode, but as we
451
- // probably want to experiment with it in the future, I've decided to import https://github.com/ruby/ruby/pull/9310
452
- // here.
453
- if (ec == NULL) return 0;
509
+ // I suspect this won't happen for ddtrace, but just-in-case we've imported a potential fix for
510
+ // https://github.com/ruby/ruby/pull/13643 by assuming that these can be NULL/zero with the cfp being non-NULL yet.
511
+ if (ec->vm_stack == NULL || ec->vm_stack_size == 0) {
512
+ return 0;
513
+ }
454
514
 
455
- // Fix: Skip dummy frame that shows up in main thread.
456
- //
457
- // According to a comment in `backtrace_each` (`vm_backtrace.c`), there's two dummy frames that we should ignore
458
- // at the base of every thread's stack.
459
- // (see https://github.com/ruby/ruby/blob/4bd38e8120f2fdfdd47a34211720e048502377f1/vm_backtrace.c#L890-L914 )
460
- //
461
- // One is being pointed to by `RUBY_VM_END_CONTROL_FRAME(ec)`, and so we need to advance to the next one, and
462
- // reaching it will be used as a condition to break out of the loop below.
463
- //
464
- // Note that in `backtrace_each` there's two calls to `RUBY_VM_NEXT_CONTROL_FRAME`, but the loop bounds there
465
- // are computed in a different way, so the two calls really are equivalent to one here.
466
- end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
467
-
468
- // See comment on `record_placeholder_stack_in_native_code` for a full explanation of what this means (and why we don't just return 0)
469
- if (end_cfp <= cfp) return PLACEHOLDER_STACK_IN_NATIVE_CODE;
470
-
471
- for (i=0; i<limit && cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
472
- if (cfp->iseq && !cfp->pc) {
473
- // Fix: Do nothing -- this frame should not be used
474
- //
475
- // rb_profile_frames does not do this check, but `backtrace_each` (`vm_backtrace.c`) does. This frame is not
476
- // exposed by the Ruby backtrace APIs and for now we want to match its behavior 1:1
515
+ const rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
516
+ #ifndef NO_JIT_RETURN
517
+ const rb_control_frame_t *top = cfp;
518
+ #endif
519
+ const rb_callable_method_entry_t *cme;
520
+
521
+ // `vm_backtrace.c` includes this check in several methods. This happens on newly-created threads, and may
522
+ // also (not entirely sure) happen on dead threads
523
+ if (end_cfp == NULL) {
524
+ return PLACEHOLDER_STACK_IN_NATIVE_CODE;
525
+ }
526
+
527
+ // Fix: Skip dummy frame that shows up in main thread.
528
+ //
529
+ // According to a comment in `backtrace_each` (`vm_backtrace.c`), there's two dummy frames that we should ignore
530
+ // at the base of every thread's stack.
531
+ // (see https://github.com/ruby/ruby/blob/4bd38e8120f2fdfdd47a34211720e048502377f1/vm_backtrace.c#L890-L914 )
532
+ //
533
+ // One is being pointed to by `RUBY_VM_END_CONTROL_FRAME(ec)`, and so we need to advance to the next one, and
534
+ // reaching it will be used as a condition to break out of the loop below.
535
+ //
536
+ // Note that in `backtrace_each` there's two calls to `RUBY_VM_NEXT_CONTROL_FRAME`, but the loop bounds there
537
+ // are computed in a different way, so the two calls really are equivalent to one here.
538
+ end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
539
+
540
+ // See comment on `record_placeholder_stack_in_native_code` for a full explanation of what this means (and why we don't just return 0)
541
+ if (end_cfp <= cfp) {
542
+ return PLACEHOLDER_STACK_IN_NATIVE_CODE;
543
+ }
544
+
545
+ // This is the position just after the top of the stack -- e.g. where a new frame pushed on the stack would end up.
546
+ const rb_control_frame_t *top_sentinel = RUBY_VM_NEXT_CONTROL_FRAME(cfp);
547
+
548
+ // We iterate the stack from bottom (beginning of thread) to the top (currently-active frame). This is different
549
+ // from upstream rb_profile_frames, but actually matches what `backtrace_each` does (yes, different Ruby VM APIs
550
+ // iterate in different directions).
551
+ // We do this to better take advantage of the `same_frame` caching mechanism: By starting from the bottom of the
552
+ // stack towards the top, we can usually keep most of the stack intact when the code is only going up and down
553
+ // a few methods at the top. Before this change, the cache was really only useful if between samples the app had
554
+ // not moved from the current stack, as adding or removing one frame would invalidate the existing cache (because
555
+ // every position would shift).
556
+ cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
557
+
558
+ for (i=0; i<limit && cfp != top_sentinel; cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
559
+ #ifndef NO_T_MOVED
560
+ if (cfp->iseq && RB_TYPE_P((VALUE) cfp->iseq, T_MOVED)) {
561
+ // The profiler is not supposed to sample during GC compaction, so T_MOVED is not expected here.
562
+ // Yet, crash tracking also uses this walker and may run at any time. For now, we choose to skip these frames.
563
+ continue;
564
+ }
565
+ #endif
566
+
567
+ if (cfp->iseq && !cfp->pc) {
568
+ // Fix: Do nothing -- this frame should not be used
569
+ //
570
+ // rb_profile_frames does not do this check, but `backtrace_each` (`vm_backtrace.c`) does. This frame is not
571
+ // exposed by the Ruby backtrace APIs and for now we want to match its behavior 1:1
572
+ } else if (cfp->ep == NULL) {
573
+ // Do nothing -- this frame should not be used
574
+ //
575
+ // We're not sure this can ever happen, but we've seen a crash inside `VM_FRAME_RUBYFRAME_P` below (which
576
+ // dereferences `cfp->ep`), so "just in case" we're adding this extra sanity check to avoid crashing on a
577
+ // NULL `ep`.
578
+ } else if (VM_FRAME_RUBYFRAME_P(cfp)) {
579
+ if (start > 0) {
580
+ start--;
581
+ continue;
582
+ }
583
+
584
+ cme = safe_vm_frame_method_entry(cfp);
585
+
586
+ // Upstream (Ruby 4.0) does:
587
+ // if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
588
+ // buff[i] = (VALUE)cme;
589
+ // } else {
590
+ // buff[i] = (VALUE)cfp->iseq;
591
+ // }
592
+ // We get both the iseq and CME because we need both to format like Ruby backtraces
593
+
594
+ stack_buffer[i].same_frame =
595
+ stack_buffer[i].is_ruby_frame &&
596
+ stack_buffer[i].as.ruby_frame.iseq == cfp->iseq &&
597
+ stack_buffer[i].as.ruby_frame.caching_pc == cfp->pc &&
598
+ stack_buffer[i].cme == cme;
599
+
600
+ if (stack_buffer[i].same_frame) { // Nothing to do, buffer already contains this frame
601
+ i++;
602
+ continue;
603
+ }
604
+
605
+ stack_buffer[i].as.ruby_frame.iseq = cfp->iseq;
606
+ stack_buffer[i].as.ruby_frame.caching_pc = (void *) cfp->pc;
607
+ stack_buffer[i].cme = cme;
608
+
609
+ // The topmost frame may not have an updated PC because the JIT
610
+ // may not have set one. The JIT compiler will update the PC
611
+ // before entering a new function (so that `caller` will work),
612
+ // so only the topmost frame could possibly have an out of date PC
613
+ #ifndef NO_JIT_RETURN
614
+ if (cfp == top && cfp->jit_return) {
615
+ stack_buffer[i].as.ruby_frame.line = 0;
616
+ } else {
617
+ stack_buffer[i].as.ruby_frame.line = calc_lineno(cfp->iseq, cfp->pc);
477
618
  }
478
- else if (VM_FRAME_RUBYFRAME_P(cfp)) {
479
- if (start > 0) {
480
- start--;
481
- continue;
482
- }
483
-
484
- stack_buffer[i].same_frame =
485
- stack_buffer[i].is_ruby_frame &&
486
- stack_buffer[i].as.ruby_frame.iseq == (VALUE) cfp->iseq &&
487
- stack_buffer[i].as.ruby_frame.caching_pc == cfp->pc;
488
-
489
- if (stack_buffer[i].same_frame) { // Nothing to do, buffer already contains this frame
490
- i++;
491
- continue;
492
- }
493
-
494
- // dd-trace-rb NOTE:
495
- // Upstream Ruby has code here to retrieve the rb_callable_method_entry_t (cme) and in some cases to use it
496
- // instead of the iseq.
497
- // In practice, they are usually the same; the difference is that when you have e.g. block, one gets you a
498
- // reference to the block, and the other to the method containing the block.
499
- // This would be important if we used `rb_profile_frame_label` and wanted the "block in foo" label instead
500
- // of just "foo". But we're currently using `rb_profile_frame_base_label` which I believe is always the same
501
- // between the rb_callable_method_entry_t and the iseq. Thus, to simplify a bit our logic and reduce a bit
502
- // the overhead, we always use the iseq here.
503
- //
504
- // @ivoanjo: I've left the upstream Ruby code commented out below for reference, so it's more obvious that
505
- // we're diverging, and we can easily compare and experiment with the upstream version in the future.
506
- //
507
- // cme = rb_vm_frame_method_entry(cfp);
508
-
509
- // if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ &&
510
- // // Fix: Do not use callable method entry when iseq is for an eval.
511
- // // TL;DR: This fix is needed for us to match the Ruby reference API information in the
512
- // // "when sampling an eval/instance eval inside an object" spec.
513
- // cfp->iseq->body->type != ISEQ_TYPE_EVAL) {
514
- // buff[i] = (VALUE)cme;
515
- // }
516
- // else {
517
- stack_buffer[i].as.ruby_frame.iseq = (VALUE)cfp->iseq;
518
- stack_buffer[i].as.ruby_frame.caching_pc = (void *) cfp->pc;
519
- // }
520
-
521
- // The topmost frame may not have an updated PC because the JIT
522
- // may not have set one. The JIT compiler will update the PC
523
- // before entering a new function (so that `caller` will work),
524
- // so only the topmost frame could possibly have an out of date PC
525
- #ifndef NO_JIT_RETURN
526
- if (cfp == top && cfp->jit_return) {
527
- stack_buffer[i].as.ruby_frame.line = 0;
528
- } else {
529
- stack_buffer[i].as.ruby_frame.line = calc_lineno(cfp->iseq, cfp->pc);
530
- }
531
- #else // Ruby < 3.1
532
- stack_buffer[i].as.ruby_frame.line = calc_lineno(cfp->iseq, cfp->pc);
533
- #endif
534
-
535
- stack_buffer[i].is_ruby_frame = true;
536
- i++;
619
+ #else // Ruby < 3.1
620
+ stack_buffer[i].as.ruby_frame.line = calc_lineno(cfp->iseq, cfp->pc);
621
+ #endif
622
+
623
+ stack_buffer[i].is_ruby_frame = true;
624
+ i++;
625
+ } else {
626
+ cme = get_cfunc_method_entry(cfp);
627
+ if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
628
+ if (start > 0) {
629
+ start--;
630
+ continue;
537
631
  }
538
- else {
539
- cme = rb_vm_frame_method_entry(cfp);
540
- if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
541
- if (start > 0) {
542
- start--;
543
- continue;
544
- }
545
-
546
- stack_buffer[i].same_frame =
547
- !stack_buffer[i].is_ruby_frame &&
548
- stack_buffer[i].as.native_frame.caching_cme == (VALUE) cme;
549
-
550
- if (stack_buffer[i].same_frame) { // Nothing to do, buffer already contains this frame
551
- i++;
552
- continue;
553
- }
554
-
555
- stack_buffer[i].as.native_frame.caching_cme = (VALUE)cme;
556
- stack_buffer[i].as.native_frame.method_id = cme->def->original_id;
557
- stack_buffer[i].is_ruby_frame = false;
558
- i++;
559
- }
632
+
633
+ stack_buffer[i].same_frame =
634
+ !stack_buffer[i].is_ruby_frame &&
635
+ stack_buffer[i].cme == cme;
636
+
637
+ if (stack_buffer[i].same_frame) { // Nothing to do, buffer already contains this frame
638
+ i++;
639
+ continue;
560
640
  }
641
+
642
+ stack_buffer[i].cme = cme;
643
+ stack_buffer[i].is_ruby_frame = false;
644
+ i++;
645
+ }
561
646
  }
647
+ }
562
648
 
563
- return i;
649
+ return i;
564
650
  }
565
651
 
566
- // Support code for older Rubies that cannot use the MJIT header
567
- #ifndef RUBY_MJIT_HEADER
568
-
569
- #define MJIT_STATIC // No-op on older Rubies
570
-
571
652
  // Taken from upstream include/ruby/backward/2/bool.h at commit 5f10bd634fb6ae8f74a4ea730176233b0ca96954 (March 2022, Ruby 3.2 trunk)
572
653
  // Copyright (C) Ruby developers <ruby-core@ruby-lang.org>
573
654
  // to support our custom rb_profile_frames (see above)
574
655
  // Modifications: None
575
656
  #ifndef FALSE
576
- # define FALSE false
657
+ #define FALSE false
577
658
  #elif FALSE
578
- # error FALSE must be false
659
+ #error FALSE must be false
579
660
  #endif
580
661
 
581
662
  #ifndef TRUE
582
- # define TRUE true
663
+ #define TRUE true
583
664
  #elif ! TRUE
584
- # error TRUE must be true
665
+ #error TRUE must be true
585
666
  #endif
586
667
 
587
668
  // Taken from upstream vm_insnhelper.c at commit 5f10bd634fb6ae8f74a4ea730176233b0ca96954 (March 2022, Ruby 3.2 trunk)
588
669
  // Copyright (C) 2007 Koichi Sasada
589
670
  // to support our custom rb_profile_frames (see above)
590
- // Modifications: None
671
+ // Modifications:
672
+ // * Removed debug checks (they were ifdef'd out anyway)
673
+ // * Optimized to avoid recursion
591
674
  static rb_callable_method_entry_t *
592
- check_method_entry(VALUE obj, int can_be_svar)
593
- {
594
- if (obj == Qfalse) return NULL;
595
-
596
- #if VM_CHECK_MODE > 0
597
- if (!RB_TYPE_P(obj, T_IMEMO)) rb_bug("check_method_entry: unknown type: %s", rb_obj_info(obj));
598
- #endif
675
+ check_method_entry(VALUE obj, int can_be_svar) {
676
+ if (obj == Qfalse) {
677
+ return NULL;
678
+ }
599
679
 
600
- switch (imemo_type(obj)) {
601
- case imemo_ment:
602
- return (rb_callable_method_entry_t *)obj;
603
- case imemo_cref:
604
- return NULL;
605
- case imemo_svar:
606
- if (can_be_svar) {
607
- return check_method_entry(((struct vm_svar *)obj)->cref_or_me, FALSE);
608
- }
609
- // fallthrough
610
- default:
611
- #if VM_CHECK_MODE > 0
612
- rb_bug("check_method_entry: svar should not be there:");
613
- #endif
614
- return NULL;
680
+ enum imemo_type type = imemo_type(obj);
681
+ if (type == imemo_ment) {
682
+ return (rb_callable_method_entry_t *)obj;
683
+ } else if (can_be_svar && type == imemo_svar) {
684
+ VALUE cref_or_me = ((struct vm_svar *)obj)->cref_or_me;
685
+ if (imemo_type(cref_or_me) == imemo_ment) {
686
+ return (rb_callable_method_entry_t *)cref_or_me;
615
687
  }
688
+ }
689
+
690
+ return NULL;
616
691
  }
617
692
 
618
- // Taken from upstream vm_insnhelper.c at commit 5f10bd634fb6ae8f74a4ea730176233b0ca96954 (March 2022, Ruby 3.2 trunk)
619
- // Copyright (C) 2007 Koichi Sasada
620
- // to support our custom rb_profile_frames (see above)
621
- //
622
- // While older Rubies may have this function, the symbol is not exported which leads to dynamic loader issues, e.g.
623
- // `dyld: lazy symbol binding failed: Symbol not found: _rb_vm_frame_method_entry`.
693
+ // Identical to upstream rb_vm_frame_method_entry (vm_insnhelper.c) with two additions:
694
+ // 1. FIXNUM_P check on ep[FLAGS] before each iteration to detect torn EPs
695
+ // 2. NULL check on ep after VM_ENV_PREV_EP
624
696
  //
625
- // Modifications: None
626
- MJIT_STATIC const rb_callable_method_entry_t *
627
- rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
628
- {
629
- const VALUE *ep = cfp->ep;
630
- rb_callable_method_entry_t *me;
631
-
632
- while (!VM_ENV_LOCAL_P(ep)) {
633
- if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return me;
634
- ep = VM_ENV_PREV_EP(ep);
697
+ // When the profiler's signal handler interrupts vm_make_env_each (vm.c) mid-escape,
698
+ // a child frame's SPECVAL can still point to the parent's old stack EP whose flags
699
+ // slot has been overwritten with (VALUE)env for GC marking.
700
+ static const rb_callable_method_entry_t *
701
+ safe_vm_frame_method_entry(const rb_control_frame_t *cfp) {
702
+ const VALUE *ep = cfp->ep;
703
+ rb_callable_method_entry_t *me;
704
+
705
+ // Torn-EP check before VM_ENV_LOCAL_P, check_method_entry, and VM_ENV_PREV_EP
706
+ // dereference ep
707
+ while (FIXNUM_P(ep[VM_ENV_DATA_INDEX_FLAGS]) && !VM_ENV_LOCAL_P(ep)) {
708
+ if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) {
709
+ return me;
710
+ }
711
+ ep = VM_ENV_PREV_EP(ep);
712
+ if (ep == NULL) {
713
+ return NULL;
635
714
  }
715
+ }
636
716
 
637
- return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
717
+ // If we exited because of a torn EP (failed FIXNUM_P), bail out
718
+ if (!FIXNUM_P(ep[VM_ENV_DATA_INDEX_FLAGS])) {
719
+ return NULL;
720
+ }
721
+
722
+ return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
723
+ }
724
+
725
+ // Optimized version of rb_vm_frame_method_entry() for cfunc frames.
726
+ // Cfunc frames always have VM_ENV_FLAG_LOCAL set, so ep[-2] is the cme directly
727
+ // with no EP chain walk needed. The only complication is cfuncs that set $~ or $_
728
+ // (e.g. Regexp#match, String#gsub) which replace ep[-2] with an imemo_svar wrapping
729
+ // the cme - in that case svar->cref_or_me is always the cme (never a cref).
730
+ static inline const rb_callable_method_entry_t *
731
+ get_cfunc_method_entry(const rb_control_frame_t *cfp) {
732
+ return check_method_entry(cfp->ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
638
733
  }
639
- #endif // RUBY_MJIT_HEADER
640
734
 
641
735
  #ifndef NO_RACTORS
642
- // This API and definition are exported as a public symbol by the VM BUT the function header is not defined in any public header, so we
643
- // repeat it here to be able to use in our code.
644
- #ifndef USE_RACTOR_INTERNAL_APIS_DIRECTLY
645
- // Disable fast path for detecting multiple Ractors. Unfortunately this symbol is no longer visible on modern Ruby
646
- // versions, so we need to do a bit more work.
647
- struct rb_ractor_struct *ruby_single_main_ractor = NULL;
648
-
649
- // Alternative implementation of rb_ractor_main_p_ that avoids relying on non-public symbols
650
- bool rb_ractor_main_p_(void) {
651
- // We need to get the main ractor in a bit of a roundabout way, since Ruby >= 3.3 hid `GET_VM()`
652
- return ddtrace_get_ractor() == thread_struct_from_object(rb_thread_current())->vm->ractor.main_ractor;
653
- }
654
- #else
655
- // Directly access Ruby internal fast path for detecting multiple Ractors.
656
- extern struct rb_ractor_struct *ruby_single_main_ractor;
736
+ // This API and definition are exported as a public symbol by the VM BUT the function header is not defined in any public header, so we
737
+ // repeat it here to be able to use in our code.
738
+ #ifndef USE_RACTOR_INTERNAL_APIS_DIRECTLY
739
+ // Disable fast path for detecting multiple Ractors. Unfortunately this symbol is no longer visible on modern Ruby
740
+ // versions, so we need to do a bit more work.
741
+ struct rb_ractor_struct *ruby_single_main_ractor = NULL;
742
+
743
+ // Alternative implementation of rb_ractor_main_p_ that avoids relying on non-public symbols
744
+ bool rb_ractor_main_p_(void) {
745
+ // We need to get the main ractor in a bit of a roundabout way, since Ruby >= 3.3 hid `GET_VM()`
746
+ return ddtrace_get_ractor() == thread_struct_from_object(rb_thread_current())->vm->ractor.main_ractor;
747
+ }
748
+ #else
749
+ // Directly access Ruby internal fast path for detecting multiple Ractors.
750
+ extern struct rb_ractor_struct *ruby_single_main_ractor;
657
751
 
658
- // Ruby 3.0 to 3.2 directly expose this symbol, we just need to tell the compiler it exists.
659
- bool rb_ractor_main_p_(void);
660
- #endif
752
+ // Ruby 3.0 to 3.2 directly expose this symbol, we just need to tell the compiler it exists.
753
+ bool rb_ractor_main_p_(void);
754
+ #endif
661
755
 
662
- // Taken from upstream ractor_core.h at commit d9cf0388599a3234b9f3c06ddd006cd59a58ab8b (November 2022, Ruby 3.2 trunk)
663
- // to allow us to ensure that we're always operating on the main ractor (if Ruby has ractors)
664
- // Modifications:
665
- // * None
666
- bool ddtrace_rb_ractor_main_p(void)
667
- {
668
- if (ruby_single_main_ractor) {
669
- return true;
670
- }
671
- else {
672
- return rb_ractor_main_p_();
673
- }
756
+ // Taken from upstream ractor_core.h at commit d9cf0388599a3234b9f3c06ddd006cd59a58ab8b (November 2022, Ruby 3.2 trunk)
757
+ // to allow us to ensure that we're always operating on the main ractor (if Ruby has ractors)
758
+ // Modifications:
759
+ // * None
760
+ bool ddtrace_rb_ractor_main_p(void) {
761
+ if (ruby_single_main_ractor) {
762
+ return true;
763
+ } else {
764
+ return rb_ractor_main_p_();
674
765
  }
766
+ }
675
767
  #else
676
- // Simplify callers on older Rubies, instead of having them probe if the VM supports Ractors we just tell them that yes
677
- // they're always on the main Ractor
678
- bool ddtrace_rb_ractor_main_p(void) { return true; }
768
+ // Simplify callers on older Rubies, instead of having them probe if the VM supports Ractors we just tell them that yes
769
+ // they're always on the main Ractor
770
+ bool ddtrace_rb_ractor_main_p(void) { return true; }
679
771
  #endif // NO_RACTORS
680
772
 
681
773
  // This is a tweaked and inlined version of
@@ -687,17 +779,23 @@ static const rb_iseq_t *maybe_thread_invoke_proc_iseq(VALUE thread_value) {
687
779
  rb_thread_t *thread = thread_struct_from_object(thread_value);
688
780
 
689
781
  #ifndef NO_THREAD_INVOKE_ARG // Ruby 2.6+
690
- if (thread->invoke_type != thread_invoke_type_proc) return NULL;
782
+ if (thread->invoke_type != thread_invoke_type_proc) {
783
+ return NULL;
784
+ }
691
785
 
692
786
  VALUE proc = thread->invoke_arg.proc.proc;
693
787
  #else
694
- if (thread->first_func || !thread->first_proc) return NULL;
788
+ if (thread->first_func || !thread->first_proc) {
789
+ return NULL;
790
+ }
695
791
 
696
792
  VALUE proc = thread->first_proc;
697
793
  #endif
698
794
 
699
795
  const rb_iseq_t *iseq = rb_proc_get_iseq(proc, 0);
700
- if (iseq == NULL) return NULL;
796
+ if (iseq == NULL) {
797
+ return NULL;
798
+ }
701
799
 
702
800
  rb_iseq_check(iseq);
703
801
  return iseq;
@@ -706,10 +804,12 @@ static const rb_iseq_t *maybe_thread_invoke_proc_iseq(VALUE thread_value) {
706
804
  VALUE invoke_location_for(VALUE thread, int *line_location) {
707
805
  const rb_iseq_t *iseq = maybe_thread_invoke_proc_iseq(thread);
708
806
 
709
- if (iseq == NULL) return Qnil;
807
+ if (iseq == NULL) {
808
+ return Qnil;
809
+ }
710
810
 
711
811
  *line_location = NUM2INT(rb_iseq_first_lineno(iseq));
712
- return rb_iseq_path(iseq);
812
+ return ddtrace_iseq_path(iseq);
713
813
  }
714
814
 
715
815
  void self_test_mn_enabled(void) {
@@ -740,69 +840,348 @@ static inline int ddtrace_imemo_type(VALUE imemo) {
740
840
  // Safety: This function assumes the object passed in is of the imemo type. But in the worst case, you'll just get
741
841
  // a string that doesn't make any sense.
742
842
  #ifndef NO_IMEMO_NAME
743
- const char *imemo_kind(VALUE imemo) {
744
- return rb_imemo_name(ddtrace_imemo_type(imemo));
745
- }
843
+ const char *imemo_kind(VALUE imemo) {
844
+ return rb_imemo_name(ddtrace_imemo_type(imemo));
845
+ }
746
846
  #else
747
- const char *imemo_kind(__attribute__((unused)) VALUE imemo) {
748
- return NULL;
749
- }
847
+ const char *imemo_kind(__attribute__((unused)) VALUE imemo) {
848
+ return NULL;
849
+ }
750
850
  #endif
751
851
 
752
852
  // This is used to workaround a VM bug. See "handle_sampling_signal" in "collectors_cpu_and_wall_time_worker" for details.
753
853
  #ifdef NO_POSTPONED_TRIGGER
754
- void *objspace_ptr_for_gc_finalize_deferred_workaround(void) {
755
- return GET_VM()->objspace;
854
+ void *objspace_ptr_for_gc_finalize_deferred_workaround(void) {
855
+ return GET_VM()->objspace;
856
+ }
857
+ #endif
858
+
859
+ #ifndef HAVE_RUBY_THREAD_STORAGE_API
860
+ #include "gvl_profiling_helper.h"
861
+
862
+ // Hack: In Ruby 3.3+ we attach gvl profiling state to Ruby threads using the
863
+ // rb_internal_thread_specific_* APIs. These APIs did not exist on Ruby <= 3.2. On Ruby <= 3.2 we instead store the
864
+ // needed data inside the `rb_thread_t` structure, specifically in `stat_insn_usage` as a Ruby FIXNUM.
865
+ //
866
+ // Why `stat_insn_usage`? We needed some per-thread storage, and while looking at the Ruby VM sources I noticed
867
+ // that `stat_insn_usage` has been in `rb_thread_t` for a long time, but is not used anywhere in the VM
868
+ // code. There's a comment attached to it "/* statistics data for profiler */" but other than marking this
869
+ // field for GC, I could not find any place in the VM commit history or on GitHub where this has ever been used.
870
+ //
871
+ // Thus, since this hack is only for Ruby <= 3.2, which presumably will never see this field either removed or used
872
+ // we... kinda take it for our own usage. It's ugly, I know...
873
+ //
874
+ // 64-bit pointers actually use 48-bit virtual addresses (https://muxup.com/2023q4/storing-data-in-pointers),
875
+ // so we are sure the addresses fit in Fixnums.
876
+ per_thread_context *get_per_thread_context(VALUE thread) {
877
+ VALUE current_value = thread_struct_from_object(thread)->stat_insn_usage;
878
+ return RB_FIXNUM_P(current_value) ? (per_thread_context *) FIX2LONG(current_value) : NULL;
879
+ }
880
+
881
+ void set_per_thread_context(VALUE thread, per_thread_context *value) {
882
+ if (!RB_FIXABLE((intptr_t) value)) {
883
+ rb_bug("per_thread_context pointer does not fit in a Fixnum: %p", value);
756
884
  }
885
+ thread_struct_from_object(thread)->stat_insn_usage = value ? LONG2FIX((intptr_t) value) : Qfalse;
886
+ }
757
887
  #endif
758
888
 
759
- #ifdef USE_GVL_PROFILING_3_2_WORKAROUNDS // Ruby 3.2
760
- #include "gvl_profiling_helper.h"
889
+ // Is the VM smack in the middle of raising an exception?
890
+ bool is_raised_flag_set(VALUE thread) { return thread_struct_from_object(thread)->ec->raised_flag > 0; }
891
+
892
+ #ifndef NO_CURRENT_FIBER_FOR
893
+ // The following three declarations are all
894
+ // taken from upstream cont.c at commit d97884a58be32e829fd03a80cd521f4733d65c79 (February 2025, master branch)
895
+ // (See the Ruby project copyright and license above)
896
+ // to enable building `current_fiber_for`.
897
+ //
898
+ // We needed to copy them because they aren't otherwise exposed in any VM APIs or headers.
899
+ // @ivoanjo: I manually checked the Ruby 3.1, 3.2, 3.3 and 3.4 branches + master, and the parts we care about in these
900
+ // structures have not changed in many years (in fact, last change I spotted was for 2.7).
901
+ enum context_type {
902
+ CONTINUATION_CONTEXT = 0,
903
+ FIBER_CONTEXT = 1
904
+ };
905
+
906
+ typedef struct rb_context_struct { // This declaration is incomplete -- only contains up to `self` which is the part we care about
907
+ enum context_type type;
908
+ int argc;
909
+ int kw_splat;
910
+ VALUE self;
911
+ } rb_context_t;
912
+
913
+ struct rb_fiber_struct { // This declaration is incomplete -- only contains the first entry which is the part we care about
914
+ rb_context_t cont;
915
+ };
916
+
917
+ VALUE current_fiber_for(VALUE thread) {
918
+ VALUE self = thread_struct_from_object(thread)->ec->fiber_ptr->cont.self;
919
+ return self == 0 ? Qnil : self;
920
+ }
921
+
922
+ void self_test_current_fiber_for(void) {
923
+ VALUE expected_current_fiber = current_fiber_for(rb_thread_current());
924
+ VALUE actual_current_fiber = rb_fiber_current();
761
925
 
762
- gvl_profiling_thread thread_from_thread_object(VALUE thread) {
763
- return (gvl_profiling_thread) {.thread = thread_struct_from_object(thread)};
926
+ if (expected_current_fiber == Qnil) {
927
+ // On purpose above we tried reading before calling `rb_fiber_current()` so the fiber may have not existed yet.
928
+ // But now it should be there.
929
+ expected_current_fiber = current_fiber_for(rb_thread_current());
764
930
  }
765
931
 
766
- // Hack: In Ruby 3.3+ we attach gvl profiling state to Ruby threads using the
767
- // rb_internal_thread_specific_* APIs. These APIs did not exist on Ruby 3.2. On Ruby 3.2 we instead store the
768
- // needed data inside the `rb_thread_t` structure, specifically in `stat_insn_usage` as a Ruby FIXNUM.
769
- //
770
- // Why `stat_insn_usage`? We needed some per-thread storage, and while looking at the Ruby VM sources I noticed
771
- // that `stat_insn_usage` has been in `rb_thread_t` for a long time, but is not used anywhere in the VM
772
- // code. There's a comment attached to it "/* statistics data for profiler */" but other than marking this
773
- // field for GC, I could not find any place in the VM commit history or on GitHub where this has ever been used.
774
- //
775
- // Thus, since this hack is only for 3.2, which presumably will never see this field either removed or used
776
- // during its remaining maintenance release period we... kinda take it for our own usage. It's ugly, I know...
777
- intptr_t gvl_profiling_state_get(gvl_profiling_thread thread) {
778
- if (thread.thread == NULL) return 0;
932
+ if (expected_current_fiber != actual_current_fiber) {
933
+ rb_raise(rb_eRuntimeError, "current_fiber_for() self-test failed");
934
+ }
935
+ }
936
+ #else
937
+ NORETURN(VALUE current_fiber_for(DDTRACE_UNUSED VALUE thread));
938
+
939
+ VALUE current_fiber_for(DDTRACE_UNUSED VALUE thread) { rb_raise(rb_eRuntimeError, "Not implemented for Ruby < 3.1"); }
940
+ void self_test_current_fiber_for(void) { } // Nothing to do
941
+ #endif
942
+
943
+ // Variant of functions related to Thread::Backtrace::Location#label in Ruby 4.0
944
+ // (location_label(), rb_gen_method_name(), calculate_iseq_label()),
945
+ // but formatting using a C buffer instead of allocating Ruby Strings.
946
+ // Also, those functions are static functions in vm_backtrace.c so not reusable.
947
+ // There is also AFAIK no reasonable way to create a rb_backtrace_location_t from outside that file.
779
948
 
780
- VALUE current_value = ((rb_thread_t *)thread.thread)->stat_insn_usage;
781
- intptr_t result = current_value == Qnil ? 0 : FIX2LONG(current_value);
782
- return result;
949
+ // Return true if a given location is a C method or supposed to behave like one.
950
+ static bool location_cfunc_p(const rb_callable_method_entry_t *cme) {
951
+ if (!cme) {
952
+ return false;
783
953
  }
784
954
 
785
- void gvl_profiling_state_set(gvl_profiling_thread thread, intptr_t value) {
786
- if (thread.thread == NULL) return;
787
- ((rb_thread_t *)thread.thread)->stat_insn_usage = LONG2FIX(value);
955
+ switch (cme->def->type) {
956
+ case VM_METHOD_TYPE_CFUNC:
957
+ return true;
958
+ // Upstream, but we don't want that behavior:
959
+ // case VM_METHOD_TYPE_ISEQ:
960
+ // return is_internal_location(loc->cme->def->body.iseq.iseqptr);
961
+ default:
962
+ return false;
788
963
  }
964
+ }
789
965
 
790
- // Because Ruby 3.2 does not give us the current thread when calling the RUBY_INTERNAL_THREAD_EVENT_READY and
791
- // RUBY_INTERNAL_THREAD_EVENT_RESUMED APIs, we need to figure out this info ourselves.
792
- //
793
- // Specifically, this method was created to be called from a RUBY_INTERNAL_THREAD_EVENT_RESUMED callback --
794
- // when it's triggered, we know the thread the code gets executed on is holding the GVL, so we use this
795
- // opportunity to initialize our thread-local value.
796
- gvl_profiling_thread gvl_profiling_state_maybe_initialize(void) {
797
- gvl_profiling_thread current_thread = gvl_waiting_tls;
798
-
799
- if (current_thread.thread == NULL) {
800
- // threads.sched.running is the thread currently holding the GVL, which when this gets executed is the
801
- // current thread!
802
- current_thread = (gvl_profiling_thread) {.thread = (void *) rb_current_ractor()->threads.sched.running};
803
- gvl_waiting_tls = current_thread;
966
+ // RCLASS_SINGLETON_P() is only defined on Ruby 3.4+, so we have a copy for older versions
967
+ static bool ddtrace_RCLASS_SINGLETON_P(VALUE klass) {
968
+ return RB_TYPE_P(klass, T_CLASS) && FL_TEST_RAW(klass, FL_SINGLETON);
969
+ }
970
+
971
+ static VALUE get_class_attached_object(VALUE klass) {
972
+ #ifndef NO_CLASS_ATTACHED_OBJECT
973
+ return rb_class_attached_object(klass);
974
+ #else
975
+ return rb_ivar_get(klass, rb_intern("__attached__"));
976
+ #endif
977
+ }
978
+
979
+ static bool is_metaclass(VALUE mod, VALUE* attached) {
980
+ if (ddtrace_RCLASS_SINGLETON_P(mod)) {
981
+ VALUE attached_object = get_class_attached_object(mod);
982
+ if (RB_TYPE_P(attached_object, T_CLASS) || RB_TYPE_P(attached_object, T_MODULE)) {
983
+ *attached = attached_object;
984
+ return true;
804
985
  }
986
+ }
987
+ return false;
988
+ }
805
989
 
806
- return current_thread;
990
+ VALUE ddtrace_alloc_free_rb_mod_name(VALUE mod) {
991
+ #ifdef NO_ALLOC_FREE_MOD_NAME
992
+ VALUE name = rb_attr_get(mod, rb_intern("__classpath__"));
993
+ #else
994
+ VALUE name = rb_mod_name(mod);
995
+ #endif
996
+ // While Module#const_set rejects empty strings,
997
+ // an empty String is possible if `rb_const_set(mod, "", val)` was used
998
+ // but that's not understandable so consider those anonymous too.
999
+ if (name == Qnil || RSTRING_LEN(name) == 0) {
1000
+ return Qnil;
1001
+ } else {
1002
+ return name;
807
1003
  }
1004
+ }
1005
+
1006
+ // Ruby 3.3+ has a `permanent_classpath` flag on rb_classext_struct.
1007
+ // Checking for '#' in the name is equivalent on older Rubies:
1008
+ // non-permanent names contain '#' from `#<Module:0x...>` or `#<Class:0x...>` prefixes.
1009
+ static bool has_permanent_classpath(DDTRACE_UNUSED VALUE mod, DDTRACE_UNUSED VALUE mod_name) {
1010
+ #if defined(RCLASS_EXT_PRIME) // 4.0+
1011
+ // We can't actually use RCLASS_PERMANENT_CLASSPATH_P(mod) because that uses
1012
+ // RCLASS_EXT_READABLE() which uses rb_current_box(), which is a private symbol:
1013
+ // https://github.com/DataDog/dd-trace-rb/issues/6338
1014
+ // Instead we use `RCLASS_EXT_PRIME(mod)->permanent_classpath`, which is equivalent for our usage:
1015
+ // the two can only differ for boxable (= core) modules with no permanent name, i.e. metaclasses like
1016
+ // String.singleton_class, and is_metaclass() already replaced those with the attached module, so we display
1017
+ // `String.foo` and not `#<Class:String>#foo`. Same for the name in ddtrace_alloc_free_rb_mod_name().
1018
+ return RCLASS_EXT_PRIME(mod)->permanent_classpath;
1019
+ #elif defined(HAVE_PERMANENT_CLASSPATH) // 3.3 - 3.4
1020
+ return RCLASS_EXT(mod)->permanent_classpath;
1021
+ #else // 3.2 and older
1022
+ return memchr(RSTRING_PTR(mod_name), '#', RSTRING_LEN(mod_name)) == NULL;
808
1023
  #endif
1024
+ }
1025
+
1026
+ VALUE ddtrace_permanent_mod_name(VALUE mod) {
1027
+ VALUE name = ddtrace_alloc_free_rb_mod_name(mod);
1028
+
1029
+ if (NIL_P(name) || !has_permanent_classpath(mod, name)) {
1030
+ return Qnil;
1031
+ } else {
1032
+ return name;
1033
+ }
1034
+ }
1035
+
1036
+ #define ONLY_METHOD_NAME ((ssize_t) -1)
1037
+ #define BUFFER_OUT_OF_SPACE ((ssize_t) -2)
1038
+ #define NO_METHOD_NAME ((ssize_t) -3)
1039
+
1040
+ static ssize_t rb_gen_method_name(VALUE owner, VALUE method_name, char *buf, size_t buf_size) {
1041
+ if (!(RB_TYPE_P(owner, T_CLASS) || RB_TYPE_P(owner, T_MODULE))) {
1042
+ return ONLY_METHOD_NAME;
1043
+ }
1044
+
1045
+ VALUE mod = owner;
1046
+ char separator = '#';
1047
+ if (is_metaclass(owner, &mod)) {
1048
+ separator = '.';
1049
+ }
1050
+
1051
+ VALUE mod_name = ddtrace_permanent_mod_name(mod);
1052
+
1053
+ // Exclude non-permanent names (e.g. `#<Module:0x0123>::Foo`) which break flamegraph aggregation
1054
+ // since they contain addresses that differ across processes/runs.
1055
+ if (NIL_P(mod_name)) {
1056
+ return ONLY_METHOD_NAME;
1057
+ }
1058
+
1059
+ size_t mod_name_len = RSTRING_LEN(mod_name);
1060
+ size_t method_name_len = RSTRING_LEN(method_name);
1061
+ size_t total = mod_name_len + 1 + method_name_len;
1062
+ if (total <= buf_size) {
1063
+ memcpy(buf, RSTRING_PTR(mod_name), mod_name_len);
1064
+ buf[mod_name_len] = separator;
1065
+ memcpy(buf + mod_name_len + 1, RSTRING_PTR(method_name), method_name_len);
1066
+ return total;
1067
+ } else {
1068
+ return BUFFER_OUT_OF_SPACE;
1069
+ }
1070
+ }
1071
+
1072
+ static ssize_t calculate_iseq_label(VALUE owner, const rb_iseq_t *iseq, char *buf, size_t buf_size) {
1073
+ switch (ISEQ_BODY(iseq)->type) {
1074
+ case ISEQ_TYPE_TOP:
1075
+ case ISEQ_TYPE_CLASS:
1076
+ case ISEQ_TYPE_MAIN:
1077
+ // Just the method name, not `Object#<top (required)>`
1078
+ return ONLY_METHOD_NAME;
1079
+
1080
+ case ISEQ_TYPE_METHOD:
1081
+ return rb_gen_method_name(owner, ISEQ_BODY(iseq)->location.label, buf, buf_size);
1082
+
1083
+ #ifdef ISEQ_TYPE_PLAIN /* 2.5 does not have it */
1084
+ case ISEQ_TYPE_PLAIN:
1085
+ #endif
1086
+ case ISEQ_TYPE_BLOCK: {
1087
+ // CRuby uses "block in Foo#bar" and ""block (N levels) in Foo#bar" in backtraces.
1088
+ // We use "Foo#bar (block)" because it's much faster and looks better in the UI.
1089
+ const rb_iseq_t* method_iseq = ISEQ_BODY(iseq)->local_iseq;
1090
+
1091
+ static const char suffix[] = " (block)";
1092
+ size_t suffix_len = sizeof(suffix) - 1;
1093
+
1094
+ // Only use the result if there is enough space for both parts
1095
+ ssize_t written = calculate_iseq_label(owner, method_iseq, buf, buf_size);
1096
+ if (written > 0 && (written + suffix_len) <= buf_size) {
1097
+ memcpy(buf + written, suffix, suffix_len);
1098
+ return written + suffix_len;
1099
+ } else if (written == ONLY_METHOD_NAME) {
1100
+ VALUE method_name = rb_iseq_base_label(method_iseq);
1101
+ size_t method_name_len = RSTRING_LEN(method_name);
1102
+ if ((method_name_len + suffix_len) <= buf_size) {
1103
+ memcpy(buf, RSTRING_PTR(method_name), method_name_len);
1104
+ memcpy(buf + method_name_len, suffix, suffix_len);
1105
+ return method_name_len + suffix_len;
1106
+ }
1107
+ }
1108
+
1109
+ return BUFFER_OUT_OF_SPACE;
1110
+ }
1111
+
1112
+ case ISEQ_TYPE_RESCUE:
1113
+ case ISEQ_TYPE_ENSURE:
1114
+ case ISEQ_TYPE_EVAL:
1115
+ iseq = ISEQ_BODY(iseq)->parent_iseq;
1116
+ return calculate_iseq_label(owner, iseq, buf, buf_size);
1117
+
1118
+ default:
1119
+ // Upstream: rb_bug("calculate_iseq_label: unreachable");
1120
+ return ONLY_METHOD_NAME;
1121
+ }
1122
+ }
1123
+
1124
+ // MRI: location_label()
1125
+ // C methods don't have an iseq, only Ruby methods have
1126
+ ssize_t ddtrace_location_label(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq, char *buf, size_t buf_size) {
1127
+ if (location_cfunc_p(cme)) {
1128
+ VALUE method_name = rb_id2str(cme->def->original_id);
1129
+ if (method_name == Qfalse) {
1130
+ return NO_METHOD_NAME;
1131
+ }
1132
+ return rb_gen_method_name(cme->owner, method_name, buf, buf_size);
1133
+ } else {
1134
+ VALUE owner = cme ? cme->owner : Qnil;
1135
+ return calculate_iseq_label(owner, iseq, buf, buf_size);
1136
+ }
1137
+ }
1138
+
1139
+ // Returns a String or Qfalse (like rb_id2str())
1140
+ VALUE ddtrace_location_base_label(const rb_callable_method_entry_t *cme, const rb_iseq_t *iseq) {
1141
+ if (location_cfunc_p(cme)) {
1142
+ return rb_id2str(cme->def->original_id);
1143
+ } else {
1144
+ return rb_iseq_base_label(iseq);
1145
+ }
1146
+ }
1147
+
1148
+ // Always returns a String
1149
+ VALUE ddtrace_iseq_base_label(const rb_iseq_t *iseq) {
1150
+ return rb_iseq_base_label(iseq);
1151
+ }
1152
+
1153
+ // Always returns a String
1154
+ // See https://github.com/ruby/ruby/blob/75aeb225b8558ff908ea78bf608dfbba09bdc2f9/iseq.c#L564-L565
1155
+ VALUE ddtrace_iseq_path(const rb_iseq_t *iseq) {
1156
+ return rb_iseq_path(iseq);
1157
+ }
1158
+
1159
+ size_t sizeof_rb_iseq_t(void) {
1160
+ return sizeof(rb_iseq_t);
1161
+ }
1162
+
1163
+ size_t sizeof_rb_callable_method_entry_t(void) {
1164
+ return sizeof(rb_callable_method_entry_t);
1165
+ }
1166
+
1167
+ void* ddtrace_cme_cfunc_func(const rb_callable_method_entry_t *cme) {
1168
+ return cme->def->body.cfunc.func;
1169
+ }
1170
+
1171
+ const char *ddtrace_cme_original_method_name(const rb_callable_method_entry_t *cme) {
1172
+ return rb_id2name(cme->def->original_id);
1173
+ }
1174
+
1175
+ // This function is not present in the VM headers, but is a public symbol that can be invoked.
1176
+ int rb_objspace_internal_object_p(VALUE obj);
1177
+
1178
+ bool ddtrace_is_internal_object_p(VALUE obj) {
1179
+ if (RB_SPECIAL_CONST_P(obj)) {
1180
+ // Ruby special constants are not internal, except Qundef.
1181
+ // See enum ruby_special_consts in CRuby.
1182
+ return obj == Qundef;
1183
+ } else {
1184
+ // rb_objspace_internal_object_p() assumes non-immediate, so check that first above
1185
+ return rb_objspace_internal_object_p(obj);
1186
+ }
1187
+ }