datadog 2.21.0 → 2.38.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 (623) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +574 -1
  3. data/ext/LIBDATADOG_DEVELOPMENT.md +3 -0
  4. data/ext/datadog_profiling_native_extension/clock_id.h +9 -1
  5. data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +66 -0
  6. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +3 -2
  7. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +301 -82
  8. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +4 -4
  9. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +3 -2
  10. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +18 -4
  11. data/ext/datadog_profiling_native_extension/collectors_stack.c +63 -32
  12. data/ext/datadog_profiling_native_extension/collectors_stack.h +7 -2
  13. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +728 -436
  14. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +19 -6
  15. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
  16. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +65 -1
  17. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +40 -1
  18. data/ext/datadog_profiling_native_extension/encoded_profile.c +2 -1
  19. data/ext/datadog_profiling_native_extension/extconf.rb +41 -37
  20. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +4 -43
  21. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +15 -47
  22. data/ext/datadog_profiling_native_extension/heap_recorder.c +252 -103
  23. data/ext/datadog_profiling_native_extension/heap_recorder.h +12 -1
  24. data/ext/datadog_profiling_native_extension/http_transport.c +66 -68
  25. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +3 -22
  26. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +0 -5
  27. data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
  28. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +0 -13
  29. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +40 -43
  30. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +6 -0
  31. data/ext/datadog_profiling_native_extension/profiling.c +65 -19
  32. data/ext/datadog_profiling_native_extension/ruby_helpers.c +63 -46
  33. data/ext/datadog_profiling_native_extension/ruby_helpers.h +17 -5
  34. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +32 -10
  35. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +2 -1
  36. data/ext/datadog_profiling_native_extension/stack_recorder.c +110 -85
  37. data/ext/datadog_profiling_native_extension/stack_recorder.h +3 -1
  38. data/ext/datadog_profiling_native_extension/time_helpers.h +13 -7
  39. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +2 -1
  40. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +9 -4
  41. data/ext/libdatadog_api/crashtracker.c +16 -15
  42. data/ext/libdatadog_api/crashtracker_report_exception.c +126 -0
  43. data/ext/libdatadog_api/datadog_ruby_common.c +65 -1
  44. data/ext/libdatadog_api/datadog_ruby_common.h +40 -1
  45. data/ext/libdatadog_api/ddsketch.c +102 -0
  46. data/ext/libdatadog_api/di.c +203 -0
  47. data/ext/libdatadog_api/extconf.rb +18 -24
  48. data/ext/libdatadog_api/feature_flags.c +554 -0
  49. data/ext/libdatadog_api/feature_flags.h +5 -0
  50. data/ext/libdatadog_api/helpers.h +27 -0
  51. data/ext/libdatadog_api/init.c +13 -1
  52. data/ext/libdatadog_api/library_config.c +34 -25
  53. data/ext/libdatadog_api/process_discovery.c +19 -13
  54. data/ext/libdatadog_extconf_helpers.rb +94 -11
  55. data/lib/datadog/ai_guard/api_client.rb +84 -0
  56. data/lib/datadog/ai_guard/autoload.rb +10 -0
  57. data/lib/datadog/ai_guard/component.rb +44 -0
  58. data/lib/datadog/ai_guard/configuration/ext.rb +17 -0
  59. data/lib/datadog/ai_guard/configuration.rb +115 -0
  60. data/lib/datadog/ai_guard/contrib/auto_instrument.rb +24 -0
  61. data/lib/datadog/ai_guard/contrib/integration.rb +37 -0
  62. data/lib/datadog/ai_guard/contrib/rack/integration.rb +42 -0
  63. data/lib/datadog/ai_guard/contrib/rack/patcher.rb +26 -0
  64. data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +97 -0
  65. data/lib/datadog/ai_guard/contrib/rails/integration.rb +41 -0
  66. data/lib/datadog/ai_guard/contrib/rails/patcher.rb +97 -0
  67. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +80 -0
  68. data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +41 -0
  69. data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +30 -0
  70. data/lib/datadog/ai_guard/evaluation/content_builder.rb +31 -0
  71. data/lib/datadog/ai_guard/evaluation/content_part.rb +36 -0
  72. data/lib/datadog/ai_guard/evaluation/message.rb +25 -0
  73. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +36 -0
  74. data/lib/datadog/ai_guard/evaluation/request.rb +86 -0
  75. data/lib/datadog/ai_guard/evaluation/result.rb +45 -0
  76. data/lib/datadog/ai_guard/evaluation/tool_call.rb +18 -0
  77. data/lib/datadog/ai_guard/evaluation.rb +108 -0
  78. data/lib/datadog/ai_guard/ext.rb +29 -0
  79. data/lib/datadog/ai_guard.rb +181 -0
  80. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
  81. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +66 -0
  82. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +36 -0
  83. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
  84. data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
  85. data/lib/datadog/appsec/api_security/route_extractor.rb +38 -9
  86. data/lib/datadog/appsec/api_security/sampler.rb +7 -4
  87. data/lib/datadog/appsec/assets/blocked.html +10 -1
  88. data/lib/datadog/appsec/assets/blocked.json +1 -1
  89. data/lib/datadog/appsec/assets/blocked.text +3 -1
  90. data/lib/datadog/appsec/assets/waf_rules/README.md +30 -36
  91. data/lib/datadog/appsec/assets/waf_rules/recommended.json +359 -4
  92. data/lib/datadog/appsec/assets/waf_rules/strict.json +43 -2
  93. data/lib/datadog/appsec/assets.rb +1 -1
  94. data/lib/datadog/appsec/autoload.rb +1 -1
  95. data/lib/datadog/appsec/component.rb +16 -9
  96. data/lib/datadog/appsec/compressed_json.rb +3 -3
  97. data/lib/datadog/appsec/configuration.rb +427 -1
  98. data/lib/datadog/appsec/context.rb +51 -13
  99. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +3 -1
  100. data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
  101. data/lib/datadog/appsec/contrib/active_record/patcher.rb +4 -1
  102. data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +75 -0
  103. data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +39 -0
  104. data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +30 -0
  105. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +144 -0
  106. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
  107. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +2 -1
  108. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  109. data/lib/datadog/appsec/contrib/excon/patcher.rb +3 -1
  110. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +152 -12
  111. data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
  112. data/lib/datadog/appsec/contrib/faraday/patcher.rb +1 -1
  113. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +138 -12
  114. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +74 -24
  115. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +4 -2
  116. data/lib/datadog/appsec/contrib/graphql/integration.rb +2 -1
  117. data/lib/datadog/appsec/contrib/rack/buffered_input.rb +83 -0
  118. data/lib/datadog/appsec/contrib/rack/ext.rb +1 -1
  119. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +52 -13
  120. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +40 -19
  121. data/lib/datadog/appsec/contrib/rack/input_peeker.rb +79 -0
  122. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  123. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +48 -33
  124. data/lib/datadog/appsec/contrib/rack/response_body.rb +36 -0
  125. data/lib/datadog/appsec/contrib/rails/gateway/request.rb +40 -1
  126. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +26 -5
  127. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  128. data/lib/datadog/appsec/contrib/rails/patcher.rb +38 -0
  129. data/lib/datadog/appsec/contrib/rails/patches/process_action_patch.rb +2 -0
  130. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  131. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +3 -1
  132. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +167 -11
  133. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +43 -13
  134. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  135. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +4 -4
  136. data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +1 -1
  137. data/lib/datadog/appsec/counter_sampler.rb +25 -0
  138. data/lib/datadog/appsec/default_header_tags.rb +52 -0
  139. data/lib/datadog/appsec/event.rb +13 -31
  140. data/lib/datadog/appsec/ext.rb +3 -0
  141. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +2 -3
  142. data/lib/datadog/appsec/instrumentation/gateway.rb +2 -15
  143. data/lib/datadog/appsec/metrics/collector.rb +43 -5
  144. data/lib/datadog/appsec/metrics/exporter.rb +16 -3
  145. data/lib/datadog/appsec/metrics/telemetry.rb +20 -3
  146. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +20 -1
  147. data/lib/datadog/appsec/metrics.rb +5 -5
  148. data/lib/datadog/appsec/monitor/gateway/watcher.rb +8 -6
  149. data/lib/datadog/appsec/remote.rb +44 -29
  150. data/lib/datadog/appsec/response.rb +18 -4
  151. data/lib/datadog/appsec/route_normalizer/rails_route_pattern.rb +176 -0
  152. data/lib/datadog/appsec/route_normalizer/route_pattern.rb +378 -0
  153. data/lib/datadog/appsec/route_normalizer/route_text.rb +57 -0
  154. data/lib/datadog/appsec/route_normalizer.rb +80 -0
  155. data/lib/datadog/appsec/security_engine/engine.rb +26 -5
  156. data/lib/datadog/appsec/security_engine/result.rb +29 -9
  157. data/lib/datadog/appsec/security_engine/runner.rb +20 -10
  158. data/lib/datadog/appsec/security_event.rb +5 -7
  159. data/lib/datadog/appsec/trace_keeper.rb +18 -6
  160. data/lib/datadog/appsec/utils/http/body.rb +38 -0
  161. data/lib/datadog/appsec/utils/http/body_reader.rb +61 -0
  162. data/lib/datadog/appsec/utils/http/media_range.rb +2 -1
  163. data/lib/datadog/appsec/utils/http/media_type.rb +32 -26
  164. data/lib/datadog/appsec/utils/http/url_encoded.rb +52 -0
  165. data/lib/datadog/appsec.rb +6 -3
  166. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +2 -2
  167. data/lib/datadog/core/configuration/base.rb +17 -5
  168. data/lib/datadog/core/configuration/components.rb +185 -17
  169. data/lib/datadog/core/configuration/components_state.rb +6 -1
  170. data/lib/datadog/core/configuration/config_helper.rb +11 -2
  171. data/lib/datadog/core/configuration/deprecations.rb +2 -2
  172. data/lib/datadog/core/configuration/option.rb +32 -6
  173. data/lib/datadog/core/configuration/option_definition.rb +42 -14
  174. data/lib/datadog/core/configuration/options.rb +49 -12
  175. data/lib/datadog/core/configuration/settings.rb +115 -16
  176. data/lib/datadog/core/configuration/stable_config.rb +10 -0
  177. data/lib/datadog/core/configuration/supported_configurations.rb +379 -300
  178. data/lib/datadog/core/configuration.rb +3 -3
  179. data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
  180. data/lib/datadog/core/contrib/rails/utils.rb +7 -3
  181. data/lib/datadog/core/crashtracking/component.rb +73 -21
  182. data/lib/datadog/core/crashtracking/tag_builder.rb +6 -0
  183. data/lib/datadog/core/ddsketch.rb +19 -0
  184. data/lib/datadog/core/diagnostics/environment_logger.rb +3 -1
  185. data/lib/datadog/core/environment/agent_info.rb +65 -1
  186. data/lib/datadog/core/environment/cgroup.rb +52 -25
  187. data/lib/datadog/core/environment/container.rb +140 -46
  188. data/lib/datadog/core/environment/ext.rb +13 -0
  189. data/lib/datadog/core/environment/identity.rb +40 -4
  190. data/lib/datadog/core/environment/process.rb +122 -0
  191. data/lib/datadog/core/environment/socket.rb +13 -0
  192. data/lib/datadog/core/environment/yjit.rb +2 -1
  193. data/lib/datadog/core/error.rb +6 -6
  194. data/lib/datadog/core/evp.rb +11 -0
  195. data/lib/datadog/core/feature_flags.rb +61 -0
  196. data/lib/datadog/core/knuth_sampler.rb +59 -0
  197. data/lib/datadog/core/logger.rb +1 -1
  198. data/lib/datadog/core/metrics/client.rb +6 -6
  199. data/lib/datadog/core/metrics/logging.rb +1 -1
  200. data/lib/datadog/core/pin.rb +8 -8
  201. data/lib/datadog/core/process_discovery.rb +21 -18
  202. data/lib/datadog/core/rate_limiter.rb +11 -1
  203. data/lib/datadog/core/remote/client/capabilities.rb +49 -6
  204. data/lib/datadog/core/remote/client.rb +15 -7
  205. data/lib/datadog/core/remote/component.rb +64 -36
  206. data/lib/datadog/core/remote/configuration/content.rb +15 -2
  207. data/lib/datadog/core/remote/configuration/digest.rb +14 -7
  208. data/lib/datadog/core/remote/configuration/repository.rb +1 -1
  209. data/lib/datadog/core/remote/configuration/target.rb +13 -6
  210. data/lib/datadog/core/remote/transport/config.rb +9 -36
  211. data/lib/datadog/core/remote/transport/http/config.rb +15 -55
  212. data/lib/datadog/core/remote/transport/http/negotiation.rb +14 -44
  213. data/lib/datadog/core/remote/transport/http.rb +15 -24
  214. data/lib/datadog/core/remote/transport/negotiation.rb +8 -33
  215. data/lib/datadog/core/remote/worker.rb +25 -37
  216. data/lib/datadog/core/runtime/metrics.rb +11 -2
  217. data/lib/datadog/core/semaphore.rb +1 -4
  218. data/lib/datadog/core/tag_builder.rb +0 -4
  219. data/lib/datadog/core/tag_normalizer.rb +84 -0
  220. data/lib/datadog/core/telemetry/component.rb +59 -15
  221. data/lib/datadog/core/telemetry/emitter.rb +6 -6
  222. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +2 -3
  223. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
  224. data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
  225. data/lib/datadog/core/telemetry/event/app_started.rb +177 -171
  226. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
  227. data/lib/datadog/core/telemetry/event.rb +2 -7
  228. data/lib/datadog/core/telemetry/ext.rb +1 -0
  229. data/lib/datadog/core/telemetry/logger.rb +4 -2
  230. data/lib/datadog/core/telemetry/logging.rb +17 -5
  231. data/lib/datadog/core/telemetry/metrics_manager.rb +9 -0
  232. data/lib/datadog/core/telemetry/request.rb +17 -5
  233. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +8 -34
  234. data/lib/datadog/core/telemetry/transport/http.rb +21 -16
  235. data/lib/datadog/core/telemetry/transport/telemetry.rb +8 -17
  236. data/lib/datadog/core/telemetry/worker.rb +108 -32
  237. data/lib/datadog/core/transport/ext.rb +3 -0
  238. data/lib/datadog/core/transport/http/api/endpoint.rb +9 -4
  239. data/lib/datadog/core/transport/http/api/instance.rb +4 -21
  240. data/lib/datadog/core/transport/http/builder.rb +10 -6
  241. data/lib/datadog/core/transport/http/client.rb +80 -0
  242. data/lib/datadog/core/transport/http/response.rb +4 -0
  243. data/lib/datadog/core/transport/http.rb +24 -19
  244. data/lib/datadog/core/transport/parcel.rb +61 -9
  245. data/lib/datadog/core/transport/response.rb +16 -2
  246. data/lib/datadog/core/transport/transport.rb +90 -0
  247. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +2 -2
  248. data/lib/datadog/core/utils/{base64.rb → base64_codec.rb} +4 -3
  249. data/lib/datadog/core/utils/enumerable_compat.rb +29 -0
  250. data/lib/datadog/core/utils/fnv.rb +26 -0
  251. data/lib/datadog/core/utils/forking.rb +3 -1
  252. data/lib/datadog/core/utils/hash.rb +0 -23
  253. data/lib/datadog/{appsec/api_security → core/utils}/lru_cache.rb +10 -21
  254. data/lib/datadog/core/utils/network.rb +22 -1
  255. data/lib/datadog/core/utils/only_once.rb +1 -1
  256. data/lib/datadog/core/utils/only_once_successful.rb +8 -2
  257. data/lib/datadog/core/utils/safe_dup.rb +2 -2
  258. data/lib/datadog/core/utils/sequence.rb +2 -0
  259. data/lib/datadog/core/utils/spawn_monkey_patch.rb +68 -0
  260. data/lib/datadog/core/utils/time.rb +6 -2
  261. data/lib/datadog/core/utils.rb +3 -1
  262. data/lib/datadog/core/workers/async.rb +11 -2
  263. data/lib/datadog/core/workers/interval_loop.rb +51 -3
  264. data/lib/datadog/core/workers/polling.rb +2 -0
  265. data/lib/datadog/core/workers/queue.rb +96 -1
  266. data/lib/datadog/core/workers/runtime_metrics.rb +9 -1
  267. data/lib/datadog/core.rb +10 -3
  268. data/lib/datadog/data_streams/configuration.rb +50 -0
  269. data/lib/datadog/data_streams/ext.rb +11 -0
  270. data/lib/datadog/data_streams/extensions.rb +16 -0
  271. data/lib/datadog/data_streams/pathway_context.rb +169 -0
  272. data/lib/datadog/data_streams/processor.rb +511 -0
  273. data/lib/datadog/data_streams/transport/http/stats.rb +58 -0
  274. data/lib/datadog/data_streams/transport/http.rb +36 -0
  275. data/lib/datadog/data_streams/transport/stats.rb +39 -0
  276. data/lib/datadog/data_streams.rb +100 -0
  277. data/lib/datadog/di/base.rb +15 -7
  278. data/lib/datadog/di/boot.rb +7 -2
  279. data/lib/datadog/di/capture_expression.rb +21 -0
  280. data/lib/datadog/di/capture_expression_evaluator.rb +71 -0
  281. data/lib/datadog/di/capture_limits.rb +41 -0
  282. data/lib/datadog/di/code_tracker.rb +217 -15
  283. data/lib/datadog/di/component.rb +139 -51
  284. data/lib/datadog/di/configuration.rb +241 -2
  285. data/lib/datadog/di/context.rb +82 -0
  286. data/lib/datadog/di/contrib/active_record.rb +34 -5
  287. data/lib/datadog/di/el/compiler.rb +168 -0
  288. data/lib/datadog/di/el/evaluator.rb +159 -0
  289. data/lib/datadog/di/el/expression.rb +42 -0
  290. data/lib/datadog/di/el.rb +5 -0
  291. data/lib/datadog/di/error.rb +44 -0
  292. data/lib/datadog/di/fatal_exceptions.rb +26 -0
  293. data/lib/datadog/di/instrumenter.rb +623 -147
  294. data/lib/datadog/di/logger.rb +2 -2
  295. data/lib/datadog/di/probe.rb +122 -14
  296. data/lib/datadog/di/probe_builder.rb +124 -3
  297. data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
  298. data/lib/datadog/di/probe_file_loader.rb +12 -7
  299. data/lib/datadog/di/probe_manager.rb +195 -100
  300. data/lib/datadog/di/probe_notification_builder.rb +321 -90
  301. data/lib/datadog/di/probe_notifier_worker.rb +112 -36
  302. data/lib/datadog/di/probe_repository.rb +198 -0
  303. data/lib/datadog/di/proc_responder.rb +36 -0
  304. data/lib/datadog/di/redactor.rb +24 -2
  305. data/lib/datadog/di/remote.rb +258 -93
  306. data/lib/datadog/di/serializer.rb +310 -29
  307. data/lib/datadog/di/transport/diagnostics.rb +12 -42
  308. data/lib/datadog/di/transport/http/diagnostics.rb +4 -34
  309. data/lib/datadog/di/transport/http/input.rb +2 -34
  310. data/lib/datadog/di/transport/http.rb +43 -19
  311. data/lib/datadog/di/transport/input.rb +112 -38
  312. data/lib/datadog/di/utils.rb +42 -14
  313. data/lib/datadog/di.rb +204 -4
  314. data/lib/datadog/error_tracking/collector.rb +2 -1
  315. data/lib/datadog/error_tracking/component.rb +2 -2
  316. data/lib/datadog/error_tracking/configuration.rb +55 -2
  317. data/lib/datadog/error_tracking/filters.rb +2 -2
  318. data/lib/datadog/kit/appsec/events/v2.rb +60 -3
  319. data/lib/datadog/kit/enable_core_dumps.rb +1 -1
  320. data/lib/datadog/kit/tracing/method_tracer.rb +135 -0
  321. data/lib/datadog/open_feature/component.rb +100 -0
  322. data/lib/datadog/open_feature/configuration.rb +37 -0
  323. data/lib/datadog/open_feature/evaluation_engine.rb +70 -0
  324. data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
  325. data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
  326. data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
  327. data/lib/datadog/open_feature/exposures/event.rb +60 -0
  328. data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
  329. data/lib/datadog/open_feature/exposures/worker.rb +116 -0
  330. data/lib/datadog/open_feature/ext.rb +16 -0
  331. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +286 -0
  332. data/lib/datadog/open_feature/flag_evaluation/writer.rb +433 -0
  333. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +101 -0
  334. data/lib/datadog/open_feature/hooks/flag_eval_metrics_hook.rb +49 -0
  335. data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
  336. data/lib/datadog/open_feature/native_evaluator.rb +60 -0
  337. data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
  338. data/lib/datadog/open_feature/provider.rb +191 -0
  339. data/lib/datadog/open_feature/remote.rb +67 -0
  340. data/lib/datadog/open_feature/resolution_details.rb +35 -0
  341. data/lib/datadog/open_feature/transport.rb +121 -0
  342. data/lib/datadog/open_feature.rb +19 -0
  343. data/lib/datadog/opentelemetry/api/baggage.rb +1 -1
  344. data/lib/datadog/opentelemetry/configuration/settings.rb +226 -0
  345. data/lib/datadog/opentelemetry/ext.rb +9 -0
  346. data/lib/datadog/opentelemetry/logs.rb +98 -0
  347. data/lib/datadog/opentelemetry/metrics.rb +90 -0
  348. data/lib/datadog/opentelemetry/sdk/configurator.rb +65 -1
  349. data/lib/datadog/opentelemetry/sdk/id_generator.rb +16 -10
  350. data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +30 -0
  351. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +28 -0
  352. data/lib/datadog/opentelemetry/sdk/propagator.rb +9 -3
  353. data/lib/datadog/opentelemetry/sdk/span_processor.rb +4 -1
  354. data/lib/datadog/opentelemetry/sdk.rb +19 -0
  355. data/lib/datadog/opentelemetry/signal_configuration.rb +53 -0
  356. data/lib/datadog/opentelemetry.rb +4 -0
  357. data/lib/datadog/profiling/collectors/code_provenance.rb +71 -12
  358. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +52 -4
  359. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +13 -5
  360. data/lib/datadog/profiling/collectors/info.rb +18 -4
  361. data/lib/datadog/profiling/collectors/thread_context.rb +10 -5
  362. data/lib/datadog/profiling/component.rb +82 -40
  363. data/lib/datadog/profiling/exporter.rb +41 -12
  364. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +24 -5
  365. data/lib/datadog/profiling/ext/exec_monkey_patch.rb +32 -0
  366. data/lib/datadog/profiling/ext.rb +0 -2
  367. data/lib/datadog/profiling/flush.rb +23 -11
  368. data/lib/datadog/profiling/http_transport.rb +21 -8
  369. data/lib/datadog/profiling/load_native_extension.rb +2 -2
  370. data/lib/datadog/profiling/profiler.rb +31 -14
  371. data/lib/datadog/profiling/scheduler.rb +10 -9
  372. data/lib/datadog/profiling/stack_recorder.rb +0 -8
  373. data/lib/datadog/profiling/tag_builder.rb +37 -3
  374. data/lib/datadog/profiling/tasks/exec.rb +8 -3
  375. data/lib/datadog/profiling/tasks/help.rb +1 -0
  376. data/lib/datadog/profiling/tasks/setup.rb +2 -2
  377. data/lib/datadog/profiling.rb +1 -3
  378. data/lib/datadog/ruby_version.rb +25 -0
  379. data/lib/datadog/single_step_instrument.rb +2 -2
  380. data/lib/datadog/symbol_database/component.rb +734 -0
  381. data/lib/datadog/symbol_database/configuration.rb +73 -0
  382. data/lib/datadog/symbol_database/extensions.rb +19 -0
  383. data/lib/datadog/symbol_database/extractor.rb +1110 -0
  384. data/lib/datadog/symbol_database/file_hash.rb +48 -0
  385. data/lib/datadog/symbol_database/logger.rb +43 -0
  386. data/lib/datadog/symbol_database/remote.rb +180 -0
  387. data/lib/datadog/symbol_database/scope.rb +102 -0
  388. data/lib/datadog/symbol_database/scope_batcher.rb +292 -0
  389. data/lib/datadog/symbol_database/service_version.rb +66 -0
  390. data/lib/datadog/symbol_database/symbol.rb +69 -0
  391. data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
  392. data/lib/datadog/symbol_database/transport/http.rb +45 -0
  393. data/lib/datadog/symbol_database/transport.rb +54 -0
  394. data/lib/datadog/symbol_database/uploader.rb +230 -0
  395. data/lib/datadog/symbol_database.rb +71 -0
  396. data/lib/datadog/tracing/buffer.rb +3 -3
  397. data/lib/datadog/tracing/component.rb +17 -17
  398. data/lib/datadog/tracing/configuration/dynamic.rb +2 -2
  399. data/lib/datadog/tracing/configuration/ext.rb +22 -0
  400. data/lib/datadog/tracing/configuration/settings.rb +96 -4
  401. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +4 -1
  402. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +4 -1
  403. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +4 -1
  404. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +4 -1
  405. data/lib/datadog/tracing/contrib/action_mailer/event.rb +4 -1
  406. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +10 -7
  407. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +28 -0
  408. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +3 -1
  409. data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -2
  410. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +4 -1
  411. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +5 -2
  412. data/lib/datadog/tracing/contrib/active_job/data_streams.rb +62 -0
  413. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +5 -2
  414. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +5 -2
  415. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +5 -2
  416. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +5 -2
  417. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +5 -2
  418. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +5 -2
  419. data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
  420. data/lib/datadog/tracing/contrib/active_job/patcher.rb +17 -1
  421. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
  422. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +3 -4
  423. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
  424. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
  425. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +2 -5
  426. data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
  427. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +2 -5
  428. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +1 -4
  429. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
  430. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +6 -8
  431. data/lib/datadog/tracing/contrib/component.rb +3 -3
  432. data/lib/datadog/tracing/contrib/configurable.rb +18 -3
  433. data/lib/datadog/tracing/contrib/configuration/resolver.rb +14 -4
  434. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +1 -5
  435. data/lib/datadog/tracing/contrib/dalli/integration.rb +4 -1
  436. data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -1
  437. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +2 -0
  438. data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +1 -0
  439. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +2 -6
  440. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +2 -2
  441. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +5 -1
  442. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +5 -6
  443. data/lib/datadog/tracing/contrib/ethon/ext.rb +1 -0
  444. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +1 -8
  445. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +16 -5
  446. data/lib/datadog/tracing/contrib/excon/ext.rb +1 -0
  447. data/lib/datadog/tracing/contrib/excon/middleware.rb +3 -7
  448. data/lib/datadog/tracing/contrib/ext.rb +3 -1
  449. data/lib/datadog/tracing/contrib/extensions.rb +19 -2
  450. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +16 -9
  451. data/lib/datadog/tracing/contrib/faraday/ext.rb +1 -0
  452. data/lib/datadog/tracing/contrib/faraday/middleware.rb +3 -7
  453. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +7 -3
  454. data/lib/datadog/tracing/contrib/grape/endpoint.rb +10 -7
  455. data/lib/datadog/tracing/contrib/grape/instrumentation.rb +13 -8
  456. data/lib/datadog/tracing/contrib/grape/patcher.rb +6 -1
  457. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +7 -0
  458. data/lib/datadog/tracing/contrib/graphql/ext.rb +1 -0
  459. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +75 -44
  460. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +5 -2
  461. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +3 -7
  462. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +3 -7
  463. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +2 -0
  464. data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
  465. data/lib/datadog/tracing/contrib/grpc.rb +1 -0
  466. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +1 -0
  467. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +1 -0
  468. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +1 -0
  469. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +16 -5
  470. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +2 -0
  471. data/lib/datadog/tracing/contrib/http/ext.rb +1 -0
  472. data/lib/datadog/tracing/contrib/http/instrumentation.rb +4 -8
  473. data/lib/datadog/tracing/contrib/http/integration.rb +0 -2
  474. data/lib/datadog/tracing/contrib/http.rb +1 -0
  475. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +16 -5
  476. data/lib/datadog/tracing/contrib/httpclient/ext.rb +1 -0
  477. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +7 -7
  478. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +16 -5
  479. data/lib/datadog/tracing/contrib/httprb/ext.rb +1 -0
  480. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +4 -8
  481. data/lib/datadog/tracing/contrib/kafka/event.rb +1 -0
  482. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
  483. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
  484. data/lib/datadog/tracing/contrib/kafka/patcher.rb +14 -0
  485. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +5 -1
  486. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
  487. data/lib/datadog/tracing/contrib/karafka/ext.rb +1 -0
  488. data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
  489. data/lib/datadog/tracing/contrib/karafka/monitor.rb +11 -0
  490. data/lib/datadog/tracing/contrib/karafka/patcher.rb +35 -4
  491. data/lib/datadog/tracing/contrib/karafka.rb +1 -0
  492. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +5 -5
  493. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +5 -8
  494. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +6 -0
  495. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +3 -6
  496. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +2 -6
  497. data/lib/datadog/tracing/contrib/opensearch/quantize.rb +2 -2
  498. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +6 -0
  499. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +15 -18
  500. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +6 -8
  501. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +13 -0
  502. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +6 -2
  503. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +24 -0
  504. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +5 -2
  505. data/lib/datadog/tracing/contrib/que/ext.rb +1 -0
  506. data/lib/datadog/tracing/contrib/que/tracer.rb +1 -0
  507. data/lib/datadog/tracing/contrib/racecar/event.rb +1 -5
  508. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +11 -1
  509. data/lib/datadog/tracing/contrib/rack/ext.rb +28 -0
  510. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +23 -0
  511. data/lib/datadog/tracing/contrib/rack/middlewares.rb +62 -27
  512. data/lib/datadog/tracing/contrib/rack/patcher.rb +2 -2
  513. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  514. data/lib/datadog/tracing/contrib/rack/route_inference.rb +67 -0
  515. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +119 -1
  516. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +5 -2
  517. data/lib/datadog/tracing/contrib/rails/ext.rb +1 -0
  518. data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
  519. data/lib/datadog/tracing/contrib/rails/middlewares.rb +2 -2
  520. data/lib/datadog/tracing/contrib/rails/patcher.rb +0 -1
  521. data/lib/datadog/tracing/contrib/rails/runner.rb +3 -1
  522. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +6 -4
  523. data/lib/datadog/tracing/contrib/redis/quantize.rb +1 -1
  524. data/lib/datadog/tracing/contrib/redis/tags.rb +1 -6
  525. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +2 -0
  526. data/lib/datadog/tracing/contrib/registerable.rb +11 -0
  527. data/lib/datadog/tracing/contrib/resque/resque_job.rb +1 -0
  528. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +5 -2
  529. data/lib/datadog/tracing/contrib/rest_client/ext.rb +1 -0
  530. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -6
  531. data/lib/datadog/tracing/contrib/roda/ext.rb +1 -0
  532. data/lib/datadog/tracing/contrib/roda/instrumentation.rb +7 -2
  533. data/lib/datadog/tracing/contrib/sequel/database.rb +1 -0
  534. data/lib/datadog/tracing/contrib/sequel/dataset.rb +1 -0
  535. data/lib/datadog/tracing/contrib/sequel/utils.rb +2 -7
  536. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +1 -0
  537. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +1 -0
  538. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +5 -1
  539. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +2 -0
  540. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
  541. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +2 -0
  542. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +1 -0
  543. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/redis_info.rb +1 -0
  544. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +2 -0
  545. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/stop.rb +1 -0
  546. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +3 -2
  547. data/lib/datadog/tracing/contrib/sidekiq/utils.rb +1 -1
  548. data/lib/datadog/tracing/contrib/sidekiq.rb +1 -0
  549. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +5 -1
  550. data/lib/datadog/tracing/contrib/sinatra/ext.rb +1 -0
  551. data/lib/datadog/tracing/contrib/sinatra/framework.rb +1 -1
  552. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +1 -0
  553. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +4 -1
  554. data/lib/datadog/tracing/contrib/sneakers/integration.rb +15 -4
  555. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +1 -0
  556. data/lib/datadog/tracing/contrib/status_range_matcher.rb +13 -1
  557. data/lib/datadog/tracing/contrib/stripe/request.rb +1 -1
  558. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +1 -0
  559. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +6 -0
  560. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -6
  561. data/lib/datadog/tracing/contrib/utils/quantization/{hash.rb → hash_formatter.rb} +4 -2
  562. data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +31 -0
  563. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +50 -0
  564. data/lib/datadog/tracing/contrib/waterdrop/ext.rb +18 -0
  565. data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
  566. data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
  567. data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +49 -0
  568. data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
  569. data/lib/datadog/tracing/contrib/waterdrop.rb +42 -0
  570. data/lib/datadog/tracing/contrib.rb +9 -0
  571. data/lib/datadog/tracing/diagnostics/environment_logger.rb +4 -2
  572. data/lib/datadog/tracing/distributed/baggage.rb +64 -8
  573. data/lib/datadog/tracing/distributed/datadog.rb +13 -11
  574. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -14
  575. data/lib/datadog/tracing/distributed/propagation.rb +35 -3
  576. data/lib/datadog/tracing/distributed/trace_context.rb +85 -62
  577. data/lib/datadog/tracing/event.rb +1 -1
  578. data/lib/datadog/tracing/ext.rb +9 -0
  579. data/lib/datadog/tracing/metadata/ext.rb +23 -1
  580. data/lib/datadog/tracing/metadata/tagging.rb +2 -2
  581. data/lib/datadog/tracing/pipeline.rb +1 -1
  582. data/lib/datadog/tracing/remote.rb +36 -13
  583. data/lib/datadog/tracing/sampling/ext.rb +2 -0
  584. data/lib/datadog/tracing/sampling/priority_sampler.rb +16 -1
  585. data/lib/datadog/tracing/sampling/rate_sampler.rb +8 -19
  586. data/lib/datadog/tracing/sampling/rule.rb +1 -1
  587. data/lib/datadog/tracing/sampling/rule_sampler.rb +54 -25
  588. data/lib/datadog/tracing/sampling/span/rule_parser.rb +2 -2
  589. data/lib/datadog/tracing/span.rb +1 -1
  590. data/lib/datadog/tracing/span_event.rb +2 -2
  591. data/lib/datadog/tracing/span_operation.rb +34 -10
  592. data/lib/datadog/tracing/sync_writer.rb +0 -1
  593. data/lib/datadog/tracing/trace_digest.rb +7 -0
  594. data/lib/datadog/tracing/trace_operation.rb +123 -16
  595. data/lib/datadog/tracing/tracer.rb +82 -23
  596. data/lib/datadog/tracing/transport/http/client.rb +12 -26
  597. data/lib/datadog/tracing/transport/http/traces.rb +2 -50
  598. data/lib/datadog/tracing/transport/http.rb +15 -9
  599. data/lib/datadog/tracing/transport/io/client.rb +6 -9
  600. data/lib/datadog/tracing/transport/io/traces.rb +28 -34
  601. data/lib/datadog/tracing/transport/trace_formatter.rb +22 -0
  602. data/lib/datadog/tracing/transport/traces.rb +13 -81
  603. data/lib/datadog/tracing/workers.rb +2 -1
  604. data/lib/datadog/tracing/writer.rb +1 -1
  605. data/lib/datadog/version.rb +2 -2
  606. data/lib/datadog.rb +8 -1
  607. metadata +185 -36
  608. data/ext/datadog_profiling_native_extension/clock_id_noop.c +0 -21
  609. data/ext/libdatadog_api/macos_development.md +0 -26
  610. data/lib/datadog/appsec/configuration/settings.rb +0 -400
  611. data/lib/datadog/appsec/contrib/rails/ext.rb +0 -13
  612. data/lib/datadog/core/remote/transport/http/api.rb +0 -53
  613. data/lib/datadog/core/remote/transport/http/client.rb +0 -49
  614. data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
  615. data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
  616. data/lib/datadog/core/transport/http/api/spec.rb +0 -36
  617. data/lib/datadog/di/configuration/settings.rb +0 -212
  618. data/lib/datadog/di/transport/http/api.rb +0 -42
  619. data/lib/datadog/di/transport/http/client.rb +0 -47
  620. data/lib/datadog/error_tracking/configuration/settings.rb +0 -63
  621. data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
  622. data/lib/datadog/tracing/transport/http/api.rb +0 -44
  623. data/lib/datadog/tracing/workers/trace_writer.rb +0 -199
