datadog 2.17.0 → 2.37.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 (765) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +686 -1
  3. data/README.md +0 -1
  4. data/ext/LIBDATADOG_DEVELOPMENT.md +3 -0
  5. data/ext/datadog_profiling_native_extension/clock_id.h +9 -1
  6. data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +66 -0
  7. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +3 -2
  8. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +344 -126
  9. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +4 -4
  10. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +3 -2
  11. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +18 -4
  12. data/ext/datadog_profiling_native_extension/collectors_stack.c +314 -91
  13. data/ext/datadog_profiling_native_extension/collectors_stack.h +26 -3
  14. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +680 -352
  15. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +18 -5
  16. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
  17. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +65 -1
  18. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +40 -1
  19. data/ext/datadog_profiling_native_extension/encoded_profile.c +2 -1
  20. data/ext/datadog_profiling_native_extension/extconf.rb +48 -34
  21. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +4 -43
  22. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +15 -47
  23. data/ext/datadog_profiling_native_extension/heap_recorder.c +455 -430
  24. data/ext/datadog_profiling_native_extension/heap_recorder.h +16 -7
  25. data/ext/datadog_profiling_native_extension/http_transport.c +66 -68
  26. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +18 -15
  27. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -10
  28. data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
  29. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +0 -13
  30. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +73 -69
  31. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +10 -4
  32. data/ext/datadog_profiling_native_extension/profiling.c +65 -19
  33. data/ext/datadog_profiling_native_extension/ruby_helpers.c +64 -59
  34. data/ext/datadog_profiling_native_extension/ruby_helpers.h +20 -16
  35. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +32 -10
  36. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +2 -1
  37. data/ext/datadog_profiling_native_extension/stack_recorder.c +253 -131
  38. data/ext/datadog_profiling_native_extension/stack_recorder.h +3 -1
  39. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -0
  40. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +2 -1
  41. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +9 -4
  42. data/ext/libdatadog_api/crashtracker.c +16 -15
  43. data/ext/libdatadog_api/crashtracker_report_exception.c +126 -0
  44. data/ext/libdatadog_api/datadog_ruby_common.c +65 -1
  45. data/ext/libdatadog_api/datadog_ruby_common.h +40 -1
  46. data/ext/libdatadog_api/ddsketch.c +102 -0
  47. data/ext/libdatadog_api/di.c +203 -0
  48. data/ext/libdatadog_api/extconf.rb +21 -25
  49. data/ext/libdatadog_api/feature_flags.c +554 -0
  50. data/ext/libdatadog_api/feature_flags.h +5 -0
  51. data/ext/libdatadog_api/helpers.h +27 -0
  52. data/ext/libdatadog_api/init.c +13 -1
  53. data/ext/libdatadog_api/library_config.c +88 -37
  54. data/ext/libdatadog_api/library_config.h +6 -0
  55. data/ext/libdatadog_api/process_discovery.c +25 -24
  56. data/ext/libdatadog_extconf_helpers.rb +107 -14
  57. data/lib/datadog/ai_guard/api_client.rb +84 -0
  58. data/lib/datadog/ai_guard/autoload.rb +10 -0
  59. data/lib/datadog/ai_guard/component.rb +44 -0
  60. data/lib/datadog/ai_guard/configuration/ext.rb +17 -0
  61. data/lib/datadog/ai_guard/configuration.rb +115 -0
  62. data/lib/datadog/ai_guard/contrib/auto_instrument.rb +24 -0
  63. data/lib/datadog/ai_guard/contrib/integration.rb +37 -0
  64. data/lib/datadog/ai_guard/contrib/rack/integration.rb +42 -0
  65. data/lib/datadog/ai_guard/contrib/rack/patcher.rb +26 -0
  66. data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +97 -0
  67. data/lib/datadog/ai_guard/contrib/rails/integration.rb +41 -0
  68. data/lib/datadog/ai_guard/contrib/rails/patcher.rb +97 -0
  69. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +80 -0
  70. data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +41 -0
  71. data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +30 -0
  72. data/lib/datadog/ai_guard/evaluation/content_builder.rb +31 -0
  73. data/lib/datadog/ai_guard/evaluation/content_part.rb +36 -0
  74. data/lib/datadog/ai_guard/evaluation/message.rb +25 -0
  75. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +36 -0
  76. data/lib/datadog/ai_guard/evaluation/request.rb +86 -0
  77. data/lib/datadog/ai_guard/evaluation/result.rb +45 -0
  78. data/lib/datadog/ai_guard/evaluation/tool_call.rb +18 -0
  79. data/lib/datadog/ai_guard/evaluation.rb +108 -0
  80. data/lib/datadog/ai_guard/ext.rb +29 -0
  81. data/lib/datadog/ai_guard.rb +181 -0
  82. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
  83. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +66 -0
  84. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +36 -0
  85. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
  86. data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
  87. data/lib/datadog/appsec/api_security/route_extractor.rb +104 -0
  88. data/lib/datadog/appsec/api_security/sampler.rb +62 -0
  89. data/lib/datadog/appsec/api_security.rb +14 -0
  90. data/lib/datadog/appsec/assets/blocked.html +10 -1
  91. data/lib/datadog/appsec/assets/blocked.json +1 -1
  92. data/lib/datadog/appsec/assets/blocked.text +3 -1
  93. data/lib/datadog/appsec/assets/waf_rules/README.md +30 -36
  94. data/lib/datadog/appsec/assets/waf_rules/recommended.json +601 -74
  95. data/lib/datadog/appsec/assets/waf_rules/strict.json +48 -75
  96. data/lib/datadog/appsec/assets.rb +1 -1
  97. data/lib/datadog/appsec/autoload.rb +2 -2
  98. data/lib/datadog/appsec/component.rb +37 -64
  99. data/lib/datadog/appsec/compressed_json.rb +3 -3
  100. data/lib/datadog/appsec/configuration.rb +427 -1
  101. data/lib/datadog/appsec/context.rb +77 -16
  102. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +3 -1
  103. data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
  104. data/lib/datadog/appsec/contrib/active_record/patcher.rb +4 -1
  105. data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +75 -0
  106. data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +39 -0
  107. data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +30 -0
  108. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +144 -0
  109. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
  110. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +4 -2
  111. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +2 -1
  112. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +1 -1
  113. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  114. data/lib/datadog/appsec/contrib/excon/patcher.rb +3 -1
  115. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +152 -13
  116. data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
  117. data/lib/datadog/appsec/contrib/faraday/patcher.rb +1 -1
  118. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +138 -13
  119. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +74 -24
  120. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +4 -2
  121. data/lib/datadog/appsec/contrib/graphql/integration.rb +2 -1
  122. data/lib/datadog/appsec/contrib/rack/buffered_input.rb +83 -0
  123. data/lib/datadog/appsec/contrib/rack/ext.rb +1 -1
  124. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +47 -13
  125. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +40 -19
  126. data/lib/datadog/appsec/contrib/rack/input_peeker.rb +79 -0
  127. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  128. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +80 -62
  129. data/lib/datadog/appsec/contrib/rack/response_body.rb +36 -0
  130. data/lib/datadog/appsec/contrib/rails/gateway/request.rb +35 -1
  131. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +47 -5
  132. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  133. data/lib/datadog/appsec/contrib/rails/patcher.rb +52 -26
  134. data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +29 -0
  135. data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +33 -0
  136. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  137. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +3 -1
  138. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +167 -12
  139. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +63 -10
  140. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  141. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +11 -21
  142. data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +31 -0
  143. data/lib/datadog/appsec/counter_sampler.rb +25 -0
  144. data/lib/datadog/appsec/default_header_tags.rb +52 -0
  145. data/lib/datadog/appsec/event.rb +14 -47
  146. data/lib/datadog/appsec/ext.rb +3 -0
  147. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +17 -1
  148. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +2 -3
  149. data/lib/datadog/appsec/instrumentation/gateway.rb +2 -15
  150. data/lib/datadog/appsec/metrics/collector.rb +47 -5
  151. data/lib/datadog/appsec/metrics/exporter.rb +16 -3
  152. data/lib/datadog/appsec/metrics/telemetry.rb +21 -4
  153. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +47 -0
  154. data/lib/datadog/appsec/metrics.rb +5 -4
  155. data/lib/datadog/appsec/monitor/gateway/watcher.rb +8 -6
  156. data/lib/datadog/appsec/processor/rule_loader.rb +5 -6
  157. data/lib/datadog/appsec/remote.rb +51 -76
  158. data/lib/datadog/appsec/response.rb +18 -4
  159. data/lib/datadog/appsec/route_normalizer/rails_route_pattern.rb +176 -0
  160. data/lib/datadog/appsec/route_normalizer/route_pattern.rb +378 -0
  161. data/lib/datadog/appsec/route_normalizer/route_text.rb +57 -0
  162. data/lib/datadog/appsec/route_normalizer.rb +80 -0
  163. data/lib/datadog/appsec/security_engine/engine.rb +197 -0
  164. data/lib/datadog/appsec/security_engine/result.rb +45 -9
  165. data/lib/datadog/appsec/security_engine/runner.rb +44 -21
  166. data/lib/datadog/appsec/security_event.rb +5 -7
  167. data/lib/datadog/appsec/thread_safe_ref.rb +61 -0
  168. data/lib/datadog/appsec/trace_keeper.rb +36 -0
  169. data/lib/datadog/appsec/utils/hash_coercion.rb +23 -0
  170. data/lib/datadog/appsec/utils/http/body.rb +38 -0
  171. data/lib/datadog/appsec/utils/http/body_reader.rb +61 -0
  172. data/lib/datadog/appsec/utils/http/media_range.rb +2 -1
  173. data/lib/datadog/appsec/utils/http/media_type.rb +32 -26
  174. data/lib/datadog/appsec/utils/http/url_encoded.rb +52 -0
  175. data/lib/datadog/appsec.rb +10 -17
  176. data/lib/datadog/auto_instrument_base.rb +2 -1
  177. data/lib/datadog/core/configuration/agent_settings.rb +52 -0
  178. data/lib/datadog/core/configuration/agent_settings_resolver.rb +5 -47
  179. data/lib/datadog/core/configuration/base.rb +17 -5
  180. data/lib/datadog/core/configuration/components.rb +192 -20
  181. data/lib/datadog/core/configuration/components_state.rb +6 -1
  182. data/lib/datadog/core/configuration/config_helper.rb +109 -0
  183. data/lib/datadog/core/configuration/deprecations.rb +36 -0
  184. data/lib/datadog/core/configuration/ext.rb +0 -1
  185. data/lib/datadog/core/configuration/option.rb +95 -65
  186. data/lib/datadog/core/configuration/option_definition.rb +42 -23
  187. data/lib/datadog/core/configuration/options.rb +57 -18
  188. data/lib/datadog/core/configuration/settings.rb +160 -25
  189. data/lib/datadog/core/configuration/stable_config.rb +11 -2
  190. data/lib/datadog/core/configuration/supported_configurations.rb +413 -0
  191. data/lib/datadog/core/configuration.rb +4 -4
  192. data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
  193. data/lib/datadog/core/contrib/rails/utils.rb +7 -3
  194. data/lib/datadog/core/crashtracking/component.rb +73 -21
  195. data/lib/datadog/core/crashtracking/tag_builder.rb +9 -21
  196. data/lib/datadog/core/ddsketch.rb +19 -0
  197. data/lib/datadog/core/deprecations.rb +2 -2
  198. data/lib/datadog/core/diagnostics/environment_logger.rb +3 -1
  199. data/lib/datadog/core/environment/agent_info.rb +65 -1
  200. data/lib/datadog/core/environment/cgroup.rb +52 -25
  201. data/lib/datadog/core/environment/container.rb +140 -46
  202. data/lib/datadog/core/environment/ext.rb +13 -2
  203. data/lib/datadog/core/environment/git.rb +2 -2
  204. data/lib/datadog/core/environment/identity.rb +40 -4
  205. data/lib/datadog/core/environment/process.rb +122 -0
  206. data/lib/datadog/core/environment/socket.rb +13 -0
  207. data/lib/datadog/core/environment/variable_helpers.rb +3 -3
  208. data/lib/datadog/core/environment/yjit.rb +2 -1
  209. data/lib/datadog/core/error.rb +6 -6
  210. data/lib/datadog/core/evp.rb +11 -0
  211. data/lib/datadog/core/feature_flags.rb +61 -0
  212. data/lib/datadog/core/knuth_sampler.rb +57 -0
  213. data/lib/datadog/core/logger.rb +1 -1
  214. data/lib/datadog/core/metrics/client.rb +7 -7
  215. data/lib/datadog/core/metrics/logging.rb +1 -1
  216. data/lib/datadog/core/pin.rb +8 -8
  217. data/lib/datadog/core/process_discovery/tracer_memfd.rb +13 -0
  218. data/lib/datadog/core/process_discovery.rb +51 -21
  219. data/lib/datadog/core/rate_limiter.rb +11 -1
  220. data/lib/datadog/core/remote/client/capabilities.rb +49 -6
  221. data/lib/datadog/core/remote/client.rb +15 -7
  222. data/lib/datadog/core/remote/component.rb +64 -36
  223. data/lib/datadog/core/remote/configuration/content.rb +15 -2
  224. data/lib/datadog/core/remote/configuration/digest.rb +14 -7
  225. data/lib/datadog/core/remote/configuration/repository.rb +13 -1
  226. data/lib/datadog/core/remote/configuration/target.rb +13 -6
  227. data/lib/datadog/core/remote/transport/config.rb +9 -36
  228. data/lib/datadog/core/remote/transport/http/config.rb +15 -55
  229. data/lib/datadog/core/remote/transport/http/negotiation.rb +14 -44
  230. data/lib/datadog/core/remote/transport/http.rb +15 -24
  231. data/lib/datadog/core/remote/transport/negotiation.rb +8 -33
  232. data/lib/datadog/core/remote/worker.rb +25 -37
  233. data/lib/datadog/core/runtime/ext.rb +0 -1
  234. data/lib/datadog/core/runtime/metrics.rb +11 -2
  235. data/lib/datadog/core/semaphore.rb +1 -4
  236. data/lib/datadog/core/tag_builder.rb +52 -0
  237. data/lib/datadog/core/tag_normalizer.rb +84 -0
  238. data/lib/datadog/core/telemetry/component.rb +65 -17
  239. data/lib/datadog/core/telemetry/emitter.rb +6 -6
  240. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +3 -3
  241. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
  242. data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
  243. data/lib/datadog/core/telemetry/event/app_started.rb +203 -89
  244. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
  245. data/lib/datadog/core/telemetry/event.rb +2 -7
  246. data/lib/datadog/core/telemetry/ext.rb +1 -0
  247. data/lib/datadog/core/telemetry/logger.rb +5 -2
  248. data/lib/datadog/core/telemetry/logging.rb +22 -4
  249. data/lib/datadog/core/telemetry/metrics_manager.rb +9 -0
  250. data/lib/datadog/core/telemetry/request.rb +17 -5
  251. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +8 -34
  252. data/lib/datadog/core/telemetry/transport/http.rb +21 -16
  253. data/lib/datadog/core/telemetry/transport/telemetry.rb +8 -17
  254. data/lib/datadog/core/telemetry/worker.rb +108 -32
  255. data/lib/datadog/core/transport/ext.rb +3 -0
  256. data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
  257. data/lib/datadog/core/transport/http/api/endpoint.rb +9 -4
  258. data/lib/datadog/core/transport/http/api/instance.rb +4 -21
  259. data/lib/datadog/core/transport/http/builder.rb +11 -7
  260. data/lib/datadog/core/transport/http/client.rb +80 -0
  261. data/lib/datadog/core/transport/http/env.rb +8 -0
  262. data/lib/datadog/core/transport/http/response.rb +4 -0
  263. data/lib/datadog/core/transport/http.rb +24 -19
  264. data/lib/datadog/core/transport/parcel.rb +61 -9
  265. data/lib/datadog/core/transport/response.rb +16 -2
  266. data/lib/datadog/core/transport/transport.rb +90 -0
  267. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +1 -1
  268. data/lib/datadog/core/utils/{base64.rb → base64_codec.rb} +4 -3
  269. data/lib/datadog/core/utils/enumerable_compat.rb +29 -0
  270. data/lib/datadog/core/utils/fnv.rb +26 -0
  271. data/lib/datadog/core/utils/forking.rb +3 -1
  272. data/lib/datadog/core/utils/hash.rb +0 -23
  273. data/lib/datadog/{appsec/api_security → core/utils}/lru_cache.rb +10 -14
  274. data/lib/datadog/core/utils/network.rb +22 -1
  275. data/lib/datadog/core/utils/only_once.rb +1 -1
  276. data/lib/datadog/core/utils/only_once_successful.rb +8 -2
  277. data/lib/datadog/core/utils/safe_dup.rb +2 -2
  278. data/lib/datadog/core/utils/sequence.rb +2 -0
  279. data/lib/datadog/core/utils/spawn_monkey_patch.rb +68 -0
  280. data/lib/datadog/core/utils/time.rb +1 -1
  281. data/lib/datadog/core/utils.rb +10 -1
  282. data/lib/datadog/core/workers/async.rb +11 -2
  283. data/lib/datadog/core/workers/interval_loop.rb +51 -3
  284. data/lib/datadog/core/workers/polling.rb +2 -0
  285. data/lib/datadog/core/workers/queue.rb +96 -1
  286. data/lib/datadog/core/workers/runtime_metrics.rb +9 -1
  287. data/lib/datadog/core.rb +11 -2
  288. data/lib/datadog/data_streams/configuration.rb +50 -0
  289. data/lib/datadog/data_streams/ext.rb +11 -0
  290. data/lib/datadog/data_streams/extensions.rb +16 -0
  291. data/lib/datadog/data_streams/pathway_context.rb +169 -0
  292. data/lib/datadog/data_streams/processor.rb +511 -0
  293. data/lib/datadog/data_streams/transport/http/stats.rb +58 -0
  294. data/lib/datadog/data_streams/transport/http.rb +36 -0
  295. data/lib/datadog/data_streams/transport/stats.rb +39 -0
  296. data/lib/datadog/data_streams.rb +100 -0
  297. data/lib/datadog/di/base.rb +15 -7
  298. data/lib/datadog/di/boot.rb +11 -1
  299. data/lib/datadog/di/code_tracker.rb +217 -15
  300. data/lib/datadog/di/component.rb +143 -48
  301. data/lib/datadog/di/configuration.rb +235 -2
  302. data/lib/datadog/di/context.rb +76 -0
  303. data/lib/datadog/di/contrib/active_record.rb +34 -5
  304. data/lib/datadog/di/el/compiler.rb +168 -0
  305. data/lib/datadog/di/el/evaluator.rb +159 -0
  306. data/lib/datadog/di/el/expression.rb +42 -0
  307. data/lib/datadog/di/el.rb +5 -0
  308. data/lib/datadog/di/error.rb +44 -0
  309. data/lib/datadog/di/fatal_exceptions.rb +26 -0
  310. data/lib/datadog/di/instrumenter.rb +620 -132
  311. data/lib/datadog/di/logger.rb +2 -2
  312. data/lib/datadog/di/probe.rb +78 -15
  313. data/lib/datadog/di/probe_builder.rb +42 -3
  314. data/lib/datadog/di/probe_file_loader/railtie.rb +15 -0
  315. data/lib/datadog/di/probe_file_loader.rb +87 -0
  316. data/lib/datadog/di/probe_manager.rb +195 -100
  317. data/lib/datadog/di/probe_notification_builder.rb +285 -100
  318. data/lib/datadog/di/probe_notifier_worker.rb +120 -36
  319. data/lib/datadog/di/probe_repository.rb +198 -0
  320. data/lib/datadog/di/proc_responder.rb +36 -0
  321. data/lib/datadog/di/redactor.rb +24 -2
  322. data/lib/datadog/di/remote.rb +258 -95
  323. data/lib/datadog/di/serializer.rb +297 -20
  324. data/lib/datadog/di/transport/diagnostics.rb +12 -42
  325. data/lib/datadog/di/transport/http/diagnostics.rb +4 -34
  326. data/lib/datadog/di/transport/http/input.rb +12 -34
  327. data/lib/datadog/di/transport/http.rb +43 -19
  328. data/lib/datadog/di/transport/input.rb +121 -39
  329. data/lib/datadog/di/utils.rb +42 -14
  330. data/lib/datadog/di.rb +203 -10
  331. data/lib/datadog/error_tracking/collector.rb +2 -1
  332. data/lib/datadog/error_tracking/component.rb +2 -2
  333. data/lib/datadog/error_tracking/configuration.rb +55 -2
  334. data/lib/datadog/error_tracking/filters.rb +2 -2
  335. data/lib/datadog/kit/appsec/events/v2.rb +253 -0
  336. data/lib/datadog/kit/appsec/events.rb +11 -10
  337. data/lib/datadog/kit/enable_core_dumps.rb +1 -1
  338. data/lib/datadog/kit/identity.rb +17 -11
  339. data/lib/datadog/kit/tracing/method_tracer.rb +135 -0
  340. data/lib/datadog/open_feature/component.rb +100 -0
  341. data/lib/datadog/open_feature/configuration.rb +37 -0
  342. data/lib/datadog/open_feature/evaluation_engine.rb +70 -0
  343. data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
  344. data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
  345. data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
  346. data/lib/datadog/open_feature/exposures/event.rb +60 -0
  347. data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
  348. data/lib/datadog/open_feature/exposures/worker.rb +116 -0
  349. data/lib/datadog/open_feature/ext.rb +16 -0
  350. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +286 -0
  351. data/lib/datadog/open_feature/flag_evaluation/writer.rb +433 -0
  352. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +101 -0
  353. data/lib/datadog/open_feature/hooks/flag_eval_metrics_hook.rb +49 -0
  354. data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
  355. data/lib/datadog/open_feature/native_evaluator.rb +60 -0
  356. data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
  357. data/lib/datadog/open_feature/provider.rb +191 -0
  358. data/lib/datadog/open_feature/remote.rb +67 -0
  359. data/lib/datadog/open_feature/resolution_details.rb +35 -0
  360. data/lib/datadog/open_feature/transport.rb +121 -0
  361. data/lib/datadog/open_feature.rb +19 -0
  362. data/lib/datadog/opentelemetry/api/baggage.rb +3 -3
  363. data/lib/datadog/opentelemetry/api/context.rb +10 -9
  364. data/lib/datadog/opentelemetry/configuration/settings.rb +226 -0
  365. data/lib/datadog/opentelemetry/ext.rb +9 -0
  366. data/lib/datadog/opentelemetry/logs.rb +98 -0
  367. data/lib/datadog/opentelemetry/metrics.rb +90 -0
  368. data/lib/datadog/opentelemetry/sdk/configurator.rb +66 -2
  369. data/lib/datadog/opentelemetry/sdk/id_generator.rb +16 -10
  370. data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +30 -0
  371. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +28 -0
  372. data/lib/datadog/opentelemetry/sdk/propagator.rb +13 -7
  373. data/lib/datadog/opentelemetry/sdk/span_processor.rb +12 -9
  374. data/lib/datadog/opentelemetry/sdk/trace/span.rb +14 -10
  375. data/lib/datadog/opentelemetry/sdk.rb +19 -0
  376. data/lib/datadog/opentelemetry/signal_configuration.rb +53 -0
  377. data/lib/datadog/opentelemetry/trace.rb +4 -4
  378. data/lib/datadog/opentelemetry.rb +4 -0
  379. data/lib/datadog/profiling/collectors/code_provenance.rb +83 -15
  380. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +52 -3
  381. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +13 -4
  382. data/lib/datadog/profiling/collectors/info.rb +59 -4
  383. data/lib/datadog/profiling/collectors/thread_context.rb +17 -5
  384. data/lib/datadog/profiling/component.rb +73 -49
  385. data/lib/datadog/profiling/exporter.rb +48 -13
  386. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +24 -5
  387. data/lib/datadog/profiling/ext/exec_monkey_patch.rb +32 -0
  388. data/lib/datadog/profiling/ext.rb +2 -15
  389. data/lib/datadog/profiling/flush.rb +23 -11
  390. data/lib/datadog/profiling/http_transport.rb +24 -11
  391. data/lib/datadog/profiling/load_native_extension.rb +2 -2
  392. data/lib/datadog/profiling/profiler.rb +31 -12
  393. data/lib/datadog/profiling/scheduler.rb +12 -10
  394. data/lib/datadog/profiling/sequence_tracker.rb +44 -0
  395. data/lib/datadog/profiling/stack_recorder.rb +5 -13
  396. data/lib/datadog/profiling/tag_builder.rb +42 -38
  397. data/lib/datadog/profiling/tasks/exec.rb +10 -5
  398. data/lib/datadog/profiling/tasks/help.rb +1 -0
  399. data/lib/datadog/profiling/tasks/setup.rb +4 -2
  400. data/lib/datadog/profiling.rb +8 -11
  401. data/lib/datadog/ruby_version.rb +25 -0
  402. data/lib/datadog/single_step_instrument.rb +10 -1
  403. data/lib/datadog/symbol_database/component.rb +734 -0
  404. data/lib/datadog/symbol_database/configuration.rb +73 -0
  405. data/lib/datadog/symbol_database/extensions.rb +19 -0
  406. data/lib/datadog/symbol_database/extractor.rb +1110 -0
  407. data/lib/datadog/symbol_database/file_hash.rb +48 -0
  408. data/lib/datadog/symbol_database/logger.rb +43 -0
  409. data/lib/datadog/symbol_database/remote.rb +180 -0
  410. data/lib/datadog/symbol_database/scope.rb +102 -0
  411. data/lib/datadog/symbol_database/scope_batcher.rb +292 -0
  412. data/lib/datadog/symbol_database/service_version.rb +66 -0
  413. data/lib/datadog/symbol_database/symbol.rb +69 -0
  414. data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
  415. data/lib/datadog/symbol_database/transport/http.rb +45 -0
  416. data/lib/datadog/symbol_database/transport.rb +54 -0
  417. data/lib/datadog/symbol_database/uploader.rb +230 -0
  418. data/lib/datadog/symbol_database.rb +71 -0
  419. data/lib/datadog/tracing/analytics.rb +1 -1
  420. data/lib/datadog/tracing/buffer.rb +10 -10
  421. data/lib/datadog/tracing/component.rb +17 -17
  422. data/lib/datadog/tracing/configuration/dynamic.rb +6 -8
  423. data/lib/datadog/tracing/configuration/ext.rb +25 -5
  424. data/lib/datadog/tracing/configuration/settings.rb +125 -11
  425. data/lib/datadog/tracing/context.rb +2 -2
  426. data/lib/datadog/tracing/contrib/action_cable/event.rb +1 -1
  427. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +4 -1
  428. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +4 -1
  429. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +4 -1
  430. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +4 -1
  431. data/lib/datadog/tracing/contrib/action_cable/integration.rb +1 -1
  432. data/lib/datadog/tracing/contrib/action_mailer/event.rb +4 -1
  433. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +1 -1
  434. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +29 -11
  435. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +47 -12
  436. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +3 -1
  437. data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
  438. data/lib/datadog/tracing/contrib/action_pack/integration.rb +1 -1
  439. data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -2
  440. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +4 -1
  441. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +6 -3
  442. data/lib/datadog/tracing/contrib/active_job/event.rb +8 -8
  443. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +6 -3
  444. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +6 -3
  445. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +6 -3
  446. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +6 -3
  447. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +6 -3
  448. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +6 -3
  449. data/lib/datadog/tracing/contrib/active_job/integration.rb +1 -1
  450. data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
  451. data/lib/datadog/tracing/contrib/active_job/patcher.rb +5 -1
  452. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +2 -2
  453. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +4 -4
  454. data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +1 -2
  455. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +3 -3
  456. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +2 -2
  457. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +7 -10
  458. data/lib/datadog/tracing/contrib/active_record/integration.rb +1 -1
  459. data/lib/datadog/tracing/contrib/active_record/utils.rb +16 -16
  460. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +15 -12
  461. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +1 -4
  462. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +13 -0
  463. data/lib/datadog/tracing/contrib/active_support/integration.rb +1 -1
  464. data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +2 -1
  465. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +8 -10
  466. data/lib/datadog/tracing/contrib/aws/ext.rb +1 -1
  467. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +8 -10
  468. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +3 -1
  469. data/lib/datadog/tracing/contrib/aws/patcher.rb +5 -1
  470. data/lib/datadog/tracing/contrib/aws/service/base.rb +2 -1
  471. data/lib/datadog/tracing/contrib/aws/service/dynamodb.rb +1 -1
  472. data/lib/datadog/tracing/contrib/aws/service/eventbridge.rb +1 -1
  473. data/lib/datadog/tracing/contrib/aws/service/kinesis.rb +1 -1
  474. data/lib/datadog/tracing/contrib/aws/service/s3.rb +1 -1
  475. data/lib/datadog/tracing/contrib/aws/service/sns.rb +1 -1
  476. data/lib/datadog/tracing/contrib/aws/service/sqs.rb +1 -1
  477. data/lib/datadog/tracing/contrib/aws/service/states.rb +1 -1
  478. data/lib/datadog/tracing/contrib/aws/services.rb +7 -7
  479. data/lib/datadog/tracing/contrib/component.rb +3 -3
  480. data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +1 -1
  481. data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -1
  482. data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +1 -1
  483. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +1 -1
  484. data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +1 -1
  485. data/lib/datadog/tracing/contrib/configurable.rb +22 -7
  486. data/lib/datadog/tracing/contrib/configuration/resolver.rb +14 -4
  487. data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +4 -4
  488. data/lib/datadog/tracing/contrib/dalli/ext.rb +3 -2
  489. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +1 -5
  490. data/lib/datadog/tracing/contrib/dalli/integration.rb +5 -2
  491. data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -1
  492. data/lib/datadog/tracing/contrib/delayed_job/integration.rb +1 -1
  493. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +2 -0
  494. data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +1 -0
  495. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +3 -2
  496. data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +4 -4
  497. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +47 -53
  498. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +7 -7
  499. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +5 -1
  500. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +7 -8
  501. data/lib/datadog/tracing/contrib/ethon/ext.rb +4 -2
  502. data/lib/datadog/tracing/contrib/ethon/integration.rb +1 -1
  503. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +1 -8
  504. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +16 -5
  505. data/lib/datadog/tracing/contrib/excon/ext.rb +4 -2
  506. data/lib/datadog/tracing/contrib/excon/integration.rb +1 -1
  507. data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -9
  508. data/lib/datadog/tracing/contrib/ext.rb +6 -4
  509. data/lib/datadog/tracing/contrib/extensions.rb +28 -11
  510. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +16 -9
  511. data/lib/datadog/tracing/contrib/faraday/ext.rb +4 -2
  512. data/lib/datadog/tracing/contrib/faraday/integration.rb +1 -1
  513. data/lib/datadog/tracing/contrib/faraday/middleware.rb +7 -9
  514. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +7 -3
  515. data/lib/datadog/tracing/contrib/grape/endpoint.rb +18 -15
  516. data/lib/datadog/tracing/contrib/grape/instrumentation.rb +13 -8
  517. data/lib/datadog/tracing/contrib/grape/integration.rb +1 -1
  518. data/lib/datadog/tracing/contrib/grape/patcher.rb +6 -1
  519. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +7 -0
  520. data/lib/datadog/tracing/contrib/graphql/ext.rb +1 -0
  521. data/lib/datadog/tracing/contrib/graphql/integration.rb +1 -1
  522. data/lib/datadog/tracing/contrib/graphql/patcher.rb +2 -2
  523. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +105 -63
  524. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +5 -2
  525. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +11 -15
  526. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +6 -10
  527. data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +1 -1
  528. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +2 -0
  529. data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
  530. data/lib/datadog/tracing/contrib/grpc/integration.rb +1 -1
  531. data/lib/datadog/tracing/contrib/grpc.rb +1 -0
  532. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +1 -0
  533. data/lib/datadog/tracing/contrib/hanami/ext.rb +2 -2
  534. data/lib/datadog/tracing/contrib/hanami/integration.rb +1 -1
  535. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +2 -1
  536. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +10 -11
  537. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +16 -5
  538. data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +4 -4
  539. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +2 -0
  540. data/lib/datadog/tracing/contrib/http/ext.rb +4 -2
  541. data/lib/datadog/tracing/contrib/http/instrumentation.rb +9 -13
  542. data/lib/datadog/tracing/contrib/http/integration.rb +0 -2
  543. data/lib/datadog/tracing/contrib/http.rb +1 -0
  544. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +16 -5
  545. data/lib/datadog/tracing/contrib/httpclient/ext.rb +4 -2
  546. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +10 -10
  547. data/lib/datadog/tracing/contrib/httpclient/integration.rb +1 -1
  548. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +16 -5
  549. data/lib/datadog/tracing/contrib/httprb/ext.rb +4 -2
  550. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +8 -12
  551. data/lib/datadog/tracing/contrib/httprb/integration.rb +1 -1
  552. data/lib/datadog/tracing/contrib/kafka/event.rb +2 -1
  553. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +1 -1
  554. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +1 -1
  555. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +1 -1
  556. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +1 -1
  557. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +1 -1
  558. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +1 -1
  559. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +1 -1
  560. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +1 -1
  561. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +1 -1
  562. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
  563. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
  564. data/lib/datadog/tracing/contrib/kafka/integration.rb +1 -1
  565. data/lib/datadog/tracing/contrib/kafka/patcher.rb +14 -0
  566. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +5 -1
  567. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
  568. data/lib/datadog/tracing/contrib/karafka/ext.rb +1 -0
  569. data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
  570. data/lib/datadog/tracing/contrib/karafka/monitor.rb +24 -13
  571. data/lib/datadog/tracing/contrib/karafka/patcher.rb +39 -8
  572. data/lib/datadog/tracing/contrib/karafka.rb +1 -0
  573. data/lib/datadog/tracing/contrib/lograge/instrumentation.rb +1 -1
  574. data/lib/datadog/tracing/contrib/lograge/integration.rb +1 -1
  575. data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
  576. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +1 -1
  577. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -1
  578. data/lib/datadog/tracing/contrib/mongodb/integration.rb +1 -1
  579. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +6 -6
  580. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +11 -14
  581. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +6 -0
  582. data/lib/datadog/tracing/contrib/mysql2/ext.rb +1 -1
  583. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +19 -12
  584. data/lib/datadog/tracing/contrib/mysql2/integration.rb +1 -1
  585. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +1 -1
  586. data/lib/datadog/tracing/contrib/opensearch/ext.rb +3 -2
  587. data/lib/datadog/tracing/contrib/opensearch/integration.rb +1 -2
  588. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +64 -70
  589. data/lib/datadog/tracing/contrib/opensearch/quantize.rb +7 -7
  590. data/lib/datadog/tracing/contrib/patcher.rb +7 -9
  591. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +6 -0
  592. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +3 -6
  593. data/lib/datadog/tracing/contrib/pg/integration.rb +1 -1
  594. data/lib/datadog/tracing/contrib/presto/ext.rb +1 -1
  595. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +9 -11
  596. data/lib/datadog/tracing/contrib/presto/integration.rb +1 -1
  597. data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +1 -1
  598. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +13 -0
  599. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +6 -2
  600. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +25 -1
  601. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +5 -2
  602. data/lib/datadog/tracing/contrib/que/ext.rb +1 -0
  603. data/lib/datadog/tracing/contrib/que/integration.rb +1 -1
  604. data/lib/datadog/tracing/contrib/que/tracer.rb +1 -0
  605. data/lib/datadog/tracing/contrib/racecar/event.rb +2 -6
  606. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +2 -2
  607. data/lib/datadog/tracing/contrib/racecar/events/consume.rb +1 -1
  608. data/lib/datadog/tracing/contrib/racecar/events/message.rb +2 -2
  609. data/lib/datadog/tracing/contrib/racecar/integration.rb +1 -1
  610. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +11 -1
  611. data/lib/datadog/tracing/contrib/rack/ext.rb +28 -0
  612. data/lib/datadog/tracing/contrib/rack/header_collection.rb +1 -1
  613. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +55 -32
  614. data/lib/datadog/tracing/contrib/rack/integration.rb +1 -1
  615. data/lib/datadog/tracing/contrib/rack/middlewares.rb +83 -44
  616. data/lib/datadog/tracing/contrib/rack/patcher.rb +2 -2
  617. data/lib/datadog/tracing/contrib/rack/request_queue.rb +4 -3
  618. data/lib/datadog/tracing/contrib/rack/route_inference.rb +67 -0
  619. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +126 -2
  620. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +6 -3
  621. data/lib/datadog/tracing/contrib/rails/ext.rb +3 -1
  622. data/lib/datadog/tracing/contrib/rails/integration.rb +2 -2
  623. data/lib/datadog/tracing/contrib/rails/log_injection.rb +2 -2
  624. data/lib/datadog/tracing/contrib/rails/middlewares.rb +3 -3
  625. data/lib/datadog/tracing/contrib/rails/patcher.rb +4 -2
  626. data/lib/datadog/tracing/contrib/rails/runner.rb +64 -40
  627. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +10 -8
  628. data/lib/datadog/tracing/contrib/rake/integration.rb +1 -1
  629. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +2 -2
  630. data/lib/datadog/tracing/contrib/redis/ext.rb +3 -2
  631. data/lib/datadog/tracing/contrib/redis/integration.rb +2 -2
  632. data/lib/datadog/tracing/contrib/redis/patcher.rb +4 -4
  633. data/lib/datadog/tracing/contrib/redis/quantize.rb +2 -2
  634. data/lib/datadog/tracing/contrib/redis/tags.rb +2 -7
  635. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +6 -4
  636. data/lib/datadog/tracing/contrib/registerable.rb +11 -0
  637. data/lib/datadog/tracing/contrib/registry.rb +1 -1
  638. data/lib/datadog/tracing/contrib/resque/integration.rb +1 -1
  639. data/lib/datadog/tracing/contrib/resque/resque_job.rb +2 -1
  640. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +5 -2
  641. data/lib/datadog/tracing/contrib/rest_client/ext.rb +4 -2
  642. data/lib/datadog/tracing/contrib/rest_client/integration.rb +1 -1
  643. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +8 -9
  644. data/lib/datadog/tracing/contrib/roda/ext.rb +1 -0
  645. data/lib/datadog/tracing/contrib/roda/instrumentation.rb +8 -3
  646. data/lib/datadog/tracing/contrib/roda/integration.rb +1 -1
  647. data/lib/datadog/tracing/contrib/semantic_logger/instrumentation.rb +1 -1
  648. data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +1 -1
  649. data/lib/datadog/tracing/contrib/sequel/database.rb +6 -5
  650. data/lib/datadog/tracing/contrib/sequel/dataset.rb +2 -1
  651. data/lib/datadog/tracing/contrib/sequel/integration.rb +1 -1
  652. data/lib/datadog/tracing/contrib/sequel/utils.rb +1 -6
  653. data/lib/datadog/tracing/contrib/shoryuken/integration.rb +1 -1
  654. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +1 -0
  655. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +1 -0
  656. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +5 -1
  657. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +2 -0
  658. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +2 -0
  659. data/lib/datadog/tracing/contrib/sidekiq/integration.rb +1 -1
  660. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +2 -0
  661. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +1 -0
  662. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/redis_info.rb +1 -0
  663. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +2 -0
  664. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/stop.rb +1 -0
  665. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +8 -4
  666. data/lib/datadog/tracing/contrib/sidekiq/utils.rb +1 -1
  667. data/lib/datadog/tracing/contrib/sidekiq.rb +1 -0
  668. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +5 -1
  669. data/lib/datadog/tracing/contrib/sinatra/ext.rb +1 -0
  670. data/lib/datadog/tracing/contrib/sinatra/integration.rb +1 -1
  671. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +1 -0
  672. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +40 -39
  673. data/lib/datadog/tracing/contrib/sneakers/integration.rb +15 -4
  674. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +1 -0
  675. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +1 -1
  676. data/lib/datadog/tracing/contrib/status_range_matcher.rb +13 -1
  677. data/lib/datadog/tracing/contrib/stripe/integration.rb +1 -1
  678. data/lib/datadog/tracing/contrib/stripe/request.rb +2 -2
  679. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +1 -0
  680. data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +1 -1
  681. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +6 -0
  682. data/lib/datadog/tracing/contrib/trilogy/ext.rb +1 -1
  683. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -6
  684. data/lib/datadog/tracing/contrib/trilogy/integration.rb +1 -1
  685. data/lib/datadog/tracing/contrib/utils/quantization/{hash.rb → hash_formatter.rb} +15 -13
  686. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +6 -6
  687. data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +31 -0
  688. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +50 -0
  689. data/lib/datadog/tracing/contrib/waterdrop/ext.rb +18 -0
  690. data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
  691. data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
  692. data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +49 -0
  693. data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
  694. data/lib/datadog/tracing/contrib/waterdrop.rb +42 -0
  695. data/lib/datadog/tracing/contrib.rb +9 -0
  696. data/lib/datadog/tracing/diagnostics/environment_logger.rb +12 -4
  697. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  698. data/lib/datadog/tracing/distributed/baggage.rb +133 -12
  699. data/lib/datadog/tracing/distributed/datadog.rb +17 -16
  700. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +11 -26
  701. data/lib/datadog/tracing/distributed/helpers.rb +1 -1
  702. data/lib/datadog/tracing/distributed/none.rb +4 -2
  703. data/lib/datadog/tracing/distributed/propagation.rb +39 -4
  704. data/lib/datadog/tracing/distributed/propagation_policy.rb +1 -1
  705. data/lib/datadog/tracing/distributed/trace_context.rb +107 -78
  706. data/lib/datadog/tracing/event.rb +5 -7
  707. data/lib/datadog/tracing/ext.rb +9 -0
  708. data/lib/datadog/tracing/flush.rb +1 -1
  709. data/lib/datadog/tracing/metadata/analytics.rb +1 -1
  710. data/lib/datadog/tracing/metadata/ext.rb +23 -1
  711. data/lib/datadog/tracing/metadata/tagging.rb +6 -6
  712. data/lib/datadog/tracing/pipeline/span_filter.rb +3 -1
  713. data/lib/datadog/tracing/pipeline/span_processor.rb +3 -1
  714. data/lib/datadog/tracing/pipeline.rb +2 -2
  715. data/lib/datadog/tracing/remote.rb +36 -13
  716. data/lib/datadog/tracing/sampling/ext.rb +2 -2
  717. data/lib/datadog/tracing/sampling/priority_sampler.rb +16 -1
  718. data/lib/datadog/tracing/sampling/rate_sampler.rb +8 -19
  719. data/lib/datadog/tracing/sampling/rule.rb +1 -1
  720. data/lib/datadog/tracing/sampling/rule_sampler.rb +77 -48
  721. data/lib/datadog/tracing/sampling/span/rule_parser.rb +3 -3
  722. data/lib/datadog/tracing/sampling/span/sampler.rb +0 -7
  723. data/lib/datadog/tracing/span.rb +2 -2
  724. data/lib/datadog/tracing/span_event.rb +12 -12
  725. data/lib/datadog/tracing/span_link.rb +12 -12
  726. data/lib/datadog/tracing/span_operation.rb +63 -19
  727. data/lib/datadog/tracing/sync_writer.rb +1 -2
  728. data/lib/datadog/tracing/trace_digest.rb +28 -23
  729. data/lib/datadog/tracing/trace_operation.rb +209 -98
  730. data/lib/datadog/tracing/trace_segment.rb +2 -2
  731. data/lib/datadog/tracing/tracer.rb +113 -52
  732. data/lib/datadog/tracing/transport/http/client.rb +12 -26
  733. data/lib/datadog/tracing/transport/http/traces.rb +4 -52
  734. data/lib/datadog/tracing/transport/http.rb +15 -9
  735. data/lib/datadog/tracing/transport/io/client.rb +11 -14
  736. data/lib/datadog/tracing/transport/io/traces.rb +28 -34
  737. data/lib/datadog/tracing/transport/statistics.rb +1 -1
  738. data/lib/datadog/tracing/transport/trace_formatter.rb +22 -0
  739. data/lib/datadog/tracing/transport/traces.rb +14 -82
  740. data/lib/datadog/tracing/workers.rb +4 -3
  741. data/lib/datadog/tracing/writer.rb +1 -1
  742. data/lib/datadog/tracing.rb +2 -2
  743. data/lib/datadog/version.rb +2 -2
  744. data/lib/datadog.rb +14 -0
  745. metadata +201 -40
  746. data/ext/datadog_profiling_native_extension/clock_id_noop.c +0 -21
  747. data/ext/libdatadog_api/macos_development.md +0 -26
  748. data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -321
  749. data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -1023
  750. data/lib/datadog/appsec/configuration/settings.rb +0 -342
  751. data/lib/datadog/appsec/contrib/rails/ext.rb +0 -13
  752. data/lib/datadog/appsec/processor/rule_merger.rb +0 -171
  753. data/lib/datadog/appsec/processor.rb +0 -107
  754. data/lib/datadog/core/remote/transport/http/api.rb +0 -53
  755. data/lib/datadog/core/remote/transport/http/client.rb +0 -49
  756. data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
  757. data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
  758. data/lib/datadog/core/transport/http/api/spec.rb +0 -36
  759. data/lib/datadog/di/configuration/settings.rb +0 -212
  760. data/lib/datadog/di/transport/http/api.rb +0 -42
  761. data/lib/datadog/di/transport/http/client.rb +0 -47
  762. data/lib/datadog/error_tracking/configuration/settings.rb +0 -63
  763. data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
  764. data/lib/datadog/tracing/transport/http/api.rb +0 -44
  765. data/lib/datadog/tracing/workers/trace_writer.rb +0 -199
