datadog 2.7.1 → 2.17.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 (417) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +310 -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 +66 -56
  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 +10 -10
  9. data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
  10. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +314 -145
  11. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  12. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  13. data/ext/datadog_profiling_native_extension/encoded_profile.c +79 -0
  14. data/ext/datadog_profiling_native_extension/encoded_profile.h +8 -0
  15. data/ext/datadog_profiling_native_extension/extconf.rb +7 -8
  16. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
  17. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
  18. data/ext/datadog_profiling_native_extension/heap_recorder.c +61 -174
  19. data/ext/datadog_profiling_native_extension/heap_recorder.h +2 -2
  20. data/ext/datadog_profiling_native_extension/http_transport.c +64 -98
  21. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +68 -1
  22. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +10 -1
  23. data/ext/datadog_profiling_native_extension/profiling.c +19 -8
  24. data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
  25. data/ext/datadog_profiling_native_extension/stack_recorder.c +84 -131
  26. data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -2
  27. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
  28. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
  29. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
  30. data/ext/libdatadog_api/crashtracker.c +17 -15
  31. data/ext/libdatadog_api/crashtracker.h +5 -0
  32. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  33. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  34. data/ext/libdatadog_api/init.c +15 -0
  35. data/ext/libdatadog_api/library_config.c +122 -0
  36. data/ext/libdatadog_api/library_config.h +19 -0
  37. data/ext/libdatadog_api/macos_development.md +3 -3
  38. data/ext/libdatadog_api/process_discovery.c +117 -0
  39. data/ext/libdatadog_api/process_discovery.h +5 -0
  40. data/ext/libdatadog_extconf_helpers.rb +1 -1
  41. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
  42. data/lib/datadog/appsec/actions_handler.rb +49 -0
  43. data/lib/datadog/appsec/anonymizer.rb +16 -0
  44. data/lib/datadog/appsec/api_security/lru_cache.rb +49 -0
  45. data/lib/datadog/appsec/api_security.rb +9 -0
  46. data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
  47. data/lib/datadog/appsec/assets/waf_rules/processors.json +239 -10
  48. data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
  49. data/lib/datadog/appsec/assets/waf_rules/scanners.json +926 -17
  50. data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
  51. data/lib/datadog/appsec/autoload.rb +1 -1
  52. data/lib/datadog/appsec/component.rb +41 -33
  53. data/lib/datadog/appsec/compressed_json.rb +40 -0
  54. data/lib/datadog/appsec/configuration/settings.rb +152 -25
  55. data/lib/datadog/appsec/context.rb +74 -0
  56. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +92 -0
  57. data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
  58. data/lib/datadog/appsec/contrib/active_record/patcher.rb +101 -0
  59. data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
  60. data/lib/datadog/appsec/contrib/devise/configuration.rb +52 -0
  61. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +78 -0
  62. data/lib/datadog/appsec/contrib/devise/ext.rb +22 -0
  63. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -2
  64. data/lib/datadog/appsec/contrib/devise/patcher.rb +33 -25
  65. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
  66. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -0
  67. data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +3 -3
  68. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +106 -0
  69. data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
  70. data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
  71. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +42 -0
  72. data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
  73. data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
  74. data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
  75. data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
  76. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +41 -0
  77. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
  78. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +17 -30
  79. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  80. data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
  81. data/lib/datadog/appsec/contrib/rack/ext.rb +34 -0
  82. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
  83. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +78 -98
  84. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  85. data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
  86. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
  87. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +52 -68
  88. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +16 -33
  89. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  90. data/lib/datadog/appsec/contrib/rails/patcher.rb +25 -38
  91. data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
  92. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
  93. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +38 -0
  94. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +31 -68
  95. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  96. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -31
  97. data/lib/datadog/appsec/event.rb +96 -135
  98. data/lib/datadog/appsec/ext.rb +12 -3
  99. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +7 -2
  100. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
  101. data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
  102. data/lib/datadog/appsec/metrics/collector.rb +38 -0
  103. data/lib/datadog/appsec/metrics/exporter.rb +35 -0
  104. data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
  105. data/lib/datadog/appsec/metrics.rb +13 -0
  106. data/lib/datadog/appsec/monitor/gateway/watcher.rb +52 -32
  107. data/lib/datadog/appsec/processor/rule_loader.rb +26 -31
  108. data/lib/datadog/appsec/processor/rule_merger.rb +7 -6
  109. data/lib/datadog/appsec/processor.rb +5 -4
  110. data/lib/datadog/appsec/remote.rb +26 -12
  111. data/lib/datadog/appsec/response.rb +19 -85
  112. data/lib/datadog/appsec/security_engine/result.rb +67 -0
  113. data/lib/datadog/appsec/security_engine/runner.rb +88 -0
  114. data/lib/datadog/appsec/security_engine.rb +9 -0
  115. data/lib/datadog/appsec/security_event.rb +39 -0
  116. data/lib/datadog/appsec/utils.rb +0 -2
  117. data/lib/datadog/appsec.rb +23 -10
  118. data/lib/datadog/auto_instrument.rb +3 -0
  119. data/lib/datadog/core/buffer/random.rb +18 -2
  120. data/lib/datadog/core/configuration/agent_settings_resolver.rb +42 -14
  121. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  122. data/lib/datadog/core/configuration/components.rb +76 -32
  123. data/lib/datadog/core/configuration/components_state.rb +23 -0
  124. data/lib/datadog/core/configuration/ext.rb +5 -1
  125. data/lib/datadog/core/configuration/option.rb +79 -43
  126. data/lib/datadog/core/configuration/option_definition.rb +6 -4
  127. data/lib/datadog/core/configuration/options.rb +3 -3
  128. data/lib/datadog/core/configuration/settings.rb +100 -41
  129. data/lib/datadog/core/configuration/stable_config.rb +23 -0
  130. data/lib/datadog/core/configuration.rb +43 -11
  131. data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
  132. data/lib/datadog/core/crashtracking/component.rb +4 -13
  133. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  134. data/lib/datadog/core/encoding.rb +17 -1
  135. data/lib/datadog/core/environment/agent_info.rb +78 -0
  136. data/lib/datadog/core/environment/cgroup.rb +10 -12
  137. data/lib/datadog/core/environment/container.rb +38 -40
  138. data/lib/datadog/core/environment/ext.rb +6 -6
  139. data/lib/datadog/core/environment/git.rb +1 -0
  140. data/lib/datadog/core/environment/identity.rb +3 -3
  141. data/lib/datadog/core/environment/platform.rb +3 -3
  142. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  143. data/lib/datadog/core/error.rb +11 -9
  144. data/lib/datadog/core/logger.rb +2 -2
  145. data/lib/datadog/core/metrics/client.rb +27 -27
  146. data/lib/datadog/core/metrics/logging.rb +5 -5
  147. data/lib/datadog/core/process_discovery.rb +32 -0
  148. data/lib/datadog/core/rate_limiter.rb +4 -2
  149. data/lib/datadog/core/remote/client/capabilities.rb +6 -0
  150. data/lib/datadog/core/remote/client.rb +107 -92
  151. data/lib/datadog/core/remote/component.rb +18 -19
  152. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  153. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  154. data/lib/datadog/core/remote/configuration/repository.rb +2 -1
  155. data/lib/datadog/core/remote/negotiation.rb +9 -9
  156. data/lib/datadog/core/remote/transport/config.rb +4 -3
  157. data/lib/datadog/core/remote/transport/http/api.rb +13 -18
  158. data/lib/datadog/core/remote/transport/http/client.rb +5 -4
  159. data/lib/datadog/core/remote/transport/http/config.rb +27 -55
  160. data/lib/datadog/core/remote/transport/http/negotiation.rb +8 -51
  161. data/lib/datadog/core/remote/transport/http.rb +25 -94
  162. data/lib/datadog/core/remote/transport/negotiation.rb +17 -4
  163. data/lib/datadog/core/remote/worker.rb +10 -7
  164. data/lib/datadog/core/runtime/metrics.rb +12 -5
  165. data/lib/datadog/core/telemetry/component.rb +84 -49
  166. data/lib/datadog/core/telemetry/emitter.rb +23 -11
  167. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +65 -0
  168. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  169. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  170. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  171. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  172. data/lib/datadog/core/telemetry/event/app_started.rb +179 -0
  173. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  174. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  175. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  176. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  177. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  178. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  179. data/lib/datadog/core/telemetry/event.rb +17 -383
  180. data/lib/datadog/core/telemetry/ext.rb +1 -0
  181. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  182. data/lib/datadog/core/telemetry/logger.rb +1 -1
  183. data/lib/datadog/core/telemetry/logging.rb +2 -2
  184. data/lib/datadog/core/telemetry/metric.rb +28 -6
  185. data/lib/datadog/core/telemetry/request.rb +4 -4
  186. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  187. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  188. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  189. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  190. data/lib/datadog/core/telemetry/transport/telemetry.rb +51 -0
  191. data/lib/datadog/core/telemetry/worker.rb +128 -25
  192. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  193. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
  194. data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +18 -1
  195. data/lib/datadog/core/transport/http/api/spec.rb +36 -0
  196. data/lib/datadog/{tracing → core}/transport/http/builder.rb +53 -31
  197. data/lib/datadog/core/transport/http.rb +75 -0
  198. data/lib/datadog/core/transport/response.rb +4 -0
  199. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  200. data/lib/datadog/core/utils/duration.rb +32 -32
  201. data/lib/datadog/core/utils/forking.rb +2 -2
  202. data/lib/datadog/core/utils/network.rb +6 -6
  203. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  204. data/lib/datadog/core/utils/time.rb +20 -0
  205. data/lib/datadog/core/utils/truncation.rb +21 -0
  206. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  207. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  208. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  209. data/lib/datadog/core/worker.rb +1 -1
  210. data/lib/datadog/core/workers/async.rb +29 -12
  211. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  212. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  213. data/lib/datadog/core.rb +8 -0
  214. data/lib/datadog/di/base.rb +115 -0
  215. data/lib/datadog/di/boot.rb +34 -0
  216. data/lib/datadog/di/code_tracker.rb +26 -15
  217. data/lib/datadog/di/component.rb +23 -14
  218. data/lib/datadog/di/configuration/settings.rb +25 -1
  219. data/lib/datadog/di/contrib/active_record.rb +1 -0
  220. data/lib/datadog/di/contrib/railtie.rb +15 -0
  221. data/lib/datadog/di/contrib.rb +28 -0
  222. data/lib/datadog/di/error.rb +5 -0
  223. data/lib/datadog/di/instrumenter.rb +111 -20
  224. data/lib/datadog/di/logger.rb +30 -0
  225. data/lib/datadog/di/preload.rb +18 -0
  226. data/lib/datadog/di/probe.rb +14 -7
  227. data/lib/datadog/di/probe_builder.rb +1 -0
  228. data/lib/datadog/di/probe_manager.rb +11 -5
  229. data/lib/datadog/di/probe_notification_builder.rb +34 -8
  230. data/lib/datadog/di/probe_notifier_worker.rb +52 -26
  231. data/lib/datadog/di/redactor.rb +0 -1
  232. data/lib/datadog/di/remote.rb +147 -0
  233. data/lib/datadog/di/serializer.rb +14 -7
  234. data/lib/datadog/di/transport/diagnostics.rb +62 -0
  235. data/lib/datadog/di/transport/http/api.rb +42 -0
  236. data/lib/datadog/di/transport/http/client.rb +47 -0
  237. data/lib/datadog/di/transport/http/diagnostics.rb +65 -0
  238. data/lib/datadog/di/transport/http/input.rb +67 -0
  239. data/lib/datadog/di/transport/http.rb +57 -0
  240. data/lib/datadog/di/transport/input.rb +62 -0
  241. data/lib/datadog/di/utils.rb +103 -0
  242. data/lib/datadog/di.rb +14 -76
  243. data/lib/datadog/error_tracking/collector.rb +87 -0
  244. data/lib/datadog/error_tracking/component.rb +167 -0
  245. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  246. data/lib/datadog/error_tracking/configuration.rb +11 -0
  247. data/lib/datadog/error_tracking/ext.rb +18 -0
  248. data/lib/datadog/error_tracking/extensions.rb +16 -0
  249. data/lib/datadog/error_tracking/filters.rb +77 -0
  250. data/lib/datadog/error_tracking.rb +18 -0
  251. data/lib/datadog/kit/appsec/events.rb +15 -3
  252. data/lib/datadog/kit/identity.rb +9 -5
  253. data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
  254. data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
  255. data/lib/datadog/opentelemetry/api/context.rb +16 -2
  256. data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
  257. data/lib/datadog/opentelemetry.rb +2 -1
  258. data/lib/datadog/profiling/collectors/code_provenance.rb +1 -1
  259. data/lib/datadog/profiling/collectors/info.rb +3 -0
  260. data/lib/datadog/profiling/collectors/thread_context.rb +1 -1
  261. data/lib/datadog/profiling/component.rb +60 -76
  262. data/lib/datadog/profiling/encoded_profile.rb +11 -0
  263. data/lib/datadog/profiling/exporter.rb +3 -4
  264. data/lib/datadog/profiling/ext.rb +0 -2
  265. data/lib/datadog/profiling/flush.rb +5 -8
  266. data/lib/datadog/profiling/http_transport.rb +6 -85
  267. data/lib/datadog/profiling/load_native_extension.rb +1 -33
  268. data/lib/datadog/profiling/scheduler.rb +8 -1
  269. data/lib/datadog/profiling/stack_recorder.rb +4 -4
  270. data/lib/datadog/profiling/tag_builder.rb +1 -5
  271. data/lib/datadog/profiling.rb +6 -2
  272. data/lib/datadog/tracing/analytics.rb +1 -1
  273. data/lib/datadog/tracing/component.rb +16 -12
  274. data/lib/datadog/tracing/configuration/ext.rb +8 -1
  275. data/lib/datadog/tracing/configuration/settings.rb +22 -10
  276. data/lib/datadog/tracing/context_provider.rb +1 -1
  277. data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
  278. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
  279. data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
  280. data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
  281. data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
  282. data/lib/datadog/tracing/contrib/active_record/integration.rb +7 -3
  283. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +7 -2
  284. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +36 -1
  285. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  286. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +14 -4
  287. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
  288. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
  289. data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
  290. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  291. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
  292. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  293. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
  294. data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
  295. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
  296. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  297. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
  298. data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
  299. data/lib/datadog/tracing/contrib/ext.rb +1 -0
  300. data/lib/datadog/tracing/contrib/extensions.rb +29 -3
  301. data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
  302. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
  303. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
  304. data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
  305. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
  306. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
  307. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
  308. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
  309. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
  310. data/lib/datadog/tracing/contrib/http/instrumentation.rb +6 -10
  311. data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
  312. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -16
  313. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +7 -15
  314. data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
  315. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
  316. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +27 -0
  317. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +48 -0
  318. data/lib/datadog/tracing/contrib/karafka/ext.rb +27 -0
  319. data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
  320. data/lib/datadog/tracing/contrib/karafka/monitor.rb +66 -0
  321. data/lib/datadog/tracing/contrib/karafka/patcher.rb +71 -0
  322. data/lib/datadog/tracing/contrib/karafka.rb +37 -0
  323. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  324. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  325. data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
  326. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  327. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
  328. data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
  329. data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
  330. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
  331. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  332. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
  333. data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
  334. data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
  335. data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
  336. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  337. data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
  338. data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
  339. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
  340. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
  341. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
  342. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
  343. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +1 -1
  344. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
  345. data/lib/datadog/tracing/contrib/support.rb +28 -0
  346. data/lib/datadog/tracing/contrib.rb +1 -0
  347. data/lib/datadog/tracing/correlation.rb +9 -2
  348. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  349. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  350. data/lib/datadog/tracing/distributed/baggage.rb +131 -0
  351. data/lib/datadog/tracing/distributed/datadog.rb +4 -2
  352. data/lib/datadog/tracing/distributed/propagation.rb +25 -4
  353. data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
  354. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  355. data/lib/datadog/tracing/metadata/ext.rb +5 -0
  356. data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
  357. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
  358. data/lib/datadog/tracing/metadata.rb +2 -0
  359. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  360. data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
  361. data/lib/datadog/tracing/span.rb +22 -5
  362. data/lib/datadog/tracing/span_event.rb +124 -4
  363. data/lib/datadog/tracing/span_operation.rb +52 -16
  364. data/lib/datadog/tracing/sync_writer.rb +9 -5
  365. data/lib/datadog/tracing/trace_digest.rb +9 -2
  366. data/lib/datadog/tracing/trace_operation.rb +44 -24
  367. data/lib/datadog/tracing/trace_segment.rb +6 -4
  368. data/lib/datadog/tracing/tracer.rb +60 -12
  369. data/lib/datadog/tracing/transport/http/api.rb +5 -4
  370. data/lib/datadog/tracing/transport/http/client.rb +5 -4
  371. data/lib/datadog/tracing/transport/http/traces.rb +13 -44
  372. data/lib/datadog/tracing/transport/http.rb +13 -70
  373. data/lib/datadog/tracing/transport/serializable_trace.rb +31 -7
  374. data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
  375. data/lib/datadog/tracing/transport/traces.rb +47 -13
  376. data/lib/datadog/tracing/utils.rb +1 -1
  377. data/lib/datadog/tracing/workers/trace_writer.rb +8 -5
  378. data/lib/datadog/tracing/workers.rb +5 -4
  379. data/lib/datadog/tracing/writer.rb +10 -6
  380. data/lib/datadog/tracing.rb +16 -3
  381. data/lib/datadog/version.rb +2 -2
  382. data/lib/datadog.rb +2 -0
  383. metadata +143 -50
  384. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
  385. data/ext/datadog_profiling_loader/extconf.rb +0 -60
  386. data/lib/datadog/appsec/contrib/devise/event.rb +0 -57
  387. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -77
  388. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -54
  389. data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
  390. data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
  391. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
  392. data/lib/datadog/appsec/contrib/patcher.rb +0 -12
  393. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
  394. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
  395. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
  396. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
  397. data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
  398. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
  399. data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
  400. data/lib/datadog/appsec/processor/actions.rb +0 -49
  401. data/lib/datadog/appsec/processor/context.rb +0 -107
  402. data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
  403. data/lib/datadog/appsec/reactive/engine.rb +0 -47
  404. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  405. data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
  406. data/lib/datadog/appsec/scope.rb +0 -58
  407. data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
  408. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
  409. data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
  410. data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
  411. data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
  412. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  413. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  414. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  415. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
  416. data/lib/datadog/di/transport.rb +0 -81
  417. 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;