@@ -9,6 +9,7 @@
9
9
  #include "time_helpers.h"
10
10
  #include "heap_recorder.h"
11
11
  #include "encoded_profile.h"
12
+ #include "collectors_thread_context.h"
12
13
 
13
14
  // Used to wrap a ddog_prof_Profile in a Ruby object and expose Ruby-level serialization APIs
14
15
  // This file implements the native bits of the Datadog::Profiling::StackRecorder class
@@ -131,46 +132,32 @@
131
132
  static VALUE ok_symbol = Qnil; // :ok in Ruby
132
133
  static VALUE error_symbol = Qnil; // :error in Ruby
133
134
 
134
- // Note: Please DO NOT use `VALUE_STRING` anywhere else, instead use `DDOG_CHARSLICE_C`.
135
- // `VALUE_STRING` is only needed because older versions of gcc (4.9.2, used in our Ruby 2.2 CI test images)
136
- // tripped when compiling `enabled_value_types` using `-std=gnu99` due to the extra cast that is included in
137
- // `DDOG_CHARSLICE_C` with the following error:
138
- //
139
- // ```
140
- // compiling ../../../../ext/ddtrace_profiling_native_extension/stack_recorder.c
141
- // ../../../../ext/ddtrace_profiling_native_extension/stack_recorder.c:23:1: error: initializer element is not constant
142
- // static const ddog_prof_ValueType enabled_value_types[] = {CPU_TIME_VALUE, CPU_SAMPLES_VALUE, WALL_TIME_VALUE};
143
- // ^
144
- // ```
145
- #define VALUE_STRING(string) {.ptr = "" string, .len = sizeof(string) - 1}
146
-
147
- #define CPU_TIME_VALUE {.type_ = VALUE_STRING("cpu-time"), .unit = VALUE_STRING("nanoseconds")}
148
135
  #define CPU_TIME_VALUE_ID 0