@@ -0,0 +1,734 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../symbol_database'
4
+ require_relative 'extractor'
5
+ require_relative 'logger'
6
+ require_relative 'scope_batcher'
7
+ require_relative 'uploader'
8
+ require_relative '../core/utils/time'
9
+ require_relative '../di/fatal_exceptions'
10
+
11
+ module Datadog
12
+ module SymbolDatabase
13
+ # Main coordinator for symbol database upload functionality.
14
+ #
15
+ # Responsibilities:
16
+ # - Lifecycle management: Initialization, shutdown, upload triggering
17
+ # - Coordination: Connects Extractor → ScopeBatcher → Uploader
18
+ # - Remote config handling: start_upload called by Remote module on config changes
19
+ # - Debounce: extraction is deferred by EXTRACT_DEBOUNCE_INTERVAL seconds so
20
+ # reconfigurations during boot coalesce into a single extraction on the
21
+ # final Component instance.
22
+ # - Hot-load coverage: TracePoint :class hook captures classes loaded after
23
+ # initial extraction, enqueues them on a per-instance buffer; the scheduler
24
+ # drains the buffer on debounce and extracts each one via Extractor#extract,
25
+ # matching Java/Python/.NET continuous coverage.
26
+ #
27
+ # Upload flow:
28
+ # 1. Remote config sends upload_symbols: true (or force_upload mode)
29
+ # 2. start_upload called — schedules extraction EXTRACT_DEBOUNCE_INTERVAL
30
+ # seconds in the future on a per-instance scheduler thread, and lazily
31
+ # installs the TracePoint :class hook if not already installed.
32
+ # 3. When the timer fires (no further start_upload calls reset it),
33
+ # extract_and_upload runs. On the first call: ObjectSpace iteration →
34
+ # Extractor#extract_all. On subsequent calls: drain the hot-load buffer →
35
+ # Extractor#extract per module.
36
+ # 4. ScopeBatcher batches and triggers Uploader.
37
+ # 5. As new classes load throughout the process lifetime, the TracePoint hook
38
+ # fires and signals the scheduler — the next debounce window produces an
39
+ # incremental upload of just the new classes.
40
+ #
41
+ # Created by: Components#initialize (in Core::Configuration::Components)
42
+ # Accessed by: Remote config receiver via Datadog.send(:components).symbol_database
43
+ # Requires: Remote config enabled (unless force mode)
44
+ #
45
+ # @api private
46
+ class Component
47
+ # Debounce window for extraction. Multiple start_upload calls within this
48
+ # window coalesce; the timer fires once after the window of inactivity.
49
+ # Long enough to absorb reconfiguration cascades during Rails boot.
50
+ EXTRACT_DEBOUNCE_INTERVAL = 5 # seconds
51
+
52
+ # Cached unbound Module#singleton_class? — dispatched explicitly inside the
53
+ # hot-load TracePoint so user code that overrides `singleton_class?` (e.g.
54
+ # `def self.singleton_class?(arg)`) cannot raise inside the :class hook and
55
+ # abort the user's class definition. Mirrors the cache in Extractor.
56
+ MODULE_SINGLETON_CLASS_PRED = Module.instance_method(:singleton_class?)
57
+ private_constant :MODULE_SINGLETON_CLASS_PRED
58
+
59
+ # Build a new Component if the runtime supports it and dependencies are met.
60
+ # The caller (Core::Configuration::Components) decides whether the feature is
61
+ # enabled and only invokes build when it is, so a disabled component is never
62
+ # constructed. This method gates only on symbol database's own requirements
63
+ # (supported platform, remote config availability).
64
+ # @param settings [Configuration::Settings] Tracer settings
65
+ # @param agent_settings [Configuration::AgentSettings] Agent configuration
66
+ # @param logger [Logger] Logger instance
67
+ # @param telemetry [Core::Telemetry::Component, nil] Telemetry component for error reporting
68
+ # @param di_active [Proc, nil] Predicate returning whether Dynamic
69
+ # Instrumentation is currently active (started). Gates remote-config
70
+ # uploads in the nil-default case; nil means "no gate" (standalone
71
+ # force_upload contexts).
72
+ # @return [Component, nil] Component instance or nil if requirements not met
73
+ def self.build(settings, agent_settings, logger, telemetry: nil, di_active: nil)
74
+ symdb_logger = SymbolDatabase::Logger.new(settings, logger)
75
+
76
+ # Symbol database requires MRI Ruby 2.7+.
77
+ # Configuration accessors (settings.symbol_database.*) remain available on all
78
+ # platforms — only the component (upload) is disabled on unsupported engines/versions.
79
+ # environment_supported? logs the specific reason (engine or version) internally.
80
+ return nil unless environment_supported?(symdb_logger)
81
+
82
+ # Requires remote config (unless force mode)
83
+ if !settings.remote&.enabled && !settings.symbol_database.internal.force_upload
84
+ symdb_logger.debug("symdb: remote config not available and force_upload not set, skipping")
85
+ return nil
86
+ end
87
+
88
+ new(settings, agent_settings, symdb_logger, telemetry: telemetry, di_active: di_active).tap do |component|
89
+ # Defer extraction if force upload mode — wait for app boot to complete
90
+ component.schedule_deferred_upload if settings.symbol_database.internal.force_upload
91
+ end
92
+ end
93
+
94
+ attr_reader :settings, :logger, :last_upload_time, :last_upload_scope_count, :upload_in_progress
95
+
96
+ # Initialize component.
97
+ # @param settings [Configuration::Settings] Tracer settings
98
+ # @param agent_settings [Configuration::AgentSettings] Agent configuration
99
+ # @param logger [Logger] Logger instance
100
+ # @param telemetry [Core::Telemetry::Component, nil] Telemetry component for error reporting
101
+ # @param di_active [Proc, nil] Predicate returning whether Dynamic Instrumentation is currently active
102
+ def initialize(settings, agent_settings, logger, telemetry: nil, di_active: nil)
103
+ @settings = settings
104
+ @agent_settings = agent_settings
105
+ @logger = logger
106
+ @telemetry = telemetry
107
+ @di_active = di_active
108
+
109
+ @extractor = Extractor.new(logger: logger, settings: settings)
110
+ @uploader = Uploader.new(settings: settings, agent_settings: agent_settings, logger: logger, telemetry: telemetry)
111
+ @scope_batcher = ScopeBatcher.new(@uploader, logger: logger)
112
+
113
+ @last_upload_time = nil
114
+ @last_upload_scope_count = nil
115
+ @mutex = Mutex.new
116
+ @upload_in_progress = false
117
+ @upload_in_progress_cv = ConditionVariable.new
118
+ @shutdown = false
119
+ # PID at construction time. Compared against Process.pid in shutdown!
120
+ # to detect forked-child callers, whose inherited @upload_in_progress
121
+ # snapshot is stale: the scheduler thread that would clear it lives
122
+ # only in the parent. See shutdown! for details.
123
+ @owner_pid = Process.pid
124
+
125
+ # Signalled when @last_upload_time advances. wait_for_idle blocks on this
126
+ # so short-lived scripts that trigger an upload can wait for an upload
127
+ # attempt to complete without depending on a one-shot flag.
128
+ @last_upload_time_cv = ConditionVariable.new
129
+
130
+ # Per-instance scheduler state. The scheduler thread is started lazily
131
+ # on the first start_upload call.
132
+ @scheduler_mutex = Mutex.new
133
+ @scheduler_cv = ConditionVariable.new
134
+ @scheduled_at = nil
135
+ @scheduler_signaled = false
136
+ @scheduler_thread = nil
137
+
138
+ # Hot-load coverage state. TracePoint :class hook is installed lazily on
139
+ # the first start_upload call; classes defined after that point are
140
+ # enqueued here and drained by the scheduler on debounce. Distinguishes
141
+ # initial extraction (extract_all) from incremental (per-module extract).
142
+ @hot_load_buffer = []
143
+ @hot_load_buffer_mutex = Mutex.new
144
+ @hot_load_tracepoint = nil
145
+ @initial_extraction_done = false
146
+
147
+ # Sticky record of "remote config (or force mode) wants symbols
148
+ # uploaded", independent of whether DI is currently active. Set when an
149
+ # upload is requested and either allowed or deferred by the DI gate;
150
+ # cleared only when RC explicitly disables uploads (stop_upload). It
151
+ # survives stop_for_di_disable's scheduler teardown, so
152
+ # resume_pending_upload can restart uploads after a DI disable->re-enable
153
+ # cycle even though RC does not re-dispatch the unchanged symbol-database
154
+ # config.
155
+ @upload_requested = false
156
+ end
157
+
158
+ # Schedule a deferred upload that waits for app boot to complete.
159
+ #
160
+ # In Rails: registers ActiveSupport.on_load(:after_initialize). When the
161
+ # hook has already fired (e.g., this Component was built by a reconfigure
162
+ # after Rails finished initializing), the callback runs immediately.
163
+ #
164
+ # In non-Rails: triggers start_upload immediately.
165
+ #
166
+ # Each Component registers its own callback. Old Components that have
167
+ # been shut down short-circuit in start_upload via @shutdown. The hot-load
168
+ # hook handles classes loaded after this initial trigger, so under
169
+ # eager_load=false an under-extracted initial upload self-corrects as the
170
+ # app exercises code.
171
+ #
172
+ # @return [void]
173
+ def schedule_deferred_upload
174
+ if defined?(::ActiveSupport) && defined?(::Rails::Railtie)
175
+ # Capture self — on_load runs the block via instance_exec on the
176
+ # loaded object (Rails::Application), so a bare `start_upload`
177
+ # would resolve against it.
178
+ component = self
179
+ ::ActiveSupport.on_load(:after_initialize) do
180
+ component.start_upload
181
+ end
182
+ else
183
+ start_upload
184
+ end
185
+ end
186
+
187
+ # Whether this component has been shut down.
188
+ # @return [Boolean]
189
+ def shutdown?
190
+ @scheduler_mutex.synchronize { @shutdown }
191
+ end
192
+
193
+ # Schedule symbol upload (triggered by remote config or force mode).
194
+ # The actual extraction is debounced by EXTRACT_DEBOUNCE_INTERVAL seconds —
195
+ # subsequent calls within the window restart the timer.
196
+ # Thread-safe: can be called concurrently from multiple remote config updates.
197
+ # @return [void]
198
+ def start_upload
199
+ @scheduler_mutex.synchronize do
200
+ return if @shutdown
201
+
202
+ unless upload_allowed?
203
+ if deferred_by_di_gate?
204
+ # nil-default case: Symbol Database mirrors Dynamic Instrumentation
205
+ # and DI is not active. Record the desire and defer; resume_pending_upload
206
+ # re-attempts when DI is enabled. Without this gate the tracer would
207
+ # extract and upload symbols for applications that never enabled DI.
208
+ @upload_requested = true
209
+ @logger.debug("symdb: upload requested but Dynamic Instrumentation is not active; deferring until DI is enabled")
210
+ else
211
+ # Explicit symbol_database.enabled = false: the feature is disabled,
212
+ # not merely waiting on DI. Clear the desire so resume_pending_upload
213
+ # does not retry a disabled feature.
214
+ @upload_requested = false
215
+ @logger.debug("symdb: upload requested but symbol database upload is disabled; skipping")
216
+ end
217
+ return
218
+ end
219
+ @upload_requested = true
220
+
221
+ if @owner_pid != Process.pid
222
+ # Forked child: claim ownership and clear inherited
223
+ # @upload_in_progress. The inherited flag was the parent's
224
+ # snapshot; the parent's scheduler thread does not exist in this
225
+ # process. Any upload starting now is child-owned and must be
226
+ # waited on in shutdown! via the PID-match branch.
227
+ @owner_pid = Process.pid
228
+ @mutex.synchronize { @upload_in_progress = false }
229
+ end
230
+
231
+ install_hot_load_hook
232
+ @scheduled_at = Datadog::Core::Utils::Time.get_time + EXTRACT_DEBOUNCE_INTERVAL
233
+ @scheduler_signaled = true
234
+ @scheduler_cv.signal
235
+ ensure_scheduler_thread
236
+ end
237
+ rescue Exception => e # standard:disable Lint/RescueException
238
+ Datadog::DI.reraise_if_fatal(e)
239
+ @logger.debug { "symdb: error scheduling upload: #{e.class}: #{e.message}" }
240
+ @telemetry&.report(e, description: 'symdb: error scheduling upload')
241
+ end
242
+
243
+ # Stop symbol upload in response to remote config sending
244
+ # upload_symbols: false or deleting the config: the customer no longer wants
245
+ # uploads, so clear the sticky @upload_requested desire (a later
246
+ # resume_pending_upload must not restart it) and tear down the scheduler and
247
+ # hot-load hook.
248
+ # Thread-safe: can be called concurrently from multiple remote config updates.
249
+ # @return [void]
250
+ def stop_upload
251
+ @scheduler_mutex.synchronize { @upload_requested = false }
252
+ suspend_scheduling
253
+ end
254
+
255
+ # Re-attempt a symbol upload that remote config requested but that is not
256
+ # currently running because Dynamic Instrumentation was inactive — either
257
+ # deferred at request time, or suspended by stop_for_di_disable when DI was
258
+ # turned off. Called from the orchestration layer (Tracing::Remote) when DI
259
+ # is enabled via remote configuration (implicit enablement). No-op unless an
260
+ # upload was requested and not since disabled. Mirrors DI's
261
+ # replay_current_probes: RC does not re-dispatch the unchanged
262
+ # symbol-database config on DI re-enable, so the tracer restarts the upload
263
+ # from its own retained desire.
264
+ # @return [void]
265
+ def resume_pending_upload
266
+ requested = @scheduler_mutex.synchronize { @upload_requested }
267
+ start_upload if requested
268
+ nil
269
+ end
270
+
271
+ # Stop uploading when Dynamic Instrumentation is disabled via remote
272
+ # configuration. Only the nil-default (follows-DI) case stops; an explicit
273
+ # symbol_database.enabled = true and force_upload are independent of DI and
274
+ # keep running. Called from the orchestration layer (Tracing::Remote) so
275
+ # Symbol Database's TracePoint and scheduler don't keep uploading after DI
276
+ # is turned off. No-op if uploads were never started.
277
+ # @return [void]
278
+ def stop_for_di_disable
279
+ return if @settings.symbol_database.internal.force_upload
280
+ return unless @settings.symbol_database.enabled.nil?
281
+
282
+ # Suspend, don't stop: preserve @upload_requested so resume_pending_upload
283
+ # restarts the upload when DI is re-enabled and RC never re-sends the
284
+ # (unchanged) symbol-database config.
285
+ suspend_scheduling
286
+ end
287
+
288
+ # Block until this Component finishes an extract+upload after this call,
289
+ # or until the timeout elapses. Used by short-lived scripts that trigger
290
+ # an upload via force_upload and need to wait before exiting.
291
+ # Tracks @last_upload_time advance — returns true once any upload attempt
292
+ # completes (success or failure), false on timeout.
293
+ # @param timeout [Numeric] Maximum seconds to wait
294
+ # @return [Boolean] true if an upload completed; false on timeout
295
+ def wait_for_idle(timeout: 30)
296
+ deadline = Datadog::Core::Utils::Time.get_time + timeout
297
+ @mutex.synchronize do
298
+ start_time = @last_upload_time
299
+ while @last_upload_time == start_time
300
+ remaining = deadline - Datadog::Core::Utils::Time.get_time
301
+ return false if remaining <= 0
302
+ @last_upload_time_cv.wait(@mutex, remaining)
303
+ end
304
+ end
305
+ true
306
+ end
307
+
308
+ # Shutdown component and cleanup resources.
309
+ # Disables the hot-load TracePoint so no events queue for a dead
310
+ # scheduler. Cancels the per-instance scheduler so any pending debounced
311
+ # extraction is dropped. Waits for an in-flight extraction to complete
312
+ # before returning. Does not touch any sibling Components, so a sibling
313
+ # Component built after shutdown can still upload.
314
+ # The TracePoint teardown sits inside the same @scheduler_mutex critical
315
+ # section as the @shutdown flag flip, so it is atomic against a concurrent
316
+ # start_upload (which installs the TracePoint under @scheduler_mutex). Without
317
+ # that, a shutdown interleaved with a start could leave an enabled TracePoint
318
+ # rooted by the VM — class loads would keep growing @hot_load_buffer for the
319
+ # rest of the process lifetime (enqueue_hot_load's @shutdown check skips
320
+ # re-scheduling but only after the buffer push).
321
+ # @return [void]
322
+ def shutdown!
323
+ @scheduler_mutex.synchronize do
324
+ @hot_load_tracepoint&.disable
325
+ @hot_load_tracepoint = nil
326
+ @shutdown = true
327
+ @scheduler_signaled = true
328
+ @scheduler_cv.signal
329
+ end
330
+ @scheduler_thread&.join(5)
331
+ @scheduler_thread = nil
332
+
333
+ @mutex.synchronize do
334
+ if @upload_in_progress
335
+ if Process.pid == @owner_pid
336
+ @upload_in_progress_cv.wait(@mutex, 5)
337
+ else
338
+ # We are in a forked child that inherited this Component but
339
+ # never called start_upload here. The scheduler thread (the
340
+ # only writer that clears @upload_in_progress and signals the
341
+ # cv) lives only in the parent — fork carries only the calling
342
+ # thread, so nothing in this process can ever signal us.
343
+ # Waiting would burn the full 5s timeout for no benefit. Treat
344
+ # the inherited @upload_in_progress as a stale snapshot and
345
+ # proceed; the parent's shutdown! (running in the parent) is
346
+ # authoritative. Child-owned uploads (where start_upload was
347
+ # called in this process) take the PID-match branch above,
348
+ # because start_upload claims @owner_pid for the current
349
+ # process.
350
+ @upload_in_progress = false
351
+ end
352
+ end
353
+ end
354
+
355
+ @scope_batcher.shutdown
356
+ end
357
+
358
+ # Reinitialize per-instance state in a forked child process.
359
+ #
360
+ # `Process.fork` copies the parent's memory but only the forking thread
361
+ # survives in the child. Background threads (`@scheduler_thread`) are
362
+ # dead, mutexes and condition variables are copied without owner
363
+ # tracking (orphan-lock risk if the parent held a mutex at the fork
364
+ # instant), and the TracePoint hook is bound to the dead scheduler.
365
+ #
366
+ # State reset (the child does its own initial extraction, then hot-load
367
+ # continues from there):
368
+ # - Hot-load buffer cleared — the child will rediscover via extract_all.
369
+ # - `@initial_extraction_done = false` — child has not extracted yet.
370
+ # - `@hot_load_tracepoint = nil` — `start_upload` reinstalls a fresh one
371
+ # bound to the child's component.
372
+ # - `@scheduler_thread = nil`, `@scheduled_at = nil`,
373
+ # `@scheduler_signaled = false` — scheduler restarts on next
374
+ # `start_upload`.
375
+ # - `@upload_in_progress = false` — parent may have been mid-upload at
376
+ # the fork instant; the child has no upload in flight.
377
+ # - `@scope_batcher` replaced with a fresh instance. The inherited batcher
378
+ # carries the parent's `@uploaded_modules` set, which `add_scope` uses
379
+ # to dedup by scope name. Without a fresh batcher, the child's
380
+ # re-extraction silently drops every scope whose name the parent
381
+ # already uploaded — under `preload_app!` that's most of the app.
382
+ #
383
+ # Mutex/CV reinit (orphan-lock guard):
384
+ # - `@scheduler_mutex`, `@scheduler_cv`, `@mutex`,
385
+ # `@upload_in_progress_cv`, `@last_upload_time_cv`,
386
+ # `@hot_load_buffer_mutex`.
387
+ #
388
+ # Force-upload mode: the parent's scheduled extraction is dead in the
389
+ # child, so re-register the deferred-upload callback. In Rails the
390
+ # `:after_initialize` hook has already fired (initialization happened
391
+ # in the parent), so the on_load block runs immediately and the child
392
+ # schedules its own upload. In non-Rails, this calls `start_upload`
393
+ # directly.
394
+ #
395
+ # Cross-process upload deduplication is intentionally not handled here.
396
+ # Each forked Component does its own initial extraction. Workers in
397
+ # `preload_app! + eager_load=true` deployments hold identical code to
398
+ # the parent — backend dedup of identical-content uploads is the
399
+ # backend's responsibility, not the tracer's.
400
+ #
401
+ # @return [void]
402
+ def after_fork!
403
+ # Disable the inherited TracePoint before dropping the reference: fork
404
+ # copies the enabled TP into the child, where it remains rooted by the
405
+ # VM. Without an explicit disable, every subsequent class load in the
406
+ # child would enqueue through the inherited hook in addition to the
407
+ # fresh hook that start_upload installs.
408
+ @hot_load_tracepoint&.disable
409
+ @hot_load_buffer = []
410
+ @hot_load_buffer_mutex = Mutex.new
411
+ @hot_load_tracepoint = nil
412
+ @initial_extraction_done = false
413
+
414
+ @scheduler_mutex = Mutex.new
415
+ @scheduler_cv = ConditionVariable.new
416
+ @scheduled_at = nil
417
+ @scheduler_signaled = false
418
+ @scheduler_thread = nil
419
+
420
+ @mutex = Mutex.new
421
+ @upload_in_progress = false
422
+ @upload_in_progress_cv = ConditionVariable.new
423
+ @last_upload_time_cv = ConditionVariable.new
424
+
425
+ # Fresh ScopeBatcher: the inherited one carries the parent's
426
+ # @uploaded_modules set, against which add_scope dedups by name.
427
+ @scope_batcher = ScopeBatcher.new(@uploader, logger: @logger)
428
+
429
+ schedule_deferred_upload if @settings.symbol_database.internal.force_upload
430
+ end
431
+
432
+ private
433
+
434
+ # Tear down the scheduler and hot-load hook without clearing the sticky
435
+ # @upload_requested desire, so resume_pending_upload can restart uploads
436
+ # that RC still wants. Disables the TracePoint :class hook so post-stop
437
+ # class loads don't re-arm the scheduler, clears the hot-load buffer, and
438
+ # resets @initial_extraction_done so a future resume performs a fresh
439
+ # extract_all instead of draining an empty buffer.
440
+ # The TracePoint teardown sits inside the same @scheduler_mutex critical
441
+ # section as the @scheduled_at reset, so it is atomic against a concurrent
442
+ # start_upload (which installs the TracePoint under @scheduler_mutex). Without
443
+ # that, a stop interleaved with a start could leave an enabled TracePoint
444
+ # rooted by the VM after this returned.
445
+ # @return [void]
446
+ def suspend_scheduling
447
+ @scheduler_mutex.synchronize do
448
+ @hot_load_tracepoint&.disable
449
+ @hot_load_tracepoint = nil
450
+ @scheduled_at = nil
451
+ @scheduler_signaled = true
452
+ @scheduler_cv.signal
453
+ end
454
+ @hot_load_buffer_mutex.synchronize { @hot_load_buffer.clear }
455
+ @initial_extraction_done = false
456
+ nil
457
+ end
458
+
459
+ # Whether a remote-config-triggered upload may proceed now.
460
+ #
461
+ # force_upload and an explicit `symbol_database.enabled = true` both mean
462
+ # "upload regardless of Dynamic Instrumentation". Only the nil-default case
463
+ # — where Symbol Database mirrors DI — is gated on DI actually being active,
464
+ # so the tracer never extracts symbols for an application that never
465
+ # enabled Dynamic Instrumentation.
466
+ # @return [bool]
467
+ def upload_allowed?
468
+ return true if @settings.symbol_database.internal.force_upload
469
+
470
+ case @settings.symbol_database.enabled
471
+ when true then true
472
+ when false then false
473
+ # steep:ignore NoMethod — Steep does not narrow @di_active to non-nil after the .nil? check
474
+ else @di_active.nil? || @di_active.call # steep:ignore NoMethod
475
+ end
476
+ end
477
+
478
+ # Whether upload is currently blocked specifically by the nil-default
479
+ # DI-active gate — the only case that defers and retries via
480
+ # resume_pending_upload. An explicit symbol_database.enabled = false is a
481
+ # disabled feature, not a deferral, so it clears @upload_requested and is
482
+ # not retried. force_upload and explicit true are never gated, so they are
483
+ # never deferred.
484
+ # @return [bool]
485
+ def deferred_by_di_gate?
486
+ return false if @settings.symbol_database.internal.force_upload
487
+ return false unless @settings.symbol_database.enabled.nil?
488
+
489
+ # After the guards above, upload_allowed? reduces to the DI-active gate,
490
+ # so a disallowed upload here is precisely a DI-gate deferral.
491
+ !upload_allowed?
492
+ end
493
+
494
+ # Check whether the runtime environment supports symbol database upload,
495
+ # logging the reason when it does not.
496
+ # @param logger [Logger]
497
+ # @return [Boolean]
498
+ def self.environment_supported?(logger)
499
+ return true if SymbolDatabase.supported_runtime?
500
+
501
+ if RUBY_ENGINE != 'ruby'
502
+ logger.debug { "symdb: not supported on #{RUBY_ENGINE}, skipping" }
503
+ else
504
+ logger.debug { "symdb: requires Ruby 2.7+, running #{RUBY_VERSION}, skipping" }
505
+ end
506
+ false
507
+ end
508
+ private_class_method :environment_supported?
509
+
510
+ # Start the scheduler thread if not already running.
511
+ # Must be called from within @scheduler_mutex.synchronize.
512
+ # @return [void]
513
+ def ensure_scheduler_thread
514
+ return if @scheduler_thread&.alive?
515
+ @scheduler_thread = Thread.new { scheduler_loop }
516
+ end
517
+
518
+ # Scheduler thread main loop. Waits for the debounce window to elapse,
519
+ # then runs extract_and_upload. Loops indefinitely so that hot-load
520
+ # signals fired after the initial upload trigger subsequent incremental
521
+ # uploads.
522
+ # @return [void]
523
+ def scheduler_loop
524
+ loop do
525
+ # should_fire = true means the debounce deadline elapsed without further
526
+ # signals; extract_and_upload runs once after the mutex is released.
527
+ should_fire = false
528
+
529
+ @scheduler_mutex.synchronize do
530
+ return if @shutdown
531
+
532
+ # Copy to local so Steep narrows `Float?` to `Float` in the else branch.
533
+ # Steep does not track narrowing on instance variables across nil checks.
534
+ scheduled_at = @scheduled_at
535
+ if scheduled_at.nil?
536
+ # Nothing scheduled (e.g. stop_upload cleared it, or no hot-load
537
+ # events since the last upload). Wait indefinitely for a signal,
538
+ # then re-evaluate on next loop.
539
+ @scheduler_signaled = false
540
+ @scheduler_cv.wait(@scheduler_mutex)
541
+ else
542
+ remaining = scheduled_at - Datadog::Core::Utils::Time.get_time
543
+ if remaining > 0
544
+ # Wait until the debounce deadline. Any signal (start_upload,
545
+ # stop_upload, shutdown!, hot-load event) wakes us early; we
546
+ # always re-loop and recompute rather than firing immediately
547
+ # on wake.
548
+ @scheduler_signaled = false
549
+ @scheduler_cv.wait(@scheduler_mutex, remaining)
550
+ else
551
+ # Deadline elapsed without further signal — fire after releasing
552
+ # the mutex. Clear @scheduled_at so the next loop iteration
553
+ # waits for the next start_upload or hot-load signal.
554
+ should_fire = true
555
+ @scheduled_at = nil
556
+ end
557
+ end
558
+ end
559
+
560
+ # `next` inside `synchronize` only exits the synchronize block — not the
561
+ # surrounding loop. Use an explicit flag so the loop only fires
562
+ # extract_and_upload when the debounce deadline has actually elapsed.
563
+ next unless should_fire
564
+
565
+ # Outside the mutex.
566
+ return if @shutdown
567
+
568
+ extract_and_upload
569
+ end
570
+ rescue Exception => e # standard:disable Lint/RescueException
571
+ Datadog::DI.reraise_if_fatal(e)
572
+ @logger.debug { "symdb: scheduler error: #{e.class}: #{e.message}" }
573
+ @telemetry&.report(e, description: 'symdb: scheduler error')
574
+ end
575
+
576
+ # Extract symbols and upload. First call runs extract_all (full ObjectSpace
577
+ # walk); subsequent calls drain the hot-load buffer and extract just the
578
+ # newly-loaded modules via Extractor#extract.
579
+ # @return [void]
580
+ def extract_and_upload
581
+ @mutex.synchronize { @upload_in_progress = true }
582
+
583
+ begin
584
+ @logger.trace { "symdb: starting extraction and upload" }
585
+ start_time = Datadog::Core::Utils::Time.get_time
586
+
587
+ extracted_count = 0
588
+ targetable_count = 0
589
+ consume = lambda do |scope|
590
+ @scope_batcher.add_scope(scope)
591
+ extracted_count += 1
592
+ targetable_count += count_targetable_methods_in_scope(scope)
593
+ log_scope_tree(scope, 0)
594
+ end
595
+
596
+ if @initial_extraction_done
597
+ extract_hot_load_buffer.each(&consume)
598
+ mode_label = "hot-load"
599
+ else
600
+ # Discard any TracePoint events captured between hook install and
601
+ # this initial scan — extract_all walks ObjectSpace which already
602
+ # covers everything loaded at this moment. Anything loaded during
603
+ # or after extract_all stays buffered for the next drain.
604
+ @hot_load_buffer_mutex.synchronize { @hot_load_buffer.clear }
605
+ # Stream form of extract_all yields one FILE scope at a time and frees
606
+ # the per-file intermediate tree as it goes — the full Array<Scope> is
607
+ # never materialized, keeping peak memory bounded for large workspaces.
608
+ @extractor.extract_all(&consume)
609
+ @initial_extraction_done = true
610
+ mode_label = "initial"
611
+ end
612
+
613
+ extraction_duration = Datadog::Core::Utils::Time.get_time - start_time
614
+ @logger.debug { "symdb: #{mode_label} extracted #{extracted_count} scopes (#{targetable_count} methods with targetable lines) in #{'%.2f' % extraction_duration}s" }
615
+
616
+ # Flush any remaining scopes (triggers upload)
617
+ @scope_batcher.flush
618
+
619
+ @mutex.synchronize do
620
+ @last_upload_time = Datadog::Core::Utils::Time.now
621
+ @last_upload_scope_count = extracted_count
622
+ @last_upload_time_cv.broadcast
623
+ end
624
+ rescue Exception => e # standard:disable Lint/RescueException
625
+ Datadog::DI.reraise_if_fatal(e)
626
+ @logger.debug { "symdb: extraction error: #{e.class}: #{e.message}" }
627
+ @telemetry&.report(e, description: 'symdb: extraction error')
628
+ @mutex.synchronize do
629
+ @last_upload_time = Datadog::Core::Utils::Time.now
630
+ @last_upload_time_cv.broadcast
631
+ end
632
+ ensure
633
+ @mutex.synchronize do
634
+ @upload_in_progress = false
635
+ @upload_in_progress_cv.signal
636
+ end
637
+ end
638
+ end
639
+
640
+ # Drain the hot-load buffer, dedup by object_id, return the array of
641
+ # FILE scopes from per-module extraction.
642
+ # @return [Array<Scope>]
643
+ def extract_hot_load_buffer
644
+ modules = @hot_load_buffer_mutex.synchronize { @hot_load_buffer.shift(@hot_load_buffer.length) }
645
+ return [] if modules.empty?
646
+
647
+ seen = {}
648
+ modules.each { |mod| seen[mod.object_id] = mod }
649
+ seen.values.map { |mod| @extractor.extract(mod) }.compact
650
+ end
651
+
652
+ # Install the TracePoint :class hook (lazy — only on first start_upload).
653
+ # Hook fires for every class/module body open including reopens; pushes
654
+ # the module onto @hot_load_buffer and signals the scheduler. Singleton
655
+ # classes are filtered for the same reason as in Extractor#extract_all.
656
+ # Must be called from within @scheduler_mutex.synchronize.
657
+ # @return [void]
658
+ def install_hot_load_hook
659
+ return if @hot_load_tracepoint
660
+ component = self
661
+ logger = @logger
662
+ telemetry = @telemetry
663
+ @hot_load_tracepoint = TracePoint.new(:class) do |tp|
664
+ # The :class TracePoint fires inside the customer's class body —
665
+ # any exception that escapes this block surfaces at the customer's
666
+ # `class Foo; ... end` line and breaks their class load. The
667
+ # MODULE_SINGLETON_CLASS_PRED dispatch defends against one specific
668
+ # raise source (user-overridden singleton_class?); this rescue
669
+ # closes the general case. Verified: a raise inside the callback
670
+ # backtraces through `<class:CustomerClass>` in Ruby 3.x.
671
+
672
+ mod = tp.self
673
+ next if MODULE_SINGLETON_CLASS_PRED.bind(mod).call
674
+ component.send(:enqueue_hot_load, mod)
675
+ rescue Exception => e # standard:disable Lint/RescueException
676
+ Datadog::DI.reraise_if_fatal(e)
677
+ # Logger or telemetry can themselves raise (custom logger
678
+ # implementation, telemetry worker in an unexpected state). The
679
+ # :class TracePoint fires inside customer class bodies, so the
680
+ # error boundary must hold even when error reporting fails;
681
+ # nothing useful to do if logging is broken.
682
+ begin
683
+ logger.debug { "symdb: hot-load hook error: #{e.class}: #{e.message}" }
684
+ telemetry&.report(e, description: 'symdb: hot-load hook error')
685
+ rescue Exception => report_exc # standard:disable Lint/RescueException
686
+ Datadog::DI.reraise_if_fatal(report_exc)
687
+ nil
688
+ end
689
+ end
690
+ @hot_load_tracepoint.enable # steep:ignore NoMethod
691
+ end
692
+
693
+ # Enqueue a hot-loaded module and signal the scheduler.
694
+ # Called from the TracePoint :class block — must be cheap.
695
+ # @param mod [Module]
696
+ # @return [void]
697
+ def enqueue_hot_load(mod)
698
+ @hot_load_buffer_mutex.synchronize { @hot_load_buffer << mod }
699
+ @scheduler_mutex.synchronize do
700
+ return if @shutdown
701
+ # TracePoint#disable does not wait for in-flight callbacks: a :class
702
+ # event firing concurrently with stop_upload can reach here after the
703
+ # hook has been torn down. Without this guard the stale event would
704
+ # re-arm the scheduler, contradicting stop_upload's contract. The
705
+ # buffer push above is harmless — the next start_upload runs
706
+ # extract_all, which clears the buffer before extracting.
707
+ return unless @hot_load_tracepoint
708
+ @scheduled_at = Datadog::Core::Utils::Time.get_time + EXTRACT_DEBOUNCE_INTERVAL
709
+ @scheduler_signaled = true
710
+ @scheduler_cv.signal
711
+ end
712
+ end
713
+
714
+ def log_scope_tree(scope, depth)
715
+ indent = ' ' * depth
716
+ @logger.trace { "symdb: #{indent}#{scope.scope_type} #{scope.name}" }
717
+ scope.scopes&.each { |child| log_scope_tree(child, depth + 1) }
718
+ end
719
+
720
+ # Count METHOD scopes with targetable lines inside one FILE scope. Used by
721
+ # extract_and_upload to accumulate the count while streaming, without
722
+ # retaining the Array<Scope> just to compute the total at the end.
723
+ def count_targetable_methods_in_scope(file_scope)
724
+ count = 0
725
+ file_scope.scopes&.each do |class_or_module|
726
+ class_or_module.scopes&.each do |method_scope|
727
+ count += 1 if method_scope.scope_type == 'METHOD' && method_scope.targetable_lines?
728
+ end
729
+ end
730
+ count
731
+ end
732
+ end
733
+ end
734
+ end