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
@@ -8,6 +8,7 @@
8
8
  #include "ruby_helpers.h"
9
9
  #include "time_helpers.h"
10
10
  #include "heap_recorder.h"
11
+ #include "encoded_profile.h"
11
12
 
12
13
  // Used to wrap a ddog_prof_Profile in a Ruby object and expose Ruby-level serialization APIs
13
14
  // This file implements the native bits of the Datadog::Profiling::StackRecorder class
@@ -173,18 +174,19 @@ static const uint8_t all_value_types_positions[] =
173
174
 
174
175
  // Struct for storing stats related to a profile in a particular slot.
175
176
  // These stats will share the same lifetime as the data in that profile slot.
176
- typedef struct slot_stats {
177
+ typedef struct {
177
178
  // How many individual samples were recorded into this slot (un-weighted)
178
179
  uint64_t recorded_samples;
179
180
  } stats_slot;
180
181
 
181
- typedef struct profile_slot {
182
+ typedef struct {
182
183
  ddog_prof_Profile profile;
183
184
  stats_slot stats;
185
+ ddog_Timespec start_timestamp;
184
186
  } profile_slot;
185
187
 
186
188
  // Contains native state for each instance
187
- struct stack_recorder_state {
189
+ typedef struct {
188
190
  // Heap recorder instance
189
191
  heap_recorder *heap_recorder;
190
192
  bool heap_clean_after_gc_enabled;
@@ -194,6 +196,10 @@ struct stack_recorder_state {
194
196
  pthread_mutex_t mutex_slot_two;
195
197
  profile_slot profile_slot_two;
196
198
 
199
+ ddog_prof_ManagedStringStorage string_storage;
200
+ ddog_prof_ManagedStringId label_key_allocation_class;
201
+ ddog_prof_ManagedStringId label_key_gc_gen_age;
202
+
197
203
  short active_slot; // MUST NEVER BE ACCESSED FROM record_sample; this is NOT for the sampler thread to use.
198
204
 
199
205
  uint8_t position_for[ALL_VALUE_TYPES_COUNT];
@@ -210,17 +216,17 @@ struct stack_recorder_state {
210
216
  long serialization_time_ns_max;
211
217
  uint64_t serialization_time_ns_total;
212
218
  } stats_lifetime;
213
- };
219
+ } stack_recorder_state;
214
220
 
215
221
  // Used to group mutex and the corresponding profile slot for easy unlocking after work is done.
216
- typedef struct locked_profile_slot {
222
+ typedef struct {
217
223
  pthread_mutex_t *mutex;
218
224
  profile_slot *data;
219
225
  } locked_profile_slot;
220
226
 
221
- struct call_serialize_without_gvl_arguments {
227
+ typedef struct {
222
228
  // Set by caller
223
- struct stack_recorder_state *state;
229
+ stack_recorder_state *state;
224
230
  ddog_Timespec finish_timestamp;
225
231
 
226
232
  // Set by callee
@@ -228,43 +234,43 @@ struct call_serialize_without_gvl_arguments {
228
234
  ddog_prof_Profile_SerializeResult result;
229
235
  long heap_profile_build_time_ns;
230
236
  long serialize_no_gvl_time_ns;
237
+ ddog_prof_MaybeError advance_gen_result;
231
238
 
232
239
  // Set by both
233
240
  bool serialize_ran;
234
- };
241
+ } call_serialize_without_gvl_arguments;
235
242
 
236
243
  static VALUE _native_new(VALUE klass);
237
- static void initialize_slot_concurrency_control(struct stack_recorder_state *state);
238
- static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types);
244
+ 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);
239
246
  static void stack_recorder_typed_data_free(void *data);
240
247
  static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
241
248
  static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
242
249
  static VALUE ruby_time_from(ddog_Timespec ddprof_time);
243
250
  static void *call_serialize_without_gvl(void *call_args);
244
- static locked_profile_slot sampler_lock_active_profile(struct stack_recorder_state *state);
251
+ static locked_profile_slot sampler_lock_active_profile(stack_recorder_state *state);
245
252
  static void sampler_unlock_active_profile(locked_profile_slot active_slot);
246
- static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state);
253
+ static profile_slot* serializer_flip_active_and_inactive_slots(stack_recorder_state *state);
247
254
  static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
248
255
  static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
249
256
  static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
250
257
  static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot);
251
258
  static ddog_Timespec system_epoch_now_timespec(void);
252
259
  static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance);
253
- static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time);
260
+ static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time);
254
261
  static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint);
255
- static void reset_profile_slot(profile_slot *slot, ddog_Timespec *start_time /* Can be null */);
262
+ static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp);
256
263
  static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class);
257
- static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations);
258
264
  static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
259
265
  static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
260
266
  static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
261
- static VALUE _native_gc_force_recycle(DDTRACE_UNUSED VALUE _self, VALUE obj);
262
- static VALUE _native_has_seen_id_flag(DDTRACE_UNUSED VALUE _self, VALUE obj);
263
267
  static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance);