149
- #define CPU_SAMPLES_VALUE {.type_ = VALUE_STRING("cpu-samples"), .unit = VALUE_STRING("count")}
150
136
  #define CPU_SAMPLES_VALUE_ID 1
151
- #define WALL_TIME_VALUE {.type_ = VALUE_STRING("wall-time"), .unit = VALUE_STRING("nanoseconds")}
152
137
  #define WALL_TIME_VALUE_ID 2
153
- #define ALLOC_SAMPLES_VALUE {.type_ = VALUE_STRING("alloc-samples"), .unit = VALUE_STRING("count")}
154
138
  #define ALLOC_SAMPLES_VALUE_ID 3
155
- #define ALLOC_SAMPLES_UNSCALED_VALUE {.type_ = VALUE_STRING("alloc-samples-unscaled"), .unit = VALUE_STRING("count")}
156
139
  #define ALLOC_SAMPLES_UNSCALED_VALUE_ID 4
157
- #define HEAP_SAMPLES_VALUE {.type_ = VALUE_STRING("heap-live-samples"), .unit = VALUE_STRING("count")}
158
140
  #define HEAP_SAMPLES_VALUE_ID 5
159
- #define HEAP_SIZE_VALUE {.type_ = VALUE_STRING("heap-live-size"), .unit = VALUE_STRING("bytes")}
160
141
  #define HEAP_SIZE_VALUE_ID 6