@@ -210,17 +212,17 @@ struct stack_recorder_state {
210
212
  long serialization_time_ns_max;
211
213
  uint64_t serialization_time_ns_total;
212
214
  } stats_lifetime;
213
- };
215
+ } stack_recorder_state;
214
216
 
215
217
  // Used to group mutex and the corresponding profile slot for easy unlocking after work is done.
216
- typedef struct locked_profile_slot {
218
+ typedef struct {
217
219
  pthread_mutex_t *mutex;
218
220
  profile_slot *data;
219
221
  } locked_profile_slot;
220
222
 
221
- struct call_serialize_without_gvl_arguments {
223
+ typedef struct {
222
224
  // Set by caller
223
- struct stack_recorder_state *state;
225
+ stack_recorder_state *state;
224
226
  ddog_Timespec finish_timestamp;
225
227
 
226
228
  // Set by callee
@@ -231,35 +233,33 @@ struct call_serialize_without_gvl_arguments {
231
233
 
232
234
  // Set by both
233
235
  bool serialize_ran;
234
- };
236
+ } call_serialize_without_gvl_arguments;
235
237
 
236
238
  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);
239
+ static void initialize_slot_concurrency_control(stack_recorder_state *state);
240
+ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types);
239
241
  static void stack_recorder_typed_data_free(void *data);