264
268
  static VALUE build_profile_stats(profile_slot *slot, long serialization_time_ns, long heap_iteration_prep_time_ns, long heap_profile_build_time_ns);
265
269
  static VALUE _native_is_object_recorded(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE object_id);
266
270
  static VALUE _native_heap_recorder_reset_last_update(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
267
271
  static VALUE _native_recorder_after_gc_step(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
272
+ static VALUE _native_benchmark_intern(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE string, VALUE times, VALUE use_all);
273
+ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE_UNUSED VALUE _self);
268
274
 
269
275
  void stack_recorder_init(VALUE profiling_module) {
270
276
  VALUE stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
@@ -290,20 +296,17 @@ void stack_recorder_init(VALUE profiling_module) {
290
296
  rb_define_singleton_method(testing_module, "_native_slot_two_mutex_locked?", _native_is_slot_two_mutex_locked, 1);
291
297
  rb_define_singleton_method(testing_module, "_native_record_endpoint", _native_record_endpoint, 3);
292
298
  rb_define_singleton_method(testing_module, "_native_track_object", _native_track_object, 4);
293
- rb_define_singleton_method(testing_module, "_native_check_heap_hashes", _native_check_heap_hashes, 1);
294
299
  rb_define_singleton_method(testing_module, "_native_start_fake_slow_heap_serialization",
295
300
  _native_start_fake_slow_heap_serialization, 1);
296
301
  rb_define_singleton_method(testing_module, "_native_end_fake_slow_heap_serialization",
297
302
  _native_end_fake_slow_heap_serialization, 1);
298
303
  rb_define_singleton_method(testing_module, "_native_debug_heap_recorder",
299
304
  _native_debug_heap_recorder, 1);
300
- rb_define_singleton_method(testing_module, "_native_gc_force_recycle",
301
- _native_gc_force_recycle, 1);
302
- rb_define_singleton_method(testing_module, "_native_has_seen_id_flag",
303
- _native_has_seen_id_flag, 1);
304
305
  rb_define_singleton_method(testing_module, "_native_is_object_recorded?", _native_is_object_recorded, 2);
305
306
  rb_define_singleton_method(testing_module, "_native_heap_recorder_reset_last_update", _native_heap_recorder_reset_last_update, 1);
306
307
  rb_define_singleton_method(testing_module, "_native_recorder_after_gc_step", _native_recorder_after_gc_step, 1);
308
+ rb_define_singleton_method(testing_module, "_native_benchmark_intern", _native_benchmark_intern, 4);
309
+ rb_define_singleton_method(testing_module, "_native_test_managed_string_storage_produces_valid_profiles", _native_test_managed_string_storage_produces_valid_profiles, 0);
307
310
 
308
311
  ok_symbol = ID2SYM(rb_intern_const("ok"));
309
312
  error_symbol = ID2SYM(rb_intern_const("error"));
@@ -322,7 +325,7 @@ static const rb_data_type_t stack_recorder_typed_data = {
322
325
  };
323
326
 
324
327
  static VALUE _native_new(VALUE klass) {
325
- struct stack_recorder_state *state = ruby_xcalloc(1, sizeof(struct stack_recorder_state));
328
+ stack_recorder_state *state = ruby_xcalloc(1, sizeof(stack_recorder_state));
326
329
 
327
330
  // Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory
328
331
  // being leaked.
@@ -338,29 +341,32 @@ static VALUE _native_new(VALUE klass) {
338
341
  .serialization_time_ns_min = INT64_MAX,
339
342
  };
340
343
 
341
- // Note: At this point, slot_one_profile and slot_two_profile contain null pointers. Libdatadog validates pointers
344
+ // Note: At this point, slot_one_profile/slot_two_profile/string_storage contain null pointers. Libdatadog validates pointers
342
345
  // before using them so it's ok for us to go ahead and create the StackRecorder object.
343
346
 
344
- // Note: As of this writing, no new Ruby objects get created and stored in the state. If that ever changes, remember
345
- // to keep them on the stack and mark them with RB_GC_GUARD -- otherwise it's possible for a GC to run and
346
- // since the instance representing the state does not yet exist, such objects will not get marked.
347
-
348
347
  VALUE stack_recorder = TypedData_Wrap_Struct(klass, &stack_recorder_typed_data, state);
349
348
 
350
- // NOTE: We initialize this because we want a new recorder to be operational even without initialization and our
351
- // default is everything enabled. However, if during recording initialization it turns out we don't want
352
- // heap samples, we will free and reset heap_recorder to NULL, effectively disabling all behaviour specific
353
- // to heap profiling (all calls to heap_recorder_* with a NULL heap recorder are noops).
354
- state->heap_recorder = heap_recorder_new();
349
+ ddog_prof_ManagedStringStorageNewResult string_storage = ddog_prof_ManagedStringStorage_new();
350
+
351
+ 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));
353
+ }
355
354
 
356
- // Note: Don't raise exceptions after this point, since it'll lead to libdatadog memory leaking!
355
+ state->string_storage = string_storage.ok;
356
+ state->label_key_allocation_class = intern_or_raise(state->string_storage, DDOG_CHARSLICE_C("allocation class"));
357
+ state->label_key_gc_gen_age = intern_or_raise(state->string_storage, DDOG_CHARSLICE_C("gc gen age"));
357
358
 
358
359
  initialize_profiles(state, sample_types);
359
360
 
361
+ // NOTE: We initialize this because we want a new recorder to be operational even before #initialize runs and our
362
+ // default is everything enabled. However, if during recording initialization it turns out we don't want
363
+ // heap samples, we will free and reset heap_recorder back to NULL.
364
+ state->heap_recorder = heap_recorder_new(state->string_storage);
365
+
360
366
  return stack_recorder;
361
367
  }