161
- #define TIMELINE_VALUE {.type_ = VALUE_STRING("timeline"), .unit = VALUE_STRING("nanoseconds")}
162
142
  #define TIMELINE_VALUE_ID 7
163
143
 
164
- static const ddog_prof_ValueType all_value_types[] =
165
- {CPU_TIME_VALUE, CPU_SAMPLES_VALUE, WALL_TIME_VALUE, ALLOC_SAMPLES_VALUE, ALLOC_SAMPLES_UNSCALED_VALUE, HEAP_SAMPLES_VALUE, HEAP_SIZE_VALUE, TIMELINE_VALUE};
144
+ static const ddog_prof_SampleType all_sample_types[] = {
145
+ DDOG_PROF_SAMPLE_TYPE_CPU_TIME,
146
+ DDOG_PROF_SAMPLE_TYPE_CPU_SAMPLES,
147
+ DDOG_PROF_SAMPLE_TYPE_WALL_TIME,
148
+ DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES,
149
+ DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES_UNSCALED,
150
+ DDOG_PROF_SAMPLE_TYPE_HEAP_LIVE_SAMPLES,
151
+ DDOG_PROF_SAMPLE_TYPE_HEAP_LIVE_SIZE,
152
+ DDOG_PROF_SAMPLE_TYPE_TIMELINE,
153
+ };
166
154
 