240
242
  static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _self);
241
243
  static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
242
244
  static VALUE ruby_time_from(ddog_Timespec ddprof_time);
243
245
  static void *call_serialize_without_gvl(void *call_args);
244
- static locked_profile_slot sampler_lock_active_profile(struct stack_recorder_state *state);
246
+ static locked_profile_slot sampler_lock_active_profile(stack_recorder_state *state);
245
247
  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);
248
+ static profile_slot* serializer_flip_active_and_inactive_slots(stack_recorder_state *state);
247
249
  static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
248
250
  static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
249
251
  static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
250
252
  static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot);
251
253
  static ddog_Timespec system_epoch_now_timespec(void);
252
254
  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);
255
+ static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time);
254
256
  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 */);
257
+ static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp);
256
258
  static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class);
257
259
  static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations);
258
260
  static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
259
261
  static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
260
262
  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
263
  static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance);
264
264
  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
265
  static VALUE _native_is_object_recorded(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE object_id);
@@ -297,10 +297,6 @@ void stack_recorder_init(VALUE profiling_module) {
297
297
  _native_end_fake_slow_heap_serialization, 1);
298
298
  rb_define_singleton_method(testing_module, "_native_debug_heap_recorder",
299
299
  _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
300
  rb_define_singleton_method(testing_module, "_native_is_object_recorded?", _native_is_object_recorded, 2);
305
301
  rb_define_singleton_method(testing_module, "_native_heap_recorder_reset_last_update", _native_heap_recorder_reset_last_update, 1);
306
302
  rb_define_singleton_method(testing_module, "_native_recorder_after_gc_step", _native_recorder_after_gc_step, 1);
@@ -322,7 +318,7 @@ static const rb_data_type_t stack_recorder_typed_data = {
322
318
  };
323
319
 
324
320
  static VALUE _native_new(VALUE klass) {
325
- struct stack_recorder_state *state = ruby_xcalloc(1, sizeof(struct stack_recorder_state));
321
+ stack_recorder_state *state = ruby_xcalloc(1, sizeof(stack_recorder_state));
326
322
 
327
323
  // Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory
328
324
  // being leaked.
@@ -338,29 +334,22 @@ static VALUE _native_new(VALUE klass) {
338
334
  .serialization_time_ns_min = INT64_MAX,
339
335
  };
340
336
 
341
- // Note: At this point, slot_one_profile and slot_two_profile contain null pointers. Libdatadog validates pointers
337
+ // Note: At this point, slot_one_profile/slot_two_profile contain null pointers. Libdatadog validates pointers
342
338
  // before using them so it's ok for us to go ahead and create the StackRecorder object.
343
339
 
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
340
  VALUE stack_recorder = TypedData_Wrap_Struct(klass, &stack_recorder_typed_data, state);
349
341
 
350
- // NOTE: We initialize this because we want a new recorder to be operational even without initialization and our
342
+ // NOTE: We initialize this because we want a new recorder to be operational even before #initialize runs and our
351
343
  // 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).
344
+ // heap samples, we will free and reset heap_recorder back to NULL.
354
345
  state->heap_recorder = heap_recorder_new();
355
346
 
356
- // Note: Don't raise exceptions after this point, since it'll lead to libdatadog memory leaking!
357
-
358
347
  initialize_profiles(state, sample_types);
359
348
 
360
349
  return stack_recorder;
361
350
  }
362
351
 
363
- static void initialize_slot_concurrency_control(struct stack_recorder_state *state) {
352
+ static void initialize_slot_concurrency_control(stack_recorder_state *state) {
364
353
  state->mutex_slot_one = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
365
354
  state->mutex_slot_two = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
366
355
 
@@ -370,34 +359,31 @@ static void initialize_slot_concurrency_control(struct stack_recorder_state *sta
370
359
  state->active_slot = 1;
371
360
  }
372
361
 
373
- static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
362
+ static void initialize_profiles(stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
363
+ ddog_Timespec start_timestamp = system_epoch_now_timespec();
364
+
374
365
  ddog_prof_Profile_NewResult slot_one_profile_result =
375
- ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
366
+ ddog_prof_Profile_new(sample_types, NULL /* period is optional */);
376
367
 
377
368
  if (slot_one_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
378
369
  rb_raise(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
379
370
  }
380
371
 
372
+ state->profile_slot_one = (profile_slot) { .profile = slot_one_profile_result.ok, .start_timestamp = start_timestamp };
373
+
381
374
  ddog_prof_Profile_NewResult slot_two_profile_result =
382
- ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
375
+ ddog_prof_Profile_new(sample_types, NULL /* period is optional */);
383
376
 
384
377
  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...
378
+ // Note: No need to take any special care of slot one, it'll get cleaned up by stack_recorder_typed_data_free
388
379
  rb_raise(rb_eRuntimeError, "Failed to initialize slot two profile: %"PRIsVALUE, get_error_details_and_drop(&slot_two_profile_result.err));
389
380
  }
390
381
 
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
- };
382
+ state->profile_slot_two = (profile_slot) { .profile = slot_two_profile_result.ok, .start_timestamp = start_timestamp };
397
383
  }
398
384
 
399
385
  static void stack_recorder_typed_data_free(void *state_ptr) {
400
- struct stack_recorder_state *state = (struct stack_recorder_state *) state_ptr;
386
+ stack_recorder_state *state = (stack_recorder_state *) state_ptr;
401
387
 
402
388
  pthread_mutex_destroy(&state->mutex_slot_one);
403
389
  ddog_prof_Profile_drop(&state->profile_slot_one.profile);
@@ -432,8 +418,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
432
418
  ENFORCE_BOOLEAN(timeline_enabled);
433
419
  ENFORCE_BOOLEAN(heap_clean_after_gc_enabled);
434
420
 
435
- struct stack_recorder_state *state;
436
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
421
+ stack_recorder_state *state;
422
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
437
423
 
438
424
  state->heap_clean_after_gc_enabled = (heap_clean_after_gc_enabled == Qtrue);
439
425
 
@@ -523,8 +509,8 @@ static VALUE _native_initialize(int argc, VALUE *argv, DDTRACE_UNUSED VALUE _sel
523
509
  }
524
510
 
525
511
  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);
512
+ stack_recorder_state *state;
513
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
528
514
 
529
515
  ddog_Timespec finish_timestamp = system_epoch_now_timespec();
530
516
  // Need to do this while still holding on to the Global VM Lock; see comments on method for why
@@ -538,7 +524,7 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
538
524
 
539
525
  // We'll release the Global VM Lock while we're calling serialize, so that the Ruby VM can continue to work while this
540
526
  // is pending
541
- struct call_serialize_without_gvl_arguments args = {
527
+ call_serialize_without_gvl_arguments args = {
542
528
  .state = state,
543
529
  .finish_timestamp = finish_timestamp,
544
530
  .serialize_ran = false
@@ -582,18 +568,14 @@ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instan
582
568
 
583
569
  state->stats_lifetime.serialization_successes++;
584
570
 
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;
571
+ // Once we wrap this into a Ruby object, our `EncodedProfile` class will automatically manage memory for it
572
+ VALUE encoded_profile = from_ddog_prof_EncodedProfile(serialized_profile.ok);
589
573
 
590
- ddog_prof_EncodedProfile_drop(&serialized_profile.ok);
591
-
592
- VALUE start = ruby_time_from(ddprof_start);
593
- VALUE finish = ruby_time_from(ddprof_finish);
574
+ VALUE start = ruby_time_from(args.slot->start_timestamp);
575
+ VALUE finish = ruby_time_from(finish_timestamp);
594
576
  VALUE profile_stats = build_profile_stats(args.slot, serialization_time_ns, heap_iteration_prep_time_ns, args.heap_profile_build_time_ns);
595
577
 
596
- return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_pprof, profile_stats));
578
+ return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(4, start, finish, encoded_profile, profile_stats));
597
579
  }