362
368
 
363
- static void initialize_slot_concurrency_control(struct stack_recorder_state *state) {
369
+ static void initialize_slot_concurrency_control(stack_recorder_state *state) {
364
370
  state->mutex_slot_one = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
365
371
  state->mutex_slot_two = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
366
372
 
@@ -370,34 +376,31 @@ static void initialize_slot_concurrency_control(struct stack_recorder_state *sta
370
376
  state->active_slot = 1;
371
377
  }
372
378
 
373
- static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
379
+ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
380
+ ddog_Timespec start_timestamp = system_epoch_now_timespec();
381
+
374
382
  ddog_prof_Profile_NewResult slot_one_profile_result =
375
- ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
383
+ ddog_prof_Profile_with_string_storage(sample_types, NULL /* period is optional */, state->string_storage);
376
384
 
377
385
  if (slot_one_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
378
386
  rb_raise(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
379
387
  }
380
388
 
389
+ state->profile_slot_one = (profile_slot) { .profile = slot_one_profile_result.ok, .start_timestamp = start_timestamp };
390
+
381
391
  ddog_prof_Profile_NewResult slot_two_profile_result =
382
- ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
392
+ ddog_prof_Profile_with_string_storage(sample_types, NULL /* period is optional */, state->string_storage);
383
393
 
384
394
  if (slot_two_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
385
- // Uff! Though spot. We need to make sure to properly clean up the other profile as well first
386
- ddog_prof_Profile_drop(&slot_one_profile_result.ok);
387
- // And now we can raise...
395
+ // Note: No need to take any special care of slot one, it'll get cleaned up by stack_recorder_typed_data_free
388
396
  rb_raise(rb_eRuntimeError, "Failed to initialize slot two profile: %"PRIsVALUE, get_error_details_and_drop(&slot_two_profile_result.err));
389
397
  }
390
398
 
391
- state->profile_slot_one = (profile_slot) {
392
- .profile = slot_one_profile_result.ok,
393
- };
394
- state->profile_slot_two = (profile_slot) {
395
- .profile = slot_two_profile_result.ok,
396
- };
399
+ state->profile_slot_two = (profile_slot) { .profile = slot_two_profile_result.ok, .start_timestamp = start_timestamp };
397
400
  }
398
401
 
399
402
  static void stack_recorder_typed_data_free(void *state_ptr) {
400
- struct stack_recorder_state *state = (struct stack_recorder_state *) state_ptr;
403
+ stack_recorder_state *state = (stack_recorder_state *) state_ptr;
401
404
 
402
405
  pthread_mutex_destroy(&state->mutex_slot_one);
403
406
  ddog_prof_Profile_drop(&state->profile_slot_one.profile);
@@ -407,6 +410,8 @@ static void stack_recorder_typed_data_free(void *state_ptr) {
407
410
 
408
411
  heap_recorder_free(state->heap_recorder);
409
412
 
413
+ ddog_prof_ManagedStringStorage_drop(state->string_storage);
414
+
410
415
  ruby_xfree(state);
411
416
  }
412
417
 
@@ -432,8 +437,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
432
437
  ENFORCE_BOOLEAN(timeline_enabled);
433
438
  ENFORCE_BOOLEAN(heap_clean_after_gc_enabled);
434
439
 
435
- struct stack_recorder_state *state;
436
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
440
+ stack_recorder_state *state;
441
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
437
442
 
438
443
  state->heap_clean_after_gc_enabled = (heap_clean_after_gc_enabled == Qtrue);
439
444
 
@@ -523,8 +528,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
523
528
  }
524
529
 
525
530
  static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
526
- struct stack_recorder_state *state;
527
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
531
+ stack_recorder_state *state;
532
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
528
533
 
529
534
  ddog_Timespec finish_timestamp = system_epoch_now_timespec();
530
535
  // Need to do this while still holding on to the Global VM Lock; see comments on method for why
@@ -533,15 +538,17 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
533
538
  long heap_iteration_prep_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
534
539
  // Prepare the iteration on heap recorder we'll be doing outside the GVL. The preparation needs to
535
540
  // happen while holding on to the GVL.
541
+ // NOTE: While rare, it's possible for the GVL to be released inside this function (see comments on `heap_recorder_update`)
542
+ // and thus don't assume this is an "atomic" step -- other threads may get some running time in the meanwhile.
536
543
  heap_recorder_prepare_iteration(state->heap_recorder);
537
544
  long heap_iteration_prep_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - heap_iteration_prep_start_time_ns;
538
545
 
539
546
  // We'll release the Global VM Lock while we're calling serialize, so that the Ruby VM can continue to work while this
540
547
  // is pending
541
- struct call_serialize_without_gvl_arguments args = {
548
+ call_serialize_without_gvl_arguments args = {
542
549
  .state = state,
543
550
  .finish_timestamp = finish_timestamp,
544
- .serialize_ran = false
551
+ .serialize_ran = false,
545
552
  };
546
553
 
547
554
  while (!args.serialize_ran) {
@@ -565,13 +572,9 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
565
572
  // really cover the full serialization process but it gives a more useful number since it bypasses
566
573
  // the noise of acquiring GVLs and dealing with interruptions which is highly specific to runtime
567
574
  // conditions and over which we really have no control about.
568
- long serialization_time_ns = args.serialize_no_gvl_time_ns;
569
- if (serialization_time_ns >= 0) {
570
- // Only update stats if our serialization time is valid.
571
- state->stats_lifetime.serialization_time_ns_max = long_max_of(state->stats_lifetime.serialization_time_ns_max, serialization_time_ns);
572
- state->stats_lifetime.serialization_time_ns_min = long_min_of(state->stats_lifetime.serialization_time_ns_min, serialization_time_ns);
573
- state->stats_lifetime.serialization_time_ns_total += serialization_time_ns;
574
- }
575
+ state->stats_lifetime.serialization_time_ns_max = long_max_of(state->stats_lifetime.serialization_time_ns_max, args.serialize_no_gvl_time_ns);
576
+ state->stats_lifetime.serialization_time_ns_min = long_min_of(state->stats_lifetime.serialization_time_ns_min, args.serialize_no_gvl_time_ns);
577
+ state->stats_lifetime.serialization_time_ns_total += args.serialize_no_gvl_time_ns;
575
578
 
576
579
  ddog_prof_Profile_SerializeResult serialized_profile = args.result;
577
580
 
@@ -580,20 +583,22 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
580
583
  return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&serialized_profile.err));
581
584
  }
582
585
 
586
+ // Note: If we got here, the profile serialized correctly.
587
+ // Once we wrap this into a Ruby object, our `EncodedProfile` class will automatically manage memory for it and we
588
+ // can raise exceptions without worrying about leaking the profile.
583
589
  state->stats_lifetime.serialization_successes++;
590
+ VALUE encoded_profile = from_ddog_prof_EncodedProfile(serialized_profile.ok);
584
591
 
585
- VALUE encoded_pprof = ruby_string_from_vec_u8(serialized_profile.ok.buffer);
586
-
587
- ddog_Timespec ddprof_start = serialized_profile.ok.start;
588
- ddog_Timespec ddprof_finish = serialized_profile.ok.end;
589
-
590
- ddog_prof_EncodedProfile_drop(&serialized_profile.ok);
592
+ ddog_prof_MaybeError result = args.advance_gen_result;
593
+ 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));
595
+ }
591
596
 
