datadog 2.39.0 → 2.47.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 (296) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +269 -44
  3. data/README.md +3 -0
  4. data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +12 -24
  5. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +256 -193
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -5
  7. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +0 -2
  8. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +19 -20
  9. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.h +5 -1
  10. data/ext/datadog_profiling_native_extension/collectors_stack.c +267 -171
  11. data/ext/datadog_profiling_native_extension/collectors_stack.h +17 -3
  12. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +307 -217
  13. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +10 -5
  14. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +5 -4
  15. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +19 -11
  16. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -10
  17. data/ext/datadog_profiling_native_extension/extconf.rb +67 -99
  18. data/ext/datadog_profiling_native_extension/heap_recorder.c +353 -257
  19. data/ext/datadog_profiling_native_extension/heap_recorder.h +50 -31
  20. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -27
  21. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +853 -496
  22. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +42 -15
  23. data/ext/datadog_profiling_native_extension/profiling.c +30 -23
  24. data/ext/datadog_profiling_native_extension/ruby_helpers.c +4 -80
  25. data/ext/datadog_profiling_native_extension/ruby_helpers.h +4 -7
  26. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +0 -2
  27. data/ext/datadog_profiling_native_extension/stack_recorder.c +116 -89
  28. data/ext/datadog_profiling_native_extension/stack_recorder.h +12 -5
  29. data/ext/datadog_profiling_native_extension/time_helpers.c +2 -4
  30. data/ext/datadog_profiling_native_extension/time_helpers.h +15 -15
  31. data/ext/libdatadog_api/datadog_ruby_common.c +19 -11
  32. data/ext/libdatadog_api/datadog_ruby_common.h +7 -10
  33. data/ext/libdatadog_api/di.c +43 -3
  34. data/ext/libdatadog_api/extconf.rb +6 -1
  35. data/ext/libdatadog_api/feature_flags.c +8 -0
  36. data/ext/libdatadog_api/init.c +9 -1
  37. data/ext/libdatadog_api/otel_thread_context.c +274 -0
  38. data/ext/libdatadog_api/otel_thread_context.h +5 -0
  39. data/ext/libdatadog_api/process_discovery.c +15 -1
  40. data/ext/libdatadog_api/trace_exporter.c +2078 -0
  41. data/ext/libdatadog_api/trace_exporter.h +5 -0
  42. data/ext/libdatadog_extconf_helpers.rb +14 -9
  43. data/lib/datadog/ai_guard/component.rb +17 -8
  44. data/lib/datadog/ai_guard/configuration/ext.rb +2 -0
  45. data/lib/datadog/ai_guard/configuration.rb +13 -0
  46. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +48 -55
  47. data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +1 -1
  48. data/lib/datadog/ai_guard/contrib/ruby_llm/message_adapter.rb +76 -0
  49. data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +1 -0
  50. data/lib/datadog/ai_guard/contrib/ruby_llm/redaction_change_set.rb +135 -0
  51. data/lib/datadog/ai_guard/evaluation/client.rb +50 -0
  52. data/lib/datadog/ai_guard/evaluation/content_part.rb +12 -0
  53. data/lib/datadog/ai_guard/evaluation/message.rb +25 -7
  54. data/lib/datadog/ai_guard/evaluation/message_builder.rb +31 -0
  55. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +6 -6
  56. data/lib/datadog/ai_guard/evaluation/outcome.rb +24 -0
  57. data/lib/datadog/ai_guard/evaluation/request.rb +8 -64
  58. data/lib/datadog/ai_guard/evaluation/response.rb +33 -0
  59. data/lib/datadog/ai_guard/evaluation/result.rb +11 -18
  60. data/lib/datadog/ai_guard/evaluation/tool_call.rb +15 -2
  61. data/lib/datadog/ai_guard/evaluation.rb +36 -14
  62. data/lib/datadog/ai_guard/ext.rb +4 -1
  63. data/lib/datadog/ai_guard/{api_client.rb → http_client.rb} +7 -5
  64. data/lib/datadog/ai_guard/metrics/telemetry.rb +43 -0
  65. data/lib/datadog/ai_guard/redaction/replacements.rb +97 -0
  66. data/lib/datadog/ai_guard/redaction/result.rb +29 -0
  67. data/lib/datadog/ai_guard/redaction.rb +80 -0
  68. data/lib/datadog/ai_guard.rb +58 -57
  69. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +21 -42
  70. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +1 -1
  71. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +1 -1
  72. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +1 -1
  73. data/lib/datadog/appsec/assets/blocked.html +1 -108
  74. data/lib/datadog/appsec/configuration.rb +11 -2
  75. data/lib/datadog/appsec/context.rb +1 -1
  76. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +1 -1
  77. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +2 -2
  78. data/lib/datadog/appsec/contrib/devise/configuration.rb +1 -1
  79. data/lib/datadog/appsec/contrib/devise/patcher.rb +1 -1
  80. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +2 -2
  81. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +2 -2
  82. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
  83. data/lib/datadog/appsec/contrib/rack/ext.rb +2 -2
  84. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +2 -2
  85. data/lib/datadog/appsec/contrib/rack/patcher.rb +1 -1
  86. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +6 -3
  87. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +30 -3
  88. data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +8 -7
  89. data/lib/datadog/appsec/contrib/rails/request_middleware.rb +2 -1
  90. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +2 -2
  91. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +15 -3
  92. data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +8 -7
  93. data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
  94. data/lib/datadog/appsec/processor/rule_loader.rb +12 -12
  95. data/lib/datadog/appsec/response.rb +1 -1
  96. data/lib/datadog/appsec/route_normalizer/route_pattern.rb +3 -3
  97. data/lib/datadog/appsec/security_engine/engine.rb +5 -4
  98. data/lib/datadog/core/configuration/components.rb +50 -19
  99. data/lib/datadog/core/configuration/components_state.rb +8 -1
  100. data/lib/datadog/core/configuration/option_definition.rb +1 -1
  101. data/lib/datadog/core/configuration/options.rb +1 -1
  102. data/lib/datadog/core/configuration/settings.rb +38 -43
  103. data/lib/datadog/core/configuration/supported_configurations.rb +18 -2
  104. data/lib/datadog/core/crashtracking/component.rb +5 -1
  105. data/lib/datadog/core/diagnostics/environment_logger.rb +36 -1
  106. data/lib/datadog/core/environment/gc.rb +1 -1
  107. data/lib/datadog/core/environment/vm_cache.rb +1 -1
  108. data/lib/datadog/core/environment/yjit.rb +2 -2
  109. data/lib/datadog/core/metrics/helpers.rb +1 -1
  110. data/lib/datadog/core/metrics/options.rb +2 -2
  111. data/lib/datadog/core/process_discovery.rb +6 -2
  112. data/lib/datadog/core/remote/client/capabilities.rb +32 -21
  113. data/lib/datadog/core/remote/client.rb +45 -4
  114. data/lib/datadog/core/remote/component.rb +30 -7
  115. data/lib/datadog/core/remote/configuration/repository.rb +2 -2
  116. data/lib/datadog/core/remote/dispatcher.rb +47 -6
  117. data/lib/datadog/core/remote/worker.rb +8 -0
  118. data/lib/datadog/core/telemetry/configuration_value.rb +38 -0
  119. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +3 -1
  120. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +1 -1
  121. data/lib/datadog/core/telemetry/event/app_started.rb +5 -24
  122. data/lib/datadog/core/telemetry/event/generate_metrics.rb +1 -1
  123. data/lib/datadog/core/telemetry/event/log.rb +2 -2
  124. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
  125. data/lib/datadog/core/telemetry/metric.rb +2 -2
  126. data/lib/datadog/core/telemetry/request.rb +2 -2
  127. data/lib/datadog/core/transport/http.rb +1 -1
  128. data/lib/datadog/core/transport/transport.rb +1 -1
  129. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +170 -18
  130. data/lib/datadog/core/utils/sequence.rb +3 -6
  131. data/lib/datadog/core/utils/time.rb +16 -54
  132. data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
  133. data/lib/datadog/data_streams/pathway_context.rb +20 -22
  134. data/lib/datadog/data_streams/processor.rb +45 -14
  135. data/lib/datadog/di/boot.rb +1 -0
  136. data/lib/datadog/di/capture_expression_evaluator/result.rb +30 -0
  137. data/lib/datadog/di/capture_expression_evaluator.rb +39 -9
  138. data/lib/datadog/di/component.rb +108 -3
  139. data/lib/datadog/di/configuration.rb +53 -2
  140. data/lib/datadog/di/context.rb +7 -2
  141. data/lib/datadog/di/contrib/active_record.rb +8 -2
  142. data/lib/datadog/di/el/compiler.rb +88 -12
  143. data/lib/datadog/di/el/evaluator.rb +82 -2
  144. data/lib/datadog/di/el/expression.rb +13 -2
  145. data/lib/datadog/di/evaluation_failure.rb +28 -0
  146. data/lib/datadog/di/guardrails_telemetry/reason.rb +87 -0
  147. data/lib/datadog/di/guardrails_telemetry.rb +203 -0
  148. data/lib/datadog/di/instrumenter.rb +106 -15
  149. data/lib/datadog/di/logger.rb +32 -10
  150. data/lib/datadog/di/probe.rb +9 -1
  151. data/lib/datadog/di/probe_builder.rb +7 -6
  152. data/lib/datadog/di/probe_manager.rb +56 -8
  153. data/lib/datadog/di/probe_notification_builder.rb +31 -28
  154. data/lib/datadog/di/probe_notifier_worker.rb +56 -6
  155. data/lib/datadog/di/proc_responder.rb +1 -1
  156. data/lib/datadog/di/remote.rb +49 -5
  157. data/lib/datadog/di/serializer.rb +172 -55
  158. data/lib/datadog/di/snapshot_event.rb +38 -0
  159. data/lib/datadog/di/transport/http.rb +13 -3
  160. data/lib/datadog/di/transport/input.rb +32 -7
  161. data/lib/datadog/error_tracking/component.rb +1 -1
  162. data/lib/datadog/kit/appsec/events/v2.rb +2 -2
  163. data/lib/datadog/open_feature/activation.rb +268 -0
  164. data/lib/datadog/open_feature/agentless/configuration_source.rb +246 -0
  165. data/lib/datadog/open_feature/agentless/parser.rb +43 -0
  166. data/lib/datadog/open_feature/agentless/response.rb +19 -0
  167. data/lib/datadog/open_feature/agentless/transport.rb +103 -0
  168. data/lib/datadog/open_feature/component.rb +85 -13
  169. data/lib/datadog/open_feature/configuration/agentless_endpoint.rb +90 -0
  170. data/lib/datadog/open_feature/configuration/source/resolution.rb +22 -0
  171. data/lib/datadog/open_feature/configuration/source.rb +43 -0
  172. data/lib/datadog/open_feature/configuration.rb +124 -0
  173. data/lib/datadog/open_feature/evaluation_engine.rb +29 -3
  174. data/lib/datadog/open_feature/exposures/batch_builder.rb +1 -1
  175. data/lib/datadog/open_feature/exposures/event.rb +15 -8
  176. data/lib/datadog/open_feature/ext.rb +19 -0
  177. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +236 -80
  178. data/lib/datadog/open_feature/flag_evaluation/writer.rb +179 -68
  179. data/lib/datadog/open_feature/hooks/evaluation_telemetry_opt_out_hook.rb +25 -0
  180. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +24 -21
  181. data/lib/datadog/open_feature/native_evaluator.rb +20 -6
  182. data/lib/datadog/open_feature/noop_evaluator.rb +5 -0
  183. data/lib/datadog/open_feature/provider.rb +315 -10
  184. data/lib/datadog/open_feature/remote.rb +5 -5
  185. data/lib/datadog/open_feature/transport.rb +5 -0
  186. data/lib/datadog/open_feature.rb +31 -1
  187. data/lib/datadog/opentelemetry/sdk/propagator.rb +1 -1
  188. data/lib/datadog/opentelemetry/signal_configuration.rb +13 -9
  189. data/lib/datadog/opentelemetry/trace.rb +3 -0
  190. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +10 -2
  191. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +5 -7
  192. data/lib/datadog/profiling/collectors/info.rb +40 -13
  193. data/lib/datadog/profiling/collectors/thread_context.rb +6 -17
  194. data/lib/datadog/profiling/component.rb +33 -39
  195. data/lib/datadog/profiling/exporter.rb +10 -10
  196. data/lib/datadog/profiling/tasks/exec.rb +1 -1
  197. data/lib/datadog/profiling.rb +4 -0
  198. data/lib/datadog/symbol_database/extractor.rb +89 -107
  199. data/lib/datadog/tracing/component.rb +44 -2
  200. data/lib/datadog/tracing/configuration/dynamic/option.rb +4 -0
  201. data/lib/datadog/tracing/configuration/dynamic.rb +5 -3
  202. data/lib/datadog/tracing/configuration/ext.rb +4 -0
  203. data/lib/datadog/tracing/configuration/settings.rb +36 -0
  204. data/lib/datadog/tracing/context.rb +24 -2
  205. data/lib/datadog/tracing/context_provider.rb +17 -5
  206. data/lib/datadog/tracing/contrib/action_cable/events.rb +1 -1
  207. data/lib/datadog/tracing/contrib/action_mailer/events.rb +1 -1
  208. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +2 -2
  209. data/lib/datadog/tracing/contrib/action_view/events.rb +1 -1
  210. data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +1 -1
  211. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +1 -1
  212. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -0
  213. data/lib/datadog/tracing/contrib/active_record/events.rb +1 -1
  214. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +2 -2
  215. data/lib/datadog/tracing/contrib/aws/ext.rb +1 -1
  216. data/lib/datadog/tracing/contrib/aws/services.rb +1 -1
  217. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +1 -1
  218. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +10 -5
  219. data/lib/datadog/tracing/contrib/excon/middleware.rb +10 -3
  220. data/lib/datadog/tracing/contrib/ext.rb +3 -3
  221. data/lib/datadog/tracing/contrib/faraday/middleware.rb +10 -4
  222. data/lib/datadog/tracing/contrib/grape/endpoint.rb +32 -5
  223. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +1 -1
  224. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +1 -1
  225. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +1 -1
  226. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +2 -1
  227. data/lib/datadog/tracing/contrib/http/instrumentation.rb +16 -1
  228. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +8 -2
  229. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +10 -4
  230. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +4 -0
  231. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +7 -2
  232. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +7 -2
  233. data/lib/datadog/tracing/contrib/kafka/events.rb +1 -1
  234. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +1 -1
  235. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -1
  236. data/lib/datadog/tracing/contrib/opensearch/ext.rb +1 -1
  237. data/lib/datadog/tracing/contrib/opensearch/quantize.rb +1 -1
  238. data/lib/datadog/tracing/contrib/patchable.rb +1 -1
  239. data/lib/datadog/tracing/contrib/patcher.rb +1 -1
  240. data/lib/datadog/tracing/contrib/que/tracer.rb +1 -1
  241. data/lib/datadog/tracing/contrib/racecar/events.rb +1 -1
  242. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +1 -1
  243. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +1 -1
  244. data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
  245. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +1 -1
  246. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +1 -1
  247. data/lib/datadog/tracing/contrib/redis/quantize.rb +36 -2
  248. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +9 -3
  249. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +10 -3
  250. data/lib/datadog/tracing/contrib/sequel/database.rb +1 -5
  251. data/lib/datadog/tracing/contrib/sequel/jdbc_connection_string.rb +140 -0
  252. data/lib/datadog/tracing/contrib/sequel/utils.rb +50 -63
  253. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +1 -1
  254. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +1 -1
  255. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +1 -1
  256. data/lib/datadog/tracing/contrib/utils/quantization/hash_formatter.rb +1 -1
  257. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +108 -3
  258. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +1 -1
  259. data/lib/datadog/tracing/correlation.rb +2 -2
  260. data/lib/datadog/tracing/diagnostics/environment_logger.rb +3 -2
  261. data/lib/datadog/tracing/distributed/baggage.rb +1 -3
  262. data/lib/datadog/tracing/distributed/datadog.rb +3 -3
  263. data/lib/datadog/tracing/distributed/propagation.rb +3 -0
  264. data/lib/datadog/tracing/distributed/propagation_policy.rb +5 -0
  265. data/lib/datadog/tracing/distributed/trace_context.rb +14 -271
  266. data/lib/datadog/tracing/distributed/trace_state/datadog.rb +233 -0
  267. data/lib/datadog/tracing/distributed/trace_state/ext.rb +44 -0
  268. data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +156 -0
  269. data/lib/datadog/tracing/distributed/trace_state.rb +121 -0
  270. data/lib/datadog/tracing/metadata/ext.rb +3 -0
  271. data/lib/datadog/tracing/metadata/tagging.rb +1 -1
  272. data/lib/datadog/tracing/otel_thread_context.rb +97 -0
  273. data/lib/datadog/tracing/remote.rb +236 -37
  274. data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -0
  275. data/lib/datadog/tracing/span.rb +1 -1
  276. data/lib/datadog/tracing/span_operation.rb +1 -1
  277. data/lib/datadog/tracing/sync_writer.rb +8 -3
  278. data/lib/datadog/tracing/trace_digest.rb +22 -4
  279. data/lib/datadog/tracing/trace_operation.rb +22 -10
  280. data/lib/datadog/tracing/tracer.rb +28 -7
  281. data/lib/datadog/tracing/transport/http/telemetry.rb +94 -0
  282. data/lib/datadog/tracing/transport/http/traces.rb +2 -0
  283. data/lib/datadog/tracing/transport/io/traces.rb +1 -1
  284. data/lib/datadog/tracing/transport/native/response.rb +71 -0
  285. data/lib/datadog/tracing/transport/native/telemetry.rb +17 -0
  286. data/lib/datadog/tracing/transport/native.rb +395 -0
  287. data/lib/datadog/tracing/transport/span_events_negotiation.rb +41 -0
  288. data/lib/datadog/tracing/transport/telemetry.rb +62 -0
  289. data/lib/datadog/tracing/transport/trace_formatter.rb +14 -4
  290. data/lib/datadog/tracing/transport/traces.rb +85 -38
  291. data/lib/datadog/tracing/writer.rb +17 -4
  292. data/lib/datadog/version.rb +1 -1
  293. metadata +51 -13
  294. data/lib/datadog/ai_guard/evaluation/content_builder.rb +0 -31
  295. data/lib/datadog/appsec/utils/hash_coercion.rb +0 -23
  296. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -69
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "set"
4
- require "time"
3
+ require "json"
5
4
  require "libdatadog"