598
580
 
599
581
  static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
@@ -603,8 +585,8 @@ static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
603
585
  }
604
586
 
605
587
  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);
588
+ stack_recorder_state *state;
589
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
608
590
 
609
591
  locked_profile_slot active_slot = sampler_lock_active_profile(state);
610
592
 
@@ -657,9 +639,9 @@ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations,
657
639
  }
658
640
  }
659
641
 
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);
642
+ void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice alloc_class) {
643
+ stack_recorder_state *state;
644
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
663
645
  // FIXME: Heap sampling currently has to be done in 2 parts because the construction of locations is happening
664
646
  // very late in the allocation-sampling path (which is shared with the cpu sampling path). This can
665
647
  // be fixed with some refactoring but for now this leads to a less impactful change.
@@ -667,8 +649,8 @@ void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample
667
649
  }
668
650
 
669
651
  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);
652
+ stack_recorder_state *state;
653
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
672
654
 
673
655
  locked_profile_slot active_slot = sampler_lock_active_profile(state);
674
656
 
@@ -682,8 +664,8 @@ void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_
682
664
  }
683
665
 
684
666
  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);
667
+ stack_recorder_state *state;
668
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
687
669
 
688
670
  if (state->heap_clean_after_gc_enabled) heap_recorder_update_young_objects(state->heap_recorder);
