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
@@ -0,0 +1,1092 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "scope"
4
+ require_relative "symbol"
5
+ require_relative "file_hash"
6
+ require_relative "../core/utils/enumerable_compat"
7
+ require_relative "../di/fatal_exceptions"
8
+
9
+ module Datadog
10
+ module SymbolDatabase
11
+ # Extracts symbol metadata from loaded Ruby modules and classes via introspection.
12
+ #
13
+ # Instance created by Component with injected dependencies (logger, settings).
14
+ # All methods are instance methods accessing @logger, @settings directly —
15
+ # no parameter threading needed.
16
+ #
17
+ # Uses Ruby's reflection APIs (Module#constants, Class#instance_methods, Method#parameters)
18
+ # to build hierarchical Scope structures representing code organization.
19
+ # Filters to user code only (excludes gems, stdlib, test files).
20
+ #
21
+ # Extraction flow:
22
+ # 1. ObjectSpace.each_object(Module) - Iterate all loaded modules/classes
23
+ # 2. Filter to user code (user_code_module?)
24
+ # 3. Build MODULE or CLASS scope with nested METHOD scopes
25
+ # 4. Extract symbols: constants, class variables, method parameters
26
+ #
27
+ # Called by: Component.extract_and_upload (during upload trigger)
28
+ # Produces: Scope objects passed to ScopeBatcher for batching
29
+ # File hashing: Calls FileHash.compute for MODULE scopes
30
+ #
31
+ # Error handling strategy (defense-in-depth):
32
+ #
33
+ # The extractor introspects arbitrary Ruby objects via ObjectSpace. Ruby's
34
+ # reflection APIs (Module#name, #instance_methods, #const_get, #source_location,
35
+ # #parameters) can fail unpredictably on third-party code: NameError from removed
36
+ # constants, LoadError from autoload, ArgumentError from overridden #name methods,
37
+ # SecurityError in restricted contexts, and more.
38
+ #
39
+ # Rescue blocks are organized in three layers:
40
+ #
41
+ # 1. **Inner per-item rescues** (bare `rescue` in const_get loops, method.name):
42
+ # Skip one constant or name lookup without aborting the enclosing collection.
43
+ # These are expected failures — no logging needed.
44
+ #
45
+ # 2. **Method-level rescues** (`rescue => e` with logging):
46
+ # Catch failures in build_class_method_scopes, find_source_file, etc. Log at debug
47
+ # for post-hoc diagnosis, return nil or empty array. One bad method/module
48
+ # doesn't kill the entire class extraction.
49
+ #
50
+ # 3. **Top-level entry rescues** (`rescue => e` with logging):
51
+ # extract() and extract_all() are the error boundaries. Any exception that
52
+ # escapes layers 1-2 is caught here and logged.
53
+ #
54
+ # @api private
55
+ class Extractor
56
+ # Common Ruby core modules to exclude from included_modules extraction.
57
+ # These are ubiquitous mix-ins that don't provide meaningful context about the class structure.
58
+ # Kernel: Mixed into Object, appears in nearly all classes
59
+ # PP: Pretty-printing module, loaded by many tools
60
+ # JSON: JSON serialization module, loaded by many tools
61
+ # Enumerable: Core iteration protocol, extremely common
62
+ # Comparable: Core comparison protocol, extremely common
63
+ # Sentinel for unknown minimum line number. 0 means "available throughout the scope."
64
+ # Defined here (the only runtime consumer) so extractor.rb is self-contained.
65
+ # The parent module (lib/datadog/symbol_database.rb) defines the same values for
66
+ # documentation and external reference, but is not required by this file.
67
+ UNKNOWN_MIN_LINE = 0
68
+ # PostgreSQL signed INT_MAX (2^31 - 1). Means "entire file" or "unknown end."
69
+ UNKNOWN_MAX_LINE = 2147483647
70
+
71
+ EXCLUDED_COMMON_MODULES = ["Kernel", "PP::", "JSON::", "Enumerable", "Comparable"].freeze
72
+
73
+ # RubyVM::InstructionSequence#trace_points event types included when
74
+ # computing targetable lines on METHOD scopes.
75
+ # :line — any line with executable bytecode (primary line probe target)
76
+ # :return — last expression before method returns (DI instruments return events)
77
+ # :call excluded — method entry is handled by method probes, not line probes
78
+ TARGETABLE_LINE_EVENTS = [:line, :return].freeze
79
+
80
+ # Cached unbound Module#singleton_class? — dispatched explicitly so user classes
81
+ # that define their own `singleton_class?` (e.g. with required arguments) cannot
82
+ # intercept the predicate and cause the module to be silently dropped from
83
+ # extract_all. Cached at load time because build_per_file_index iterates
84
+ # ObjectSpace.each_object(Module) over tens of thousands of modules.
85
+ MODULE_SINGLETON_CLASS_PRED = Module.instance_method(:singleton_class?)
86
+ private_constant :MODULE_SINGLETON_CLASS_PRED
87
+
88
+ # Cached UnboundMethod for Module#name — avoids resolving it on every
89
+ # safe_mod_name call. Some classes override .name (e.g. Faker::Travel::Airport),
90
+ # so we bind the original Module#name to get the real module name safely.
91
+ MODULE_NAME = Module.instance_method(:name)
92
+
93
+ # Cached UnboundMethods for the remaining class/module/object introspection
94
+ # used during extraction. Like MODULE_NAME, these bind the original
95
+ # implementations and are dispatched explicitly so that application code
96
+ # which overrides any of them (per-class, on a subclass, or in a singleton
97
+ # class) can neither intercept extraction nor be executed as a side effect
98
+ # of it. KERNEL_CLASS recovers an object's real class without calling a
99
+ # possibly-overridden #class.
100
+ CLASS_SUPERCLASS = Class.instance_method(:superclass)
101
+ MODULE_INCLUDED_MODULES = Module.instance_method(:included_modules)
102
+ MODULE_ANCESTORS = Module.instance_method(:ancestors)
103
+ MODULE_CLASS_VARIABLES = Module.instance_method(:class_variables)
104
+ MODULE_CONSTANTS = Module.instance_method(:constants)
105
+ MODULE_AUTOLOAD_P = Module.instance_method(:autoload?)
106
+ MODULE_CONST_GET = Module.instance_method(:const_get)
107
+ MODULE_CONST_DEFINED = Module.instance_method(:const_defined?)
108
+ KERNEL_CLASS = ::Kernel.instance_method(:class)
109
+ private_constant :CLASS_SUPERCLASS, :MODULE_INCLUDED_MODULES, :MODULE_ANCESTORS,
110
+ :MODULE_CLASS_VARIABLES, :MODULE_CONSTANTS, :MODULE_AUTOLOAD_P, :MODULE_CONST_GET,
111
+ :MODULE_CONST_DEFINED, :KERNEL_CLASS
112
+
113
+ # @param logger [Logger] Logger instance (SymbolDatabase::Logger facade or compatible)
114
+ # @param settings [Configuration::Settings] Tracer settings
115
+ def initialize(logger:, settings:)
116
+ @logger = logger
117
+ @settings = settings
118
+ end
119
+
120
+ # Extract symbols from a single module or class.
121
+ # Returns nil if module should be skipped (anonymous, gem code, stdlib).
122
+ #
123
+ # Returns a FILE scope wrapping the extracted CLASS or MODULE scope.
124
+ # The backend requires root-level scopes to be in ROOT_SCOPES (MODULE, JAR,
125
+ # ASSEMBLY, PACKAGE, FILE). FILE is the natural root for Ruby — one per source file.
126
+ #
127
+ # For full extraction with proper FQN-based nesting and per-file method grouping,
128
+ # use extract_all instead. This method is kept for single-module extraction in tests.
129
+ #
130
+ # @param mod [Module, Class] The module or class to extract from
131
+ # @return [Scope, nil] FILE scope wrapping extracted scope, or nil if filtered out
132
+ def extract(mod)
133
+ return nil unless Module === mod
134
+ mod_name = safe_mod_name(mod)
135
+ return nil unless mod_name
136
+ return nil unless user_code_module_name?(mod)
137
+
138
+ source_file = find_source_file(mod)
139
+ return nil unless source_file
140
+ return nil unless user_code_path?(source_file)
141
+
142
+ inner_scope = if Class === mod
143
+ extract_class_scope(mod, source_file)
144
+ else
145
+ extract_module_scope(mod, source_file)
146
+ end
147
+
148
+ wrap_in_file_scope(source_file, [inner_scope])
149
+ rescue Exception => e # standard:disable Lint/RescueException
150
+ Datadog::DI.reraise_if_fatal(e)
151
+ @logger.debug { "symdb: failed to extract #{mod_name || "<unknown>"}: #{e.class}: #{e.message}" }
152
+ nil
153
+ end
154
+
155
+ # Extract symbols from all loaded modules and classes.
156
+ # Returns an array of FILE scopes with proper FQN-based nesting.
157
+ #
158
+ # Two-pass algorithm:
159
+ # Pass 1 (`build_per_file_index`): iterate ObjectSpace once, building
160
+ # `{ file_path => [[mod_name, mod, [method_name_symbol, ...]], ...] }`.
161
+ # Stores Symbol method names + Module refs only; no UnboundMethod retention
162
+ # between passes.
163
+ # Pass 2 (`build_file_scope`): for each file in the index, resolve
164
+ # UnboundMethods just-in-time, build the nested MODULE/CLASS scope tree from
165
+ # FQN splitting, and produce one FILE Scope. The per-file working set is
166
+ # released as soon as the FILE scope is yielded (or accumulated into the
167
+ # returned Array, in legacy mode).
168
+ #
169
+ # This is the production path used by Component. Methods are split by source file,
170
+ # so a class reopened across two files produces two FILE scopes, each with only
171
+ # the methods defined in that file.
172
+ #
173
+ # Memory profile (with a block):
174
+ # - Pass 1 builds a per-file index containing only Symbol method names plus
175
+ # Module references. No UnboundMethod objects are retained between passes.
176
+ # - Pass 2 processes one file at a time. The peak per file is bounded by the
177
+ # number of methods that live in that one file across all its modules
178
+ # (typical Rails: tens of methods; pathological case: a single very large
179
+ # source file). Once a FILE scope is yielded and the caller stops referencing
180
+ # it, the entire per-file working set becomes garbage.
181
+ #
182
+ # This is O(largest_file + batch_buffer), not O(total_classes).
183
+ #
184
+ # Without a block, returns the full `Array<Scope>` (legacy form, used by specs).
185
+ # The Array itself still scales with the number of files, so block form is the
186
+ # one to use for production memory bounds.
187
+ #
188
+ # @yieldparam scope [Scope] FILE scope for one source file
189
+ # @return [Array<Scope>, nil] Array of FILE scopes when called without a block; nil when a block is given
190
+ def extract_all
191
+ index = build_per_file_index
192
+
193
+ if block_given?
194
+ # Drain the index destructively so each per-file entry becomes eligible for
195
+ # collection as soon as its FILE scope is yielded and consumed. Hash#shift
196
+ # returns [key, value] on a non-empty hash and nil when empty, so the
197
+ # `while (pair = ...)` form is the drain. Indexing pair[0]/pair[1] rather
198
+ # than destructuring avoids introducing names into method scope that would
199
+ # then shadow the else-branch's block parameters.
200
+ while (pair = index.shift)
201
+ scope = build_file_scope(pair[0], pair[1])
202
+ yield scope if scope
203
+ end
204
+ nil
205
+ else
206
+ # Legacy non-block form for specs. No memory bound — the full Array is
207
+ # materialized.
208
+ result = []
209
+ index.each do |path, file_entries|
210
+ scope = build_file_scope(path, file_entries)
211
+ result << scope if scope
212
+ end
213
+ result
214
+ end
215
+ rescue Exception => e # standard:disable Lint/RescueException
216
+ Datadog::DI.reraise_if_fatal(e)
217
+ @logger.debug { "symdb: error in extract_all: #{e.class}: #{e.message}" }
218
+ block_given? ? nil : []
219
+ end
220
+
221
+ private
222
+
223
+ # Safe Module#name lookup — some classes override the singleton `name` method
224
+ # (e.g. Faker::Travel::Airport defines `def name(size:, region:)` in class << self,
225
+ # which shadows Module#name and raises ArgumentError when called without args).
226
+ # @param mod [Module] The module
227
+ # @return [String, nil] Module name or nil
228
+ def safe_mod_name(mod)
229
+ MODULE_NAME.bind(mod).call
230
+ rescue Exception => e # standard:disable Lint/RescueException
231
+ Datadog::DI.reraise_if_fatal(e)
232
+ @logger.debug { "symdb: safe_mod_name failed: #{e.class}: #{e.message}" }
233
+ nil
234
+ end
235
+
236
+ # Verify that mod_name still resolves to mod through Ruby's constant
237
+ # table. Returns false when a Class/Module has been detached from its
238
+ # constant (via remove_const) but still carries the cached Module#name —
239
+ # see build_per_file_index for the failure mode this protects.
240
+ #
241
+ # Walks the namespace path segment-by-segment. For each segment:
242
+ # 1. Check for a pending autoload directly on the current namespace.
243
+ # If present, const_get would trigger it — loading customer code as
244
+ # a side effect of symbol extraction and raising LoadError if the
245
+ # target file is missing (LoadError is ScriptError, not StandardError,
246
+ # and would propagate past the outer rescue in
247
+ # build_per_file_index). Return false instead.
248
+ # 2. Otherwise, require the constant to be directly defined on this
249
+ # namespace (const_defined?(sym, false)) and descend via
250
+ # const_get(sym, false). The direct-only lookup means an ancestor's
251
+ # pending autoload at the same name does not affect the result: a
252
+ # subclass with its own binding resolves through the binding, an
253
+ # inherited autoload triggers nothing.
254
+ #
255
+ # Uses `current.autoload?(sym, false)` (the inherit=false form, added
256
+ # in Ruby 2.7) so the question is strictly "is there an autoload
257
+ # registered directly on this namespace?" and ancestors' pending
258
+ # autoloads at the same name do not affect the result.
259
+ # @param mod_name [String]
260
+ # @param mod [Module]
261
+ # @return [Boolean]
262
+ def resolves_to_same_module?(mod_name, mod)
263
+ current = Object
264
+ mod_name.split("::").each do |seg|
265
+ sym = seg.to_sym
266
+ return false if MODULE_AUTOLOAD_P.bind(current).call(sym, false)
267
+ return false unless MODULE_CONST_DEFINED.bind(current).call(sym, false)
268
+ current = MODULE_CONST_GET.bind(current).call(sym, false)
269
+ end
270
+ current.equal?(mod)
271
+ rescue NameError, ArgumentError, TypeError
272
+ # Expected "no" outcome for stale/detached classes — the whole point
273
+ # of this predicate. Per the rescue convention in this file's header
274
+ # comment: inner per-item rescues are expected failures, no logging.
275
+ false
276
+ end
277
+
278
+ # Return whether +mod+ passes the name-based user-code exclusions
279
+ # (named, outside Datadog, not a Ruby root class). Does not resolve
280
+ # a source file.
281
+ # @param mod [Module]
282
+ # @return [Boolean]
283
+ def user_code_module_name?(mod)
284
+ mod_name = safe_mod_name(mod)
285
+ return false unless mod_name
286
+
287
+ # CRITICAL: Exclude entire Datadog namespace (prevents circular extraction)
288
+ # Matches Java: className.startsWith("com/datadog/")
289
+ # Matches Python: packages.is_user_code() excludes ddtrace.*
290
+ # Note: bare 'Datadog' must be checked separately — start_with?('Datadog::')
291
+ # doesn't match the root module itself.
292
+ return false if mod_name == "Datadog" || mod_name.start_with?("Datadog::")
293
+
294
+ # Exclude Ruby root classes. These are never user code, but
295
+ # find_source_file can return a user-code path for them via
296
+ # const_source_location (top-level constants like User are
297
+ # Object constants, so Object.const_source_location(:User)
298
+ # points to the user's file).
299
+ return false if mod.equal?(Object) || mod.equal?(BasicObject) ||
300
+ mod.equal?(Kernel) || mod.equal?(Module) || mod.equal?(Class)
301
+
302
+ true
303
+ end
304
+
305
+ # Check if module is from user code (not gems or stdlib)
306
+ # @param mod [Module] The module to check
307
+ # @return [Boolean] true if user code
308
+ def user_code_module?(mod)
309
+ return false unless user_code_module_name?(mod)
310
+
311
+ source_file = find_source_file(mod)
312
+ return false unless source_file
313
+
314
+ user_code_path?(source_file)
315
+ end
316
+
317
+ # Check if path is user code
318
+ # @param path [String] File path
319
+ # @return [Boolean] true if user code
320
+ def user_code_path?(path)
321
+ # Only absolute paths are real source files. Pseudo-paths like '<main>',
322
+ # '<internal:...>', '(eval)' are not user code.
323
+ return false unless path.start_with?("/")
324
+ # Only .rb files are Ruby source. Excludes the Ruby binary
325
+ # (/usr/local/bin/ruby), C extensions (.so/.bundle), and other
326
+ # non-source files that appear in method source_location.
327
+ return false unless path.end_with?(".rb")
328
+ # Exclude gem paths
329
+ return false if path.include?("/gems/")
330
+ # Exclude Ruby stdlib
331
+ return false if path.include?("/ruby/")
332
+ return false if path.start_with?("<internal:")
333
+ return false if path.include?("(eval)")
334
+ # Exclude test code (not application code)
335
+ return false if path.include?("/spec/")
336
+ return false if path.include?("/test/")
337
+ # Exclude Datadog's own library code (e.g., monkey-patched methods from tracing contrib).
338
+ # Without this, stdlib classes like Net::HTTP appear as user code when dd-trace-rb
339
+ # instruments them, because the patched method source points to lib/datadog/tracing/contrib/.
340
+ return false if path.include?("/lib/datadog/")
341
+
342
+ true
343
+ end
344
+
345
+ # Resolve the UnboundMethod +mod+ itself declares for +method_name+,
346
+ # skipping prepended wrapper modules (e.g. a DI method-logpoint wrapper)
347
+ # that shadow it.
348
+ #
349
+ # @param mod [Module] Module or class expected to declare the method
350
+ # @param method_name [Symbol] Name of the method to resolve
351
+ # @return [UnboundMethod] Method whose owner is +mod+, or the
352
+ # prepend-resolved method when +mod+ owns no method in the super chain
353
+ def declared_instance_method(mod, method_name)
354
+ original_method = mod.instance_method(method_name)
355
+ method = original_method
356
+ until method.owner.equal?(mod)
357
+ super_method = method.super_method
358
+ return original_method unless super_method
359
+ method = super_method
360
+ end
361
+ method
362
+ end
363
+
364
+ # Find source file for a module.
365
+ # Prefers user code paths over gem/stdlib paths. ActiveRecord models have
366
+ # generated methods (autosave callbacks) whose source is in the gem, but
367
+ # user-defined methods point to app/models/. Without this preference,
368
+ # AR models get filtered out as gem code.
369
+ #
370
+ # For namespace-only modules (no instance or singleton methods), falls back to
371
+ # Module#const_source_location to locate the module via its constants.
372
+ # This handles patterns like `module ApplicationCable; class Channel...; end; end`
373
+ # where the namespace module itself has no methods but defines user-code classes.
374
+ #
375
+ # @param mod [Module] The module
376
+ # @return [String, nil] Source file path or nil
377
+ def find_source_file(mod)
378
+ fallback = nil
379
+
380
+ # Try instance methods first
381
+ mod.instance_methods(false).each do |method_name|
382
+ method = declared_instance_method(mod, method_name)
383
+ location = method.source_location
384
+ next unless location
385
+
386
+ path = location[0]
387
+ return path if user_code_path?(path)
388
+
389
+ fallback ||= path # steep:ignore
390
+ rescue Exception => e # standard:disable Lint/RescueException
391
+ Datadog::DI.reraise_if_fatal(e)
392
+ @logger.debug { "symdb: error resolving #{safe_mod_name(mod)}##{method_name}: #{e.class}: #{e.message}" }
393
+ end
394
+
395
+ # Try singleton methods
396
+ mod.singleton_methods(false).each do |method_name|
397
+ # Method-logpoint probes prepend instance methods only, so singleton
398
+ # methods are never shadowed by a DI wrapper.
399
+ method = mod.method(method_name)
400
+ location = method.source_location
401
+ next unless location
402
+
403
+ path = location[0]
404
+ return path if user_code_path?(path)
405
+
406
+ fallback ||= path # steep:ignore
407
+ rescue Exception => e # standard:disable Lint/RescueException
408
+ Datadog::DI.reraise_if_fatal(e)
409
+ @logger.debug { "symdb: error resolving #{safe_mod_name(mod)}.#{method_name}: #{e.class}: #{e.message}" }
410
+ end
411
+
412
+ # Use const_source_location to find where this class/module is declared.
413
+ # This handles two cases:
414
+ # 1. Classes with no user-defined methods (e.g. AR models with only associations) whose
415
+ # generated methods point to gem code — we find the `class Foo` declaration instead.
416
+ # 2. Namespace-only modules (`module Foo; class Bar; end; end`) with no methods at all.
417
+ mod_name = safe_mod_name(mod)
418
+ if mod_name
419
+ # Look up the class/module by its last name component in its enclosing namespace.
420
+ parts = mod_name.split("::")
421
+ const_name = parts.last
422
+ namespace = if parts.length > 1
423
+ begin
424
+ MODULE_CONST_GET.bind(Object).call(parts[0..-2].join("::")) # steep:ignore
425
+ rescue NameError
426
+ nil
427
+ end
428
+ else
429
+ Object
430
+ end
431
+
432
+ if namespace
433
+ location = begin
434
+ namespace.const_source_location(const_name)
435
+ rescue Exception => e # standard:disable Lint/RescueException
436
+ Datadog::DI.reraise_if_fatal(e)
437
+ @logger.debug { "symdb: const_source_location(#{const_name}) failed: #{e.class}: #{e.message}" }
438
+ nil
439
+ end
440
+
441
+ if location && !location.empty?
442
+ path = location[0]
443
+ return path if path && !path.empty? && user_code_path?(path)
444
+ fallback ||= ((path && !path.empty?) ? path : nil)
445
+ end
446
+ end
447
+
448
+ # Also scan constants defined by mod itself (namespace-only modules).
449
+ MODULE_CONSTANTS.bind(mod).call(false).each do |child_const_name|
450
+ location = begin
451
+ mod.const_source_location(child_const_name)
452
+ rescue Exception => e # standard:disable Lint/RescueException
453
+ Datadog::DI.reraise_if_fatal(e)
454
+ @logger.debug { "symdb: const_source_location(#{child_const_name}) failed: #{e.class}: #{e.message}" }
455
+ nil
456
+ end
457
+ next unless location && !location.empty?
458
+
459
+ path = location[0]
460
+ next unless path && !path.empty?
461
+
462
+ return path if user_code_path?(path)
463
+
464
+ fallback ||= path
465
+ end
466
+ end
467
+
468
+ fallback
469
+ rescue Exception => e # standard:disable Lint/RescueException
470
+ Datadog::DI.reraise_if_fatal(e)
471
+ @logger.debug { "symdb: error finding source file for #{safe_mod_name(mod) || "<unknown>"}: #{e.class}: #{e.message}" }
472
+ nil
473
+ end
474
+
475
+ # Wrap inner scopes in a FILE root scope.
476
+ # FILE is the per-source-file root scope for Ruby uploads, analogous to
477
+ # Python's MODULE-per-file or Java's JAR.
478
+ #
479
+ # @param file_path [String] Source file path
480
+ # @param inner_scopes [Array<Scope>] Child scopes to nest under FILE
481
+ # @return [Scope] FILE scope wrapping the inner scopes
482
+ def wrap_in_file_scope(file_path, inner_scopes)
483
+ file_hash = FileHash.compute(file_path, logger: @logger)
484
+ lang = {}
485
+ lang[:file_hash] = file_hash if file_hash
486
+
487
+ Scope.new(
488
+ scope_type: "FILE",
489
+ name: file_path,
490
+ source_file: file_path,
491
+ start_line: UNKNOWN_MIN_LINE,
492
+ end_line: UNKNOWN_MAX_LINE,
493
+ language_specifics: lang,
494
+ scopes: inner_scopes
495
+ )
496
+ end
497
+
498
+ # Extract MODULE scope (without file_hash — that belongs on the FILE root scope).
499
+ # Does not include nested classes — nesting is handled by extract_all via FQN splitting.
500
+ # @param mod [Module] The module
501
+ # @param source_file [String] Source file resolved by the caller
502
+ # @return [Scope] The module scope
503
+ def extract_module_scope(mod, source_file)
504
+ Scope.new(
505
+ scope_type: "MODULE",
506
+ name: safe_mod_name(mod),
507
+ source_file: source_file,
508
+ start_line: UNKNOWN_MIN_LINE,
509
+ end_line: UNKNOWN_MAX_LINE,
510
+ symbols: extract_scope_symbols(mod)
511
+ )
512
+ end
513
+
514
+ # Extract CLASS scope
515
+ # @param klass [Class] The class
516
+ # @param source_file [String] Source file resolved by the caller
517
+ # @return [Scope] The class scope
518
+ def extract_class_scope(klass, source_file)
519
+ method_scopes = build_class_method_scopes(klass)
520
+ start_line, end_line = line_range_from_scopes(method_scopes)
521
+
522
+ Scope.new(
523
+ scope_type: "CLASS",
524
+ name: safe_mod_name(klass),
525
+ source_file: source_file,
526
+ start_line: start_line,
527
+ end_line: end_line,
528
+ language_specifics: build_class_language_specifics(klass),
529
+ scopes: method_scopes,
530
+ symbols: extract_scope_symbols(klass)
531
+ )
532
+ end
533
+
534
+ # Derive a [start_line, end_line] range from method scopes, ignoring
535
+ # UNKNOWN sentinel values. The end is the max of method end_lines so a
536
+ # multi-line method's last line is not truncated to its start_line.
537
+ # @param method_scopes [Array<Scope>]
538
+ # @return [Array<Integer, Integer>] [start_line, end_line]
539
+ def line_range_from_scopes(method_scopes)
540
+ starts = method_scopes.map(&:start_line).reject { |line| line == UNKNOWN_MIN_LINE }
541
+ ends = method_scopes.map(&:end_line).reject { |line| line == UNKNOWN_MAX_LINE }
542
+ [starts.min || UNKNOWN_MIN_LINE, ends.max || UNKNOWN_MAX_LINE]
543
+ end
544
+
545
+ # Build language specifics for CLASS
546
+ # @param klass [Class] The class
547
+ # @return [Hash] Language-specific metadata
548
+ def build_class_language_specifics(klass)
549
+ specifics = {}
550
+
551
+ # Superclass chain (exclude Object and BasicObject).
552
+ # Emitted as an array named super_classes — consistent with Java, .NET, and Python.
553
+ # Array allows for multiple entries if future Ruby versions or mixins expand the chain.
554
+ # Anonymous superclasses (class Foo < Class.new { ... }) have nil name; compact to skip.
555
+ superclass = CLASS_SUPERCLASS.bind(klass).call
556
+ if superclass && !superclass.equal?(Object) && !superclass.equal?(BasicObject)
557
+ super_name = safe_mod_name(superclass)
558
+ specifics[:super_classes] = [super_name] if super_name
559
+ end
560
+
561
+ # Included modules (exclude common ones).
562
+ # included_modules returns the entire ancestor chain's mixins, not only directly
563
+ # included ones. This is intentional: the field reports "modules this class
564
+ # responds to," which is what the consumer (UI navigation, probe context) needs.
565
+ included = MODULE_INCLUDED_MODULES.bind(klass).call.map { |m| safe_mod_name(m) }.reject do |name|
566
+ name.nil? || EXCLUDED_COMMON_MODULES.any? { |prefix| name.start_with?(prefix) }
567
+ end
568
+ specifics[:included_modules] = included unless included.empty?
569
+
570
+ # Prepended modules
571
+ # Take all ancestors before the class itself (prepending inserts modules before the class in ancestor chain).
572
+ # This code path is taken when a class has prepended modules (e.g., class Foo; prepend Bar; end).
573
+ # Single-pass collection avoids the intermediate arrays from take_while.map.compact.
574
+ # Test coverage: spec/datadog/symbol_database/extractor_spec.rb tests prepend behavior.
575
+ prepended = []
576
+ MODULE_ANCESTORS.bind(klass).call.each do |a|
577
+ break if a.equal?(klass)
578
+ name = safe_mod_name(a)
579
+ prepended << name if name
580
+ end
581
+ specifics[:prepended_modules] = prepended unless prepended.empty?
582
+
583
+ specifics
584
+ rescue Exception => e # standard:disable Lint/RescueException
585
+ Datadog::DI.reraise_if_fatal(e)
586
+ @logger.debug { "symdb: error building language specifics for #{safe_mod_name(klass)}: #{e.class}: #{e.message}" }
587
+ {}
588
+ end
589
+
590
+ # Build a METHOD scope for each user-code instance method +klass+
591
+ # declares.
592
+ # @param klass [Class]
593
+ # @return [Array<Scope>]
594
+ def build_class_method_scopes(klass)
595
+ method_names = (klass.instance_methods(false) +
596
+ klass.protected_instance_methods(false) +
597
+ klass.private_instance_methods(false)).uniq
598
+
599
+ Core::Utils::EnumerableCompat.filter_map(method_names) do |method_name|
600
+ method = declared_instance_method(klass, method_name)
601
+ location = method.source_location
602
+ next unless location
603
+ next unless user_code_path?(location[0])
604
+
605
+ build_instance_method_scope(klass, method_name, method)
606
+ rescue Exception => e # standard:disable Lint/RescueException
607
+ Datadog::DI.reraise_if_fatal(e)
608
+ @logger.debug { "symdb: error resolving #{safe_mod_name(klass)}##{method_name}: #{e.class}: #{e.message}" }
609
+ nil
610
+ end
611
+ rescue Exception => e # standard:disable Lint/RescueException
612
+ Datadog::DI.reraise_if_fatal(e)
613
+ @logger.debug { "symdb: failed to extract methods from #{safe_mod_name(klass)}: #{e.class}: #{e.message}" }
614
+ []
615
+ end
616
+
617
+ # Get method visibility
618
+ # @param klass [Class] The class
619
+ # @param method_name [Symbol] Method name
620
+ # @return [String] 'public', 'private', or 'protected'
621
+ def method_visibility(klass, method_name)
622
+ if klass.private_instance_methods(false).include?(method_name)
623
+ "private"
624
+ elsif klass.protected_instance_methods(false).include?(method_name)
625
+ "protected"
626
+ else
627
+ "public"
628
+ end
629
+ end
630
+
631
+ # Extract targetable lines and end_line from a method's bytecode.
632
+ # Returns [ranges, end_line] where ranges is an array of {start:, end:} hashes
633
+ # or nil if iseq is unavailable (C-extension methods).
634
+ # @param method [Method, UnboundMethod] The method
635
+ # @param start_line [Integer] Fallback end_line if iseq unavailable
636
+ # @return [Array(Array<Hash>, Integer), Array(nil, Integer)]
637
+ def extract_targetable_lines(method, start_line)
638
+ iseq = RubyVM::InstructionSequence.of(method)
639
+ unless iseq
640
+ @logger.debug { "symdb: no iseq for #{method.name} (C extension or native), skipping targetable lines" }
641
+ return [nil, start_line]
642
+ end
643
+
644
+ lines = iseq.trace_points
645
+ .select { |_, event| TARGETABLE_LINE_EVENTS.include?(event) }
646
+ .map(&:first)
647
+ .uniq
648
+ .sort
649
+
650
+ end_line = lines.max || start_line
651
+ ranges = build_targetable_ranges(lines)
652
+ result = ranges.empty? ? nil : ranges
653
+ @logger.debug { "symdb: #{method.name} targetable lines: #{result ? "#{ranges.size} range(s), lines #{lines.first}..#{lines.last}" : "none (no matching events)"}" }
654
+ [result, end_line]
655
+ end
656
+
657
+ # Compress sorted line numbers into consecutive ranges.
658
+ # [4, 5, 6, 8, 10, 11] => [{start: 4, end: 6}, {start: 8, end: 8}, {start: 10, end: 11}]
659
+ # @param lines [Array<Integer>] Sorted, deduplicated line numbers
660
+ # @return [Array<Hash>] Array of {start:, end:} range hashes
661
+ def build_targetable_ranges(lines)
662
+ return [] if lines.empty?
663
+
664
+ ranges = []
665
+ range_start = lines[0]
666
+ prev = range_start
667
+
668
+ lines[1..-1].each do |line| # steep:ignore
669
+ if line == prev + 1
670
+ prev = line
671
+ else
672
+ ranges << {start: range_start, end: prev}
673
+ range_start = line
674
+ prev = line
675
+ end
676
+ end
677
+ ranges << {start: range_start, end: prev}
678
+ ranges
679
+ end
680
+
681
+ # Extract method parameters as symbols.
682
+ # Does NOT include `self` — Ruby's implicit receiver is not a declared parameter.
683
+ # Java skips slot 0 (this) for the same reason. .NET uploads `this` but the web-ui
684
+ # filters it for dotnet. Ruby follows Java's approach: don't upload it.
685
+ # @param method [UnboundMethod] The method
686
+ # @return [Array<Symbol>] Parameter symbols
687
+ def extract_method_parameters(method)
688
+ method_name = begin
689
+ method.name.to_s
690
+ rescue Exception => e # standard:disable Lint/RescueException
691
+ Datadog::DI.reraise_if_fatal(e)
692
+ @logger.debug { "symdb: method.name failed: #{e.class}: #{e.message}" }
693
+ "unknown"
694
+ end
695
+ params = method.parameters
696
+
697
+ return [] if params.nil? || params.empty?
698
+
699
+ Core::Utils::EnumerableCompat.filter_map(params) do |param_type, param_name|
700
+ # Skip block parameters for MVP
701
+ next if param_type == :block
702
+
703
+ # Skip if param_name is nil — normal for generated methods (attr_writer, attr_accessor).
704
+ # See pitfall 37 and specs/json-schema.md "Discovered During Implementation".
705
+ next if param_name.nil?
706
+
707
+ Symbol.new(
708
+ symbol_type: "ARG",
709
+ name: param_name.to_s,
710
+ line: UNKNOWN_MIN_LINE, # Parameters available in entire method
711
+ )
712
+ end
713
+ rescue Exception => e # standard:disable Lint/RescueException
714
+ Datadog::DI.reraise_if_fatal(e)
715
+ @logger.debug { "symdb: failed to extract parameters from #{method_name}: #{e.class}: #{e.message}" }
716
+ []
717
+ end
718
+
719
+ # ── extract_all helpers ──────────────────────────────────────────────
720
+
721
+ # Sleep between chunks of modules processed in build_per_file_index so
722
+ # request-handling threads have guaranteed CPU time while extraction is in
723
+ # flight. Unlike Thread.pass (which only offers the GVL among runnable
724
+ # threads and leaves the extractor immediately re-runnable), sleep removes
725
+ # the extractor thread from the runnable set for a fixed duration, capping
726
+ # its CPU share at sleep_work_ratio regardless of GVL scheduling.
727
+ #
728
+ # The cadence is measured in modules that pass the singleton-class fast-path
729
+ # skip — singleton classes are discarded in microseconds and counting them
730
+ # would add wall-clock delay disproportionate to the work being done (e.g.
731
+ # on heavily monkey-patched processes that retain large singleton chains).
732
+ SLEEP_EVERY_N_MODULES = 100
733
+ SLEEP_SECONDS = 0.001
734
+ private_constant :SLEEP_EVERY_N_MODULES, :SLEEP_SECONDS
735
+
736
+ # Pass 1 (memory-bounded form): build a per-file index of
737
+ # `{ file_path => [[mod_name, mod, [method_name_symbol, ...]], ...] }`.
738
+ #
739
+ # Stores Symbol method names plus Module references only — no UnboundMethod
740
+ # objects retained between passes. UnboundMethods created here (to read
741
+ # `source_location`) become garbage as the inner loop ends.
742
+ #
743
+ # The Module references are pointer-sized and the modules are already kept
744
+ # alive in ObjectSpace, so adding them to the index costs no extra retention.
745
+ #
746
+ # @return [Hash{String=>Array<Array(String, Module, Array<Symbol>)>}]
747
+ def build_per_file_index
748
+ index = {}
749
+ seen = 0
750
+
751
+ ObjectSpace.each_object(Module) do |mod|
752
+ # Singleton classes (per-object metaclasses) are never user-code classes.
753
+ # They're not const-referenced, DI cannot instrument methods on a singular
754
+ # object instance, so skipping them is both correct and cheap.
755
+ next if MODULE_SINGLETON_CLASS_PRED.bind(mod).call
756
+
757
+ seen += 1
758
+ sleep SLEEP_SECONDS if (seen % SLEEP_EVERY_N_MODULES).zero?
759
+
760
+ mod_name = safe_mod_name(mod)
761
+ next unless mod_name
762
+ next unless resolves_to_same_module?(mod_name, mod)
763
+ next unless user_code_module?(mod)
764
+
765
+ file_to_names = collect_method_names_by_file(mod)
766
+
767
+ # Namespace-only modules (no own methods) — use find_source_file as the
768
+ # canonical file so the FILE scope still gets a MODULE entry.
769
+ if file_to_names.empty?
770
+ source_file = find_source_file(mod)
771
+ file_to_names[source_file] = [] if source_file
772
+ end
773
+
774
+ next if file_to_names.empty?
775
+
776
+ file_to_names.each do |file_path, method_names|
777
+ (index[file_path] ||= []) << [mod_name, mod, method_names]
778
+ end
779
+ rescue Exception => e # standard:disable Lint/RescueException
780
+ Datadog::DI.reraise_if_fatal(e)
781
+ @logger.debug { "symdb: error indexing #{mod_name || "<unknown>"}: #{e.class}: #{e.message}" }
782
+ end
783
+
784
+ index
785
+ end
786
+
787
+ # For a single module, return `{ file_path => [method_name_symbol, ...] }`.
788
+ # Stores only the method-name symbols and their file paths — UnboundMethod
789
+ # objects allocated to read `source_location` are not retained between
790
+ # passes, so they can be GC'd as soon as the inner loop ends.
791
+ def collect_method_names_by_file(mod)
792
+ result = Hash.new { |h, k| h[k] = [] }
793
+
794
+ # Module#instance_methods(false) already returns both public and protected
795
+ # methods, so iterating it plus private_instance_methods covers all three
796
+ # visibilities without an intermediate merged array.
797
+ [mod.instance_methods(false), mod.private_instance_methods(false)].each do |method_names|
798
+ method_names.each do |method_name|
799
+ method = declared_instance_method(mod, method_name)
800
+ loc = method.source_location
801
+ next unless loc
802
+ next unless user_code_path?(loc[0])
803
+
804
+ result[loc[0]] << method_name
805
+ rescue Exception => e # standard:disable Lint/RescueException
806
+ Datadog::DI.reraise_if_fatal(e)
807
+ @logger.debug { "symdb: error indexing method #{method_name}: #{e.class}: #{e.message}" }
808
+ end
809
+ end
810
+
811
+ result
812
+ rescue Exception => e # standard:disable Lint/RescueException
813
+ Datadog::DI.reraise_if_fatal(e)
814
+ @logger.debug { "symdb: error indexing methods: #{e.class}: #{e.message}" }
815
+ {}
816
+ end
817
+
818
+ # Pass 2: build the FILE scope for one source file by walking just the modules
819
+ # that contribute methods to it. Resolves UnboundMethods just-in-time per
820
+ # method; the per-method scratch is collected by GC as each module's loop body
821
+ # ends. The returned Scope is the only thing the caller needs to keep alive
822
+ # — once the caller drops it, the entire per-file working set is collectable.
823
+ #
824
+ # @param file_path [String]
825
+ # @param entries [Array<Array(String, Module, Array<Symbol>)>] tuples produced by build_per_file_index
826
+ # @return [Scope, nil] FILE scope, or nil if nothing extractable
827
+ def build_file_scope(file_path, entries)
828
+ return nil if entries.empty?
829
+
830
+ root = {
831
+ name: file_path, type: "FILE", children: {},
832
+ methods: [], mod: nil, source_file: file_path, fqn: nil,
833
+ }
834
+
835
+ # Sort by FQN depth so parent namespaces are placed before children.
836
+ sorted = entries.sort_by { |(mod_name, _, _)| mod_name.count(":") }
837
+
838
+ sorted.each do |mod_name, mod, method_names|
839
+ # Resolve UnboundMethods for this (mod, file) just-in-time. These objects
840
+ # live only as long as the tree node holds them; they are released when
841
+ # convert_tree_to_scope finishes building the file's Scope.
842
+ method_infos = Core::Utils::EnumerableCompat.filter_map(method_names) do |name|
843
+ method = declared_instance_method(mod, name)
844
+ # Pass 1 (build_per_file_index) recorded this method under file_path.
845
+ # If the method has been redefined in another file between the two
846
+ # passes (e.g. a class reopened during a Rails reload while extract_all
847
+ # is iterating), the resolved UnboundMethod's source_location now
848
+ # points elsewhere. Drop the stale entry — the hot-load TracePoint
849
+ # enqueues the redefined class and the next debounce window extracts
850
+ # it under the new file_path.
851
+ loc = method.source_location
852
+ next nil unless loc && loc[0] == file_path
853
+ {name: name, method: method, type: :instance}
854
+ rescue Exception => e # standard:disable Lint/RescueException
855
+ Datadog::DI.reraise_if_fatal(e)
856
+ @logger.debug { "symdb: error resolving #{mod_name}##{name}: #{e.class}: #{e.message}" }
857
+ nil
858
+ end
859
+
860
+ # If Pass 1 recorded methods for this module but every one of them has
861
+ # moved out of file_path between the passes, drop the entry — otherwise
862
+ # the FILE scope would carry an empty CLASS/MODULE node at a location
863
+ # the module no longer lives in.
864
+ next if method_names.any? && method_infos.empty?
865
+
866
+ parts = mod_name.split("::")
867
+ place_in_tree(root, parts, mod, mod_name, method_infos, file_path)
868
+ rescue Exception => e # standard:disable Lint/RescueException
869
+ Datadog::DI.reraise_if_fatal(e)
870
+ @logger.debug { "symdb: error placing #{mod_name} in tree: #{e.class}: #{e.message}" }
871
+ end
872
+
873
+ # steep:ignore:start
874
+ # Steep widens root[:children] to the union of all value types declared in
875
+ # the literal (String | Hash | Array | nil), losing the Hash narrowing.
876
+ return nil if root[:children].empty?
877
+ # steep:ignore:end
878
+
879
+ convert_tree_to_scope(file_path, root)
880
+ end
881
+
882
+ # Place a module/class in the file tree at the correct nesting depth.
883
+ # Creates intermediate namespace nodes as needed.
884
+ # mod_name is the safe name (resolved via Module#instance_method bind) —
885
+ # callers must not pass raw mod.name, since classes that override singleton
886
+ # name (e.g. Faker::Travel::Airport) will raise.
887
+ def place_in_tree(root, name_parts, mod, mod_name, methods, file_path)
888
+ current = root
889
+
890
+ # Create/find intermediate nodes for each namespace segment except the last
891
+ name_parts[0..-2].each_with_index do |part, idx| # steep:ignore
892
+ fqn = name_parts[0..idx].join("::") # steep:ignore
893
+ current[:children][part] ||= {
894
+ name: fqn, type: resolve_scope_type(fqn),
895
+ children: {}, methods: [], mod: nil,
896
+ source_file: file_path, fqn: fqn,
897
+ }
898
+ current = current[:children][part]
899
+ end
900
+
901
+ # Create or find the leaf node
902
+ leaf_name = name_parts.last
903
+ leaf = current[:children][leaf_name]
904
+ if leaf
905
+ # Node exists (was created as intermediate or from another entry).
906
+ # Update type and mod — the actual module object is authoritative.
907
+ leaf[:type] = (Class === mod) ? "CLASS" : "MODULE"
908
+ leaf[:mod] = mod
909
+ else
910
+ leaf = {
911
+ name: mod_name,
912
+ type: (Class === mod) ? "CLASS" : "MODULE",
913
+ children: {}, methods: [],
914
+ mod: mod, source_file: file_path,
915
+ fqn: mod_name,
916
+ }
917
+ current[:children][leaf_name] = leaf
918
+ end
919
+
920
+ # Add methods for this file
921
+ leaf[:methods].concat(methods)
922
+ end
923
+
924
+ # Determine scope type (CLASS or MODULE) for a fully-qualified name.
925
+ # Looks up the actual Ruby constant to check if it's a Class.
926
+ # @param fqn [String] Fully-qualified name (e.g. "Authentication::Strategies")
927
+ # @return [String] 'CLASS' or 'MODULE'
928
+ def resolve_scope_type(fqn)
929
+ current = Object
930
+ fqn.split("::").each do |seg|
931
+ sym = seg.to_sym
932
+ pending_autoload = if RubyVersion.is?(">= 2.7")
933
+ MODULE_AUTOLOAD_P.bind(current).call(sym, false)
934
+ else
935
+ MODULE_AUTOLOAD_P.bind(current).call(sym)
936
+ end
937
+ return "MODULE" if pending_autoload
938
+ return "MODULE" unless MODULE_CONST_DEFINED.bind(current).call(sym, false)
939
+ current = MODULE_CONST_GET.bind(current).call(sym, false)
940
+ end
941
+ (Class === current) ? "CLASS" : "MODULE"
942
+ rescue Exception => e # standard:disable Lint/RescueException
943
+ Datadog::DI.reraise_if_fatal(e)
944
+ @logger.debug { "symdb: resolve_scope_type(#{fqn}) failed: #{e.class}: #{e.message}, defaulting to MODULE" }
945
+ "MODULE"
946
+ end
947
+
948
+ # Convert a single file tree (built by build_file_scope) to a FILE Scope.
949
+ # @param file_path [String] Source file path
950
+ # @param root [Hash] Tree node from build_file_scope
951
+ # @return [Scope] FILE scope
952
+ def convert_tree_to_scope(file_path, root)
953
+ file_hash = FileHash.compute(file_path, logger: @logger)
954
+ lang = {}
955
+ lang[:file_hash] = file_hash if file_hash
956
+
957
+ Scope.new(
958
+ scope_type: "FILE",
959
+ name: file_path,
960
+ source_file: file_path,
961
+ start_line: UNKNOWN_MIN_LINE,
962
+ end_line: UNKNOWN_MAX_LINE,
963
+ language_specifics: lang,
964
+ scopes: root[:children].values.map { |child| convert_node_to_scope(child) },
965
+ )
966
+ end
967
+
968
+ # Convert a single hash node to a Scope object (recursive).
969
+ # @param node [Hash] Tree node
970
+ # @return [Scope] Scope object
971
+ def convert_node_to_scope(node)
972
+ # Build method scopes from collected method entries
973
+ method_scopes = Core::Utils::EnumerableCompat.filter_map(node[:methods]) do |method_info|
974
+ build_instance_method_scope(node[:mod], method_info[:name], method_info[:method])
975
+ end
976
+
977
+ # Recurse into child scopes (nested modules/classes)
978
+ child_scopes = node[:children].values.map { |child| convert_node_to_scope(child) }
979
+
980
+ start_line, end_line = line_range_from_scopes(method_scopes)
981
+
982
+ # Extract symbols (constants, class variables) if we have the actual module object
983
+ symbols = node[:mod] ? extract_scope_symbols(node[:mod]) : []
984
+
985
+ # Build language specifics
986
+ lang = if node[:type] == "CLASS" && node[:mod]
987
+ build_class_language_specifics(node[:mod])
988
+ else
989
+ {}
990
+ end
991
+
992
+ Scope.new(
993
+ scope_type: node[:type],
994
+ name: node[:name],
995
+ source_file: node[:source_file],
996
+ start_line: start_line,
997
+ end_line: end_line,
998
+ language_specifics: lang,
999
+ scopes: method_scopes + child_scopes,
1000
+ symbols: symbols
1001
+ )
1002
+ end
1003
+
1004
+ # Build a METHOD scope from a pre-resolved instance method.
1005
+ # Used by extract_all path where methods are collected in Pass 1.
1006
+ # @param klass [Module] The class/module (for visibility lookup)
1007
+ # @param method_name [Symbol] Method name
1008
+ # @param method [UnboundMethod] The method object
1009
+ # @return [Scope, nil] Method scope or nil
1010
+ def build_instance_method_scope(klass, method_name, method)
1011
+ location = method.source_location
1012
+ return nil unless location
1013
+
1014
+ source_file, line = location
1015
+
1016
+ targetable_lines, end_line = extract_targetable_lines(method, line)
1017
+
1018
+ Scope.new(
1019
+ scope_type: "METHOD",
1020
+ name: method_name.to_s,
1021
+ source_file: source_file,
1022
+ start_line: line,
1023
+ end_line: end_line,
1024
+ targetable_lines: targetable_lines,
1025
+ language_specifics: {
1026
+ visibility: klass ? method_visibility(klass, method_name) : "public", # steep:ignore
1027
+ method_type: "instance",
1028
+ arity: method.arity,
1029
+ },
1030
+ symbols: extract_method_parameters(method)
1031
+ )
1032
+ rescue Exception => e # standard:disable Lint/RescueException
1033
+ Datadog::DI.reraise_if_fatal(e)
1034
+ klass_name = klass ? (safe_mod_name(klass) || "<unknown>") : "<unknown>"
1035
+ @logger.debug { "symdb: failed to build method scope #{klass_name}##{method_name}: #{e.class}: #{e.message}" }
1036
+ nil
1037
+ end
1038
+
1039
+ # Extract symbols (constants, class variables) from a module or class.
1040
+ # Class variables are emitted only for classes; constants for both.
1041
+ # @param mod [Module] The module or class
1042
+ # @return [Array<Symbol>] Symbols
1043
+ def extract_scope_symbols(mod)
1044
+ symbols = []
1045
+
1046
+ # Class variables (only for classes)
1047
+ if Class === mod
1048
+ MODULE_CLASS_VARIABLES.bind(mod).call(false).each do |var_name|
1049
+ symbols << Symbol.new(
1050
+ symbol_type: "STATIC_FIELD",
1051
+ name: var_name.to_s,
1052
+ line: UNKNOWN_MIN_LINE
1053
+ )
1054
+ end
1055
+ end
1056
+
1057
+ # Constants (excluding nested modules/classes).
1058
+ # Skip autoloaded constants to avoid triggering loading as a side effect.
1059
+ MODULE_CONSTANTS.bind(mod).call(false).each do |const_name|
1060
+ next if MODULE_AUTOLOAD_P.bind(mod).call(const_name)
1061
+ const_value = MODULE_CONST_GET.bind(mod).call(const_name)
1062
+ next if Module === const_value
1063
+
1064
+ symbols << Symbol.new(
1065
+ symbol_type: "STATIC_FIELD",
1066
+ name: const_name.to_s,
1067
+ line: UNKNOWN_MIN_LINE,
1068
+ type: safe_mod_name(KERNEL_CLASS.bind(const_value).call)
1069
+ )
1070
+ rescue NameError, LoadError, NoMethodError, TypeError => e # standard:disable Lint/ShadowedException
1071
+ # Expected: constant removed/undefined (NameError), autoload failure (LoadError),
1072
+ # or a value whose class cannot be read (NoMethodError/TypeError). Skipping one
1073
+ # constant here keeps the rest of the module's symbols. Logged separately from
1074
+ # unexpected errors so the latter stand out in triage. Lint/ShadowedException
1075
+ # disabled: these descend from StandardError, but Ruby's rescue-clause-order
1076
+ # semantics ensure the catch-all rescue below only catches exceptions not matched here.
1077
+ @logger.debug { "symdb: skipping module constant #{const_name}: #{e.class}: #{e.message}" }
1078
+ rescue Exception => e # standard:disable Lint/RescueException
1079
+ Datadog::DI.reraise_if_fatal(e)
1080
+ @logger.debug { "symdb: unexpected error reading module constant #{const_name}: #{e.class}: #{e.message}" }
1081
+ end
1082
+
1083
+ symbols
1084
+ rescue Exception => e # standard:disable Lint/RescueException
1085
+ Datadog::DI.reraise_if_fatal(e)
1086
+ mod_name = safe_mod_name(mod) || "<unknown>"
1087
+ @logger.debug { "symdb: failed to extract symbols from #{mod_name}: #{e.class}: #{e.message}" }
1088
+ []
1089
+ end
1090
+ end
1091
+ end
1092
+ end