5
+ require_relative "../../core/utils/time"
6
6
 
7
7
  module Datadog
8
8
  module Profiling
@@ -10,11 +10,11 @@ module Datadog
10
10
  # Collects information of relevance for profiler. This will get sent alongside
11
11
  # the profile and show up in the UI or potentially influence processing in some way.
12
12
  #
13
- # Information is currently collected and frozen at construction time. A full collector
14
- # could be seen as overkill for this case but it allows us to centralize information
15
- # gathering and easily support more flexible/dynamic info collection in the future.
13
+ # Most information is static: collected and frozen at construction time. The exception is
14
+ # what `collect_dynamic_info` collects, which can change during the process lifetime.
16
15
  class Info
17
- # @rbs @info: ::Hash[::Symbol, ::Hash[::Symbol, untyped]]
16
+ # @rbs @static_info: ::Hash[::Symbol, ::Hash[::Symbol, untyped]]
17
+ # @rbs @info_json_cache: [::Hash[::Symbol, bool], ::String]?
18
18
  # @rbs @platform_info: ::Hash[::Symbol, untyped]
19
19
  # @rbs @runtime_info: ::Hash[::Symbol, untyped]
20
20
  # @rbs @application_info: ::Hash[::Symbol, untyped]
@@ -25,18 +25,48 @@ module Datadog
25
25
  def initialize(settings)