167
- // This array MUST be kept in sync with all_value_types above and is intended to act as a "hashmap" between VALUE_ID and the position it
168
- // occupies on the all_value_types array.
169
- // E.g. all_value_types_positions[CPU_TIME_VALUE_ID] => 0, means that CPU_TIME_VALUE was declared at position 0 of all_value_types.
155
+ // This array MUST be kept in sync with all_sample_types above and is intended to act as a "hashmap" between VALUE_ID and the position it
156
+ // occupies on the all_sample_types array.
170
157
  static const uint8_t all_value_types_positions[] =
171
158
  {CPU_TIME_VALUE_ID, CPU_SAMPLES_VALUE_ID, WALL_TIME_VALUE_ID, ALLOC_SAMPLES_VALUE_ID, ALLOC_SAMPLES_UNSCALED_VALUE_ID, HEAP_SAMPLES_VALUE_ID, HEAP_SIZE_VALUE_ID, TIMELINE_VALUE_ID};
172
159
 
173
- #define ALL_VALUE_TYPES_COUNT (sizeof(all_value_types) / sizeof(ddog_prof_ValueType))
160
+ #define ALL_VALUE_TYPES_COUNT (sizeof(all_sample_types) / sizeof(ddog_prof_SampleType))
174
161
 
175
162
  // Struct for storing stats related to a profile in a particular slot.
176
163
  // These stats will share the same lifetime as the data in that profile slot.
@@ -191,6 +178,10 @@ typedef struct {
191
178
  heap_recorder *heap_recorder;
192
179
  bool heap_clean_after_gc_enabled;
193
180
 
181
+ // When set, _native_serialize will call thread_context_collector_on_serialize on this instance
182
+ // before serializing, so that threads suspended across the whole profile period still get sampled.
183
+ VALUE thread_context_collector_instance;
184
+
194
185
  pthread_mutex_t mutex_slot_one;
195
186
  profile_slot profile_slot_one;
196
187
  pthread_mutex_t mutex_slot_two;
@@ -242,7 +233,8 @@ typedef struct {
242
233
 
243
234
  static VALUE _native_new(VALUE klass);
244
235
  static void initialize_slot_concurrency_control(stack_recorder_state *state);
245
- static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types);
236
+ static void stack_recorder_typed_data_mark(void *data);
237
+ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_SampleType sample_types);
246
238
  static void stack_recorder_typed_data_free(void *data);
247
239
  static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
248
240
  static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
@@ -271,6 +263,7 @@ static VALUE _native_heap_recorder_reset_last_update(DDTRACE_UNUSED VALUE _self,
271
263
  static VALUE _native_recorder_after_gc_step(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
272
264
  static VALUE _native_benchmark_intern(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE string, VALUE times, VALUE use_all);
273
265
  static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE_UNUSED VALUE _self);
266
+ static VALUE _native_finalize_pending_heap_recordings(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
274
267
 
275
268
  void stack_recorder_init(VALUE profiling_module) {
276
269
  VALUE stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
@@ -307,6 +300,7 @@ void stack_recorder_init(VALUE profiling_module) {
307
300
  rb_define_singleton_method(testing_module, "_native_recorder_after_gc_step", _native_recorder_after_gc_step, 1);
308
301
  rb_define_singleton_method(testing_module, "_native_benchmark_intern", _native_benchmark_intern, 4);
309
302
  rb_define_singleton_method(testing_module, "_native_test_managed_string_storage_produces_valid_profiles", _native_test_managed_string_storage_produces_valid_profiles, 0);
303
+ rb_define_singleton_method(testing_module, "_native_finalize_pending_heap_recordings", _native_finalize_pending_heap_recordings, 1);
310
304
 
311
305
  ok_symbol = ID2SYM(rb_intern_const("ok"));
312
306
  error_symbol = ID2SYM(rb_intern_const("error"));
@@ -317,9 +311,9 @@ void stack_recorder_init(VALUE profiling_module) {
317
311
  static const rb_data_type_t stack_recorder_typed_data = {
318
312
  .wrap_struct_name = "Datadog::Profiling::StackRecorder",
319
313
  .function = {
314
+ .dmark = stack_recorder_typed_data_mark,
320
315
  .dfree = stack_recorder_typed_data_free,
321
316
  .dsize = NULL, // We don't track profile memory usage (although it'd be cool if we did!)
322
- // No need to provide dmark nor dcompact because we don't directly reference Ruby VALUEs from inside this object
323
317
  },
324
318
  .flags = RUBY_TYPED_FREE_IMMEDIATELY
325
319
  };
@@ -331,8 +325,9 @@ static VALUE _native_new(VALUE klass) {
331
325
  // being leaked.
332
326
 
333
327
  state->heap_clean_after_gc_enabled = false;
328
+ state->thread_context_collector_instance = Qnil;
334
329
 
335
- ddog_prof_Slice_ValueType sample_types = {.ptr = all_value_types, .len = ALL_VALUE_TYPES_COUNT};
330
+ ddog_prof_Slice_SampleType sample_types = {.ptr = all_sample_types, .len = ALL_VALUE_TYPES_COUNT};
336
331
 
337
332
  initialize_slot_concurrency_control(state);
338
333
  for (uint8_t i = 0; i < ALL_VALUE_TYPES_COUNT; i++) { state->position_for[i] = all_value_types_positions[i]; }
@@ -349,7 +344,7 @@ static VALUE _native_new(VALUE klass) {
349
344
  ddog_prof_ManagedStringStorageNewResult string_storage = ddog_prof_ManagedStringStorage_new();
350
345
 
351
346
  if (string_storage.tag == DDOG_PROF_MANAGED_STRING_STORAGE_NEW_RESULT_ERR) {
352
- rb_raise(rb_eRuntimeError, "Failed to initialize string storage: %"PRIsVALUE, get_error_details_and_drop(&string_storage.err));
347
+ raise_error(rb_eRuntimeError, "Failed to initialize string storage: %"PRIsVALUE, get_error_details_and_drop(&string_storage.err));
353
348
  }
354
349
 
355
350
  state->string_storage = string_storage.ok;
@@ -376,14 +371,14 @@ static void initialize_slot_concurrency_control(stack_recorder_state *state) {
376
371
  state->active_slot = 1;
377
372
  }
378
373
 
379
- static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
374
+ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_SampleType sample_types) {
380
375
  ddog_Timespec start_timestamp = system_epoch_now_timespec();
381
376
 
382
377
  ddog_prof_Profile_NewResult slot_one_profile_result =
383
378
  ddog_prof_Profile_with_string_storage(sample_types, NULL /* period is optional */, state->string_storage);
384
379
 
385
380
  if (slot_one_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
386
- rb_raise(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
381
+ raise_error(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
387
382
  }
388
383
 
389
384
  state->profile_slot_one = (profile_slot) { .profile = slot_one_profile_result.ok, .start_timestamp = start_timestamp };
@@ -393,12 +388,19 @@ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_Val
393
388
 
394
389
  if (slot_two_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
395
390
  // Note: No need to take any special care of slot one, it'll get cleaned up by stack_recorder_typed_data_free
396
- rb_raise(rb_eRuntimeError, "Failed to initialize slot two profile: %"PRIsVALUE, get_error_details_and_drop(&slot_two_profile_result.err));
391
+ raise_error(rb_eRuntimeError, "Failed to initialize slot two profile: %"PRIsVALUE, get_error_details_and_drop(&slot_two_profile_result.err));
397
392
  }
398
393
 
399
394
  state->profile_slot_two = (profile_slot) { .profile = slot_two_profile_result.ok, .start_timestamp = start_timestamp };
400
395
  }
401
396
 
397
+ static void stack_recorder_typed_data_mark(void *state_ptr) {
398
+ stack_recorder_state *state = (stack_recorder_state *) state_ptr;
399
+
400
+ rb_gc_mark(state->thread_context_collector_instance);
401
+ heap_recorder_mark_pending_recordings(state->heap_recorder);
402
+ }
403
+
402
404
  static void stack_recorder_typed_data_free(void *state_ptr) {
403
405
  stack_recorder_state *state = (stack_recorder_state *) state_ptr;
404
406
 
@@ -421,20 +423,16 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
421
423
  if (options == Qnil) options = rb_hash_new();
422
424
 
423
425
  VALUE recorder_instance = rb_hash_fetch(options, ID2SYM(rb_intern("self_instance")));
424
- VALUE cpu_time_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("cpu_time_enabled")));
425
426
  VALUE alloc_samples_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("alloc_samples_enabled")));
426
427
  VALUE heap_samples_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("heap_samples_enabled")));
427
428
  VALUE heap_size_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("heap_size_enabled")));
428
429
  VALUE heap_sample_every = rb_hash_fetch(options, ID2SYM(rb_intern("heap_sample_every")));
429
- VALUE timeline_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("timeline_enabled")));
430
430
  VALUE heap_clean_after_gc_enabled = rb_hash_fetch(options, ID2SYM(rb_intern("heap_clean_after_gc_enabled")));