689
671
  }
@@ -693,7 +675,7 @@ void recorder_after_gc_step(VALUE recorder_instance) {
693
675
  // Heap recorder iteration context allows us access to stack recorder state and profile being serialized
694
676
  // during iteration of heap recorder live objects.
695
677
  typedef struct heap_recorder_iteration_context {
696
- struct stack_recorder_state *state;
678
+ stack_recorder_state *state;
697
679
  profile_slot *slot;
698
680
 
699
681
  bool error;
@@ -755,7 +737,7 @@ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteratio
755
737
  return true;
756
738
  }
757
739
 
758
- static void build_heap_profile_without_gvl(struct stack_recorder_state *state, profile_slot *slot) {
740
+ static void build_heap_profile_without_gvl(stack_recorder_state *state, profile_slot *slot) {
759
741
  heap_recorder_iteration_context iteration_context = {
760
742
  .state = state,
761
743
  .slot = slot,
@@ -776,12 +758,11 @@ static void build_heap_profile_without_gvl(struct stack_recorder_state *state, p
776
758
  }
777
759
 
778
760
  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;
761
+ call_serialize_without_gvl_arguments *args = (call_serialize_without_gvl_arguments *) call_args;
780
762
 
781
763
  long serialize_no_gvl_start_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE);
782
764
 
783
765
  profile_slot *slot_now_inactive = serializer_flip_active_and_inactive_slots(args->state);
784
-
785
766
  args->slot = slot_now_inactive;
786
767
 
787
768
  // Now that we have the inactive profile with all but heap samples, lets fill it with heap data
@@ -790,7 +771,7 @@ static void *call_serialize_without_gvl(void *call_args) {
790
771
  args->heap_profile_build_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
791
772
 
792
773
  // 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 */);
774
+ args->result = ddog_prof_Profile_serialize(&args->slot->profile, &args->slot->start_timestamp, &args->finish_timestamp);
794
775
  args->serialize_ran = true;
795
776
  args->serialize_no_gvl_time_ns = monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE) - serialize_no_gvl_start_time_ns;
796
777
 
@@ -798,11 +779,11 @@ static void *call_serialize_without_gvl(void *call_args) {
798
779
  }
799
780
 
800
781
  VALUE enforce_recorder_instance(VALUE object) {
801
- Check_TypedStruct(object, &stack_recorder_typed_data);
782
+ ENFORCE_TYPED_DATA(object, &stack_recorder_typed_data);
802
783
  return object;
803
784
  }
804
785
 
805
- static locked_profile_slot sampler_lock_active_profile(struct stack_recorder_state *state) {
786
+ static locked_profile_slot sampler_lock_active_profile(stack_recorder_state *state) {
806
787
  int error;
807
788
 
808
789
  for (int attempts = 0; attempts < 2; attempts++) {
@@ -829,7 +810,7 @@ static void sampler_unlock_active_profile(locked_profile_slot active_slot) {
829
810
  ENFORCE_SUCCESS_GVL(pthread_mutex_unlock(active_slot.mutex));
830
811
  }
831
812
 
832
- static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state) {
813
+ static profile_slot* serializer_flip_active_and_inactive_slots(stack_recorder_state *state) {
833
814
  int previously_active_slot = state->active_slot;
834
815
 
835
816
  if (previously_active_slot != 1 && previously_active_slot != 2) {
@@ -855,8 +836,8 @@ static profile_slot* serializer_flip_active_and_inactive_slots(struct stack_reco
855
836
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
856
837
  // It SHOULD NOT be used for other purposes.
857
838
  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);
839
+ stack_recorder_state *state;
840
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
860
841
 
861
842
  return INT2NUM(state->active_slot);
862
843
  }
@@ -870,8 +851,8 @@ static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE
870
851
  static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { return test_slot_mutex_state(recorder_instance, 2); }
871
852
 
872
853
  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);
854
+ stack_recorder_state *state;
855
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
875
856
 
876
857
  pthread_mutex_t *slot_mutex = (slot == 1) ? &state->mutex_slot_one : &state->mutex_slot_two;
877
858
 
@@ -901,15 +882,15 @@ static ddog_Timespec system_epoch_now_timespec(void) {
901
882
  // Assumption: This method gets called BEFORE restarting profiling -- e.g. there are no components attempting to
902
883
  // trigger samples at the same time.
903
884
  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);
885
+ stack_recorder_state *state;
886
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
906
887
 
907
888
  // In case the fork happened halfway through `serializer_flip_active_and_inactive_slots` execution and the
908
889
  // resulting state is inconsistent, we make sure to reset it back to the initial state.
909
890
  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);
891
+ ddog_Timespec start_timestamp = system_epoch_now_timespec();
892
+ reset_profile_slot(&state->profile_slot_one, start_timestamp);
893
+ reset_profile_slot(&state->profile_slot_two, start_timestamp);
913
894
 
914
895
  heap_recorder_after_fork(state->heap_recorder);
915
896
 
@@ -918,10 +899,10 @@ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_
918
899
 
919
900
  // Assumption 1: This method is called with the GVL being held, because `ddog_prof_Profile_reset` mutates the profile and must
920
901
  // 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) {
902
+ static void serializer_set_start_timestamp_for_next_profile(stack_recorder_state *state, ddog_Timespec start_time) {
922
903
  // Before making this profile active, we reset it so that it uses the correct start_time for its start
923
904
  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);
905
+ reset_profile_slot(next_profile_slot, start_time);
925
906
  }
926
907
 
927
908
  static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint) {
@@ -932,8 +913,7 @@ static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_
932
913
 
933
914
  static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class) {
934
915
  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);
916
+ track_object(recorder_instance, new_obj, NUM2UINT(weight), char_slice_from_ruby_string(alloc_class));
937
917
  return Qtrue;
938
918
  }
939
919
 
@@ -967,19 +947,20 @@ static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locatio
967
947
  return Qnil;
968
948
  }
969
949
 
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);
950
+ static void reset_profile_slot(profile_slot *slot, ddog_Timespec start_timestamp) {
951
+ ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(&slot->profile);
972
952
  if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
973
953
  rb_raise(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
974
954
  }
955
+ slot->start_timestamp = start_timestamp;
975
956
  slot->stats = (stats_slot) {};
976
957
  }