26
26
  @profiler_info = nil
27
27
 
28
- @info = {
28
+ @static_info = {
29
29
  platform: collect_platform_info,
30
30
  runtime: collect_runtime_info,
31
31
  application: collect_application_info(settings),
32
32
  profiler: collect_profiler_info(settings),
33
33
  }.freeze
34
+ @info_json_cache = nil
34
35
  end
35
36
 
36
- attr_reader :info #: ::Hash[::Symbol, ::Hash[::Symbol, untyped]]
37
+ #: () -> ::Hash[::Symbol, ::Hash[::Symbol, untyped]]
38
+ def info
39
+ build_info(collect_dynamic_info)
40
+ end
41
+
42
+ # Serializing the same info on every flush would be wasteful, so the latest result is
43
+ # cached and reused for as long as the dynamic info is unchanged.
44
+ #: () -> ::String
45
+ def info_json
46
+ dynamic_info = collect_dynamic_info
47
+ cached_dynamic_info, cached_json = @info_json_cache
48
+ return cached_json if cached_json && cached_dynamic_info == dynamic_info
49
+
50
+ json = JSON.generate(build_info(dynamic_info)).freeze
51
+ @info_json_cache = [dynamic_info, json].freeze #: [::Hash[::Symbol, bool], ::String]
52
+ json
53
+ end
37
54
 
38
55
  private
39
56
 
57
+ #: (::Hash[::Symbol, bool]) -> ::Hash[::Symbol, ::Hash[::Symbol, untyped]]
58
+ def build_info(dynamic_info)
59
+ @static_info.merge(runtime: @static_info.fetch(:runtime).merge(dynamic_info))
60
+ end
61
+
62
+ #: () -> ::Hash[::Symbol, bool]
63
+ def collect_dynamic_info
64
+ {
65
+ yjit_enabled: defined?(::RubyVM::YJIT) ? ::RubyVM::YJIT.enabled? : false,
66
+ zjit_enabled: defined?(::RubyVM::ZJIT) ? ::RubyVM::ZJIT.enabled? : false,
67
+ }
68
+ end
69
+
40
70
  # Ruby GC tuning environment variables
41
71
  RUBY_GC_TUNING_ENV_VARS = [
42
72
  "RUBY_GC_HEAP_FREE_SLOTS",
@@ -71,10 +101,7 @@ module Datadog
71
101
  # Instead of trying to figure out real process start time by checking
72
102
  # /proc or some other complex/non-portable way, approximate start time
73
103
  # by time of requirement of this file.
74
- #
75
- # Note: this does not use Core::Utils::Time.now because this constant
76
- # gets initialized before a user has a chance to configure the library.
77
- START_TIME = Time.now.utc.freeze
104
+ START_TIME = Datadog::Core::Utils::Time.now.utc.freeze
78
105
 
79
106
  #: () -> ::Hash[::Symbol, untyped]
80
107
  def collect_platform_info
@@ -83,7 +110,7 @@ module Datadog
83
110
  hostname: Datadog::Core::Environment::Platform.hostname,
84
111
  kernel_name: Datadog::Core::Environment::Platform.kernel_name,
85
112
  kernel_release: Datadog::Core::Environment::Platform.kernel_release,
86
- kernel_version: Datadog::Core::Environment::Platform.kernel_version
113
+ kernel_version: Datadog::Core::Environment::Platform.kernel_version,
87
114
  }.freeze
88
115
  end
89
116
 
@@ -19,9 +19,9 @@ module Datadog
19
19
  max_frames:,
20
20
  tracer:,
21
21
  endpoint_collection_enabled:,
22
- waiting_for_gvl_threshold_ns:,
23
22
  otel_context_enabled:,
24
- native_filenames_enabled:
23
+ native_filenames_enabled:,
24
+ show_classes:
25
25
  )