592
- VALUE start = ruby_time_from(ddprof_start);
593
- VALUE finish = ruby_time_from(ddprof_finish);
594
- VALUE profile_stats = build_profile_stats(args.slot, serialization_time_ns, heap_iteration_prep_time_ns, args.heap_profile_build_time_ns);
597
+ VALUE start = ruby_time_from(args.slot->start_timestamp);
598
+ VALUE finish = ruby_time_from(finish_timestamp);
599
+ VALUE profile_stats = build_profile_stats(args.slot, args.serialize_no_gvl_time_ns, heap_iteration_prep_time_ns, args.heap_profile_build_time_ns);
595
600
 
596
- return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_pprof, profile_stats));
601
+ return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_profile, profile_stats));
597
602
  }
598
603
 
599
604
  static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
@@ -603,8 +608,8 @@ static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
603
608
  }
604
609
 
605
610
  void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, sample_values values, sample_labels labels) {
606
- struct stack_recorder_state *state;
607
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
611
+ stack_recorder_state *state;
612
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
608
613
 
609
614
  locked_profile_slot active_slot = sampler_lock_active_profile(state);
610
615
 
@@ -657,9 +662,9 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
657
662
  }
658
663
  }
659
664
 
660
- void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice *alloc_class) {
661
- struct stack_recorder_state *state;
662
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
665
+ void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice alloc_class) {
666
+ stack_recorder_state *state;
667
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
663
668
  // FIXME: Heap sampling currently has to be done in 2 parts because the construction of locations is happening
664
669
  // very late in the allocation-sampling path (which is shared with the cpu sampling path). This can
665
670
  // be fixed with some refactoring but for now this leads to a less impactful change.
@@ -667,8 +672,8 @@ void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample
667
672
  }