977
958
 
978
959
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
979
960
  // It SHOULD NOT be used for other purposes.
980
961
  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);
962
+ stack_recorder_state *state;
963
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
983
964
 
984
965
  heap_recorder_prepare_iteration(state->heap_recorder);
985
966
 
@@ -989,8 +970,8 @@ static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _se
989
970
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
990
971
  // It SHOULD NOT be used for other purposes.
991
972
  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);
973
+ stack_recorder_state *state;
974
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
994
975
 
995
976
  heap_recorder_finish_iteration(state->heap_recorder);
996
977
 
@@ -1000,43 +981,15 @@ static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self
1000
981
  // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
1001
982
  // It SHOULD NOT be used for other purposes.
1002
983
  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);
984
+ stack_recorder_state *state;
985
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1005
986
 
1006
987
  return heap_recorder_testonly_debug(state->heap_recorder);
1007
988
  }
1008
989
 
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
990
  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);
991
+ stack_recorder_state *state;
992
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1040
993
 
1041
994
  uint64_t total_serializations = state->stats_lifetime.serialization_successes + state->stats_lifetime.serialization_failures;
1042
995
 
@@ -1074,15 +1027,15 @@ static VALUE build_profile_stats(profile_slot *slot, long serialization_time_ns,
1074
1027
  static VALUE _native_is_object_recorded(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE obj_id) {
1075
1028
  ENFORCE_TYPE(obj_id, T_FIXNUM);
1076
1029
 
1077
- struct stack_recorder_state *state;
1078
- TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
1030
+ stack_recorder_state *state;
1031
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1079
1032
 
1080
1033
  return heap_recorder_testonly_is_object_recorded(state->heap_recorder, obj_id);
1081
1034
  }
1082
1035
 
1083
1036
  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);