26
26
  tracer_context_key = safely_extract_context_key_from(tracer)
27
27
  self.class._native_initialize(
@@ -30,9 +30,9 @@ module Datadog
30
30
  max_frames: max_frames,
31
31
  tracer_context_key: tracer_context_key,
32
32
  endpoint_collection_enabled: endpoint_collection_enabled,
33
- waiting_for_gvl_threshold_ns: waiting_for_gvl_threshold_ns,
34
33
  otel_context_enabled: otel_context_enabled,
35
- native_filenames_enabled: validate_native_filenames(native_filenames_enabled),
34
+ native_filenames_enabled: native_filenames_enabled,
35
+ show_classes: show_classes,
36
36
  overhead_filename: __FILE__,
37
37
  )
38
38
  end
@@ -42,9 +42,9 @@ module Datadog
42
42
  max_frames: 400,
43
43
  tracer: nil,
44
44
  endpoint_collection_enabled: false,
45
- waiting_for_gvl_threshold_ns: 10_000_000,
46
45
  otel_context_enabled: false,
47
46
  native_filenames_enabled: true,
47
+ show_classes: false,
48
48
  trigger_global_reset: true,
49
49
  **options
50
50
  )
@@ -53,9 +53,9 @@ module Datadog
53
53
  max_frames: max_frames,