431
431
 
432
- ENFORCE_BOOLEAN(cpu_time_enabled);
433
432
  ENFORCE_BOOLEAN(alloc_samples_enabled);
434
433
  ENFORCE_BOOLEAN(heap_samples_enabled);
435
434
  ENFORCE_BOOLEAN(heap_size_enabled);
436
435
  ENFORCE_TYPE(heap_sample_every, T_FIXNUM);
437
- ENFORCE_BOOLEAN(timeline_enabled);
438
436
  ENFORCE_BOOLEAN(heap_clean_after_gc_enabled);
439
437
 
440
438
  stack_recorder_state *state;
@@ -445,11 +443,9 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
445
443
  heap_recorder_set_sample_rate(state->heap_recorder, NUM2INT(heap_sample_every));
446
444
 
447
445
  uint8_t requested_values_count = ALL_VALUE_TYPES_COUNT -
448
- (cpu_time_enabled == Qtrue ? 0 : 1) -
449
446
  (alloc_samples_enabled == Qtrue? 0 : 2) -
450
447
  (heap_samples_enabled == Qtrue ? 0 : 1) -
451
- (heap_size_enabled == Qtrue ? 0 : 1) -
452
- (timeline_enabled == Qtrue ? 0 : 1);
448
+ (heap_size_enabled == Qtrue ? 0 : 1);
453
449
 
454
450
  if (requested_values_count == ALL_VALUE_TYPES_COUNT) return Qtrue; // Nothing to do, this is the default
455
451
 
@@ -459,30 +455,31 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
459
455
 
460
456
  state->enabled_values_count = requested_values_count;
461
457
 
462
- ddog_prof_ValueType enabled_value_types[ALL_VALUE_TYPES_COUNT];
458
+ ddog_prof_SampleType enabled_sample_types[ALL_VALUE_TYPES_COUNT];
463
459
  uint8_t next_enabled_pos = 0;
464
460
  uint8_t next_disabled_pos = requested_values_count;
465
461
 
466
- // CPU_SAMPLES_VALUE is always enabled
467
- enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) CPU_SAMPLES_VALUE;
462
+ // CPU_SAMPLES is always enabled
463
+ enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_CPU_SAMPLES;
468
464
  state->position_for[CPU_SAMPLES_VALUE_ID] = next_enabled_pos++;
469
465
 
470
- // WALL_TIME_VALUE is always enabled
471
- enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) WALL_TIME_VALUE;
466
+ // WALL_TIME is always enabled
467
+ enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_WALL_TIME;
472
468
  state->position_for[WALL_TIME_VALUE_ID] = next_enabled_pos++;
473
469
 
474
- if (cpu_time_enabled == Qtrue) {
475
- enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) CPU_TIME_VALUE;
476
- state->position_for[CPU_TIME_VALUE_ID] = next_enabled_pos++;
477
- } else {
478
- state->position_for[CPU_TIME_VALUE_ID] = next_disabled_pos++;
479
- }
470
+ // CPU_TIME is always enabled
471
+ enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_CPU_TIME;
472
+ state->position_for[CPU_TIME_VALUE_ID] = next_enabled_pos++;
473
+
474
+ // TIMELINE is always enabled
475
+ enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_TIMELINE;
476
+ state->position_for[TIMELINE_VALUE_ID] = next_enabled_pos++;
480
477
 
481
478
  if (alloc_samples_enabled == Qtrue) {
482
- enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) ALLOC_SAMPLES_VALUE;
479
+ enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES;
483
480
  state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_enabled_pos++;
484
481
 
485
- enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) ALLOC_SAMPLES_UNSCALED_VALUE;
482
+ enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_ALLOC_SAMPLES_UNSCALED;
486
483
  state->position_for[ALLOC_SAMPLES_UNSCALED_VALUE_ID] = next_enabled_pos++;
487
484
  } else {
488
485
  state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_disabled_pos++;
@@ -490,14 +487,14 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
490
487
  }
491
488
 
492
489
  if (heap_samples_enabled == Qtrue) {
493
- enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) HEAP_SAMPLES_VALUE;
490
+ enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_HEAP_LIVE_SAMPLES;
494
491
  state->position_for[HEAP_SAMPLES_VALUE_ID] = next_enabled_pos++;
495
492
  } else {
496
493
  state->position_for[HEAP_SAMPLES_VALUE_ID] = next_disabled_pos++;
497
494
  }
498
495
 
499
496
  if (heap_size_enabled == Qtrue) {
500
- enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) HEAP_SIZE_VALUE;
497
+ enabled_sample_types[next_enabled_pos] = DDOG_PROF_SAMPLE_TYPE_HEAP_LIVE_SIZE;
501
498
  state->position_for[HEAP_SIZE_VALUE_ID] = next_enabled_pos++;
502
499
  } else {
503
500
  state->position_for[HEAP_SIZE_VALUE_ID] = next_disabled_pos++;
@@ -511,17 +508,10 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
511
508
  state->heap_recorder = NULL;
512
509
  }
513
510
 
514
- if (timeline_enabled == Qtrue) {
515
- enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) TIMELINE_VALUE;
516
- state->position_for[TIMELINE_VALUE_ID] = next_enabled_pos++;
517
- } else {
518
- state->position_for[TIMELINE_VALUE_ID] = next_disabled_pos++;
519
- }
520
-
521
511
  ddog_prof_Profile_drop(&state->profile_slot_one.profile);
522
512
  ddog_prof_Profile_drop(&state->profile_slot_two.profile);
523
513
 
524
- ddog_prof_Slice_ValueType sample_types = {.ptr = enabled_value_types, .len = state->enabled_values_count};
514
+ ddog_prof_Slice_SampleType sample_types = {.ptr = enabled_sample_types, .len = state->enabled_values_count};
525
515
  initialize_profiles(state, sample_types);
526
516
 
527
517
  return Qtrue;
@@ -532,12 +522,16 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
532
522
  TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
533
523
 
534
524
  ddog_Timespec finish_timestamp = system_epoch_now_timespec();
535
- // Need to do this while still holding on to the Global VM Lock; see comments on method for why
525
+ // Need to do this while still holding the Global VM Lock; see comments on method for why
536
526
  serializer_set_start_timestamp_for_next_profile(state, finish_timestamp);
537
527
 
528
+ if (state->thread_context_collector_instance != Qnil) {
529
+ thread_context_collector_on_serialize(state->thread_context_collector_instance);
530
+ }
531
+
538
532
  long heap_iteration_prep_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
539
533
  // Prepare the iteration on heap recorder we'll be doing outside the GVL. The preparation needs to