668
673
 
669
674
  void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_CharSlice endpoint) {
670
- struct stack_recorder_state *state;
671
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
675
+ stack_recorder_state *state;
676
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
672
677
 
673
678
  locked_profile_slot active_slot = sampler_lock_active_profile(state);
674
679
 
@@ -682,8 +687,8 @@ void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_
682
687
  }
683
688
 
684
689
  void recorder_after_gc_step(VALUE recorder_instance) {
685
- struct stack_recorder_state *state;
686
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
690
+ stack_recorder_state *state;
691
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
687
692
 
688
693
  if (state->heap_clean_after_gc_enabled) heap_recorder_update_young_objects(state->heap_recorder);
689
694
  }
@@ -693,7 +698,7 @@ void recorder_after_gc_step(VALUE recorder_instance) {
693
698
  // Heap recorder iteration context allows us access to stack recorder state and profile being serialized
694
699
  // during iteration of heap recorder live objects.
695
700
  typedef struct heap_recorder_iteration_context {
696
- struct stack_recorder_state *state;
701
+ stack_recorder_state *state;
697
702
  profile_slot *slot;
698
703
 
699
704
  bool error;
@@ -714,18 +719,15 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
714
719
  ddog_prof_Label labels[2];
715
720
  size_t label_offset = 0;
716
721
 
717
- if (object_data->class != NULL) {
722
+ if (object_data->class.value > 0) {
718
723
  labels[label_offset++] = (ddog_prof_Label) {
719
- .key = DDOG_CHARSLICE_C("allocation class"),
720
- .str = (ddog_CharSlice) {
721
- .ptr = object_data->class,
722
- .len = strlen(object_data->class),
723
- },
724
+ .key_id = context->state->label_key_allocation_class,
725
+ .str_id = object_data->class,
724
726
  .num = 0, // This shouldn't be needed but the tracer-2.7 docker image ships a buggy gcc that complains about this
725
727
  };
726
728
  }
727
729
  labels[label_offset++] = (ddog_prof_Label) {
728
- .key = DDOG_CHARSLICE_C("gc gen age"),
730
+ .key_id = context->state->label_key_gc_gen_age,
729
731
  .num = object_data->gen_age,
730
732
  };
731
733
 
@@ -755,7 +757,7 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
755
757
  return true;
756
758
  }
757
759
 
758
- static void build_heap_profile_without_gvl(struct stack_recorder_state *state, profile_slot *slot) {
760
+ static void build_heap_profile_without_gvl(stack_recorder_state *state, profile_slot *slot) {
759
761
  heap_recorder_iteration_context iteration_context = {
760
762
  .state = state,
761
763
  .slot = slot,
@@ -776,12 +778,11 @@ static void build_heap_profile_without_gvl(struct stack_recorder_state *state, p
776
778
  }
777
779
 
778
780
  static void *call_serialize_without_gvl(void *call_args) {
779
- struct call_serialize_without_gvl_arguments *args = (struct call_serialize_without_gvl_arguments *) call_args;
781
+ call_serialize_without_gvl_arguments *args = (call_serialize_without_gvl_arguments *) call_args;
780
782
 
781
783
  long serialize_no_gvl_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
782
784
 
783
785
  profile_slot *slot_now_inactive = serializer_flip_active_and_inactive_slots(args->state);
784
-
785
786
  args->slot = slot_now_inactive;
786
787
 
787
788
  // Now that we have the inactive profile with all but heap samples, lets fill it with heap data
@@ -790,19 +791,20 @@ static void *call_serialize_without_gvl(void *call_args) {
790
791
  args->heap_profile_build_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
791
792
 
792
793
  // Note: The profile gets reset by the serialize call
793
- args->result = ddog_prof_Profile_serialize(&args->slot->profile, &args->finish_timestamp, NULL /* duration_nanos is optional */, NULL /* start_time is optional */);
794
+ args->result = ddog_prof_Profile_serialize(&args->slot->profile, &args->slot->start_timestamp, &args->finish_timestamp);
795
+ args->advance_gen_result = ddog_prof_ManagedStringStorage_advance_gen(args->state->string_storage);
794
796
  args->serialize_ran = true;
795
- args->serialize_no_gvl_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
797
+ args->serialize_no_gvl_time_ns = long_max_of(0, monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns);
796
798
 
797
799
  return NULL; // Unused
798
800
  }
799
801
 
800
802
  VALUE enforce_recorder_instance(VALUE object) {
801
- Check_TypedStruct(object, &stack_recorder_typed_data);
803
+ ENFORCE_TYPED_DATA(object, &stack_recorder_typed_data);
802
804
  return object;
803
805
  }
804
806
 
805
- static locked_profile_slot sampler_lock_active_profile(struct stack_recorder_state *state) {
807
+ static locked_profile_slot sampler_lock_active_profile(stack_recorder_state *state) {
806
808
  int error;
807
809
 
808
810
  for (int attempts = 0; attempts < 2; attempts++) {
@@ -829,7 +831,7 @@ static void sampler_unlock_active_profile(locked_profile_slot active_slot) {
829
831
  ENFORCE_SUCCESS_GVL(pthread_mutex_unlock(active_slot.mutex));
830
832
  }
831
833
 
832
- static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state) {
834
+ static profile_slot* serializer_flip_active_and_inactive_slots(stack_recorder_state *state) {
833
835
  int previously_active_slot = state->active_slot;
834
836
 
835
837
  if (previously_active_slot != 1 && previously_active_slot != 2) {
@@ -855,8 +857,8 @@ static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_reco
855
857
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
856
858
  // It SHOULD NOT be used for other purposes.
857
859
  static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
858
- struct stack_recorder_state *state;
859
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
860
+ stack_recorder_state *state;
861
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
860
862
 
861
863
  return INT2NUM(state->active_slot);
862
864
  }
@@ -870,8 +872,8 @@ static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE
870
872
  static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { return test_slot_mutex_state(recorder_instance, 2); }
871
873
 
872
874
  static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot) {
873
- struct stack_recorder_state *state;
874
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
875
+ stack_recorder_state *state;
876
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
875
877
 
876
878
  pthread_mutex_t *slot_mutex = (slot == 1) ? &state->mutex_slot_one : &state->mutex_slot_two;
877
879
 
@@ -901,15 +903,15 @@ static ddog_Timespec system_epoch_now_timespec(void) {
901
903
  // Assumption: This method gets called BEFORE restarting profiling -- e.g. there are no components attempting to
902
904
  // trigger samples at the same time.
903
905
  static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance) {
904
- struct stack_recorder_state *state;
905
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
906
+ stack_recorder_state *state;
907
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
906
908
 
907
909
  // In case the fork happened halfway through `serializer_flip_active_and_inactive_slots` execution and the
908
910
  // resulting state is inconsistent, we make sure to reset it back to the initial state.
909
911
  initialize_slot_concurrency_control(state);
910
-
911
- reset_profile_slot(&state->profile_slot_one, /* start_time: */ NULL);
912
- reset_profile_slot(&state->profile_slot_two, /* start_time: */ NULL);
912
+ ddog_Timespec start_timestamp = system_epoch_now_timespec();
913
+ reset_profile_slot(&state->profile_slot_one, start_timestamp);
914
+ reset_profile_slot(&state->profile_slot_two, start_timestamp);
913
915
 
914
916
  heap_recorder_after_fork(state->heap_recorder);
915
917
 
@@ -918,10 +920,10 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_
918
920
 
919
921
  // Assumption 1: This method is called with the GVL being held, because `ddog_prof_Profile_reset` mutates the profile and must
920
922
  // not be interrupted part-way through by a VM fork.
921
- static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time) {
923
+ static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time) {
922
924
  // Before making this profile active, we reset it so that it uses the correct start_time for its start
923
925
  profile_slot *next_profile_slot = (state->active_slot == 1) ? &state->profile_slot_two : &state->profile_slot_one;
924
- reset_profile_slot(next_profile_slot, &start_time);
926
+ reset_profile_slot(next_profile_slot, start_time);
925
927
  }
926
928
 
927
929
  static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint) {
@@ -932,54 +934,24 @@ static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_
932
934
 
933
935
  static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class) {
934
936
  ENFORCE_TYPE(weight, T_FIXNUM);
935
- ddog_CharSlice alloc_class_slice = char_slice_from_ruby_string(alloc_class);
936
- track_object(recorder_instance, new_obj, NUM2UINT(weight), &alloc_class_slice);
937
+ track_object(recorder_instance, new_obj, NUM2UINT(weight), char_slice_from_ruby_string(alloc_class));
937
938
  return Qtrue;
938
939
  }
939
940
 
940
- static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations) {
941
- ENFORCE_TYPE(locations, T_ARRAY);
942
- size_t locations_len = rb_array_len(locations);
943
- ddog_prof_Location locations_arr[locations_len];
944
- for (size_t i = 0; i < locations_len; i++) {
945
- VALUE location = rb_ary_entry(locations, i);
946
- ENFORCE_TYPE(location, T_ARRAY);
947
- VALUE name = rb_ary_entry(location, 0);
948
- VALUE filename = rb_ary_entry(location, 1);
949
- VALUE line = rb_ary_entry(location, 2);
950
- ENFORCE_TYPE(name, T_STRING);
951
- ENFORCE_TYPE(filename, T_STRING);
952
- ENFORCE_TYPE(line, T_FIXNUM);
953
- locations_arr[i] = (ddog_prof_Location) {
954
- .line = line,
955
- .function = (ddog_prof_Function) {
956
- .name = char_slice_from_ruby_string(name),
957
- .filename = char_slice_from_ruby_string(filename),
958
- }
959
- };
960
- }
961
- ddog_prof_Slice_Location ddog_locations = {
962
- .len = locations_len,
963
- .ptr = locations_arr,
964
- };
965
- heap_recorder_testonly_assert_hash_matches(ddog_locations);
966
-
967
- return Qnil;
968
- }
969
-
970
- static void reset_profile_slot(profile_slot *slot, ddog_Timespec *start_time /* Can be null */) {
971
- ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile, start_time);
941
+ static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp) {
942
+ ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile);
972
943
  if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
973
944
  rb_raise(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
974
945
  }
946
+ slot->start_timestamp = start_timestamp;
975
947
  slot->stats = (stats_slot) {};
976
948
  }
977
949
 
978
950
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
979
951
  // It SHOULD NOT be used for other purposes.
980
952
  static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
981
- struct stack_recorder_state *state;
982
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
953
+ stack_recorder_state *state;
954
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
983
955
 
984
956
  heap_recorder_prepare_iteration(state->heap_recorder);
985
957
 
@@ -989,8 +961,8 @@ static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _se
989
961
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
990
962
  // It SHOULD NOT be used for other purposes.
991
963
  static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
992
- struct stack_recorder_state *state;
993
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
964
+ stack_recorder_state *state;
965
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
994
966
 
995
967
  heap_recorder_finish_iteration(state->heap_recorder);
996
968
 
@@ -1000,43 +972,15 @@ static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self
1000
972
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
1001
973
  // It SHOULD NOT be used for other purposes.
1002
974
  static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
1003
- struct stack_recorder_state *state;
1004
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
975
+ stack_recorder_state *state;
976
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1005
977
 
1006
978
  return heap_recorder_testonly_debug(state->heap_recorder);
1007
979
  }
1008
980
 
1009
- #pragma GCC diagnostic push
1010
- // rb_gc_force_recycle was deprecated in latest versions of Ruby and is a noop.
1011
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1012
- #pragma GCC diagnostic ignored "-Wunused-parameter"
1013
- // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
1014
- // It SHOULD NOT be used for other purposes.
1015
- static VALUE _native_gc_force_recycle(DDTRACE_UNUSED VALUE _self, VALUE obj) {
1016
- #ifdef HAVE_WORKING_RB_GC_FORCE_RECYCLE
1017
- rb_gc_force_recycle(obj);
1018
- #endif
1019
- return Qnil;
1020
- }
1021
- #pragma GCC diagnostic pop
1022
-
1023
- // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
1024
- // It SHOULD NOT be used for other purposes.
1025
- static VALUE _native_has_seen_id_flag(DDTRACE_UNUSED VALUE _self, VALUE obj) {
1026
- #ifndef NO_SEEN_OBJ_ID_FLAG
1027
- if (RB_FL_TEST(obj, RUBY_FL_SEEN_OBJ_ID)) {
1028
- return Qtrue;
1029
- } else {
1030
- return Qfalse;
1031
- }
1032
- #else
1033
- return Qfalse;
1034
- #endif
1035
- }
1036
-
1037
981
  static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE recorder_instance) {
1038
- struct stack_recorder_state *state;
1039
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
982
+ stack_recorder_state *state;
983
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1040
984
 
1041
985
  uint64_t total_serializations = state->stats_lifetime.serialization_successes + state->stats_lifetime.serialization_failures;
1042
986
 
@@ -1074,15 +1018,15 @@ static VALUE build_profile_stats(profile_slot *slot, long serialization_time_ns,
1074
1018
  static VALUE _native_is_object_recorded(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE obj_id) {
1075
1019
  ENFORCE_TYPE(obj_id, T_FIXNUM);
1076
1020
 
1077
- struct stack_recorder_state *state;
1078
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
1021
+ stack_recorder_state *state;
1022
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1079
1023
 
1080
1024
  return heap_recorder_testonly_is_object_recorded(state->heap_recorder, obj_id);
1081
1025
  }
1082
1026
 
1083
1027
  static VALUE _native_heap_recorder_reset_last_update(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
1084
- struct stack_recorder_state *state;
1085
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
1028
+ stack_recorder_state *state;
1029
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1086
1030
 
1087
1031
  heap_recorder_testonly_reset_last_update(state->heap_recorder);
1088
1032
 
@@ -1093,3 +1037,109 @@ static VALUE _native_recorder_after_gc_step(DDTRACE_UNUSED VALUE _self, VALUE re
1093
1037
  recorder_after_gc_step(recorder_instance);
1094
1038
  return Qtrue;
1095
1039
  }
1040
+
1041
+ static VALUE _native_benchmark_intern(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE string, VALUE times, VALUE use_all) {
1042
+ ENFORCE_TYPE(string, T_STRING);
1043
+ ENFORCE_TYPE(times, T_FIXNUM);
1044
+ ENFORCE_BOOLEAN(use_all);
1045
+
1046
+ stack_recorder_state *state;
1047
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1048
+
1049
+ heap_recorder_testonly_benchmark_intern(state->heap_recorder, char_slice_from_ruby_string(string), FIX2INT(times), use_all == Qtrue);
1050
+
1051
+ return Qtrue;
1052
+ }
1053
+
1054
+ // See comments in rspec test for details on what we're testing here.
1055
+ static VALUE _native_test_managed_string_storage_produces_valid_profiles(DDTRACE_UNUSED VALUE _self) {
1056
+ ddog_prof_ManagedStringStorageNewResult string_storage = ddog_prof_ManagedStringStorage_new();
1057
+
1058
+ 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));
1060
+ }
1061
+
1062
+ ddog_prof_Slice_ValueType sample_types = {.ptr = all_value_types, .len = ALL_VALUE_TYPES_COUNT};
1063
+ ddog_prof_Profile_NewResult profile = ddog_prof_Profile_with_string_storage(sample_types, NULL, string_storage.ok);
1064
+
1065
+ 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));
1067
+ }
1068
+
1069
+ ddog_prof_ManagedStringId hello = intern_or_raise(string_storage.ok, DDOG_CHARSLICE_C("hello"));
1070
+ ddog_prof_ManagedStringId world = intern_or_raise(string_storage.ok, DDOG_CHARSLICE_C("world"));
1071
+ ddog_prof_ManagedStringId key = intern_or_raise(string_storage.ok, DDOG_CHARSLICE_C("key"));
1072
+
1073
+ int64_t metric_values[] = {1, 2, 3, 4, 5, 6, 7, 8};
1074
+ ddog_prof_Label labels[] = {{.key_id = key, .str_id = key}};
1075
+
1076
+ ddog_prof_Location locations[] = {
1077
+ (ddog_prof_Location) {
1078
+ .mapping = {.filename = DDOG_CHARSLICE_C(""), .build_id = DDOG_CHARSLICE_C(""), .build_id_id = {}},
1079
+ .function = {
1080
+ .name = DDOG_CHARSLICE_C(""),
1081
+ .name_id = hello,
1082
+ .filename = DDOG_CHARSLICE_C(""),
1083
+ .filename_id = world,
1084
+ },
1085
+ .line = 1,
1086
+ }
1087
+ };
1088
+
1089
+ ddog_prof_Profile_Result result = ddog_prof_Profile_add(
1090
+ &profile.ok,
1091
+ (ddog_prof_Sample) {
1092
+ .locations = (ddog_prof_Slice_Location) { .ptr = locations, .len = 1},
1093
+ .values = (ddog_Slice_I64) {.ptr = metric_values, .len = 8},
1094
+ .labels = (ddog_prof_Slice_Label) { .ptr = labels, .len = 1 }
1095
+ },
1096
+ 0
1097
+ );
1098
+
1099
+ 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));
1101
+ }
1102
+
1103
+ ddog_Timespec finish_timestamp = system_epoch_now_timespec();
1104
+ ddog_Timespec start_timestamp = {.seconds = finish_timestamp.seconds - 60};
1105
+ ddog_prof_Profile_SerializeResult serialize_result = ddog_prof_Profile_serialize(&profile.ok, &start_timestamp, &finish_timestamp);
1106
+
1107
+ 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));
1109
+ }
1110
+
1111
+ ddog_prof_MaybeError advance_gen_result = ddog_prof_ManagedStringStorage_advance_gen(string_storage.ok);
1112
+
1113
+ 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));
1115
+ }
1116
+
1117
+ VALUE encoded_pprof_1 = from_ddog_prof_EncodedProfile(serialize_result.ok);
1118
+
1119
+ result = ddog_prof_Profile_add(
1120
+ &profile.ok,
1121
+ (ddog_prof_Sample) {
1122
+ .locations = (ddog_prof_Slice_Location) { .ptr = locations, .len = 1},
1123
+ .values = (ddog_Slice_I64) {.ptr = metric_values, .len = 8},
1124
+ .labels = (ddog_prof_Slice_Label) { .ptr = labels, .len = 1 }
1125
+ },
1126
+ 0
1127
+ );
1128
+
1129
+ 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));
1131
+ }
1132
+
1133
+ serialize_result = ddog_prof_Profile_serialize(&profile.ok, &start_timestamp, &finish_timestamp);
1134
+
1135
+ 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));
1137
+ }
1138
+
1139
+ VALUE encoded_pprof_2 = from_ddog_prof_EncodedProfile(serialize_result.ok);
1140
+
1141
+ ddog_prof_Profile_drop(&profile.ok);
1142
+ ddog_prof_ManagedStringStorage_drop(string_storage.ok);
1143
+
1144
+ return rb_ary_new_from_args(2, encoded_pprof_1, encoded_pprof_2);
1145
+ }