54
54
  tracer: tracer,
55
55
  endpoint_collection_enabled: endpoint_collection_enabled,
56
- waiting_for_gvl_threshold_ns: waiting_for_gvl_threshold_ns,
57
56
  otel_context_enabled: otel_context_enabled,
58
57
  native_filenames_enabled: native_filenames_enabled,
58
+ show_classes: show_classes,
59
59
  **options,
60
60
  )
61
61
 
@@ -90,17 +90,6 @@ module Datadog
90
90
  context = provider.instance_variable_get(:@context)
91
91
  context&.instance_variable_get(:@key)
92
92
  end
93
-
94
- def validate_native_filenames(native_filenames_enabled)
95
- if native_filenames_enabled && !Datadog::Profiling::Collectors::Stack._native_filenames_available?
96
- Datadog.logger.debug(
97
- "Native filenames are enabled, but the required dladdr API was not available. Disabling native filenames."
98
- )
99
- false
100
- else
101
- native_filenames_enabled
102
- end
103
- end
104
93
  end
105
94
  end
106
95
  end
@@ -65,6 +65,7 @@ module Datadog
65
65
  gvl_profiling_enabled: enable_gvl_profiling?(settings, logger),
66
66
  sighandler_sampling_enabled: settings.profiling.advanced.sighandler_sampling_enabled,