540
- // happen while holding on to the GVL.
534
+ // happen while holding the GVL.
541
535
  // NOTE: While rare, it's possible for the GVL to be released inside this function (see comments on `heap_recorder_update`)
542
536
  // and thus don't assume this is an "atomic" step -- other threads may get some running time in the meanwhile.
543
537
  heap_recorder_prepare_iteration(state->heap_recorder);
@@ -565,7 +559,7 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
565
559
  rb_thread_call_without_gvl2(call_serialize_without_gvl, &args, NULL /* No interruption function needed in this case */, NULL /* Not needed */);
566
560
  }
567
561
 
568
- // Cleanup after heap recorder iteration. This needs to happen while holding on to the GVL.
562
+ // Cleanup after heap recorder iteration. This needs to happen while holding the GVL.
569
563
  heap_recorder_finish_iteration(state->heap_recorder);
570
564
 
571
565
  // NOTE: We are focusing on the serialization time outside of the GVL in this stat here. This doesn't
@@ -591,7 +585,7 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
591
585
 
592
586
  ddog_prof_MaybeError result = args.advance_gen_result;
593
587
  if (result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
594
- rb_raise(rb_eRuntimeError, "Failed to advance string storage gen: %"PRIsVALUE, get_error_details_and_drop(&result.some));
588
+ raise_error(rb_eRuntimeError, "Failed to advance string storage gen: %"PRIsVALUE, get_error_details_and_drop(&result.some));
595
589
  }
596
590
 
597
591
  VALUE start = ruby_time_from(args.slot->start_timestamp);
@@ -650,6 +644,7 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
650
644
  .values = (ddog_Slice_I64) {.ptr = metric_values, .len = state->enabled_values_count},
651
645
  .labels = labels.labels
652
646
  },
647
+ /* To disable end_timestamp_ns to get aggregated profiles in pprof, replace the below with `0` */
653
648
  labels.end_timestamp_ns
654
649
  );
655
650
 
@@ -658,17 +653,18 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
658
653
  sampler_unlock_active_profile(active_slot);
659
654
 
660
655
  if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
661
- rb_raise(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
656
+ raise_error(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
662
657
  }
663
658
  }
664
659
 
665
- void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice alloc_class) {
660
+ // Returns needs_after_allocation: true whenever an after_sample callback is required
661
+ bool track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice alloc_class) {
666
662
  stack_recorder_state *state;
667
663
  TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
668
664
  // FIXME: Heap sampling currently has to be done in 2 parts because the construction of locations is happening
669
665
  // very late in the allocation-sampling path (which is shared with the cpu sampling path). This can
670
666
  // be fixed with some refactoring but for now this leads to a less impactful change.
671
- start_heap_allocation_recording(state->heap_recorder, new_object, sample_weight, alloc_class);
667
+ return start_heap_allocation_recording(state->heap_recorder, new_object, sample_weight, alloc_class);
672
668
  }
673
669
 
674
670
  void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_CharSlice endpoint) {
@@ -682,7 +678,7 @@ void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_
682
678
  sampler_unlock_active_profile(active_slot);
683
679
 
684
680
  if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
685
- rb_raise(rb_eArgError, "Failed to record endpoint: %"PRIsVALUE, get_error_details_and_drop(&result.err));
681
+ raise_error(rb_eArgError, "Failed to record endpoint: %"PRIsVALUE, get_error_details_and_drop(&result.err));
686
682
  }
687
683
  }
688
684
 
@@ -693,6 +689,13 @@ void recorder_after_gc_step(VALUE recorder_instance) {
693
689
  if (state->heap_clean_after_gc_enabled) heap_recorder_update_young_objects(state->heap_recorder);
694
690
  }
695
691
 
692
+ void recorder_after_sample(VALUE recorder_instance) {
693
+ stack_recorder_state *state;
694
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
695
+
696
+ heap_recorder_finalize_pending_recordings(state->heap_recorder);
697
+ }
698
+
696
699
  #define MAX_LEN_HEAP_ITERATION_ERROR_MSG 256
697
700
 
698
701
  // Heap recorder iteration context allows us access to stack recorder state and profile being serialized
@@ -824,7 +827,7 @@ static locked_profile_slot sampler_lock_active_profile(stack_recorder_state *sta
824
827
  }
825
828
 
826
829
  // We already tried both multiple times, and we did not succeed. This is not expected to happen. Let's stop sampling.
827
- rb_raise(rb_eRuntimeError, "Failed to grab either mutex in sampler_lock_active_profile");
830
+ raise_error(rb_eRuntimeError, "Failed to grab either mutex in sampler_lock_active_profile");
828
831
  }
829
832
 
830
833
  static void sampler_unlock_active_profile(locked_profile_slot active_slot) {
@@ -889,7 +892,7 @@ static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot) {
889
892
  return Qtrue;
890
893
  } else {
891
894
  ENFORCE_SUCCESS_GVL(error);
892
- rb_raise(rb_eRuntimeError, "Failed to raise exception in test_slot_mutex_state; this should never happen");
895
+ raise_error(rb_eRuntimeError, "Failed to raise exception in test_slot_mutex_state; this should never happen");
893
896
  }
894
897
  }
895
898
 
@@ -902,6 +905,9 @@ static ddog_Timespec system_epoch_now_timespec(void) {
902
905
  //
903
906
  // Assumption: This method gets called BEFORE restarting profiling -- e.g. there are no components attempting to
904
907
  // trigger samples at the same time.
908
+ //
909
+ // Note that tests call this method directly in the same process without forking,
910
+ // and in such a case non-current Threads keep running.
905
911
  static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance) {
906
912
  stack_recorder_state *state;
907
913
  TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
@@ -934,14 +940,17 @@ static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_
934
940
 
935
941
  static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class) {
936
942
  ENFORCE_TYPE(weight, T_FIXNUM);
937
- track_object(recorder_instance, new_obj, NUM2UINT(weight), char_slice_from_ruby_string(alloc_class));
938
- return Qtrue;
943
+ bool needs_after_allocation = track_object(recorder_instance, new_obj, NUM2UINT(weight), char_slice_from_ruby_string(alloc_class));
944
+
945
+ // We could instead choose to automatically trigger the after allocation here; yet, it seems kinda nice to keep it manual for
946
+ // the tests so we can pull on each lever separately and observe "the sausage being made" in steps
947
+ return needs_after_allocation ? Qtrue : Qfalse;
939
948
  }
940
949
 
941
950
  static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp) {
942
951
  ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile);
943
952
  if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
944
- rb_raise(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
953
+ raise_error(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
945
954
  }
946
955
  slot->start_timestamp = start_timestamp;
947
956
  slot->stats = (stats_slot) {};
@@ -1056,14 +1065,14 @@ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE
1056
1065
  ddog_prof_ManagedStringStorageNewResult string_storage = ddog_prof_ManagedStringStorage_new();
1057
1066
 
1058
1067
  if (string_storage.tag == DDOG_PROF_MANAGED_STRING_STORAGE_NEW_RESULT_ERR) {
1059
- rb_raise(rb_eRuntimeError, "Failed to initialize string storage: %"PRIsVALUE, get_error_details_and_drop(&string_storage.err));
1068
+ raise_error(rb_eRuntimeError, "Failed to initialize string storage: %"PRIsVALUE, get_error_details_and_drop(&string_storage.err));
1060
1069
  }
1061
1070
 
1062
- ddog_prof_Slice_ValueType sample_types = {.ptr = all_value_types, .len = ALL_VALUE_TYPES_COUNT};
1071
+ ddog_prof_Slice_SampleType sample_types = {.ptr = all_sample_types, .len = ALL_VALUE_TYPES_COUNT};
1063
1072
  ddog_prof_Profile_NewResult profile = ddog_prof_Profile_with_string_storage(sample_types, NULL, string_storage.ok);
1064
1073
 
1065
1074
  if (profile.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
1066
- rb_raise(rb_eRuntimeError, "Failed to initialize profile: %"PRIsVALUE, get_error_details_and_drop(&profile.err));
1075
+ raise_error(rb_eRuntimeError, "Failed to initialize profile: %"PRIsVALUE, get_error_details_and_drop(&profile.err));
1067
1076
  }
1068
1077
 
1069
1078
  ddog_prof_ManagedStringId hello = intern_or_raise(string_storage.ok, DDOG_CHARSLICE_C("hello"));
@@ -1097,7 +1106,7 @@ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE
1097
1106
  );
1098
1107
 
1099
1108
  if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
1100
- rb_raise(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
1109
+ raise_error(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
1101
1110
  }
1102
1111
 
1103
1112
  ddog_Timespec finish_timestamp = system_epoch_now_timespec();
@@ -1105,13 +1114,13 @@ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE
1105
1114
  ddog_prof_Profile_SerializeResult serialize_result = ddog_prof_Profile_serialize(&profile.ok, &start_timestamp, &finish_timestamp);
1106
1115
 
1107
1116
  if (serialize_result.tag == DDOG_PROF_PROFILE_SERIALIZE_RESULT_ERR) {
1108
- rb_raise(rb_eRuntimeError, "Failed to serialize: %"PRIsVALUE, get_error_details_and_drop(&serialize_result.err));
1117
+ raise_error(rb_eRuntimeError, "Failed to serialize: %"PRIsVALUE, get_error_details_and_drop(&serialize_result.err));
1109
1118
  }
1110
1119
 
1111
1120
  ddog_prof_MaybeError advance_gen_result = ddog_prof_ManagedStringStorage_advance_gen(string_storage.ok);
1112
1121
 
1113
1122
  if (advance_gen_result.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
1114
- rb_raise(rb_eRuntimeError, "Failed to advance string storage gen: %"PRIsVALUE, get_error_details_and_drop(&advance_gen_result.some));
1123
+ raise_error(rb_eRuntimeError, "Failed to advance string storage gen: %"PRIsVALUE, get_error_details_and_drop(&advance_gen_result.some));
1115
1124
  }
1116
1125
 
1117
1126
  VALUE encoded_pprof_1 = from_ddog_prof_EncodedProfile(serialize_result.ok);
@@ -1127,13 +1136,13 @@ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE
1127
1136
  );
