datadog 2.7.1 → 2.18.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 (441) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +353 -1
  3. data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +78 -102
  5. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
  7. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
  8. data/ext/datadog_profiling_native_extension/collectors_stack.c +235 -57
  9. data/ext/datadog_profiling_native_extension/collectors_stack.h +21 -5
  10. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +376 -156
  11. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
  12. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  13. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  14. data/ext/datadog_profiling_native_extension/encoded_profile.c +79 -0
  15. data/ext/datadog_profiling_native_extension/encoded_profile.h +8 -0
  16. data/ext/datadog_profiling_native_extension/extconf.rb +14 -8
  17. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
  18. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
  19. data/ext/datadog_profiling_native_extension/heap_recorder.c +295 -532
  20. data/ext/datadog_profiling_native_extension/heap_recorder.h +6 -8
  21. data/ext/datadog_profiling_native_extension/http_transport.c +64 -98
  22. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +22 -0
  23. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -5
  24. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +69 -1
  25. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +16 -4
  26. data/ext/datadog_profiling_native_extension/profiling.c +19 -8
  27. data/ext/datadog_profiling_native_extension/ruby_helpers.c +9 -21
  28. data/ext/datadog_profiling_native_extension/ruby_helpers.h +2 -10
  29. data/ext/datadog_profiling_native_extension/stack_recorder.c +231 -181
  30. data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -2
  31. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
  32. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
  33. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
  34. data/ext/libdatadog_api/crashtracker.c +17 -15
  35. data/ext/libdatadog_api/crashtracker.h +5 -0
  36. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  37. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  38. data/ext/libdatadog_api/extconf.rb +2 -2
  39. data/ext/libdatadog_api/init.c +15 -0
  40. data/ext/libdatadog_api/library_config.c +164 -0
  41. data/ext/libdatadog_api/library_config.h +25 -0
  42. data/ext/libdatadog_api/macos_development.md +3 -3
  43. data/ext/libdatadog_api/process_discovery.c +112 -0
  44. data/ext/libdatadog_api/process_discovery.h +5 -0
  45. data/ext/libdatadog_extconf_helpers.rb +2 -2
  46. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
  47. data/lib/datadog/appsec/actions_handler.rb +49 -0
  48. data/lib/datadog/appsec/anonymizer.rb +16 -0
  49. data/lib/datadog/appsec/api_security/lru_cache.rb +56 -0
  50. data/lib/datadog/appsec/api_security/route_extractor.rb +65 -0
  51. data/lib/datadog/appsec/api_security/sampler.rb +59 -0
  52. data/lib/datadog/appsec/api_security.rb +23 -0
  53. data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
  54. data/lib/datadog/appsec/assets/waf_rules/recommended.json +623 -253
  55. data/lib/datadog/appsec/assets/waf_rules/strict.json +69 -107
  56. data/lib/datadog/appsec/autoload.rb +1 -1
  57. data/lib/datadog/appsec/component.rb +49 -65
  58. data/lib/datadog/appsec/compressed_json.rb +40 -0
  59. data/lib/datadog/appsec/configuration/settings.rb +212 -27
  60. data/lib/datadog/appsec/context.rb +74 -0
  61. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +92 -0
  62. data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
  63. data/lib/datadog/appsec/contrib/active_record/patcher.rb +101 -0
  64. data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
  65. data/lib/datadog/appsec/contrib/devise/configuration.rb +52 -0
  66. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +78 -0
  67. data/lib/datadog/appsec/contrib/devise/ext.rb +22 -0
  68. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -2
  69. data/lib/datadog/appsec/contrib/devise/patcher.rb +33 -25
  70. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
  71. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -0
  72. data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +3 -3
  73. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +106 -0
  74. data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
  75. data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
  76. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +42 -0
  77. data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
  78. data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
  79. data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
  80. data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
  81. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +41 -0
  82. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
  83. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +17 -30
  84. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  85. data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
  86. data/lib/datadog/appsec/contrib/rack/ext.rb +34 -0
  87. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
  88. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +78 -98
  89. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  90. data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
  91. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
  92. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +73 -78
  93. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +16 -33
  94. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  95. data/lib/datadog/appsec/contrib/rails/patcher.rb +25 -38
  96. data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
  97. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
  98. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +38 -0
  99. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +31 -68
  100. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  101. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -31
  102. data/lib/datadog/appsec/event.rb +96 -135
  103. data/lib/datadog/appsec/ext.rb +12 -3
  104. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +7 -2
  105. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
  106. data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
  107. data/lib/datadog/appsec/metrics/collector.rb +38 -0
  108. data/lib/datadog/appsec/metrics/exporter.rb +35 -0
  109. data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
  110. data/lib/datadog/appsec/metrics.rb +13 -0
  111. data/lib/datadog/appsec/monitor/gateway/watcher.rb +52 -32
  112. data/lib/datadog/appsec/processor/rule_loader.rb +30 -36
  113. data/lib/datadog/appsec/remote.rb +31 -57
  114. data/lib/datadog/appsec/response.rb +19 -85
  115. data/lib/datadog/appsec/security_engine/engine.rb +194 -0
  116. data/lib/datadog/appsec/security_engine/result.rb +67 -0
  117. data/lib/datadog/appsec/security_engine/runner.rb +87 -0
  118. data/lib/datadog/appsec/security_engine.rb +9 -0
  119. data/lib/datadog/appsec/security_event.rb +39 -0
  120. data/lib/datadog/appsec/utils.rb +0 -2
  121. data/lib/datadog/appsec.rb +22 -12
  122. data/lib/datadog/auto_instrument.rb +3 -0
  123. data/lib/datadog/core/buffer/random.rb +18 -2
  124. data/lib/datadog/core/configuration/agent_settings.rb +52 -0
  125. data/lib/datadog/core/configuration/agent_settings_resolver.rb +4 -18
  126. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  127. data/lib/datadog/core/configuration/components.rb +74 -32
  128. data/lib/datadog/core/configuration/components_state.rb +23 -0
  129. data/lib/datadog/core/configuration/ext.rb +5 -1
  130. data/lib/datadog/core/configuration/option.rb +81 -45
  131. data/lib/datadog/core/configuration/option_definition.rb +6 -4
  132. data/lib/datadog/core/configuration/options.rb +3 -3
  133. data/lib/datadog/core/configuration/settings.rb +121 -50
  134. data/lib/datadog/core/configuration/stable_config.rb +22 -0
  135. data/lib/datadog/core/configuration.rb +43 -11
  136. data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
  137. data/lib/datadog/core/crashtracking/component.rb +4 -13
  138. data/lib/datadog/core/crashtracking/tag_builder.rb +4 -22
  139. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  140. data/lib/datadog/core/encoding.rb +17 -1
  141. data/lib/datadog/core/environment/agent_info.rb +78 -0
  142. data/lib/datadog/core/environment/cgroup.rb +10 -12
  143. data/lib/datadog/core/environment/container.rb +38 -40
  144. data/lib/datadog/core/environment/ext.rb +6 -6
  145. data/lib/datadog/core/environment/git.rb +1 -0
  146. data/lib/datadog/core/environment/identity.rb +3 -3
  147. data/lib/datadog/core/environment/platform.rb +3 -3
  148. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  149. data/lib/datadog/core/error.rb +11 -9
  150. data/lib/datadog/core/logger.rb +2 -2
  151. data/lib/datadog/core/metrics/client.rb +27 -27
  152. data/lib/datadog/core/metrics/logging.rb +5 -5
  153. data/lib/datadog/core/process_discovery/tracer_memfd.rb +15 -0
  154. data/lib/datadog/core/process_discovery.rb +36 -0
  155. data/lib/datadog/core/rate_limiter.rb +4 -2
  156. data/lib/datadog/core/remote/client/capabilities.rb +6 -0
  157. data/lib/datadog/core/remote/client.rb +107 -92
  158. data/lib/datadog/core/remote/component.rb +18 -19
  159. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  160. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  161. data/lib/datadog/core/remote/configuration/repository.rb +14 -1
  162. data/lib/datadog/core/remote/negotiation.rb +9 -9
  163. data/lib/datadog/core/remote/transport/config.rb +4 -3
  164. data/lib/datadog/core/remote/transport/http/api.rb +13 -18
  165. data/lib/datadog/core/remote/transport/http/client.rb +5 -4
  166. data/lib/datadog/core/remote/transport/http/config.rb +27 -55
  167. data/lib/datadog/core/remote/transport/http/negotiation.rb +8 -51
  168. data/lib/datadog/core/remote/transport/http.rb +25 -94
  169. data/lib/datadog/core/remote/transport/negotiation.rb +17 -4
  170. data/lib/datadog/core/remote/worker.rb +10 -7
  171. data/lib/datadog/core/runtime/metrics.rb +12 -5
  172. data/lib/datadog/core/tag_builder.rb +56 -0
  173. data/lib/datadog/core/telemetry/component.rb +84 -49
  174. data/lib/datadog/core/telemetry/emitter.rb +23 -11
  175. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +66 -0
  176. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  177. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  178. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  179. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  180. data/lib/datadog/core/telemetry/event/app_started.rb +269 -0
  181. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  182. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  183. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  184. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  185. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  186. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  187. data/lib/datadog/core/telemetry/event.rb +17 -383
  188. data/lib/datadog/core/telemetry/ext.rb +1 -0
  189. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  190. data/lib/datadog/core/telemetry/logger.rb +5 -4
  191. data/lib/datadog/core/telemetry/logging.rb +12 -6
  192. data/lib/datadog/core/telemetry/metric.rb +28 -6
  193. data/lib/datadog/core/telemetry/request.rb +4 -4
  194. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  195. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  196. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  197. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  198. data/lib/datadog/core/telemetry/transport/telemetry.rb +51 -0
  199. data/lib/datadog/core/telemetry/worker.rb +128 -25
  200. data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
  201. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  202. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
  203. data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +18 -1
  204. data/lib/datadog/core/transport/http/api/spec.rb +36 -0
  205. data/lib/datadog/{tracing → core}/transport/http/builder.rb +53 -31
  206. data/lib/datadog/core/transport/http/env.rb +8 -0
  207. data/lib/datadog/core/transport/http.rb +75 -0
  208. data/lib/datadog/core/transport/response.rb +4 -0
  209. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  210. data/lib/datadog/core/utils/duration.rb +32 -32
  211. data/lib/datadog/core/utils/forking.rb +2 -2
  212. data/lib/datadog/core/utils/network.rb +6 -6
  213. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  214. data/lib/datadog/core/utils/time.rb +20 -0
  215. data/lib/datadog/core/utils/truncation.rb +21 -0
  216. data/lib/datadog/core/utils.rb +7 -0
  217. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  218. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  219. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  220. data/lib/datadog/core/worker.rb +1 -1
  221. data/lib/datadog/core/workers/async.rb +29 -12
  222. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  223. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  224. data/lib/datadog/core.rb +8 -0
  225. data/lib/datadog/di/base.rb +115 -0
  226. data/lib/datadog/di/boot.rb +34 -0
  227. data/lib/datadog/di/code_tracker.rb +26 -15
  228. data/lib/datadog/di/component.rb +23 -14
  229. data/lib/datadog/di/configuration/settings.rb +25 -1
  230. data/lib/datadog/di/contrib/active_record.rb +1 -0
  231. data/lib/datadog/di/contrib/railtie.rb +15 -0
  232. data/lib/datadog/di/contrib.rb +28 -0
  233. data/lib/datadog/di/error.rb +5 -0
  234. data/lib/datadog/di/instrumenter.rb +162 -21
  235. data/lib/datadog/di/logger.rb +30 -0
  236. data/lib/datadog/di/preload.rb +18 -0
  237. data/lib/datadog/di/probe.rb +14 -7
  238. data/lib/datadog/di/probe_builder.rb +1 -0
  239. data/lib/datadog/di/probe_manager.rb +11 -5
  240. data/lib/datadog/di/probe_notification_builder.rb +54 -38
  241. data/lib/datadog/di/probe_notifier_worker.rb +60 -26
  242. data/lib/datadog/di/redactor.rb +0 -1
  243. data/lib/datadog/di/remote.rb +147 -0
  244. data/lib/datadog/di/serializer.rb +19 -8
  245. data/lib/datadog/di/transport/diagnostics.rb +62 -0
  246. data/lib/datadog/di/transport/http/api.rb +42 -0
  247. data/lib/datadog/di/transport/http/client.rb +47 -0
  248. data/lib/datadog/di/transport/http/diagnostics.rb +65 -0
  249. data/lib/datadog/di/transport/http/input.rb +77 -0
  250. data/lib/datadog/di/transport/http.rb +57 -0
  251. data/lib/datadog/di/transport/input.rb +70 -0
  252. data/lib/datadog/di/utils.rb +103 -0
  253. data/lib/datadog/di.rb +14 -76
  254. data/lib/datadog/error_tracking/collector.rb +87 -0
  255. data/lib/datadog/error_tracking/component.rb +167 -0
  256. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  257. data/lib/datadog/error_tracking/configuration.rb +11 -0
  258. data/lib/datadog/error_tracking/ext.rb +18 -0
  259. data/lib/datadog/error_tracking/extensions.rb +16 -0
  260. data/lib/datadog/error_tracking/filters.rb +77 -0
  261. data/lib/datadog/error_tracking.rb +18 -0
  262. data/lib/datadog/kit/appsec/events.rb +15 -3
  263. data/lib/datadog/kit/identity.rb +9 -5
  264. data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
  265. data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
  266. data/lib/datadog/opentelemetry/api/context.rb +16 -2
  267. data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
  268. data/lib/datadog/opentelemetry.rb +2 -1
  269. data/lib/datadog/profiling/collectors/code_provenance.rb +18 -9
  270. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -0
  271. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
  272. data/lib/datadog/profiling/collectors/info.rb +3 -0
  273. data/lib/datadog/profiling/collectors/thread_context.rb +17 -2
  274. data/lib/datadog/profiling/component.rb +64 -82
  275. data/lib/datadog/profiling/encoded_profile.rb +11 -0
  276. data/lib/datadog/profiling/exporter.rb +3 -4
  277. data/lib/datadog/profiling/ext.rb +0 -14
  278. data/lib/datadog/profiling/flush.rb +5 -8
  279. data/lib/datadog/profiling/http_transport.rb +8 -87
  280. data/lib/datadog/profiling/load_native_extension.rb +1 -33
  281. data/lib/datadog/profiling/profiler.rb +2 -0
  282. data/lib/datadog/profiling/scheduler.rb +10 -2
  283. data/lib/datadog/profiling/stack_recorder.rb +9 -9
  284. data/lib/datadog/profiling/tag_builder.rb +5 -41
  285. data/lib/datadog/profiling/tasks/setup.rb +2 -0
  286. data/lib/datadog/profiling.rb +6 -2
  287. data/lib/datadog/tracing/analytics.rb +1 -1
  288. data/lib/datadog/tracing/component.rb +16 -12
  289. data/lib/datadog/tracing/configuration/ext.rb +8 -1
  290. data/lib/datadog/tracing/configuration/settings.rb +22 -10
  291. data/lib/datadog/tracing/context_provider.rb +1 -1
  292. data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
  293. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
  294. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -0
  295. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +19 -12
  296. data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
  297. data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
  298. data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
  299. data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
  300. data/lib/datadog/tracing/contrib/active_record/integration.rb +7 -3
  301. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +7 -2
  302. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +36 -1
  303. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  304. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +14 -4
  305. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
  306. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
  307. data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
  308. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  309. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
  310. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  311. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
  312. data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
  313. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
  314. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  315. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
  316. data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
  317. data/lib/datadog/tracing/contrib/ext.rb +1 -0
  318. data/lib/datadog/tracing/contrib/extensions.rb +29 -3
  319. data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
  320. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
  321. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
  322. data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
  323. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
  324. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
  325. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
  326. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
  327. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
  328. data/lib/datadog/tracing/contrib/http/instrumentation.rb +6 -10
  329. data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
  330. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -16
  331. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +7 -15
  332. data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
  333. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
  334. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +27 -0
  335. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +48 -0
  336. data/lib/datadog/tracing/contrib/karafka/ext.rb +27 -0
  337. data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
  338. data/lib/datadog/tracing/contrib/karafka/monitor.rb +66 -0
  339. data/lib/datadog/tracing/contrib/karafka/patcher.rb +71 -0
  340. data/lib/datadog/tracing/contrib/karafka.rb +37 -0
  341. data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
  342. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  343. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  344. data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
  345. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  346. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
  347. data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
  348. data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
  349. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
  350. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  351. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
  352. data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
  353. data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
  354. data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
  355. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  356. data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
  357. data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
  358. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
  359. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
  360. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
  361. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
  362. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
  363. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -2
  364. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
  365. data/lib/datadog/tracing/contrib/support.rb +28 -0
  366. data/lib/datadog/tracing/contrib.rb +1 -0
  367. data/lib/datadog/tracing/correlation.rb +9 -2
  368. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  369. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  370. data/lib/datadog/tracing/distributed/baggage.rb +131 -0
  371. data/lib/datadog/tracing/distributed/datadog.rb +4 -2
  372. data/lib/datadog/tracing/distributed/propagation.rb +25 -4
  373. data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
  374. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  375. data/lib/datadog/tracing/metadata/ext.rb +5 -0
  376. data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
  377. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
  378. data/lib/datadog/tracing/metadata.rb +2 -0
  379. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  380. data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
  381. data/lib/datadog/tracing/span.rb +22 -5
  382. data/lib/datadog/tracing/span_event.rb +124 -4
  383. data/lib/datadog/tracing/span_operation.rb +52 -16
  384. data/lib/datadog/tracing/sync_writer.rb +10 -6
  385. data/lib/datadog/tracing/trace_digest.rb +9 -2
  386. data/lib/datadog/tracing/trace_operation.rb +55 -27
  387. data/lib/datadog/tracing/trace_segment.rb +6 -4
  388. data/lib/datadog/tracing/tracer.rb +66 -14
  389. data/lib/datadog/tracing/transport/http/api.rb +5 -4
  390. data/lib/datadog/tracing/transport/http/client.rb +5 -4
  391. data/lib/datadog/tracing/transport/http/traces.rb +13 -44
  392. data/lib/datadog/tracing/transport/http.rb +13 -70
  393. data/lib/datadog/tracing/transport/serializable_trace.rb +31 -7
  394. data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
  395. data/lib/datadog/tracing/transport/traces.rb +47 -13
  396. data/lib/datadog/tracing/utils.rb +1 -1
  397. data/lib/datadog/tracing/workers/trace_writer.rb +8 -5
  398. data/lib/datadog/tracing/workers.rb +5 -4
  399. data/lib/datadog/tracing/writer.rb +10 -6
  400. data/lib/datadog/tracing.rb +16 -3
  401. data/lib/datadog/version.rb +2 -2
  402. data/lib/datadog.rb +2 -0
  403. metadata +149 -54
  404. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
  405. data/ext/datadog_profiling_loader/extconf.rb +0 -60
  406. data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -92
  407. data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -114
  408. data/lib/datadog/appsec/contrib/devise/event.rb +0 -57
  409. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -77
  410. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -54
  411. data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
  412. data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
  413. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
  414. data/lib/datadog/appsec/contrib/patcher.rb +0 -12
  415. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
  416. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
  417. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
  418. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
  419. data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
  420. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
  421. data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
  422. data/lib/datadog/appsec/processor/actions.rb +0 -49
  423. data/lib/datadog/appsec/processor/context.rb +0 -107
  424. data/lib/datadog/appsec/processor/rule_merger.rb +0 -170
  425. data/lib/datadog/appsec/processor.rb +0 -106
  426. data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
  427. data/lib/datadog/appsec/reactive/engine.rb +0 -47
  428. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  429. data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
  430. data/lib/datadog/appsec/scope.rb +0 -58
  431. data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
  432. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
  433. data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
  434. data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
  435. data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
  436. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  437. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  438. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  439. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
  440. data/lib/datadog/di/transport.rb +0 -81
  441. data/lib/datadog/tracing/transport/http/api/spec.rb +0 -19