67
67
  cpu_sampling_interval_ms: cpu_sampling_interval_ms,
68
+ waiting_for_gvl_threshold_ns: settings.profiling.advanced.waiting_for_gvl_threshold_ns,
68
69
  )
69
70
 
70
71
  internal_metadata = {
@@ -72,7 +73,7 @@ module Datadog
72
73
  heap_sample_every: heap_sample_every,
73
74
  }.freeze
74
75
 
75
- exporter = build_profiler_exporter(settings, recorder, worker, internal_metadata: internal_metadata)
76
+ exporter = build_profiler_exporter(settings, worker, internal_metadata: internal_metadata)
76
77
  transport = build_profiler_transport(settings, agent_settings)
77
78
  scheduler = Profiling::Scheduler.new(exporter: exporter, transport: transport, interval: upload_period_seconds)
78
79
  profiler = Profiling::Profiler.new(worker: worker, scheduler: scheduler)
@@ -102,19 +103,18 @@ module Datadog
102
103
  max_frames: settings.profiling.advanced.max_frames,
103
104
  tracer: optional_tracer,
104
105
  endpoint_collection_enabled: settings.profiling.advanced.endpoint.collection.enabled,
105
- waiting_for_gvl_threshold_ns: settings.profiling.advanced.waiting_for_gvl_threshold_ns,
106
106
  otel_context_enabled: settings.profiling.advanced.preview_otel_context_enabled,
107
107
  native_filenames_enabled: settings.profiling.advanced.native_filenames_enabled,
108
+ show_classes: settings.profiling.advanced.experimental_show_classes_enabled,
108
109
  )
109
110
  end
110
111
 
111
- private_class_method def self.build_profiler_exporter(settings, recorder, worker, internal_metadata:)
112
+ private_class_method def self.build_profiler_exporter(settings, worker, internal_metadata:)
112
113
  info_collector = Profiling::Collectors::Info.new(settings)
113
114
  code_provenance_collector =
114
115
  (Profiling::Collectors::CodeProvenance.new if settings.profiling.advanced.code_provenance_enabled)
115
116
 