1128
1137
 
1129
1138
  if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
1130
- rb_raise(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
1139
+ raise_error(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
1131
1140
  }
1132
1141
 
1133
1142
  serialize_result = ddog_prof_Profile_serialize(&profile.ok, &start_timestamp, &finish_timestamp);
1134
1143
 
1135
1144
  if (serialize_result.tag == DDOG_PROF_PROFILE_SERIALIZE_RESULT_ERR) {
1136
- rb_raise(rb_eArgError, "Failed to serialize: %"PRIsVALUE, get_error_details_and_drop(&serialize_result.err));
1145
+ raise_error(rb_eArgError, "Failed to serialize: %"PRIsVALUE, get_error_details_and_drop(&serialize_result.err));
1137
1146
  }
1138
1147
 
1139
1148
  VALUE encoded_pprof_2 = from_ddog_prof_EncodedProfile(serialize_result.ok);
@@ -1143,3 +1152,19 @@ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE
1143
1152
 
1144
1153
  return rb_ary_new_from_args(2, encoded_pprof_1, encoded_pprof_2);
1145
1154
  }
1155
+
1156
+ static VALUE _native_finalize_pending_heap_recordings(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
1157
+ stack_recorder_state *state;
1158
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1159
+
1160
+ heap_recorder_finalize_pending_recordings(state->heap_recorder);
1161
+
1162
+ return Qtrue;
1163
+ }
1164
+
1165
+ void recorder_install_on_serialize(VALUE recorder_instance, VALUE thread_context_collector_instance) {
1166
+ stack_recorder_state *state;
1167
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1168
+
1169
+ state->thread_context_collector_instance = enforce_thread_context_collector_instance(thread_context_collector_instance);
1170
+ }
@@ -26,6 +26,8 @@ typedef struct {
26
26
 
27
27
  void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, sample_values values, sample_labels labels);
28
28
  void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_CharSlice endpoint);
29
- void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice alloc_class);
29
+ __attribute__((warn_unused_result)) bool track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice alloc_class);
30
+ void recorder_after_sample(VALUE recorder_instance);
30
31
  void recorder_after_gc_step(VALUE recorder_instance);
32
+ void recorder_install_on_serialize(VALUE recorder_instance, VALUE thread_context_collector_instance);
31
33
  VALUE enforce_recorder_instance(VALUE object);
@@ -4,11 +4,12 @@
4
4
  #include <errno.h>
5
5
  #include <time.h>
6
6
 
7
- #include "extconf.h" // Needed for HAVE_CLOCK_MONOTONIC_COARSE
7
+ #include "extconf.h"
8
8
  #include "ruby_helpers.h"
9
9
 
10
10
  #define SECONDS_AS_NS(value) (value * 1000 * 1000 * 1000L)
11
11
  #define MILLIS_AS_NS(value) (value * 1000 * 1000L)
12
+ #define MICROS_AS_NS(value) (value * 1000L)
12
13
 
13
14
  typedef enum { RAISE_ON_FAILURE, DO_NOT_RAISE_ON_FAILURE } raise_on_failure_setting;
14
15
 
@@ -32,7 +33,16 @@ static inline long retrieve_clock_as_ns(clockid_t clock_id, raise_on_failure_set
32
33
  return clock_value.tv_nsec + SECONDS_AS_NS(clock_value.tv_sec);
33
34
  }
34
35
 
35
- static inline long monotonic_wall_time_now_ns(raise_on_failure_setting raise_on_failure) { return retrieve_clock_as_ns(CLOCK_MONOTONIC, raise_on_failure); }
36
+ // CLOCK_MONOTONIC on macOS only has microsecond precision, CLOCK_MONOTONIC_RAW has nanosecond precision
37
+ #ifdef __APPLE__
38
+ #define CLOCK_MONOTONIC_FOR_PROFILING CLOCK_MONOTONIC_RAW
39
+ #define CLOCK_MONOTONIC_COARSE_FOR_PROFILING CLOCK_MONOTONIC_RAW_APPROX
40
+ #else
41
+ #define CLOCK_MONOTONIC_FOR_PROFILING CLOCK_MONOTONIC
42
+ #define CLOCK_MONOTONIC_COARSE_FOR_PROFILING CLOCK_MONOTONIC_COARSE
43
+ #endif
44
+
45
+ static inline long monotonic_wall_time_now_ns(raise_on_failure_setting raise_on_failure) { return retrieve_clock_as_ns(CLOCK_MONOTONIC_FOR_PROFILING, raise_on_failure); }
36
46
  static inline long system_epoch_time_now_ns(raise_on_failure_setting raise_on_failure) { return retrieve_clock_as_ns(CLOCK_REALTIME, raise_on_failure); }
37
47
 
38
48
  // Coarse instants use CLOCK_MONOTONIC_COARSE on Linux which is expected to provide resolution in the millisecond range:
@@ -46,11 +56,7 @@ typedef struct {
46
56
  static inline coarse_instant to_coarse_instant(long timestamp_ns) { return (coarse_instant) {.timestamp_ns = timestamp_ns}; }
47
57
 
48
58
  static inline coarse_instant monotonic_coarse_wall_time_now_ns(void) {
49
- #ifdef HAVE_CLOCK_MONOTONIC_COARSE // Linux
50
- return to_coarse_instant(retrieve_clock_as_ns(CLOCK_MONOTONIC_COARSE, DO_NOT_RAISE_ON_FAILURE));
51
- #else // macOS
52
- return to_coarse_instant(retrieve_clock_as_ns(CLOCK_MONOTONIC, DO_NOT_RAISE_ON_FAILURE));
53
- #endif
59
+ return to_coarse_instant(retrieve_clock_as_ns(CLOCK_MONOTONIC_COARSE_FOR_PROFILING, DO_NOT_RAISE_ON_FAILURE));
54
60
  }
55
61
 
56
62
  long monotonic_to_system_epoch_ns(monotonic_to_system_epoch_state *state, long monotonic_wall_time_ns);
@@ -3,6 +3,7 @@
3
3
  #include <stdbool.h>
4
4
 
5
5
  #include "datadog_ruby_common.h"
6
+ #include "ruby_helpers.h"
6
7
  #include "unsafe_api_calls_check.h"
7
8
  #include "extconf.h"
8
9
 
@@ -21,7 +22,7 @@ void unsafe_api_calls_check_init(void) {
21
22
  check_for_unsafe_api_calls_handle = rb_postponed_job_preregister(unused_flags, check_for_unsafe_api_calls, NULL);
22
23
 
23
24
  if (check_for_unsafe_api_calls_handle == POSTPONED_JOB_HANDLE_INVALID) {
24
- rb_raise(rb_eRuntimeError, "Failed to register check_for_unsafe_api_calls_handle postponed job (got POSTPONED_JOB_HANDLE_INVALID)");
25
+ raise_error(rb_eRuntimeError, "Failed to register check_for_unsafe_api_calls_handle postponed job (got POSTPONED_JOB_HANDLE_INVALID)");
25
26
  }
26
27
  #endif
27
28
  }
@@ -4,9 +4,12 @@
4
4
  //
5
5
  // Specifically, when the profiler is sampling, we're never supposed to call into Ruby code (e.g. methods
6
6
  // implemented using Ruby code) or allocate Ruby objects.
7
- // That's because those events introduce thread switch points, and really we don't the VM switching between threads
8
- // in the middle of the profiler sampling.
9
- // This includes raising exceptions, unless we're trying to stop the profiler, and even then we must be careful.
7
+ // That's because those events introduce thread switch points, and really we don't want the VM switching between threads
8
+ // in the middle of the profiler sampling. This includes raising exceptions.
9
+ //
10
+ // Raising exceptions as the very last operation, to stop the profiler is ok, but comes a caveat: raising exceptions
11
+ // will fail the unsafe check. When testing exception paths, you must disable unsafe checking for that test execution.
12
+ // See `allow_exception` usage for how to we disable it for testing today.
10
13
  //
11
14
  // The above is especially true in situations such as GC profiling or allocation/heap profiling, as in those situations
12
15
  // we can even crash the Ruby VM if we switch away at the wrong time.
@@ -15,10 +18,12 @@
15
18
  // in most (all?) thread switch points, Ruby will check for interrupts and run the postponed jobs.
16
19
  //
17
20
  // Thus, if we set a flag while we're sampling (inside_unsafe_context), trigger the postponed job, and then only unset
18
- // the flag after sampling, he correct thing to happen is that the postponed job should never see the flag.
21
+ // the flag after sampling, the correct thing to happen is that the postponed job should never see the flag.
19
22
  //
20
23
  // If, however, we have a bug and there's a thread switch point, our postponed job will see the flag and immediately
21
24
  // stop the Ruby VM before further damage happens (and hopefully giving us a stack trace clearly pointing to the culprit).
25
+ //
26
+ // Note that this check currently does not detect Ruby object allocations, as those do not check for interrupts.
22
27
 
23
28
  void unsafe_api_calls_check_init(void);
24
29