@@ -1,9 +1,21 @@
1
1
  #include <ruby.h>
2
2
  #include <ruby/debug.h>
3
- #include "extconf.h"
4
- #include "helpers.h"
5
- #include "libdatadog_helpers.h"
6
- #include "ruby_helpers.h"
3
+ #include <ruby/st.h>
4
+
5
+ #include "extconf.h" // This is needed for the HAVE_DLADDR and friends below
6
+
7
+ // For dladdr/dladdr1
8
+ #if defined(HAVE_DLADDR1) || defined(HAVE_DLADDR)
9
+ #ifndef _GNU_SOURCE
10
+ #define _GNU_SOURCE
11
+ #endif
12
+ #include <dlfcn.h>
13
+ #ifdef HAVE_DLADDR1
14
+ #include <link.h>
15
+ #endif
16
+ #endif
17
+
18
+ #include "datadog_ruby_common.h"
7
19
  #include "private_vm_api_access.h"
8
20
  #include "stack_recorder.h"
9
21
  #include "collectors_stack.h"
@@ -11,18 +23,22 @@
11
23
  // Gathers stack traces from running threads, storing them in a StackRecorder instance
12
24
  // This file implements the native bits of the Datadog::Profiling::Collectors::Stack class
13
25
 
14
- static VALUE missing_string = Qnil;
15
-
16
- // Used as scratch space during sampling
17
- struct sampling_buffer {
18
- uint16_t max_frames;
19
- ddog_prof_Location *locations;
20
- frame_info *stack_buffer;
21
- }; // Note: typedef'd in the header to sampling_buffer
22
-
26
+ static VALUE _native_filenames_available(DDTRACE_UNUSED VALUE self);
27
+ static VALUE _native_ruby_native_filename(DDTRACE_UNUSED VALUE self);
23
28
  static VALUE _native_sample(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
24
29
  static VALUE native_sample_do(VALUE args);
25
30
  static VALUE native_sample_ensure(VALUE args);
31
+ static void set_file_info_for_cfunc(
32
+ ddog_CharSlice *filename_slice,
33
+ int *line,
34
+ ddog_CharSlice last_ruby_frame_filename,
35
+ int last_ruby_line,
36
+ void *function,
37
+ bool top_of_the_stack,
38
+ bool native_filenames_enabled,
39
+ st_table *native_filenames_cache
40
+ );
41
+ static const char *get_or_compute_native_filename(void *function, st_table *native_filenames_cache);
26
42
  static void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer* buffer, char *frames_omitted_message, int frames_omitted_message_size);