116
117
  Profiling::Exporter.new(
117
- pprof_recorder: recorder,
118
118
  worker: worker,
119
119
  info_collector: info_collector,
120
120
  code_provenance_collector: code_provenance_collector,
@@ -226,11 +226,13 @@ module Datadog
226
226
  return false
227
227
  end
228
228
 
229
- # Heap profiling relies on `ObjectSpace._id2ref`, which was removed on Ruby 4.1
230
- # (https://bugs.ruby-lang.org/issues/22135).
231
- if RubyVersion.is?(">= 4.1")
229
+ # Heap profiling tracks live objects using an `ObjectSpace::WeakMap`, which could corrupt its internal
230
+ # state during compaction before these versions (https://bugs.ruby-lang.org/issues/19529).
231
+ if RubyVersion.is?("< 3.1.4") || RubyVersion.is?(">= 3.2", "< 3.2.3")
232
232
  logger.warn(
233
- "Heap profiling is currently incompatible with Ruby 4.1+ and has been disabled."
233
+ "Current Ruby version (#{RUBY_VERSION}) cannot support heap profiling due to a VM bug. " \
234
+ "Please upgrade to Ruby >= 3.1.4 or >= 3.2.3 in order to use this feature. " \
235
+ "Heap profiling has been disabled."
234
236
  )
235
237
  return false
236
238
  end
@@ -251,17 +253,7 @@ module Datadog
251
253
  private_class_method def self.enable_heap_size_profiling?(settings, heap_profiling_enabled, logger)
252
254
  heap_size_profiling_enabled = settings.profiling.advanced.experimental_heap_size_enabled
253
255
 
254
- return false unless heap_profiling_enabled && heap_size_profiling_enabled
255
-
256
- if RubyVersion.is?(">= 4")
257
- logger.info(
258
- "Heap live size profiling is currently incompatible with Ruby 4 and has been disabled. " \
259
- "Heap live objects is not affected and remains enabled."
260
- )
261
- return false
262
- end
263
-
264
- true
256
+ heap_profiling_enabled && heap_size_profiling_enabled
265
257
  end
266
258
 
267
259
  private_class_method def self.no_signals_workaround_enabled?(settings, logger) # rubocop:disable Metrics/MethodLength
@@ -435,33 +427,35 @@ module Datadog
435
427
  end
436
428
  end
437
429
 
438
- # To add just a bit more complexity to our detection code, in https://github.com/DataDog/dd-trace-rb/issues/3334
439
- # a user reported that our code was incorrectly flagging the mariadb variant of libmysqlclient as being
440
- # incompatible. In fact we have no reports of the mariadb variant needing the "no signals" workaround,
441
- # so we flag it as compatible when it's in use.
430
+ # MariaDB's client has diverged from Oracle's and has no reported need for the "no signals" workaround, as
431
+ # reported in https://github.com/DataDog/dd-trace-rb/issues/3334, so we flag it as compatible when it's in use.
442
432
  #
443
- # A problem is that there doesn't seem to be an obvious way to query the mysql2 gem on which kind of
444
- # libmysqlclient it's using, so we detect it by looking at the version.
433
+ # There's no way to ask the mysql2 gem which client it was built against, so we infer it from the two versions
434
+ # that `Mysql2::Client.info` exposes:
445
435
  #
446
- # The info method for mysql2 with mariadb looks something like this:
447
- # `{:id=>30308, :version=>"3.3.8", :header_version=>"11.2.2"}`
436
+ # * `version` is `mysql_get_client_info()`. For MariaDB that's the version of
437
+ # https://github.com/mariadb-corporation/mariadb-connector-c, which is still 3.x.
438
+ # * `header_version` is a constant baked in when mysql2 was compiled. Up to mysql2 0.5.6 it was the MariaDB
439
+ # server version, which is what people usually call "the mariadb version"; 0.5.7 switched it to the
440
+ # Connector/C version (https://github.com/brianmario/mysql2/pull/1406) and that broke our detection, as
441
+ # reported in https://github.com/DataDog/dd-trace-rb/issues/6536.
448
442
  #
449
- # * The version seems to come from https://github.com/mariadb-corporation/mariadb-connector-c and the latest
450
- # one is 3.x.
451
- # * The header_version is what people usually see as the "mariadb version"
443
+ # So MariaDB shows up as `{version: "3.3.8", header_version: "11.2.2"}` with mysql2 < 0.5.7 and as
444
+ # `{version: "3.4.9", header_version: "3.4.9"}` from 0.5.7 on. We accept both shapes: a header that is a server
445
+ # version (10 or newer, a sane range for modern releases per https://endoflife.date/mariadb) or one that is a
446
+ # Connector/C version (3.x, matching the client version).
452
447
  #
453
- # As a comparison, for libmysql the info looks like:
454
- # * `{:id=>80035, :version=>"8.0.35", :header_version=>"8.0.35"}`
455
- #
456
- # Thus our detection is version 4 or older, because libmysqlclient 4 is almost 20 years old so it's most probably
457
- # not that one + header_version being 10 or newer, since according to https://endoflife.date/mariadb that's a
458
- # sane range for modern mariadb releases.
448
+ # Oracle's client repeats one version in both fields (`{version: "8.0.35", header_version: "8.0.35"}`), and our
449
+ # caller already considers 8.0.0 and above compatible, so only a client older than 5.0.0 gets this far -- and
450
+ # no Oracle release has been one since libmysqlclient 4.1, which is from 2004.
459
451
  private_class_method def self.looks_like_mariadb?(info, libmysqlclient_version)
460
452
  header_version = Gem::Version.new(info[:header_version]) if info[:header_version]
461
453
 
462
- !!(header_version &&
463
- libmysqlclient_version < Gem::Version.new("5.0.0") &&
464
- header_version >= Gem::Version.new("10.0.0"))
454
+ return false unless header_version && libmysqlclient_version < Gem::Version.new("5.0.0")
455
+ return true if header_version >= Gem::Version.new("10.0.0")
456
+
457
+ connector_c_versions = Gem::Requirement.new(">= 3.0.0", "< 4.0.0")
458
+ connector_c_versions.satisfied_by?(libmysqlclient_version) && connector_c_versions.satisfied_by?(header_version)
465
459
  end
466
460
 
467
461
  private_class_method def self.dir_interruption_workaround_enabled?(settings, no_signals_workaround_enabled)
@@ -20,7 +20,6 @@ module Datadog
20
20
 
21
21
  private
22
22
 
23
- attr_reader :pprof_recorder #: Datadog::Profiling::StackRecorder
24
23
  # The code provenance collector acts both as collector and as a recorder
25
24
  attr_reader :code_provenance_collector #: Datadog::Profiling::Collectors::CodeProvenance?
26
25
  attr_reader :minimum_duration_seconds #: ::Integer
@@ -28,12 +27,11 @@ module Datadog
28
27
  attr_reader :last_flush_finish_at #: ::Time?
29
28
  attr_reader :created_at #: ::Time
30
29
  attr_reader :internal_metadata #: ::Hash[::Symbol, untyped]
31
- attr_reader :info_json #: ::String
30
+ attr_reader :info_collector #: Datadog::Profiling::Collectors::Info
32
31
  attr_reader :sequence_tracker #: singleton(Datadog::Profiling::SequenceTracker)
33
32
 
34
33
  public
35
34
 
36
- # @rbs pprof_recorder: Datadog::Profiling::StackRecorder
37
35
  # @rbs worker: Datadog::Profiling::Collectors::CpuAndWallTimeWorker
38
36
  # @rbs info_collector: Datadog::Profiling::Collectors::Info
39
37
  # @rbs code_provenance_collector: Datadog::Profiling::Collectors::CodeProvenance?
@@ -43,7 +41,6 @@ module Datadog
43
41
  # @rbs sequence_tracker: singleton(Datadog::Profiling::SequenceTracker)
44
42
  # @rbs return: void
45
43
  def initialize(
46
- pprof_recorder:,
47
44
  worker:,
48
45
  info_collector:,
49
46
  code_provenance_collector:,
@@ -52,7 +49,6 @@ module Datadog
52
49
  time_provider: Time,
53
50
  sequence_tracker: Datadog::Profiling::SequenceTracker
54
51
  )
55
- @pprof_recorder = pprof_recorder
56
52
  @worker = worker
57
53
  @code_provenance_collector = code_provenance_collector
58
54
  @minimum_duration_seconds = minimum_duration_seconds
@@ -60,14 +56,13 @@ module Datadog
60
56
  @last_flush_finish_at = nil
61
57
  @created_at = time_provider.now.utc
62
58
  @internal_metadata = internal_metadata
63
- # NOTE: At the time of this comment collected info does not change over time so we'll hardcode
64
- # it on startup to prevent serializing the same info on every flush.
65
- @info_json = JSON.generate(info_collector.info).freeze
59
+ @info_collector = info_collector
66
60
  @sequence_tracker = sequence_tracker
67
61
  end
68
62
 
69
63
  #: () -> Datadog::Profiling::Flush?
70
64
  def flush
65
+ pprof_recorder = @worker.prepare_serialize
71
66
  worker_stats = @worker.stats_and_reset_not_thread_safe
72
67
  serialization_result = pprof_recorder.serialize
73
68
  return if serialization_result.nil?
@@ -111,10 +106,10 @@ module Datadog
111
106
  worker_stats: worker_stats,
112
107
  profile_stats: profile_stats,
113
108
  recorder_stats: pprof_recorder.stats,
114
- gc: GC.stat,
109
+ gc: gc_stats,
115
110
  }