1037
+ stack_recorder_state *state;
1038
+ TypedData_Get_Struct(recorder_instance, stack_recorder_state, &stack_recorder_typed_data, state);
1086
1039
 
1087
1040
  heap_recorder_testonly_reset_last_update(state->heap_recorder);
1088
1041
 
@@ -13,7 +13,7 @@ typedef struct {
13
13
  int64_t timeline_wall_time_ns;
14
14
  } sample_values;
15
15
 
16
- typedef struct sample_labels {
16
+ typedef struct {
17
17
  ddog_prof_Slice_Label labels;
18
18
 
19
19
  // This is used to allow the `Collectors::Stack` to modify the existing label, if any. This MUST be NULL or point
@@ -26,6 +26,6 @@ typedef struct sample_labels {
26
26
 
27
27
  void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, sample_values values, sample_labels labels);
28
28
  void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_CharSlice endpoint);
29
- void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice *alloc_class);
29
+ void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice alloc_class);
30
30
  void recorder_after_gc_step(VALUE recorder_instance);
31
31
  VALUE enforce_recorder_instance(VALUE object);
@@ -39,7 +39,7 @@ static inline long system_epoch_time_now_ns(raise_on_failure_setting raise_on_fa
39
39
  // https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_for_real_time/7/html/reference_guide/sect-posix_clocks#Using_clock_getres_to_compare_clock_resolution
40
40
  // We introduce here a separate type for it, so as to make it harder to misuse/more explicit when these timestamps are used
41
41
 
42
- typedef struct coarse_instant {
42
+ typedef struct {
43
43
  long timestamp_ns;
44
44
  } coarse_instant;
45
45
 
@@ -0,0 +1,47 @@
1
+ #include <ruby.h>
2
+ #include <ruby/debug.h>
3
+ #include <stdbool.h>
4
+
5
+ #include "datadog_ruby_common.h"
6
+ #include "unsafe_api_calls_check.h"
7
+ #include "extconf.h"
8
+
9
+ static bool inside_unsafe_context = false;
10
+
11
+ #ifndef NO_POSTPONED_TRIGGER
12
+ static rb_postponed_job_handle_t check_for_unsafe_api_calls_handle;
13
+ #endif
14
+
15
+ static void check_for_unsafe_api_calls(DDTRACE_UNUSED void *_unused);
16
+
17
+ void unsafe_api_calls_check_init(void) {
18
+ #ifndef NO_POSTPONED_TRIGGER
19
+ int unused_flags = 0;
20
+
21
+ check_for_unsafe_api_calls_handle = rb_postponed_job_preregister(unused_flags, check_for_unsafe_api_calls, NULL);
22
+
23
+ if (check_for_unsafe_api_calls_handle == POSTPONED_JOB_HANDLE_INVALID) {
24
+ rb_raise(rb_eRuntimeError, "Failed to register check_for_unsafe_api_calls_handle postponed job (got POSTPONED_JOB_HANDLE_INVALID)");
25
+ }
26
+ #endif
27
+ }
28
+
29
+ void debug_enter_unsafe_context(void) {
30
+ inside_unsafe_context = true;
31
+
32
+ #ifndef NO_POSTPONED_TRIGGER
33
+ rb_postponed_job_trigger(check_for_unsafe_api_calls_handle);
34
+ #else
35
+ rb_postponed_job_register(0, check_for_unsafe_api_calls, NULL);
36
+ #endif
37
+ }
38
+
39
+ void debug_leave_unsafe_context(void) {
40
+ inside_unsafe_context = false;
41
+ }
42
+
43
+ static void check_for_unsafe_api_calls(DDTRACE_UNUSED void *_unused) {
44
+ if (inside_unsafe_context) rb_bug(
45
+ "Datadog Ruby profiler detected callback nested inside sample. Please report this at https://github.com/datadog/dd-trace-rb/blob/master/CONTRIBUTING.md#found-a-bug"
46
+ );
47
+ }
@@ -0,0 +1,31 @@
1
+ #pragma once
2
+
3
+ // This checker is used to detect accidental thread scheduling switching points happening during profiling sampling.
4
+ //
5
+ // Specifically, when the profiler is sampling, we're never supposed to call into Ruby code (e.g. methods
6
+ // implemented using Ruby code) or allocate Ruby objects.
7
+ // That's because those events introduce thread switch points, and really we don't the VM switching between threads
8
+ // in the middle of the profiler sampling.
9
+ // This includes raising exceptions, unless we're trying to stop the profiler, and even then we must be careful.
10
+ //
11
+ // The above is especially true in situations such as GC profiling or allocation/heap profiling, as in those situations
12
+ // we can even crash the Ruby VM if we switch away at the wrong time.
13
+ //
14
+ // The below APIs can be used to detect these situations. They work by relying on the following observation:
15
+ // in most (all?) thread switch points, Ruby will check for interrupts and run the postponed jobs.
16
+ //
17
+ // Thus, if we set a flag while we're sampling (inside_unsafe_context), trigger the postponed job, and then only unset
18
+ // the flag after sampling, he correct thing to happen is that the postponed job should never see the flag.
19
+ //
20
+ // If, however, we have a bug and there's a thread switch point, our postponed job will see the flag and immediately
21
+ // stop the Ruby VM before further damage happens (and hopefully giving us a stack trace clearly pointing to the culprit).
22
+
23
+ void unsafe_api_calls_check_init(void);
24
+
25
+ // IMPORTANT: This method **MUST** only be called from test code, as it causes an immediate hard-crash on the Ruby VM
26
+ // when it detects a potential issue, and that's not something we want for production apps.
27
+ //
28
+ // In the future we may introduce some kind of setting (off by default) to also allow this to be safely be used
29
+ // in production code if needed.
30
+ void debug_enter_unsafe_context(void);
31
+ void debug_leave_unsafe_context(void);