27
43
  static void record_placeholder_stack_in_native_code(VALUE recorder_instance, sample_values values, sample_labels labels);
28
44
  static void maybe_trim_template_random_ids(ddog_CharSlice *name_slice, ddog_CharSlice *filename_slice);
@@ -32,19 +48,50 @@ static void maybe_trim_template_random_ids(ddog_CharSlice *name_slice, ddog_Char
32
48
  extern VALUE rb_iseq_path(const VALUE);
33
49
  extern VALUE rb_iseq_base_label(const VALUE);
34
50
 
51
+ // NULL if dladdr is not available or we weren't able to get the native filename for the Ruby VM
52
+ static const char *ruby_native_filename = NULL;
53
+
35
54
  void collectors_stack_init(VALUE profiling_module) {
36
55
  VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
37
56
  VALUE collectors_stack_class = rb_define_class_under(collectors_module, "Stack", rb_cObject);
57
+
58
+ rb_define_singleton_method(collectors_stack_class, "_native_filenames_available?", _native_filenames_available, 0);
59
+ rb_define_singleton_method(collectors_stack_class, "_native_ruby_native_filename", _native_ruby_native_filename, 0);
60
+
38
61
  // Hosts methods used for testing the native code using RSpec
39
62
  VALUE testing_module = rb_define_module_under(collectors_stack_class, "Testing");
40
63
 
41
64
  rb_define_singleton_method(testing_module, "_native_sample", _native_sample, -1);
42
65
 
43
- missing_string = rb_str_new2("");
44
- rb_global_variable(&missing_string);
66
+ #if defined(HAVE_DLADDR1) || defined(HAVE_DLADDR)
67
+ // To be able to detect when a frame is coming from Ruby, we record here its filename as returned by dladdr.
68
+ // We expect this same pointer to be returned by dladdr for all frames coming from Ruby.
69
+ //
70
+ // Small note: Creating/deleting the cache is a bit awkward here, but it seems like a bigger footgun to allow
71
+ // `get_or_compute_native_filename` to run without a cache, since we never expect that to happen during sampling. So it seems
72
+ // like a reasonable trade-off to force callers to always figure that out.
73
+ st_table *temporary_cache = st_init_numtable();
74
+ const char *native_filename = get_or_compute_native_filename(rb_ary_new, temporary_cache);
75
+ if (native_filename != NULL && native_filename[0] != '\0') {
76
+ ruby_native_filename = native_filename;
77
+ }
78
+ st_free_table(temporary_cache);
79
+ #endif
80
+ }
81
+
82
+ static VALUE _native_filenames_available(DDTRACE_UNUSED VALUE self) {
83
+ #if defined(HAVE_DLADDR1) || defined(HAVE_DLADDR)
84
+ return ruby_native_filename != NULL ? Qtrue : Qfalse;
85
+ #else
86
+ return Qfalse;
87
+ #endif
45
88
  }
46
89
 
47
- struct native_sample_args {
90
+ static VALUE _native_ruby_native_filename(DDTRACE_UNUSED VALUE self) {
91
+ return ruby_native_filename != NULL ? rb_utf8_str_new_cstr(ruby_native_filename) : Qnil;
92
+ }
93
+
94
+ typedef struct {
48
95
  VALUE in_gc;
49
96
  VALUE recorder_instance;
50
97
  sample_values values;
@@ -52,7 +99,9 @@ struct native_sample_args {
52
99
  VALUE thread;
53
100
  ddog_prof_Location *locations;
54
101
  sampling_buffer *buffer;
55
- };
102
+ bool native_filenames_enabled;
103
+ st_table *native_filenames_cache;
104
+ } native_sample_args;
56
105
 
57
106
  // This method exists only to enable testing Datadog::Profiling::Collectors::Stack behavior using RSpec.
58
107
  // It SHOULD NOT be used for other purposes.
@@ -73,10 +122,15 @@ static VALUE _native_sample(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self) {
73
122
  VALUE max_frames = rb_hash_lookup2(options, ID2SYM(rb_intern("max_frames")), INT2NUM(400));
74
123
  VALUE in_gc = rb_hash_lookup2(options, ID2SYM(rb_intern("in_gc")), Qfalse);
75
124
  VALUE is_gvl_waiting_state = rb_hash_lookup2(options, ID2SYM(rb_intern("is_gvl_waiting_state")), Qfalse);
125
+ VALUE native_filenames_enabled = rb_hash_lookup2(options, ID2SYM(rb_intern("native_filenames_enabled")), Qfalse);
76
126
 
77
127
  ENFORCE_TYPE(metric_values_hash, T_HASH);
78
128
  ENFORCE_TYPE(labels_array, T_ARRAY);
79
129
  ENFORCE_TYPE(numeric_labels_array, T_ARRAY);
130
+ ENFORCE_TYPE(max_frames, T_FIXNUM);
131
+ ENFORCE_BOOLEAN(in_gc);
132
+ ENFORCE_BOOLEAN(is_gvl_waiting_state);
133
+ ENFORCE_BOOLEAN(native_filenames_enabled);
80
134
 
81
135
  VALUE zero = INT2NUM(0);
82
136
  VALUE heap_sample = rb_hash_lookup2(metric_values_hash, rb_str_new_cstr("heap_sample"), Qfalse);
@@ -119,25 +173,28 @@ static VALUE _native_sample(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self) {
119
173
  int max_frames_requested = sampling_buffer_check_max_frames(NUM2INT(max_frames));
120
174
 
121
175
  ddog_prof_Location *locations = ruby_xcalloc(max_frames_requested, sizeof(ddog_prof_Location));
122
- sampling_buffer *buffer = sampling_buffer_new(max_frames_requested, locations);
176
+ sampling_buffer buffer;
177
+ sampling_buffer_initialize(&buffer, max_frames_requested, locations);
123
178
 
124
179
  ddog_prof_Slice_Label slice_labels = {.ptr = labels, .len = labels_count};
125
180
 
126
- struct native_sample_args args_struct = {
181
+ native_sample_args args_struct = {
127
182
  .in_gc = in_gc,
128
183
  .recorder_instance = recorder_instance,
129
184
  .values = values,
130
185
  .labels = (sample_labels) {.labels = slice_labels, .state_label = state_label, .is_gvl_waiting_state = is_gvl_waiting_state == Qtrue},
131
186
  .thread = thread,
132
187
  .locations = locations,
133
- .buffer = buffer,
188
+ .buffer = &buffer,
189
+ .native_filenames_enabled = native_filenames_enabled == Qtrue,
190
+ .native_filenames_cache = st_init_numtable(),
134
191
  };
135
192
 
136
193
  return rb_ensure(native_sample_do, (VALUE) &args_struct, native_sample_ensure, (VALUE) &args_struct);
137
194
  }
138
195
 
139
196
  static VALUE native_sample_do(VALUE args) {
140
- struct native_sample_args *args_struct = (struct native_sample_args *) args;
197
+ native_sample_args *args_struct = (native_sample_args *) args;
141
198
 
142
199
  if (args_struct->in_gc == Qtrue) {
143
200
  record_placeholder_stack(
@@ -152,7 +209,9 @@ static VALUE native_sample_do(VALUE args) {
152
209
  args_struct->buffer,
153
210
  args_struct->recorder_instance,
154
211
  args_struct->values,
155
- args_struct->labels
212
+ args_struct->labels,
213
+ args_struct->native_filenames_enabled,
214
+ args_struct->native_filenames_cache
156
215
  );
157
216
  }
158
217
 
@@ -160,10 +219,11 @@ static VALUE native_sample_do(VALUE args) {
160
219
  }
161
220
 
162
221
  static VALUE native_sample_ensure(VALUE args) {
163
- struct native_sample_args *args_struct = (struct native_sample_args *) args;
222
+ native_sample_args *args_struct = (native_sample_args *) args;
164
223
 
165
224
  ruby_xfree(args_struct->locations);
166
225
  sampling_buffer_free(args_struct->buffer);
226
+ st_free_table(args_struct->native_filenames_cache);
167
227
 
168
228
  return Qtrue;
169
229
  }
@@ -184,14 +244,15 @@ void sample_thread(
184
244
  sampling_buffer* buffer,
185
245
  VALUE recorder_instance,
186
246
  sample_values values,
187
- sample_labels labels
247
+ sample_labels labels,
248
+ bool native_filenames_enabled,
249
+ st_table *native_filenames_cache
188
250
  ) {
189
- int captured_frames = ddtrace_rb_profile_frames(
190
- thread,
191
- 0 /* stack starting depth */,
192
- buffer->max_frames,
193
- buffer->stack_buffer
194
- );
251
+ // If we already prepared a sample, we use it below; if not, we prepare it now.
252
+ if (!buffer->pending_sample) prepare_sample_thread(thread, buffer);
253
+
254
+ buffer->pending_sample = false;
255
+ int captured_frames = buffer->pending_sample_result;
195
256
 
196
257
  if (captured_frames == PLACEHOLDER_STACK_IN_NATIVE_CODE) {
197
258
  record_placeholder_stack_in_native_code(recorder_instance, values, labels);
@@ -211,7 +272,7 @@ void sample_thread(
211
272
  // on the stack that is below (e.g. directly or indirectly has called) the native method.
212
273
  // Thus, we keep that frame here to able to replicate that behavior.
213
274
  // (This is why we also iterate the sampling buffers backwards below -- so that it's easier to keep the last_ruby_frame_filename)
214
- VALUE last_ruby_frame_filename = Qnil;
275
+ ddog_CharSlice last_ruby_frame_filename = DDOG_CHARSLICE_C("");
215
276
  int last_ruby_line = 0;
216
277
 
217
278
  ddog_prof_Label *state_label = labels.state_label;
@@ -230,31 +291,39 @@ void sample_thread(
230
291
  }
231
292
 
232
293
  for (int i = captured_frames - 1; i >= 0; i--) {
233
- VALUE name, filename;
294
+ ddog_CharSlice name_slice, filename_slice;
234
295
  int line;
296
+ bool top_of_the_stack = i == 0;
235
297
 
236
298
  if (buffer->stack_buffer[i].is_ruby_frame) {
237
- name = rb_iseq_base_label(buffer->stack_buffer[i].as.ruby_frame.iseq);
238
- filename = rb_iseq_path(buffer->stack_buffer[i].as.ruby_frame.iseq);
299
+ VALUE name = rb_iseq_base_label(buffer->stack_buffer[i].as.ruby_frame.iseq);
300
+ VALUE filename = rb_iseq_path(buffer->stack_buffer[i].as.ruby_frame.iseq);
301
+
302
+ name_slice = NIL_P(name) ? DDOG_CHARSLICE_C("") : char_slice_from_ruby_string(name);
303
+ filename_slice = NIL_P(filename) ? DDOG_CHARSLICE_C("") : char_slice_from_ruby_string(filename);
239
304
  line = buffer->stack_buffer[i].as.ruby_frame.line;
240
305
 
241
- last_ruby_frame_filename = filename;
306
+ last_ruby_frame_filename = filename_slice;
242
307
  last_ruby_line = line;
243
308
  } else {
244
- name = rb_id2str(buffer->stack_buffer[i].as.native_frame.method_id);
245
- filename = last_ruby_frame_filename;
246
- line = last_ruby_line;
309
+ VALUE name = rb_id2str(buffer->stack_buffer[i].as.native_frame.method_id);
310
+
311
+ name_slice = NIL_P(name) ? DDOG_CHARSLICE_C("") : char_slice_from_ruby_string(name);
312
+
313
+ set_file_info_for_cfunc(
314
+ &filename_slice,
315
+ &line,
316
+ last_ruby_frame_filename,
317
+ last_ruby_line,
318
+ buffer->stack_buffer[i].as.native_frame.function,
319
+ top_of_the_stack,
320
+ native_filenames_enabled,
321
+ native_filenames_cache
322
+ );
247
323
  }
248
324
 
249
- name = NIL_P(name) ? missing_string : name;
250
- filename = NIL_P(filename) ? missing_string : filename;
251
-
252
- ddog_CharSlice name_slice = char_slice_from_ruby_string(name);
253
- ddog_CharSlice filename_slice = char_slice_from_ruby_string(filename);
254
-
255
325
  maybe_trim_template_random_ids(&name_slice, &filename_slice);
256
326
 
257
- bool top_of_the_stack = i == 0;
258
327
 
259
328
  // When there's only wall-time in a sample, this means that the thread was not active in the sampled period.
260
329
  if (top_of_the_stack && only_wall_time) {
@@ -300,7 +369,7 @@ void sample_thread(
300
369
  }
301
370
 
302
371
  buffer->locations[i] = (ddog_prof_Location) {
303
- .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
372
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
304
373
  .function = (ddog_prof_Function) {.name = name_slice, .filename = filename_slice},
305
374
  .line = line,
306
375
  };
@@ -324,6 +393,94 @@ void sample_thread(
324
393
  );
325
394
  }
326
395
 
396
+ #if defined(HAVE_DLADDR1) || defined(HAVE_DLADDR)
397
+ static void set_file_info_for_cfunc(
398
+ ddog_CharSlice *filename_slice,
399
+ int *line,
400
+ ddog_CharSlice last_ruby_frame_filename,
401
+ int last_ruby_line,
402
+ void *function,
403
+ bool top_of_the_stack,
404
+ bool native_filenames_enabled,
405
+ st_table *native_filenames_cache
406
+ ) {
407
+ if (native_filenames_enabled) {
408
+ const char *native_filename = get_or_compute_native_filename(function, native_filenames_cache);
409
+ if (native_filename && native_filename[0] != '\0' &&
410
+ // Using the ruby_native_filename at the top of the stack has a weird effect on the "top methods" table because
411
+ // e.g. we don't have classnames for methods. This is especially visible in the allocations profile, e.g.
412
+ // what a surprise, you're telling me "libruby.so:new" is the top method always?
413
+ //
414
+ // Until we have a better way of dealing with that, we don't do this replacement for the top frame.
415
+ //
416
+ // Also, dladdr is expected to always return the same pointer to the ruby_native_filename, so that's why we're
417
+ // comparing only pointer values and not the string contents.
418
+ (native_filename != ruby_native_filename || !top_of_the_stack)
419
+ ) {
420
+ *filename_slice = (ddog_CharSlice) {.ptr = native_filename, .len = strlen(native_filename)};
421
+ // Explicitly set the line to 0 as it has no meaning on a native library (e.g. an .so is built of many source files)
422
+ // and anyway often that debug info is not available.
423
+ *line = 0;
424
+ return;
425
+ }
426
+ }
427
+
428
+ *filename_slice = last_ruby_frame_filename;
429
+ *line = last_ruby_line;
430
+ }
431
+
432
+ // `native_filenames_cache` is used to cache native filename lookup results (Map[void *function_pointer, char *filename])
433
+ //
434
+ // Caching this information is safe because there's no API in Ruby to "unrequire" a native extension. Thus, if we see a
435
+ // frame on the **Ruby** stack with a given `function`, then that `function` was registered with the Ruby VM and
436
+ // belongs to a Ruby extension, so a lot of other bad things would happen if it was dlclosed.
437
+ static const char *get_or_compute_native_filename(void *function, st_table *native_filenames_cache) {
438
+ const char *cached_filename = NULL;
439
+ st_lookup(native_filenames_cache, (st_data_t) function, (st_data_t *) &cached_filename);
440
+ if (cached_filename != NULL) return cached_filename;
441
+
442
+ Dl_info info;
443
+ const char *native_filename = NULL;
444
+ #ifdef HAVE_DLADDR1
445
+ struct link_map *extra_info = NULL;
446
+ if (dladdr1(function, &info, (void **) &extra_info, RTLD_DL_LINKMAP) != 0 && extra_info != NULL) {
447
+ native_filename = extra_info->l_name != NULL ? extra_info->l_name : info.dli_fname;
448
+ }
449
+ #elif defined(HAVE_DLADDR)
450
+ if (dladdr(function, &info) != 0) {
451
+ native_filename = info.dli_fname;
452
+ }
453
+ #endif
454
+
455
+ // We explicitly use an empty string here so as to cache lookups that somehow "failed". Otherwise we would keep trying them every time.
456
+ if (native_filename == NULL) native_filename = "";
457
+
458
+ // An st_table is what Ruby uses for its own hashtables. This allows us to get an easy estimate of the size of the cache:
459
+ // `ObjectSpace.memsize_of((0..100000).map { |it| [it, nil] }.to_h)` => 4194400 bytes as of Ruby 3.2 so that seems reasonable?
460
+ // Note: `st_table_size()` is available from Ruby 3.2+ but not before
461
+ if (native_filenames_cache->num_entries >= 100000) {
462
+ st_clear(native_filenames_cache);
463
+ }
464
+
465
+ st_insert(native_filenames_cache, (st_data_t) function, (st_data_t) native_filename);
466
+ return native_filename;
467
+ }
468
+ #else
469
+ static void set_file_info_for_cfunc(
470
+ ddog_CharSlice *filename_slice,
471
+ int *line,
472
+ ddog_CharSlice last_ruby_frame_filename,
473
+ int last_ruby_line,
474
+ DDTRACE_UNUSED void *function,
475
+ DDTRACE_UNUSED bool top_of_the_stack,
476
+ DDTRACE_UNUSED bool native_filenames_enabled,
477
+ DDTRACE_UNUSED st_table *native_filenames_cache
478
+ ) {
479
+ *filename_slice = last_ruby_frame_filename;
480
+ *line = last_ruby_line;
481
+ }
482
+ #endif
483
+
327
484
  // Rails's ActionView likes to dynamically generate method names with suffixed hashes/ids, resulting in methods with
328
485
  // names such as:
329
486
  // * "_app_views_layouts_explore_html_haml__2304485752546535910_211320" (__number_number suffix -- two underscores)
@@ -340,6 +497,7 @@ static void maybe_trim_template_random_ids(ddog_CharSlice *name_slice, ddog_Char
340
497
  if (filename_slice->len < 3 || memcmp(filename_slice->ptr + filename_slice->len - 3, ".rb", 3) == 0) return;
341
498
 
342
499
  if (name_slice->len > 1024) return;
500
+ if (name_slice->len == 0) return;
343
501
 
344
502
  int pos = ((int) name_slice->len) - 1;
345
503
 
@@ -379,7 +537,7 @@ static void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer*
379
537
  ddog_CharSlice function_name = DDOG_CHARSLICE_C("");
380
538
  ddog_CharSlice function_filename = {.ptr = frames_omitted_message, .len = strlen(frames_omitted_message)};
381
539
  buffer->locations[buffer->max_frames - 1] = (ddog_prof_Location) {
382
- .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
540
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
383
541
  .function = (ddog_prof_Function) {.name = function_name, .filename = function_filename},
384
542
  .line = 0,
385
543
  };
@@ -426,7 +584,7 @@ void record_placeholder_stack(
426
584
  ddog_CharSlice placeholder_stack
427
585
  ) {
428
586
  ddog_prof_Location placeholder_location = {
429
- .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C("")},
587
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
430
588
  .function = {.name = DDOG_CHARSLICE_C(""), .filename = placeholder_stack},
431
589
  .line = 0,
432
590
  };
@@ -439,30 +597,50 @@ void record_placeholder_stack(
439
597
  );
440
598
  }
441
599
 
600
+ void prepare_sample_thread(VALUE thread, sampling_buffer *buffer) {
601
+ buffer->pending_sample = true;
602
+ buffer->pending_sample_result = ddtrace_rb_profile_frames(thread, 0, buffer->max_frames, buffer->stack_buffer);
603
+ }
604
+
442
605
  uint16_t sampling_buffer_check_max_frames(int max_frames) {
443
606
  if (max_frames < 5) rb_raise(rb_eArgError, "Invalid max_frames: value must be >= 5");
444
607
  if (max_frames > MAX_FRAMES_LIMIT) rb_raise(rb_eArgError, "Invalid max_frames: value must be <= " MAX_FRAMES_LIMIT_AS_STRING);
445
608
  return max_frames;
446
609
  }
447
610
 
448
- sampling_buffer *sampling_buffer_new(uint16_t max_frames, ddog_prof_Location *locations) {
611
+ void sampling_buffer_initialize(sampling_buffer *buffer, uint16_t max_frames, ddog_prof_Location *locations) {
449
612
  sampling_buffer_check_max_frames(max_frames);
450
613
 
451
- // Note: never returns NULL; if out of memory, it calls the Ruby out-of-memory handlers
452
- sampling_buffer* buffer = ruby_xcalloc(1, sizeof(sampling_buffer));
453
-
454
614
  buffer->max_frames = max_frames;
455
615
  buffer->locations = locations;
456
616
  buffer->stack_buffer = ruby_xcalloc(max_frames, sizeof(frame_info));
457
-
458
- return buffer;
617
+ buffer->pending_sample = false;
618
+ buffer->pending_sample_result = 0;
459
619
  }
460
620
 
461
621
  void sampling_buffer_free(sampling_buffer *buffer) {
462
- if (buffer == NULL) rb_raise(rb_eArgError, "sampling_buffer_free called with NULL buffer");
622
+ if (buffer->max_frames == 0 || buffer->locations == NULL || buffer->stack_buffer == NULL) {
623
+ rb_raise(rb_eArgError, "sampling_buffer_free called with invalid buffer");
624
+ }
463
625
 
464
- // buffer->locations are owned by whoever called sampling_buffer_new, not us
465
626
  ruby_xfree(buffer->stack_buffer);
627
+ // Note: buffer->locations are owned by whoever called sampling_buffer_initialize, not by the buffer itself
628
+
629
+ buffer->max_frames = 0;
630
+ buffer->locations = NULL;
631
+ buffer->stack_buffer = NULL;
632
+ buffer->pending_sample = false;
633
+ buffer->pending_sample_result = 0;
634
+ }
466
635
 
467
- ruby_xfree(buffer);
636
+ void sampling_buffer_mark(sampling_buffer *buffer) {
637
+ if (!sampling_buffer_needs_marking(buffer)) {
638
+ rb_bug("sampling_buffer_mark called with no pending sample. `sampling_buffer_needs_marking` should be used before calling mark.");
639
+ }
640
+
641
+ for (int i = 0; i < buffer->pending_sample_result; i++) {
642
+ if (buffer->stack_buffer[i].is_ruby_frame) {
643
+ rb_gc_mark(buffer->stack_buffer[i].as.ruby_frame.iseq);
644
+ }
645
+ }
468
646
  }
@@ -2,19 +2,29 @@
2
2
 
3
3
  #include <datadog/profiling.h>
4
4
 
5
+ #include "private_vm_api_access.h"
5
6
  #include "stack_recorder.h"
6
7
 
7
- #define MAX_FRAMES_LIMIT 10000
8
- #define MAX_FRAMES_LIMIT_AS_STRING "10000"
8
+ #define MAX_FRAMES_LIMIT 3000
9
+ #define MAX_FRAMES_LIMIT_AS_STRING "3000"
9
10
 
10
- typedef struct sampling_buffer sampling_buffer;
11
+ // Used as scratch space during sampling
12
+ typedef struct {
13
+ uint16_t max_frames;
14
+ ddog_prof_Location *locations;
15
+ frame_info *stack_buffer;
16
+ bool pending_sample;
17
+ int pending_sample_result;
18
+ } sampling_buffer;
11
19
 
12
20
  void sample_thread(
13
21
  VALUE thread,
14
22
  sampling_buffer* buffer,
15
23
  VALUE recorder_instance,
16
24
  sample_values values,
17
- sample_labels labels
25
+ sample_labels labels,
26
+ bool native_filenames_enabled,
27
+ st_table *native_filenames_cache
18
28
  );
19
29
  void record_placeholder_stack(
20
30
  VALUE recorder_instance,
@@ -22,6 +32,12 @@ void record_placeholder_stack(
22
32
  sample_labels labels,
23
33
  ddog_CharSlice placeholder_stack
24
34
  );
35
+ void prepare_sample_thread(VALUE thread, sampling_buffer *buffer);
36
+
25
37
  uint16_t sampling_buffer_check_max_frames(int max_frames);
26
- sampling_buffer *sampling_buffer_new(uint16_t max_frames, ddog_prof_Location *locations);
38
+ void sampling_buffer_initialize(sampling_buffer *buffer, uint16_t max_frames, ddog_prof_Location *locations);
27
39
  void sampling_buffer_free(sampling_buffer *buffer);
40
+ void sampling_buffer_mark(sampling_buffer *buffer);
41
+ static inline bool sampling_buffer_needs_marking(sampling_buffer *buffer) {
42
+ return buffer->pending_sample && buffer->pending_sample_result > 0;
43
+ }