116
111
  ),
117
- info_json: info_json,
112
+ info_json: info_collector.info_json,
118
113
  )
119
114
  end
120
115
 
@@ -131,6 +126,11 @@ module Datadog
131
126
 
132
127
  private
133
128
 
129
+ # @rbs return: Hash[Symbol, Integer | bool]
130
+ def gc_stats
131
+ GC.stat.merge(auto_compact: GC.respond_to?(:auto_compact) && GC.auto_compact)
132
+ end
133
+
134
134
  #: (::Time, ::Time) -> bool
135
135
  def duration_below_threshold?(start, finish)
136
136
  (finish - start) < minimum_duration_seconds
@@ -21,7 +21,7 @@ module Datadog
21
21
  #: () -> ::Array["-rdatadog/profiling/preload"]
22
22
  def rubyopts
23
23
  [
24
- "-rdatadog/profiling/preload"
24
+ "-rdatadog/profiling/preload",
25
25
  ]
26
26
  end
27
27
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rbconfig"
3
4
  require_relative "core"
4
5
  require_relative "core/environment/variable_helpers"
5
6
  require_relative "core/utils/only_once"
@@ -7,6 +8,9 @@ require_relative "core/utils/only_once"
7
8
  module Datadog
8
9
  # Datadog Continuous Profiler implementation: https://docs.datadoghq.com/profiler/
9
10
  module Profiling
11
+ STATIC_RUBY_PATH = (RbConfig::CONFIG["ENABLE_SHARED"] == "no") ? RbConfig.ruby.freeze : nil
12
+ private_constant :STATIC_RUBY_PATH
13
+
10
14
  def self.supported?
11
15
  unsupported_reason.nil?
12
16
  end