datadog 2.0.0.beta1

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 (764) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +4236 -0
  3. data/LICENSE +6 -0
  4. data/LICENSE-3rdparty.csv +7 -0
  5. data/LICENSE.Apache +200 -0
  6. data/LICENSE.BSD3 +24 -0
  7. data/NOTICE +4 -0
  8. data/README.md +25 -0
  9. data/bin/ddprofrb +15 -0
  10. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +134 -0
  11. data/ext/datadog_profiling_loader/extconf.rb +72 -0
  12. data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +156 -0
  13. data/ext/datadog_profiling_native_extension/clock_id.h +22 -0
  14. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +56 -0
  15. data/ext/datadog_profiling_native_extension/clock_id_noop.c +22 -0
  16. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +1153 -0
  17. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +422 -0
  18. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +101 -0
  19. data/ext/datadog_profiling_native_extension/collectors_dynamic_sampling_rate.c +150 -0
  20. data/ext/datadog_profiling_native_extension/collectors_dynamic_sampling_rate.h +18 -0
  21. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +156 -0
  22. data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.h +5 -0
  23. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +244 -0
  24. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.h +3 -0
  25. data/ext/datadog_profiling_native_extension/collectors_stack.c +372 -0
  26. data/ext/datadog_profiling_native_extension/collectors_stack.h +27 -0
  27. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +1391 -0
  28. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +15 -0
  29. data/ext/datadog_profiling_native_extension/extconf.rb +302 -0
  30. data/ext/datadog_profiling_native_extension/heap_recorder.c +970 -0
  31. data/ext/datadog_profiling_native_extension/heap_recorder.h +155 -0
  32. data/ext/datadog_profiling_native_extension/helpers.h +23 -0
  33. data/ext/datadog_profiling_native_extension/http_transport.c +375 -0
  34. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +62 -0
  35. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +42 -0
  36. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +319 -0
  37. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +892 -0
  38. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +61 -0
  39. data/ext/datadog_profiling_native_extension/profiling.c +267 -0
  40. data/ext/datadog_profiling_native_extension/ruby_helpers.c +267 -0
  41. data/ext/datadog_profiling_native_extension/ruby_helpers.h +119 -0
  42. data/ext/datadog_profiling_native_extension/setup_signal_handler.c +115 -0
  43. data/ext/datadog_profiling_native_extension/setup_signal_handler.h +11 -0
  44. data/ext/datadog_profiling_native_extension/stack_recorder.c +941 -0
  45. data/ext/datadog_profiling_native_extension/stack_recorder.h +27 -0
  46. data/ext/datadog_profiling_native_extension/time_helpers.c +53 -0
  47. data/ext/datadog_profiling_native_extension/time_helpers.h +26 -0
  48. data/lib/datadog/appsec/assets/blocked.html +99 -0
  49. data/lib/datadog/appsec/assets/blocked.json +1 -0
  50. data/lib/datadog/appsec/assets/blocked.text +5 -0
  51. data/lib/datadog/appsec/assets/waf_rules/README.md +7 -0
  52. data/lib/datadog/appsec/assets/waf_rules/processors.json +92 -0
  53. data/lib/datadog/appsec/assets/waf_rules/recommended.json +7703 -0
  54. data/lib/datadog/appsec/assets/waf_rules/scanners.json +114 -0
  55. data/lib/datadog/appsec/assets/waf_rules/strict.json +1635 -0
  56. data/lib/datadog/appsec/assets.rb +46 -0
  57. data/lib/datadog/appsec/autoload.rb +13 -0
  58. data/lib/datadog/appsec/component.rb +94 -0
  59. data/lib/datadog/appsec/configuration/settings.rb +202 -0
  60. data/lib/datadog/appsec/configuration.rb +11 -0
  61. data/lib/datadog/appsec/contrib/auto_instrument.rb +25 -0
  62. data/lib/datadog/appsec/contrib/devise/event.rb +57 -0
  63. data/lib/datadog/appsec/contrib/devise/ext.rb +13 -0
  64. data/lib/datadog/appsec/contrib/devise/integration.rb +42 -0
  65. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +76 -0
  66. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +54 -0
  67. data/lib/datadog/appsec/contrib/devise/patcher.rb +45 -0
  68. data/lib/datadog/appsec/contrib/devise/resource.rb +35 -0
  69. data/lib/datadog/appsec/contrib/devise/tracking.rb +49 -0
  70. data/lib/datadog/appsec/contrib/integration.rb +37 -0
  71. data/lib/datadog/appsec/contrib/patcher.rb +12 -0
  72. data/lib/datadog/appsec/contrib/rack/ext.rb +13 -0
  73. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +104 -0
  74. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +30 -0
  75. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +162 -0
  76. data/lib/datadog/appsec/contrib/rack/integration.rb +44 -0
  77. data/lib/datadog/appsec/contrib/rack/patcher.rb +34 -0
  78. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +81 -0
  79. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +60 -0
  80. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +66 -0
  81. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +44 -0
  82. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +196 -0
  83. data/lib/datadog/appsec/contrib/rails/ext.rb +13 -0
  84. data/lib/datadog/appsec/contrib/rails/framework.rb +16 -0
  85. data/lib/datadog/appsec/contrib/rails/gateway/request.rb +67 -0
  86. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +71 -0
  87. data/lib/datadog/appsec/contrib/rails/integration.rb +43 -0
  88. data/lib/datadog/appsec/contrib/rails/patcher.rb +166 -0
  89. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +66 -0
  90. data/lib/datadog/appsec/contrib/rails/request.rb +36 -0
  91. data/lib/datadog/appsec/contrib/rails/request_middleware.rb +20 -0
  92. data/lib/datadog/appsec/contrib/sinatra/ext.rb +14 -0
  93. data/lib/datadog/appsec/contrib/sinatra/framework.rb +20 -0
  94. data/lib/datadog/appsec/contrib/sinatra/gateway/request.rb +17 -0
  95. data/lib/datadog/appsec/contrib/sinatra/gateway/route_params.rb +23 -0
  96. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +117 -0
  97. data/lib/datadog/appsec/contrib/sinatra/integration.rb +43 -0
  98. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +168 -0
  99. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +61 -0
  100. data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +20 -0
  101. data/lib/datadog/appsec/event.rb +171 -0
  102. data/lib/datadog/appsec/ext.rb +10 -0
  103. data/lib/datadog/appsec/extensions.rb +15 -0
  104. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +22 -0
  105. data/lib/datadog/appsec/instrumentation/gateway.rb +64 -0
  106. data/lib/datadog/appsec/instrumentation.rb +9 -0
  107. data/lib/datadog/appsec/monitor/gateway/watcher.rb +67 -0
  108. data/lib/datadog/appsec/monitor/reactive/set_user.rb +58 -0
  109. data/lib/datadog/appsec/monitor.rb +11 -0
  110. data/lib/datadog/appsec/processor/actions.rb +49 -0
  111. data/lib/datadog/appsec/processor/rule_loader.rb +123 -0
  112. data/lib/datadog/appsec/processor/rule_merger.rb +152 -0
  113. data/lib/datadog/appsec/processor.rb +171 -0
  114. data/lib/datadog/appsec/rate_limiter.rb +60 -0
  115. data/lib/datadog/appsec/reactive/address_hash.rb +22 -0
  116. data/lib/datadog/appsec/reactive/engine.rb +47 -0
  117. data/lib/datadog/appsec/reactive/operation.rb +68 -0
  118. data/lib/datadog/appsec/reactive/subscriber.rb +19 -0
  119. data/lib/datadog/appsec/remote.rb +129 -0
  120. data/lib/datadog/appsec/response.rb +151 -0
  121. data/lib/datadog/appsec/sample_rate.rb +21 -0
  122. data/lib/datadog/appsec/scope.rb +61 -0
  123. data/lib/datadog/appsec/utils/http/media_range.rb +201 -0
  124. data/lib/datadog/appsec/utils/http/media_type.rb +87 -0
  125. data/lib/datadog/appsec/utils/http.rb +11 -0
  126. data/lib/datadog/appsec/utils.rb +9 -0
  127. data/lib/datadog/appsec.rb +60 -0
  128. data/lib/datadog/auto_instrument.rb +16 -0
  129. data/lib/datadog/auto_instrument_base.rb +8 -0
  130. data/lib/datadog/core/buffer/cruby.rb +55 -0
  131. data/lib/datadog/core/buffer/random.rb +134 -0
  132. data/lib/datadog/core/buffer/thread_safe.rb +58 -0
  133. data/lib/datadog/core/chunker.rb +35 -0
  134. data/lib/datadog/core/configuration/agent_settings_resolver.rb +352 -0
  135. data/lib/datadog/core/configuration/base.rb +91 -0
  136. data/lib/datadog/core/configuration/components.rb +177 -0
  137. data/lib/datadog/core/configuration/ext.rb +45 -0
  138. data/lib/datadog/core/configuration/option.rb +319 -0
  139. data/lib/datadog/core/configuration/option_definition.rb +165 -0
  140. data/lib/datadog/core/configuration/options.rb +128 -0
  141. data/lib/datadog/core/configuration/settings.rb +786 -0
  142. data/lib/datadog/core/configuration.rb +296 -0
  143. data/lib/datadog/core/diagnostics/environment_logger.rb +173 -0
  144. data/lib/datadog/core/diagnostics/health.rb +19 -0
  145. data/lib/datadog/core/encoding.rb +74 -0
  146. data/lib/datadog/core/environment/cgroup.rb +53 -0
  147. data/lib/datadog/core/environment/class_count.rb +21 -0
  148. data/lib/datadog/core/environment/container.rb +91 -0
  149. data/lib/datadog/core/environment/execution.rb +103 -0
  150. data/lib/datadog/core/environment/ext.rb +45 -0
  151. data/lib/datadog/core/environment/gc.rb +20 -0
  152. data/lib/datadog/core/environment/git.rb +25 -0
  153. data/lib/datadog/core/environment/identity.rb +84 -0
  154. data/lib/datadog/core/environment/platform.rb +40 -0
  155. data/lib/datadog/core/environment/socket.rb +24 -0
  156. data/lib/datadog/core/environment/thread_count.rb +20 -0
  157. data/lib/datadog/core/environment/variable_helpers.rb +53 -0
  158. data/lib/datadog/core/environment/vm_cache.rb +64 -0
  159. data/lib/datadog/core/environment/yjit.rb +58 -0
  160. data/lib/datadog/core/error.rb +100 -0
  161. data/lib/datadog/core/extensions.rb +16 -0
  162. data/lib/datadog/core/git/ext.rb +16 -0
  163. data/lib/datadog/core/header_collection.rb +43 -0
  164. data/lib/datadog/core/logger.rb +45 -0
  165. data/lib/datadog/core/logging/ext.rb +13 -0
  166. data/lib/datadog/core/metrics/client.rb +199 -0
  167. data/lib/datadog/core/metrics/ext.rb +18 -0
  168. data/lib/datadog/core/metrics/helpers.rb +25 -0
  169. data/lib/datadog/core/metrics/logging.rb +44 -0
  170. data/lib/datadog/core/metrics/metric.rb +14 -0
  171. data/lib/datadog/core/metrics/options.rb +52 -0
  172. data/lib/datadog/core/pin.rb +75 -0
  173. data/lib/datadog/core/remote/client/capabilities.rb +62 -0
  174. data/lib/datadog/core/remote/client.rb +234 -0
  175. data/lib/datadog/core/remote/component.rb +162 -0
  176. data/lib/datadog/core/remote/configuration/content.rb +111 -0
  177. data/lib/datadog/core/remote/configuration/digest.rb +62 -0
  178. data/lib/datadog/core/remote/configuration/path.rb +90 -0
  179. data/lib/datadog/core/remote/configuration/repository.rb +294 -0
  180. data/lib/datadog/core/remote/configuration/target.rb +74 -0
  181. data/lib/datadog/core/remote/configuration.rb +18 -0
  182. data/lib/datadog/core/remote/dispatcher.rb +59 -0
  183. data/lib/datadog/core/remote/ext.rb +13 -0
  184. data/lib/datadog/core/remote/negotiation.rb +70 -0
  185. data/lib/datadog/core/remote/tie/tracing.rb +39 -0
  186. data/lib/datadog/core/remote/tie.rb +27 -0
  187. data/lib/datadog/core/remote/transport/config.rb +60 -0
  188. data/lib/datadog/core/remote/transport/http/api/instance.rb +39 -0
  189. data/lib/datadog/core/remote/transport/http/api/spec.rb +21 -0
  190. data/lib/datadog/core/remote/transport/http/api.rb +58 -0
  191. data/lib/datadog/core/remote/transport/http/builder.rb +219 -0
  192. data/lib/datadog/core/remote/transport/http/client.rb +48 -0
  193. data/lib/datadog/core/remote/transport/http/config.rb +280 -0
  194. data/lib/datadog/core/remote/transport/http/negotiation.rb +146 -0
  195. data/lib/datadog/core/remote/transport/http.rb +147 -0
  196. data/lib/datadog/core/remote/transport/negotiation.rb +62 -0
  197. data/lib/datadog/core/remote/worker.rb +102 -0
  198. data/lib/datadog/core/remote.rb +24 -0
  199. data/lib/datadog/core/runtime/ext.rb +38 -0
  200. data/lib/datadog/core/runtime/metrics.rb +185 -0
  201. data/lib/datadog/core/telemetry/client.rb +87 -0
  202. data/lib/datadog/core/telemetry/collector.rb +248 -0
  203. data/lib/datadog/core/telemetry/emitter.rb +50 -0
  204. data/lib/datadog/core/telemetry/event.rb +83 -0
  205. data/lib/datadog/core/telemetry/ext.rb +15 -0
  206. data/lib/datadog/core/telemetry/heartbeat.rb +35 -0
  207. data/lib/datadog/core/telemetry/http/adapters/net.rb +113 -0
  208. data/lib/datadog/core/telemetry/http/env.rb +20 -0
  209. data/lib/datadog/core/telemetry/http/ext.rb +22 -0
  210. data/lib/datadog/core/telemetry/http/response.rb +66 -0
  211. data/lib/datadog/core/telemetry/http/transport.rb +56 -0
  212. data/lib/datadog/core/telemetry/v1/app_event.rb +59 -0
  213. data/lib/datadog/core/telemetry/v1/application.rb +94 -0
  214. data/lib/datadog/core/telemetry/v1/configuration.rb +27 -0
  215. data/lib/datadog/core/telemetry/v1/dependency.rb +45 -0
  216. data/lib/datadog/core/telemetry/v1/host.rb +59 -0
  217. data/lib/datadog/core/telemetry/v1/install_signature.rb +38 -0
  218. data/lib/datadog/core/telemetry/v1/integration.rb +66 -0
  219. data/lib/datadog/core/telemetry/v1/product.rb +36 -0
  220. data/lib/datadog/core/telemetry/v1/telemetry_request.rb +108 -0
  221. data/lib/datadog/core/telemetry/v2/app_client_configuration_change.rb +41 -0
  222. data/lib/datadog/core/telemetry/v2/request.rb +29 -0
  223. data/lib/datadog/core/transport/ext.rb +43 -0
  224. data/lib/datadog/core/transport/http/adapters/net.rb +159 -0
  225. data/lib/datadog/core/transport/http/adapters/registry.rb +29 -0
  226. data/lib/datadog/core/transport/http/adapters/test.rb +89 -0
  227. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +83 -0
  228. data/lib/datadog/core/transport/http/api/endpoint.rb +31 -0
  229. data/lib/datadog/core/transport/http/api/fallbacks.rb +26 -0
  230. data/lib/datadog/core/transport/http/api/map.rb +18 -0
  231. data/lib/datadog/core/transport/http/env.rb +62 -0
  232. data/lib/datadog/core/transport/http/response.rb +60 -0
  233. data/lib/datadog/core/transport/parcel.rb +22 -0
  234. data/lib/datadog/core/transport/request.rb +17 -0
  235. data/lib/datadog/core/transport/response.rb +64 -0
  236. data/lib/datadog/core/utils/duration.rb +52 -0
  237. data/lib/datadog/core/utils/forking.rb +63 -0
  238. data/lib/datadog/core/utils/hash.rb +79 -0
  239. data/lib/datadog/core/utils/network.rb +121 -0
  240. data/lib/datadog/core/utils/only_once.rb +42 -0
  241. data/lib/datadog/core/utils/safe_dup.rb +40 -0
  242. data/lib/datadog/core/utils/sequence.rb +26 -0
  243. data/lib/datadog/core/utils/time.rb +52 -0
  244. data/lib/datadog/core/utils/url.rb +25 -0
  245. data/lib/datadog/core/utils.rb +94 -0
  246. data/lib/datadog/core/vendor/multipart-post/LICENSE +11 -0
  247. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +118 -0
  248. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +59 -0
  249. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +137 -0
  250. data/lib/datadog/core/vendor/multipart-post/multipart/post/version.rb +11 -0
  251. data/lib/datadog/core/vendor/multipart-post/multipart/post.rb +10 -0
  252. data/lib/datadog/core/vendor/multipart-post/multipart.rb +14 -0
  253. data/lib/datadog/core/vendor/multipart-post/net/http/post/multipart.rb +34 -0
  254. data/lib/datadog/core/worker.rb +24 -0
  255. data/lib/datadog/core/workers/async.rb +185 -0
  256. data/lib/datadog/core/workers/interval_loop.rb +123 -0
  257. data/lib/datadog/core/workers/polling.rb +59 -0
  258. data/lib/datadog/core/workers/queue.rb +44 -0
  259. data/lib/datadog/core/workers/runtime_metrics.rb +62 -0
  260. data/lib/datadog/core.rb +45 -0
  261. data/lib/datadog/kit/appsec/events.rb +169 -0
  262. data/lib/datadog/kit/enable_core_dumps.rb +49 -0
  263. data/lib/datadog/kit/identity.rb +104 -0
  264. data/lib/datadog/kit.rb +11 -0
  265. data/lib/datadog/opentelemetry/api/context.rb +193 -0
  266. data/lib/datadog/opentelemetry/api/trace/span.rb +14 -0
  267. data/lib/datadog/opentelemetry/sdk/configurator.rb +37 -0
  268. data/lib/datadog/opentelemetry/sdk/id_generator.rb +26 -0
  269. data/lib/datadog/opentelemetry/sdk/propagator.rb +92 -0
  270. data/lib/datadog/opentelemetry/sdk/span_processor.rb +134 -0
  271. data/lib/datadog/opentelemetry/sdk/trace/span.rb +167 -0
  272. data/lib/datadog/opentelemetry/trace.rb +59 -0
  273. data/lib/datadog/opentelemetry.rb +51 -0
  274. data/lib/datadog/profiling/collectors/code_provenance.rb +113 -0
  275. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +114 -0
  276. data/lib/datadog/profiling/collectors/dynamic_sampling_rate.rb +14 -0
  277. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +70 -0
  278. data/lib/datadog/profiling/collectors/info.rb +103 -0
  279. data/lib/datadog/profiling/collectors/stack.rb +13 -0
  280. data/lib/datadog/profiling/collectors/thread_context.rb +61 -0
  281. data/lib/datadog/profiling/component.rb +418 -0
  282. data/lib/datadog/profiling/exporter.rb +103 -0
  283. data/lib/datadog/profiling/ext/forking.rb +98 -0
  284. data/lib/datadog/profiling/ext.rb +35 -0
  285. data/lib/datadog/profiling/flush.rb +43 -0
  286. data/lib/datadog/profiling/http_transport.rb +143 -0
  287. data/lib/datadog/profiling/load_native_extension.rb +28 -0
  288. data/lib/datadog/profiling/native_extension.rb +20 -0
  289. data/lib/datadog/profiling/preload.rb +5 -0
  290. data/lib/datadog/profiling/profiler.rb +64 -0
  291. data/lib/datadog/profiling/scheduler.rb +137 -0
  292. data/lib/datadog/profiling/stack_recorder.rb +69 -0
  293. data/lib/datadog/profiling/tag_builder.rb +60 -0
  294. data/lib/datadog/profiling/tasks/exec.rb +50 -0
  295. data/lib/datadog/profiling/tasks/help.rb +18 -0
  296. data/lib/datadog/profiling/tasks/setup.rb +60 -0
  297. data/lib/datadog/profiling.rb +152 -0
  298. data/lib/datadog/tracing/analytics.rb +25 -0
  299. data/lib/datadog/tracing/buffer.rb +129 -0
  300. data/lib/datadog/tracing/client_ip.rb +61 -0
  301. data/lib/datadog/tracing/component.rb +206 -0
  302. data/lib/datadog/tracing/configuration/dynamic/option.rb +71 -0
  303. data/lib/datadog/tracing/configuration/dynamic.rb +64 -0
  304. data/lib/datadog/tracing/configuration/ext.rb +98 -0
  305. data/lib/datadog/tracing/configuration/http.rb +74 -0
  306. data/lib/datadog/tracing/configuration/settings.rb +421 -0
  307. data/lib/datadog/tracing/context.rb +68 -0
  308. data/lib/datadog/tracing/context_provider.rb +82 -0
  309. data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +39 -0
  310. data/lib/datadog/tracing/contrib/action_cable/event.rb +71 -0
  311. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +58 -0
  312. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +63 -0
  313. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +59 -0
  314. data/lib/datadog/tracing/contrib/action_cable/events.rb +37 -0
  315. data/lib/datadog/tracing/contrib/action_cable/ext.rb +33 -0
  316. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +90 -0
  317. data/lib/datadog/tracing/contrib/action_cable/integration.rb +50 -0
  318. data/lib/datadog/tracing/contrib/action_cable/patcher.rb +31 -0
  319. data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +43 -0
  320. data/lib/datadog/tracing/contrib/action_mailer/event.rb +52 -0
  321. data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +60 -0
  322. data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +47 -0
  323. data/lib/datadog/tracing/contrib/action_mailer/events.rb +34 -0
  324. data/lib/datadog/tracing/contrib/action_mailer/ext.rb +34 -0
  325. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +50 -0
  326. data/lib/datadog/tracing/contrib/action_mailer/patcher.rb +29 -0
  327. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +138 -0
  328. data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +29 -0
  329. data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +40 -0
  330. data/lib/datadog/tracing/contrib/action_pack/ext.rb +23 -0
  331. data/lib/datadog/tracing/contrib/action_pack/integration.rb +51 -0
  332. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +27 -0
  333. data/lib/datadog/tracing/contrib/action_pack/utils.rb +40 -0
  334. data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +43 -0
  335. data/lib/datadog/tracing/contrib/action_view/event.rb +35 -0
  336. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +54 -0
  337. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +57 -0
  338. data/lib/datadog/tracing/contrib/action_view/events.rb +34 -0
  339. data/lib/datadog/tracing/contrib/action_view/ext.rb +25 -0
  340. data/lib/datadog/tracing/contrib/action_view/integration.rb +58 -0
  341. data/lib/datadog/tracing/contrib/action_view/patcher.rb +34 -0
  342. data/lib/datadog/tracing/contrib/action_view/utils.rb +36 -0
  343. data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +39 -0
  344. data/lib/datadog/tracing/contrib/active_job/event.rb +58 -0
  345. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +50 -0
  346. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +49 -0
  347. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +49 -0
  348. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +51 -0
  349. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +49 -0
  350. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +50 -0
  351. data/lib/datadog/tracing/contrib/active_job/events.rb +42 -0
  352. data/lib/datadog/tracing/contrib/active_job/ext.rb +40 -0
  353. data/lib/datadog/tracing/contrib/active_job/integration.rb +50 -0
  354. data/lib/datadog/tracing/contrib/active_job/log_injection.rb +24 -0
  355. data/lib/datadog/tracing/contrib/active_job/patcher.rb +36 -0
  356. data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +37 -0
  357. data/lib/datadog/tracing/contrib/active_model_serializers/event.rb +68 -0
  358. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +45 -0
  359. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +47 -0
  360. data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +34 -0
  361. data/lib/datadog/tracing/contrib/active_model_serializers/ext.rb +25 -0
  362. data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +45 -0
  363. data/lib/datadog/tracing/contrib/active_model_serializers/patcher.rb +32 -0
  364. data/lib/datadog/tracing/contrib/active_record/configuration/makara_resolver.rb +36 -0
  365. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +147 -0
  366. data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +48 -0
  367. data/lib/datadog/tracing/contrib/active_record/event.rb +30 -0
  368. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +58 -0
  369. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +77 -0
  370. data/lib/datadog/tracing/contrib/active_record/events.rb +34 -0
  371. data/lib/datadog/tracing/contrib/active_record/ext.rb +30 -0
  372. data/lib/datadog/tracing/contrib/active_record/integration.rb +57 -0
  373. data/lib/datadog/tracing/contrib/active_record/patcher.rb +27 -0
  374. data/lib/datadog/tracing/contrib/active_record/utils.rb +128 -0
  375. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +186 -0
  376. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +76 -0
  377. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +47 -0
  378. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +47 -0
  379. data/lib/datadog/tracing/contrib/active_support/ext.rb +32 -0
  380. data/lib/datadog/tracing/contrib/active_support/integration.rb +52 -0
  381. data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +71 -0
  382. data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +71 -0
  383. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +164 -0
  384. data/lib/datadog/tracing/contrib/active_support/patcher.rb +27 -0
  385. data/lib/datadog/tracing/contrib/analytics.rb +28 -0
  386. data/lib/datadog/tracing/contrib/auto_instrument.rb +53 -0
  387. data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +53 -0
  388. data/lib/datadog/tracing/contrib/aws/ext.rb +50 -0
  389. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +119 -0
  390. data/lib/datadog/tracing/contrib/aws/integration.rb +47 -0
  391. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +64 -0
  392. data/lib/datadog/tracing/contrib/aws/patcher.rb +57 -0
  393. data/lib/datadog/tracing/contrib/aws/service/base.rb +16 -0
  394. data/lib/datadog/tracing/contrib/aws/service/dynamodb.rb +22 -0
  395. data/lib/datadog/tracing/contrib/aws/service/eventbridge.rb +22 -0
  396. data/lib/datadog/tracing/contrib/aws/service/kinesis.rb +32 -0
  397. data/lib/datadog/tracing/contrib/aws/service/s3.rb +22 -0
  398. data/lib/datadog/tracing/contrib/aws/service/sns.rb +30 -0
  399. data/lib/datadog/tracing/contrib/aws/service/sqs.rb +27 -0
  400. data/lib/datadog/tracing/contrib/aws/service/states.rb +40 -0
  401. data/lib/datadog/tracing/contrib/aws/services.rb +139 -0
  402. data/lib/datadog/tracing/contrib/component.rb +41 -0
  403. data/lib/datadog/tracing/contrib/concurrent_ruby/async_patch.rb +20 -0
  404. data/lib/datadog/tracing/contrib/concurrent_ruby/configuration/settings.rb +24 -0
  405. data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +53 -0
  406. data/lib/datadog/tracing/contrib/concurrent_ruby/ext.rb +16 -0
  407. data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +20 -0
  408. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +44 -0
  409. data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +49 -0
  410. data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +22 -0
  411. data/lib/datadog/tracing/contrib/configurable.rb +102 -0
  412. data/lib/datadog/tracing/contrib/configuration/resolver.rb +85 -0
  413. data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +43 -0
  414. data/lib/datadog/tracing/contrib/configuration/settings.rb +43 -0
  415. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +58 -0
  416. data/lib/datadog/tracing/contrib/dalli/ext.rb +40 -0
  417. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +75 -0
  418. data/lib/datadog/tracing/contrib/dalli/integration.rb +52 -0
  419. data/lib/datadog/tracing/contrib/dalli/patcher.rb +28 -0
  420. data/lib/datadog/tracing/contrib/dalli/quantize.rb +26 -0
  421. data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +49 -0
  422. data/lib/datadog/tracing/contrib/delayed_job/ext.rb +29 -0
  423. data/lib/datadog/tracing/contrib/delayed_job/integration.rb +43 -0
  424. data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +37 -0
  425. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +108 -0
  426. data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +34 -0
  427. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +57 -0
  428. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +34 -0
  429. data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +50 -0
  430. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +164 -0
  431. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +87 -0
  432. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +56 -0
  433. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +223 -0
  434. data/lib/datadog/tracing/contrib/ethon/ext.rb +32 -0
  435. data/lib/datadog/tracing/contrib/ethon/integration.rb +48 -0
  436. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +102 -0
  437. data/lib/datadog/tracing/contrib/ethon/patcher.rb +30 -0
  438. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +74 -0
  439. data/lib/datadog/tracing/contrib/excon/ext.rb +30 -0
  440. data/lib/datadog/tracing/contrib/excon/integration.rb +48 -0
  441. data/lib/datadog/tracing/contrib/excon/middleware.rb +196 -0
  442. data/lib/datadog/tracing/contrib/excon/patcher.rb +31 -0
  443. data/lib/datadog/tracing/contrib/ext.rb +55 -0
  444. data/lib/datadog/tracing/contrib/extensions.rb +228 -0
  445. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +77 -0
  446. data/lib/datadog/tracing/contrib/faraday/connection.rb +22 -0
  447. data/lib/datadog/tracing/contrib/faraday/ext.rb +30 -0
  448. data/lib/datadog/tracing/contrib/faraday/integration.rb +48 -0
  449. data/lib/datadog/tracing/contrib/faraday/middleware.rb +112 -0
  450. data/lib/datadog/tracing/contrib/faraday/patcher.rb +56 -0
  451. data/lib/datadog/tracing/contrib/faraday/rack_builder.rb +22 -0
  452. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +55 -0
  453. data/lib/datadog/tracing/contrib/grape/endpoint.rb +256 -0
  454. data/lib/datadog/tracing/contrib/grape/ext.rb +30 -0
  455. data/lib/datadog/tracing/contrib/grape/instrumentation.rb +37 -0
  456. data/lib/datadog/tracing/contrib/grape/integration.rb +44 -0
  457. data/lib/datadog/tracing/contrib/grape/patcher.rb +33 -0
  458. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +50 -0
  459. data/lib/datadog/tracing/contrib/graphql/ext.rb +20 -0
  460. data/lib/datadog/tracing/contrib/graphql/integration.rb +56 -0
  461. data/lib/datadog/tracing/contrib/graphql/patcher.rb +55 -0
  462. data/lib/datadog/tracing/contrib/graphql/trace_patcher.rb +24 -0
  463. data/lib/datadog/tracing/contrib/graphql/tracing_patcher.rb +28 -0
  464. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +58 -0
  465. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +117 -0
  466. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +96 -0
  467. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +107 -0
  468. data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +26 -0
  469. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +46 -0
  470. data/lib/datadog/tracing/contrib/grpc/ext.rb +29 -0
  471. data/lib/datadog/tracing/contrib/grpc/formatting.rb +127 -0
  472. data/lib/datadog/tracing/contrib/grpc/integration.rb +50 -0
  473. data/lib/datadog/tracing/contrib/grpc/intercept_with_datadog.rb +53 -0
  474. data/lib/datadog/tracing/contrib/grpc/patcher.rb +34 -0
  475. data/lib/datadog/tracing/contrib/grpc.rb +45 -0
  476. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +47 -0
  477. data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +23 -0
  478. data/lib/datadog/tracing/contrib/hanami/ext.rb +24 -0
  479. data/lib/datadog/tracing/contrib/hanami/integration.rb +44 -0
  480. data/lib/datadog/tracing/contrib/hanami/patcher.rb +33 -0
  481. data/lib/datadog/tracing/contrib/hanami/plugin.rb +23 -0
  482. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +41 -0
  483. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +44 -0
  484. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +40 -0
  485. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +69 -0
  486. data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +38 -0
  487. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +45 -0
  488. data/lib/datadog/tracing/contrib/http/ext.rb +29 -0
  489. data/lib/datadog/tracing/contrib/http/instrumentation.rb +144 -0
  490. data/lib/datadog/tracing/contrib/http/integration.rb +49 -0
  491. data/lib/datadog/tracing/contrib/http/patcher.rb +30 -0
  492. data/lib/datadog/tracing/contrib/http.rb +45 -0
  493. data/lib/datadog/tracing/contrib/http_annotation_helper.rb +17 -0
  494. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +68 -0
  495. data/lib/datadog/tracing/contrib/httpclient/ext.rb +30 -0
  496. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +137 -0
  497. data/lib/datadog/tracing/contrib/httpclient/integration.rb +48 -0
  498. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +42 -0
  499. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +68 -0
  500. data/lib/datadog/tracing/contrib/httprb/ext.rb +29 -0
  501. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +145 -0
  502. data/lib/datadog/tracing/contrib/httprb/integration.rb +48 -0
  503. data/lib/datadog/tracing/contrib/httprb/patcher.rb +42 -0
  504. data/lib/datadog/tracing/contrib/integration.rb +78 -0
  505. data/lib/datadog/tracing/contrib/kafka/configuration/settings.rb +39 -0
  506. data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +19 -0
  507. data/lib/datadog/tracing/contrib/kafka/consumer_group_event.rb +18 -0
  508. data/lib/datadog/tracing/contrib/kafka/event.rb +53 -0
  509. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +42 -0
  510. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +49 -0
  511. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +47 -0
  512. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +47 -0
  513. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +37 -0
  514. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +37 -0
  515. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +37 -0
  516. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +41 -0
  517. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +44 -0
  518. data/lib/datadog/tracing/contrib/kafka/events.rb +48 -0
  519. data/lib/datadog/tracing/contrib/kafka/ext.rb +55 -0
  520. data/lib/datadog/tracing/contrib/kafka/integration.rb +44 -0
  521. data/lib/datadog/tracing/contrib/kafka/patcher.rb +29 -0
  522. data/lib/datadog/tracing/contrib/lograge/configuration/settings.rb +24 -0
  523. data/lib/datadog/tracing/contrib/lograge/ext.rb +15 -0
  524. data/lib/datadog/tracing/contrib/lograge/instrumentation.rb +31 -0
  525. data/lib/datadog/tracing/contrib/lograge/integration.rb +50 -0
  526. data/lib/datadog/tracing/contrib/lograge/patcher.rb +29 -0
  527. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +56 -0
  528. data/lib/datadog/tracing/contrib/mongodb/ext.rb +38 -0
  529. data/lib/datadog/tracing/contrib/mongodb/instrumentation.rb +47 -0
  530. data/lib/datadog/tracing/contrib/mongodb/integration.rb +48 -0
  531. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +49 -0
  532. data/lib/datadog/tracing/contrib/mongodb/patcher.rb +34 -0
  533. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +141 -0
  534. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +64 -0
  535. data/lib/datadog/tracing/contrib/mysql2/ext.rb +28 -0
  536. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +95 -0
  537. data/lib/datadog/tracing/contrib/mysql2/integration.rb +43 -0
  538. data/lib/datadog/tracing/contrib/mysql2/patcher.rb +31 -0
  539. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +54 -0
  540. data/lib/datadog/tracing/contrib/opensearch/ext.rb +38 -0
  541. data/lib/datadog/tracing/contrib/opensearch/integration.rb +44 -0
  542. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +135 -0
  543. data/lib/datadog/tracing/contrib/opensearch/quantize.rb +81 -0
  544. data/lib/datadog/tracing/contrib/patchable.rb +109 -0
  545. data/lib/datadog/tracing/contrib/patcher.rb +85 -0
  546. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +64 -0
  547. data/lib/datadog/tracing/contrib/pg/ext.rb +35 -0
  548. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +211 -0
  549. data/lib/datadog/tracing/contrib/pg/integration.rb +43 -0
  550. data/lib/datadog/tracing/contrib/pg/patcher.rb +31 -0
  551. data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +52 -0
  552. data/lib/datadog/tracing/contrib/presto/ext.rb +38 -0
  553. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +138 -0
  554. data/lib/datadog/tracing/contrib/presto/integration.rb +43 -0
  555. data/lib/datadog/tracing/contrib/presto/patcher.rb +37 -0
  556. data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +41 -0
  557. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +33 -0
  558. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +28 -0
  559. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +55 -0
  560. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +55 -0
  561. data/lib/datadog/tracing/contrib/que/ext.rb +33 -0
  562. data/lib/datadog/tracing/contrib/que/integration.rb +44 -0
  563. data/lib/datadog/tracing/contrib/que/patcher.rb +26 -0
  564. data/lib/datadog/tracing/contrib/que/tracer.rb +63 -0
  565. data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +47 -0
  566. data/lib/datadog/tracing/contrib/racecar/event.rb +81 -0
  567. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +38 -0
  568. data/lib/datadog/tracing/contrib/racecar/events/consume.rb +35 -0
  569. data/lib/datadog/tracing/contrib/racecar/events/message.rb +38 -0
  570. data/lib/datadog/tracing/contrib/racecar/events.rb +36 -0
  571. data/lib/datadog/tracing/contrib/racecar/ext.rb +33 -0
  572. data/lib/datadog/tracing/contrib/racecar/integration.rb +44 -0
  573. data/lib/datadog/tracing/contrib/racecar/patcher.rb +29 -0
  574. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +59 -0
  575. data/lib/datadog/tracing/contrib/rack/ext.rb +30 -0
  576. data/lib/datadog/tracing/contrib/rack/header_collection.rb +40 -0
  577. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +63 -0
  578. data/lib/datadog/tracing/contrib/rack/integration.rb +50 -0
  579. data/lib/datadog/tracing/contrib/rack/middlewares.rb +265 -0
  580. data/lib/datadog/tracing/contrib/rack/patcher.rb +119 -0
  581. data/lib/datadog/tracing/contrib/rack/request_queue.rb +48 -0
  582. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +52 -0
  583. data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +10 -0
  584. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +76 -0
  585. data/lib/datadog/tracing/contrib/rails/ext.rb +23 -0
  586. data/lib/datadog/tracing/contrib/rails/framework.rb +148 -0
  587. data/lib/datadog/tracing/contrib/rails/integration.rb +52 -0
  588. data/lib/datadog/tracing/contrib/rails/log_injection.rb +29 -0
  589. data/lib/datadog/tracing/contrib/rails/middlewares.rb +46 -0
  590. data/lib/datadog/tracing/contrib/rails/patcher.rb +88 -0
  591. data/lib/datadog/tracing/contrib/rails/railtie.rb +19 -0
  592. data/lib/datadog/tracing/contrib/rails/utils.rb +26 -0
  593. data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +55 -0
  594. data/lib/datadog/tracing/contrib/rake/ext.rb +27 -0
  595. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +103 -0
  596. data/lib/datadog/tracing/contrib/rake/integration.rb +43 -0
  597. data/lib/datadog/tracing/contrib/rake/patcher.rb +33 -0
  598. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +49 -0
  599. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +57 -0
  600. data/lib/datadog/tracing/contrib/redis/ext.rb +35 -0
  601. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +53 -0
  602. data/lib/datadog/tracing/contrib/redis/integration.rb +80 -0
  603. data/lib/datadog/tracing/contrib/redis/patcher.rb +92 -0
  604. data/lib/datadog/tracing/contrib/redis/quantize.rb +80 -0
  605. data/lib/datadog/tracing/contrib/redis/tags.rb +68 -0
  606. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +85 -0
  607. data/lib/datadog/tracing/contrib/redis/vendor/LICENSE +20 -0
  608. data/lib/datadog/tracing/contrib/redis/vendor/resolver.rb +160 -0
  609. data/lib/datadog/tracing/contrib/registerable.rb +50 -0
  610. data/lib/datadog/tracing/contrib/registry.rb +52 -0
  611. data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +42 -0
  612. data/lib/datadog/tracing/contrib/resque/ext.rb +22 -0
  613. data/lib/datadog/tracing/contrib/resque/integration.rb +48 -0
  614. data/lib/datadog/tracing/contrib/resque/patcher.rb +29 -0
  615. data/lib/datadog/tracing/contrib/resque/resque_job.rb +106 -0
  616. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +55 -0
  617. data/lib/datadog/tracing/contrib/rest_client/ext.rb +28 -0
  618. data/lib/datadog/tracing/contrib/rest_client/integration.rb +43 -0
  619. data/lib/datadog/tracing/contrib/rest_client/patcher.rb +28 -0
  620. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +129 -0
  621. data/lib/datadog/tracing/contrib/roda/configuration/settings.rb +38 -0
  622. data/lib/datadog/tracing/contrib/roda/ext.rb +19 -0
  623. data/lib/datadog/tracing/contrib/roda/instrumentation.rb +76 -0
  624. data/lib/datadog/tracing/contrib/roda/integration.rb +45 -0
  625. data/lib/datadog/tracing/contrib/roda/patcher.rb +30 -0
  626. data/lib/datadog/tracing/contrib/semantic_logger/configuration/settings.rb +24 -0
  627. data/lib/datadog/tracing/contrib/semantic_logger/ext.rb +15 -0
  628. data/lib/datadog/tracing/contrib/semantic_logger/instrumentation.rb +35 -0
  629. data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +52 -0
  630. data/lib/datadog/tracing/contrib/semantic_logger/patcher.rb +29 -0
  631. data/lib/datadog/tracing/contrib/sequel/configuration/settings.rb +37 -0
  632. data/lib/datadog/tracing/contrib/sequel/database.rb +62 -0
  633. data/lib/datadog/tracing/contrib/sequel/dataset.rb +67 -0
  634. data/lib/datadog/tracing/contrib/sequel/ext.rb +23 -0
  635. data/lib/datadog/tracing/contrib/sequel/integration.rb +43 -0
  636. data/lib/datadog/tracing/contrib/sequel/patcher.rb +37 -0
  637. data/lib/datadog/tracing/contrib/sequel/utils.rb +90 -0
  638. data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +43 -0
  639. data/lib/datadog/tracing/contrib/shoryuken/ext.rb +27 -0
  640. data/lib/datadog/tracing/contrib/shoryuken/integration.rb +44 -0
  641. data/lib/datadog/tracing/contrib/shoryuken/patcher.rb +28 -0
  642. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +65 -0
  643. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +62 -0
  644. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +47 -0
  645. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +46 -0
  646. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +44 -0
  647. data/lib/datadog/tracing/contrib/sidekiq/integration.rb +61 -0
  648. data/lib/datadog/tracing/contrib/sidekiq/patcher.rb +90 -0
  649. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +61 -0
  650. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +36 -0
  651. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/redis_info.rb +34 -0
  652. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +57 -0
  653. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/stop.rb +34 -0
  654. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +88 -0
  655. data/lib/datadog/tracing/contrib/sidekiq/utils.rb +44 -0
  656. data/lib/datadog/tracing/contrib/sidekiq.rb +37 -0
  657. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +46 -0
  658. data/lib/datadog/tracing/contrib/sinatra/env.rb +38 -0
  659. data/lib/datadog/tracing/contrib/sinatra/ext.rb +31 -0
  660. data/lib/datadog/tracing/contrib/sinatra/framework.rb +116 -0
  661. data/lib/datadog/tracing/contrib/sinatra/integration.rb +43 -0
  662. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +75 -0
  663. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +86 -0
  664. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +109 -0
  665. data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +43 -0
  666. data/lib/datadog/tracing/contrib/sneakers/ext.rb +27 -0
  667. data/lib/datadog/tracing/contrib/sneakers/integration.rb +44 -0
  668. data/lib/datadog/tracing/contrib/sneakers/patcher.rb +27 -0
  669. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +60 -0
  670. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +92 -0
  671. data/lib/datadog/tracing/contrib/status_range_env_parser.rb +33 -0
  672. data/lib/datadog/tracing/contrib/status_range_matcher.rb +25 -0
  673. data/lib/datadog/tracing/contrib/stripe/configuration/settings.rb +37 -0
  674. data/lib/datadog/tracing/contrib/stripe/ext.rb +27 -0
  675. data/lib/datadog/tracing/contrib/stripe/integration.rb +43 -0
  676. data/lib/datadog/tracing/contrib/stripe/patcher.rb +28 -0
  677. data/lib/datadog/tracing/contrib/stripe/request.rb +67 -0
  678. data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +39 -0
  679. data/lib/datadog/tracing/contrib/sucker_punch/exception_handler.rb +28 -0
  680. data/lib/datadog/tracing/contrib/sucker_punch/ext.rb +28 -0
  681. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +104 -0
  682. data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +43 -0
  683. data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +35 -0
  684. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +58 -0
  685. data/lib/datadog/tracing/contrib/trilogy/ext.rb +27 -0
  686. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +94 -0
  687. data/lib/datadog/tracing/contrib/trilogy/integration.rb +43 -0
  688. data/lib/datadog/tracing/contrib/trilogy/patcher.rb +31 -0
  689. data/lib/datadog/tracing/contrib/utils/database.rb +31 -0
  690. data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +111 -0
  691. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +179 -0
  692. data/lib/datadog/tracing/contrib.rb +81 -0
  693. data/lib/datadog/tracing/correlation.rb +103 -0
  694. data/lib/datadog/tracing/diagnostics/environment_logger.rb +159 -0
  695. data/lib/datadog/tracing/diagnostics/ext.rb +36 -0
  696. data/lib/datadog/tracing/diagnostics/health.rb +40 -0
  697. data/lib/datadog/tracing/distributed/b3_multi.rb +73 -0
  698. data/lib/datadog/tracing/distributed/b3_single.rb +69 -0
  699. data/lib/datadog/tracing/distributed/datadog.rb +200 -0
  700. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +84 -0
  701. data/lib/datadog/tracing/distributed/fetcher.rb +21 -0
  702. data/lib/datadog/tracing/distributed/helpers.rb +65 -0
  703. data/lib/datadog/tracing/distributed/none.rb +18 -0
  704. data/lib/datadog/tracing/distributed/propagation.rb +121 -0
  705. data/lib/datadog/tracing/distributed/trace_context.rb +436 -0
  706. data/lib/datadog/tracing/event.rb +76 -0
  707. data/lib/datadog/tracing/flush.rb +96 -0
  708. data/lib/datadog/tracing/metadata/analytics.rb +26 -0
  709. data/lib/datadog/tracing/metadata/errors.rb +24 -0
  710. data/lib/datadog/tracing/metadata/ext.rb +193 -0
  711. data/lib/datadog/tracing/metadata/tagging.rb +131 -0
  712. data/lib/datadog/tracing/metadata.rb +20 -0
  713. data/lib/datadog/tracing/pipeline/span_filter.rb +46 -0
  714. data/lib/datadog/tracing/pipeline/span_processor.rb +39 -0
  715. data/lib/datadog/tracing/pipeline.rb +63 -0
  716. data/lib/datadog/tracing/remote.rb +78 -0
  717. data/lib/datadog/tracing/runtime/metrics.rb +17 -0
  718. data/lib/datadog/tracing/sampling/all_sampler.rb +24 -0
  719. data/lib/datadog/tracing/sampling/ext.rb +56 -0
  720. data/lib/datadog/tracing/sampling/matcher.rb +65 -0
  721. data/lib/datadog/tracing/sampling/priority_sampler.rb +160 -0
  722. data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +87 -0
  723. data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +63 -0
  724. data/lib/datadog/tracing/sampling/rate_limiter.rb +185 -0
  725. data/lib/datadog/tracing/sampling/rate_sampler.rb +58 -0
  726. data/lib/datadog/tracing/sampling/rule.rb +61 -0
  727. data/lib/datadog/tracing/sampling/rule_sampler.rb +148 -0
  728. data/lib/datadog/tracing/sampling/sampler.rb +32 -0
  729. data/lib/datadog/tracing/sampling/span/ext.rb +25 -0
  730. data/lib/datadog/tracing/sampling/span/matcher.rb +89 -0
  731. data/lib/datadog/tracing/sampling/span/rule.rb +78 -0
  732. data/lib/datadog/tracing/sampling/span/rule_parser.rb +104 -0
  733. data/lib/datadog/tracing/sampling/span/sampler.rb +77 -0
  734. data/lib/datadog/tracing/span.rb +207 -0
  735. data/lib/datadog/tracing/span_operation.rb +498 -0
  736. data/lib/datadog/tracing/sync_writer.rb +67 -0
  737. data/lib/datadog/tracing/trace_digest.rb +185 -0
  738. data/lib/datadog/tracing/trace_operation.rb +492 -0
  739. data/lib/datadog/tracing/trace_segment.rb +222 -0
  740. data/lib/datadog/tracing/tracer.rb +531 -0
  741. data/lib/datadog/tracing/transport/http/api/instance.rb +37 -0
  742. data/lib/datadog/tracing/transport/http/api/spec.rb +19 -0
  743. data/lib/datadog/tracing/transport/http/api.rb +43 -0
  744. data/lib/datadog/tracing/transport/http/builder.rb +162 -0
  745. data/lib/datadog/tracing/transport/http/client.rb +57 -0
  746. data/lib/datadog/tracing/transport/http/statistics.rb +47 -0
  747. data/lib/datadog/tracing/transport/http/traces.rb +152 -0
  748. data/lib/datadog/tracing/transport/http.rb +97 -0
  749. data/lib/datadog/tracing/transport/io/client.rb +89 -0
  750. data/lib/datadog/tracing/transport/io/response.rb +27 -0
  751. data/lib/datadog/tracing/transport/io/traces.rb +101 -0
  752. data/lib/datadog/tracing/transport/io.rb +30 -0
  753. data/lib/datadog/tracing/transport/serializable_trace.rb +126 -0
  754. data/lib/datadog/tracing/transport/statistics.rb +77 -0
  755. data/lib/datadog/tracing/transport/trace_formatter.rb +240 -0
  756. data/lib/datadog/tracing/transport/traces.rb +224 -0
  757. data/lib/datadog/tracing/utils.rb +83 -0
  758. data/lib/datadog/tracing/workers/trace_writer.rb +196 -0
  759. data/lib/datadog/tracing/workers.rb +125 -0
  760. data/lib/datadog/tracing/writer.rb +188 -0
  761. data/lib/datadog/tracing.rb +169 -0
  762. data/lib/datadog/version.rb +26 -0
  763. data/lib/datadog.rb +10 -0
  764. metadata +886 -0
@@ -0,0 +1,941 @@
1
+ #include <ruby.h>
2
+ #include <ruby/thread.h>
3
+ #include <pthread.h>
4
+ #include <errno.h>
5
+ #include "helpers.h"
6
+ #include "stack_recorder.h"
7
+ #include "libdatadog_helpers.h"
8
+ #include "ruby_helpers.h"
9
+ #include "time_helpers.h"
10
+ #include "heap_recorder.h"
11
+
12
+ // Used to wrap a ddog_prof_Profile in a Ruby object and expose Ruby-level serialization APIs
13
+ // This file implements the native bits of the Datadog::Profiling::StackRecorder class
14
+
15
+ // ---
16
+ // ## Synchronization mechanism for safe parallel access design notes
17
+ //
18
+ // The state of the StackRecorder is managed using a set of locks to avoid concurrency issues.
19
+ //
20
+ // This is needed because the state is expected to be accessed, in parallel, by two different threads.
21
+ //
22
+ // 1. The thread that is taking a stack sample and that called `record_sample`, let's call it the **sampler thread**.
23
+ // In the current implementation of the profiler, there can only exist one **sampler thread** at a time; if this
24
+ // constraint changes, we should revise the design of the StackRecorder.
25
+ //
26
+ // 2. The thread that serializes and reports profiles, let's call it the **serializer thread**. We enforce that there
27
+ // cannot be more than one thread attempting to serialize profiles at a time.
28
+ //
29
+ // If both the sampler and serializer threads are trying to access the same `ddog_prof_Profile` in parallel, we will
30
+ // have a concurrency issue. Thus, the StackRecorder has an added mechanism to avoid this.
31
+ //
32
+ // As an additional constraint, the **sampler thread** has absolute priority and must never block while
33
+ // recording a sample.
34
+ //
35
+ // ### The solution: Keep two profiles at the same time
36
+ //
37
+ // To solve for the constraints above, the StackRecorder keeps two `ddog_prof_Profile` profile instances inside itself.
38
+ // They are called the `slot_one_profile` and `slot_two_profile`.
39
+ //
40
+ // Each profile is paired with its own mutex. `slot_one_profile` is protected by `slot_one_mutex` and `slot_two_profile`
41
+ // is protected by `slot_two_mutex`.
42
+ //
43
+ // We additionally introduce the concept of **active** and **inactive** profile slots. At any point, the sampler thread
44
+ // can probe the mutexes to discover which of the profiles corresponds to the active slot, and then records samples in it.
45
+ // When the serializer thread is ready to serialize data, it flips the active and inactive slots; it reports the data
46
+ // on the previously-active profile slot, and the sampler thread can continue to record in the previously-inactive
47
+ // profile slot.
48
+ //
49
+ // Thus, the sampler and serializer threads never cross paths, avoiding concurrency issues. The sampler thread writes to
50
+ // the active profile slot, and the serializer thread reads from the inactive profile slot.
51
+ //
52
+ // ### Locking protocol, high-level
53
+ //
54
+ // The active profile slot is the slot for which its corresponding mutex **is unlocked**. That is, if the sampler
55
+ // thread can grab a lock for a profile slot, then that slot is the active one. (Here you see where the constraint
56
+ // stated above that only one sampler thread can exist kicks in -- this part would need to be more complex if multiple
57
+ // sampler threads were in play.)
58
+ //
59
+ // As a counterpart, the inactive profile slot mutex is **kept locked** until such time the serializer
60
+ // thread is ready to work and decides to flip the slots.
61
+ //
62
+ // When a new StackRecorder is initialized, the `slot_one_mutex` is unlocked, and the `slot_two_mutex` is kept locked,
63
+ // that is, a new instance always starts with slot one active.
64
+ //
65
+ // Additionally, an `active_slot` field is kept, containing a `1` or `2`; this is only kept for the serializer thread
66
+ // to use as a simplification, as well as for testing and debugging; the **sampler thread must never use the `active_slot`
67
+ // field**.
68
+ //
69
+ // ### Locking protocol, from the sampler thread side
70
+ //
71
+ // When the sampler thread wants to record a sample, it goes through the following steps to discover which is the
72
+ // active profile slot:
73
+ //
74
+ // 1. `pthread_mutex_trylock(slot_one_mutex)`. If it succeeds to grab the lock, this means the active profile slot is
75
+ // slot one. If it fails, we move to the next step.
76
+ //
77
+ // 2. `pthread_mutex_trylock(slot_two_mutex)`. If it succeeds to grab the lock, this means the active profile slot is
78
+ // slot two. If it fails, we move to the next step.
79
+ //
80
+ // 3. What does it mean for the sampler thread to have observed both `slot_one_mutex` as well as `slot_two_mutex` as
81
+ // being locked? There are two options:
82
+ // a. The sampler thread got really unlucky. When it tried to grab the `slot_one_mutex`, the active profile slot was
83
+ // the second one BUT then the serializer thread flipped the slots, and by the time the sampler thread probed the
84
+ // `slot_two_mutex`, that one was taken. Since the serializer thread is expected only to work once a minute,
85
+ // we retry steps 1. and 2. and should be able to find an active slot.
86
+ // b. Something is incorrect in the StackRecorder state. In this situation, the sampler thread should give up on
87
+ // sampling and enter an error state.
88
+ //
89
+ // Note that in the steps above, and because the sampler thread uses `trylock` to probe the mutexes, that the
90
+ // sampler thread never blocks. It either is able to find an active profile slot in a bounded amount of steps or it
91
+ // enters an error state.
92
+ //
93
+ // This guarantees that sampler performance is never constrained by serializer performance.
94
+ //
95
+ // ### Locking protocol, from the serializer thread side
96
+ //
97
+ // When the serializer thread wants to serialize a profile, it first flips the active and inactive profile slots.
98
+ //
99
+ // The flipping action is described below. Consider previously-inactive and previously-active as the state of the slots
100
+ // before the flipping happens.
101
+ //
102
+ // The flipping steps are the following:
103
+ //
104
+ // 1. Release the mutex for the previously-inactive profile slot. That slot, as seen by the sampler thread, is now
105
+ // active.
106
+ //
107
+ // 2. Grab the mutex for the previously-active profile slot. Note that this can lead to the serializer thread blocking,
108
+ // if the sampler thread is holding this mutex. After the mutex is grabbed, the previously-active slot becomes inactive,
109
+ // as seen by the sampler thread.
110
+ //
111
+ // 3. Update `active_slot`.
112
+ //
113
+ // After flipping the profile slots, the serializer thread is now free to serialize the inactive profile slot. The slot
114
+ // is kept inactive until the next time the serializer thread wants to serialize data.
115
+ //
116
+ // Note there can be a brief period between steps 1 and 2 where the serializer thread holds no lock, which means that
117
+ // the sampler thread can pick either slot. This is OK: if the sampler thread picks the previously-inactive slot, the
118
+ // samples will be reported on the next serialization; if the sampler thread picks the previously-active slot, the
119
+ // samples are still included in the current serialization. Either option is correct.
120
+ //
121
+ // ### Additional notes
122
+ //
123
+ // Q: Can the sampler thread and the serializer thread ever be the same thread? (E.g. sampling in interrupt handler)
124
+ // A: No; the current profiler design requires that sampling happens only on the thread that is holding the Global VM
125
+ // Lock (GVL). The serializer thread flipping occurs after the serializer thread releases the GVL, and thus the
126
+ // serializer thread will not be able to host the sampling process.
127
+ //
128
+ // ---
129
+
130
+ static VALUE ok_symbol = Qnil; // :ok in Ruby
131
+ static VALUE error_symbol = Qnil; // :error in Ruby
132
+
133
+ // Note: Please DO NOT use `VALUE_STRING` anywhere else, instead use `DDOG_CHARSLICE_C`.
134
+ // `VALUE_STRING` is only needed because older versions of gcc (4.9.2, used in our Ruby 2.2 CI test images)
135
+ // tripped when compiling `enabled_value_types` using `-std=gnu99` due to the extra cast that is included in
136
+ // `DDOG_CHARSLICE_C` with the following error:
137
+ //
138
+ // ```
139
+ // compiling ../../../../ext/ddtrace_profiling_native_extension/stack_recorder.c
140
+ // ../../../../ext/ddtrace_profiling_native_extension/stack_recorder.c:23:1: error: initializer element is not constant
141
+ // static const ddog_prof_ValueType enabled_value_types[] = {CPU_TIME_VALUE, CPU_SAMPLES_VALUE, WALL_TIME_VALUE};
142
+ // ^
143
+ // ```
144
+ #define VALUE_STRING(string) {.ptr = "" string, .len = sizeof(string) - 1}
145
+
146
+ #define CPU_TIME_VALUE {.type_ = VALUE_STRING("cpu-time"), .unit = VALUE_STRING("nanoseconds")}
147
+ #define CPU_TIME_VALUE_ID 0
148
+ #define CPU_SAMPLES_VALUE {.type_ = VALUE_STRING("cpu-samples"), .unit = VALUE_STRING("count")}
149
+ #define CPU_SAMPLES_VALUE_ID 1
150
+ #define WALL_TIME_VALUE {.type_ = VALUE_STRING("wall-time"), .unit = VALUE_STRING("nanoseconds")}
151
+ #define WALL_TIME_VALUE_ID 2
152
+ #define ALLOC_SAMPLES_VALUE {.type_ = VALUE_STRING("alloc-samples"), .unit = VALUE_STRING("count")}
153
+ #define ALLOC_SAMPLES_VALUE_ID 3
154
+ #define HEAP_SAMPLES_VALUE {.type_ = VALUE_STRING("heap-live-samples"), .unit = VALUE_STRING("count")}
155
+ #define HEAP_SAMPLES_VALUE_ID 4
156
+ #define HEAP_SIZE_VALUE {.type_ = VALUE_STRING("heap-live-size"), .unit = VALUE_STRING("bytes")}
157
+ #define HEAP_SIZE_VALUE_ID 5
158
+ #define TIMELINE_VALUE {.type_ = VALUE_STRING("timeline"), .unit = VALUE_STRING("nanoseconds")}
159
+ #define TIMELINE_VALUE_ID 6
160
+
161
+ static const ddog_prof_ValueType all_value_types[] =
162
+ {CPU_TIME_VALUE, CPU_SAMPLES_VALUE, WALL_TIME_VALUE, ALLOC_SAMPLES_VALUE, HEAP_SAMPLES_VALUE, HEAP_SIZE_VALUE, TIMELINE_VALUE};
163
+
164
+ // This array MUST be kept in sync with all_value_types above and is intended to act as a "hashmap" between VALUE_ID and the position it
165
+ // occupies on the all_value_types array.
166
+ // E.g. all_value_types_positions[CPU_TIME_VALUE_ID] => 0, means that CPU_TIME_VALUE was declared at position 0 of all_value_types.
167
+ static const uint8_t all_value_types_positions[] =
168
+ {CPU_TIME_VALUE_ID, CPU_SAMPLES_VALUE_ID, WALL_TIME_VALUE_ID, ALLOC_SAMPLES_VALUE_ID, HEAP_SAMPLES_VALUE_ID, HEAP_SIZE_VALUE_ID, TIMELINE_VALUE_ID};
169
+
170
+ #define ALL_VALUE_TYPES_COUNT (sizeof(all_value_types) / sizeof(ddog_prof_ValueType))
171
+
172
+ // Contains native state for each instance
173
+ struct stack_recorder_state {
174
+ // Heap recorder instance
175
+ heap_recorder *heap_recorder;
176
+
177
+ pthread_mutex_t slot_one_mutex;
178
+ ddog_prof_Profile slot_one_profile;
179
+
180
+ pthread_mutex_t slot_two_mutex;
181
+ ddog_prof_Profile slot_two_profile;
182
+
183
+ short active_slot; // MUST NEVER BE ACCESSED FROM record_sample; this is NOT for the sampler thread to use.
184
+
185
+ uint8_t position_for[ALL_VALUE_TYPES_COUNT];
186
+ uint8_t enabled_values_count;
187
+ };
188
+
189
+ // Used to return a pair of values from sampler_lock_active_profile()
190
+ struct active_slot_pair {
191
+ pthread_mutex_t *mutex;
192
+ ddog_prof_Profile *profile;
193
+ };
194
+
195
+ struct call_serialize_without_gvl_arguments {
196
+ // Set by caller
197
+ struct stack_recorder_state *state;
198
+ ddog_Timespec finish_timestamp;
199
+ size_t gc_count_before_serialize;
200
+
201
+ // Set by callee
202
+ ddog_prof_Profile *profile;
203
+ ddog_prof_Profile_SerializeResult result;
204
+
205
+ // Set by both
206
+ bool serialize_ran;
207
+ };
208
+
209
+ static VALUE _native_new(VALUE klass);
210
+ static void initialize_slot_concurrency_control(struct stack_recorder_state *state);
211
+ static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types);
212
+ static void stack_recorder_typed_data_free(void *data);
213
+ static VALUE _native_initialize(
214
+ DDTRACE_UNUSED VALUE _self,
215
+ VALUE recorder_instance,
216
+ VALUE cpu_time_enabled,
217
+ VALUE alloc_samples_enabled,
218
+ VALUE heap_samples_enabled,
219
+ VALUE heap_size_enabled,
220
+ VALUE heap_sample_every,
221
+ VALUE timeline_enabled
222
+ );
223
+ static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
224
+ static VALUE ruby_time_from(ddog_Timespec ddprof_time);
225
+ static void *call_serialize_without_gvl(void *call_args);
226
+ static struct active_slot_pair sampler_lock_active_profile(struct stack_recorder_state *state);
227
+ static void sampler_unlock_active_profile(struct active_slot_pair active_slot);
228
+ static ddog_prof_Profile *serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state);
229
+ static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
230
+ static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
231
+ static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
232
+ static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot);
233
+ static ddog_Timespec system_epoch_now_timespec(void);
234
+ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance);
235
+ static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time);
236
+ static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint);
237
+ static void reset_profile(ddog_prof_Profile *profile, ddog_Timespec *start_time /* Can be null */);
238
+ static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class);
239
+ static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations);
240
+ static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
241
+ static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
242
+ static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
243
+ static VALUE _native_gc_force_recycle(DDTRACE_UNUSED VALUE _self, VALUE obj);
244
+ static VALUE _native_has_seen_id_flag(DDTRACE_UNUSED VALUE _self, VALUE obj);
245
+
246
+
247
+ void stack_recorder_init(VALUE profiling_module) {
248
+ VALUE stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
249
+ // Hosts methods used for testing the native code using RSpec
250
+ VALUE testing_module = rb_define_module_under(stack_recorder_class, "Testing");
251
+
252
+ // Instances of the StackRecorder class are "TypedData" objects.
253
+ // "TypedData" objects are special objects in the Ruby VM that can wrap C structs.
254
+ // In this case, it wraps the stack_recorder_state.
255
+ //
256
+ // Because Ruby doesn't know how to initialize native-level structs, we MUST override the allocation function for objects
257
+ // of this class so that we can manage this part. Not overriding or disabling the allocation function is a common
258
+ // gotcha for "TypedData" objects that can very easily lead to VM crashes, see for instance
259
+ // https://bugs.ruby-lang.org/issues/18007 for a discussion around this.
260
+ rb_define_alloc_func(stack_recorder_class, _native_new);
261
+
262
+ rb_define_singleton_method(stack_recorder_class, "_native_initialize", _native_initialize, 7);
263
+ rb_define_singleton_method(stack_recorder_class, "_native_serialize", _native_serialize, 1);
264
+ rb_define_singleton_method(stack_recorder_class, "_native_reset_after_fork", _native_reset_after_fork, 1);
265
+ rb_define_singleton_method(testing_module, "_native_active_slot", _native_active_slot, 1);
266
+ rb_define_singleton_method(testing_module, "_native_slot_one_mutex_locked?", _native_is_slot_one_mutex_locked, 1);
267
+ rb_define_singleton_method(testing_module, "_native_slot_two_mutex_locked?", _native_is_slot_two_mutex_locked, 1);
268
+ rb_define_singleton_method(testing_module, "_native_record_endpoint", _native_record_endpoint, 3);
269
+ rb_define_singleton_method(testing_module, "_native_track_object", _native_track_object, 4);
270
+ rb_define_singleton_method(testing_module, "_native_check_heap_hashes", _native_check_heap_hashes, 1);
271
+ rb_define_singleton_method(testing_module, "_native_start_fake_slow_heap_serialization",
272
+ _native_start_fake_slow_heap_serialization, 1);
273
+ rb_define_singleton_method(testing_module, "_native_end_fake_slow_heap_serialization",
274
+ _native_end_fake_slow_heap_serialization, 1);
275
+ rb_define_singleton_method(testing_module, "_native_debug_heap_recorder",
276
+ _native_debug_heap_recorder, 1);
277
+ rb_define_singleton_method(testing_module, "_native_gc_force_recycle",
278
+ _native_gc_force_recycle, 1);
279
+ rb_define_singleton_method(testing_module, "_native_has_seen_id_flag",
280
+ _native_has_seen_id_flag, 1);
281
+
282
+ ok_symbol = ID2SYM(rb_intern_const("ok"));
283
+ error_symbol = ID2SYM(rb_intern_const("error"));
284
+ }
285
+
286
+ // This structure is used to define a Ruby object that stores a pointer to a ddog_prof_Profile instance
287
+ // See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works
288
+ static const rb_data_type_t stack_recorder_typed_data = {
289
+ .wrap_struct_name = "Datadog::Profiling::StackRecorder",
290
+ .function = {
291
+ .dfree = stack_recorder_typed_data_free,
292
+ .dsize = NULL, // We don't track profile memory usage (although it'd be cool if we did!)
293
+ // No need to provide dmark nor dcompact because we don't directly reference Ruby VALUEs from inside this object
294
+ },
295
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
296
+ };
297
+
298
+ static VALUE _native_new(VALUE klass) {
299
+ struct stack_recorder_state *state = ruby_xcalloc(1, sizeof(struct stack_recorder_state));
300
+
301
+ // Note: Any exceptions raised from this note until the TypedData_Wrap_Struct call will lead to the state memory
302
+ // being leaked.
303
+
304
+ ddog_prof_Slice_ValueType sample_types = {.ptr = all_value_types, .len = ALL_VALUE_TYPES_COUNT};
305
+
306
+ initialize_slot_concurrency_control(state);
307
+ for (uint8_t i = 0; i < ALL_VALUE_TYPES_COUNT; i++) { state->position_for[i] = all_value_types_positions[i]; }
308
+ state->enabled_values_count = ALL_VALUE_TYPES_COUNT;
309
+
310
+ // Note: At this point, slot_one_profile and slot_two_profile contain null pointers. Libdatadog validates pointers
311
+ // before using them so it's ok for us to go ahead and create the StackRecorder object.
312
+
313
+ VALUE stack_recorder = TypedData_Wrap_Struct(klass, &stack_recorder_typed_data, state);
314
+
315
+ // NOTE: We initialize this because we want a new recorder to be operational even without initialization and our
316
+ // default is everything enabled. However, if during recording initialization it turns out we don't want
317
+ // heap samples, we will free and reset heap_recorder to NULL, effectively disabling all behaviour specific
318
+ // to heap profiling (all calls to heap_recorder_* with a NULL heap recorder are noops).
319
+ state->heap_recorder = heap_recorder_new();
320
+
321
+ // Note: Don't raise exceptions after this point, since it'll lead to libdatadog memory leaking!
322
+
323
+ initialize_profiles(state, sample_types);
324
+
325
+ return stack_recorder;
326
+ }
327
+
328
+ static void initialize_slot_concurrency_control(struct stack_recorder_state *state) {
329
+ state->slot_one_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
330
+ state->slot_two_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
331
+
332
+ // A newly-created StackRecorder starts with slot one being active for samples, so let's lock slot two
333
+ ENFORCE_SUCCESS_GVL(pthread_mutex_lock(&state->slot_two_mutex));
334
+
335
+ state->active_slot = 1;
336
+ }
337
+
338
+ static void initialize_profiles(struct stack_recorder_state *state, ddog_prof_Slice_ValueType sample_types) {
339
+ ddog_prof_Profile_NewResult slot_one_profile_result =
340
+ ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
341
+
342
+ if (slot_one_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
343
+ rb_raise(rb_eRuntimeError, "Failed to initialize slot one profile: %"PRIsVALUE, get_error_details_and_drop(&slot_one_profile_result.err));
344
+ }
345
+
346
+ ddog_prof_Profile_NewResult slot_two_profile_result =
347
+ ddog_prof_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
348
+
349
+ if (slot_two_profile_result.tag == DDOG_PROF_PROFILE_NEW_RESULT_ERR) {
350
+ // Uff! Though spot. We need to make sure to properly clean up the other profile as well first
351
+ ddog_prof_Profile_drop(&slot_one_profile_result.ok);
352
+ // And now we can raise...
353
+ rb_raise(rb_eRuntimeError, "Failed to initialize slot two profile: %"PRIsVALUE, get_error_details_and_drop(&slot_two_profile_result.err));
354
+ }
355
+
356
+ state->slot_one_profile = slot_one_profile_result.ok;
357
+ state->slot_two_profile = slot_two_profile_result.ok;
358
+ }
359
+
360
+ static void stack_recorder_typed_data_free(void *state_ptr) {
361
+ struct stack_recorder_state *state = (struct stack_recorder_state *) state_ptr;
362
+
363
+ pthread_mutex_destroy(&state->slot_one_mutex);
364
+ ddog_prof_Profile_drop(&state->slot_one_profile);
365
+
366
+ pthread_mutex_destroy(&state->slot_two_mutex);
367
+ ddog_prof_Profile_drop(&state->slot_two_profile);
368
+
369
+ heap_recorder_free(state->heap_recorder);
370
+
371
+ ruby_xfree(state);
372
+ }
373
+
374
+ static VALUE _native_initialize(
375
+ DDTRACE_UNUSED VALUE _self,
376
+ VALUE recorder_instance,
377
+ VALUE cpu_time_enabled,
378
+ VALUE alloc_samples_enabled,
379
+ VALUE heap_samples_enabled,
380
+ VALUE heap_size_enabled,
381
+ VALUE heap_sample_every,
382
+ VALUE timeline_enabled
383
+ ) {
384
+ ENFORCE_BOOLEAN(cpu_time_enabled);
385
+ ENFORCE_BOOLEAN(alloc_samples_enabled);
386
+ ENFORCE_BOOLEAN(heap_samples_enabled);
387
+ ENFORCE_BOOLEAN(heap_size_enabled);
388
+ ENFORCE_TYPE(heap_sample_every, T_FIXNUM);
389
+ ENFORCE_BOOLEAN(timeline_enabled);
390
+
391
+ struct stack_recorder_state *state;
392
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
393
+
394
+ heap_recorder_set_sample_rate(state->heap_recorder, NUM2INT(heap_sample_every));
395
+
396
+ uint8_t requested_values_count = ALL_VALUE_TYPES_COUNT -
397
+ (cpu_time_enabled == Qtrue ? 0 : 1) -
398
+ (alloc_samples_enabled == Qtrue? 0 : 1) -
399
+ (heap_samples_enabled == Qtrue ? 0 : 1) -
400
+ (heap_size_enabled == Qtrue ? 0 : 1) -
401
+ (timeline_enabled == Qtrue ? 0 : 1);
402
+
403
+ if (requested_values_count == ALL_VALUE_TYPES_COUNT) return Qtrue; // Nothing to do, this is the default
404
+
405
+ // When some sample types are disabled, we need to reconfigure libdatadog to record less types,
406
+ // as well as reconfigure the position_for array to push the disabled types to the end so they don't get recorded.
407
+ // See record_sample for details on the use of position_for.
408
+
409
+ state->enabled_values_count = requested_values_count;
410
+
411
+ ddog_prof_ValueType enabled_value_types[ALL_VALUE_TYPES_COUNT];
412
+ uint8_t next_enabled_pos = 0;
413
+ uint8_t next_disabled_pos = requested_values_count;
414
+
415
+ // CPU_SAMPLES_VALUE is always enabled
416
+ enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) CPU_SAMPLES_VALUE;
417
+ state->position_for[CPU_SAMPLES_VALUE_ID] = next_enabled_pos++;
418
+
419
+ // WALL_TIME_VALUE is always enabled
420
+ enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) WALL_TIME_VALUE;
421
+ state->position_for[WALL_TIME_VALUE_ID] = next_enabled_pos++;
422
+
423
+ if (cpu_time_enabled == Qtrue) {
424
+ enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) CPU_TIME_VALUE;
425
+ state->position_for[CPU_TIME_VALUE_ID] = next_enabled_pos++;
426
+ } else {
427
+ state->position_for[CPU_TIME_VALUE_ID] = next_disabled_pos++;
428
+ }
429
+
430
+ if (alloc_samples_enabled == Qtrue) {
431
+ enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) ALLOC_SAMPLES_VALUE;
432
+ state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_enabled_pos++;
433
+ } else {
434
+ state->position_for[ALLOC_SAMPLES_VALUE_ID] = next_disabled_pos++;
435
+ }
436
+
437
+ if (heap_samples_enabled == Qtrue) {
438
+ enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) HEAP_SAMPLES_VALUE;
439
+ state->position_for[HEAP_SAMPLES_VALUE_ID] = next_enabled_pos++;
440
+ } else {
441
+ state->position_for[HEAP_SAMPLES_VALUE_ID] = next_disabled_pos++;
442
+ }
443
+
444
+ if (heap_size_enabled == Qtrue) {
445
+ enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) HEAP_SIZE_VALUE;
446
+ state->position_for[HEAP_SIZE_VALUE_ID] = next_enabled_pos++;
447
+ } else {
448
+ state->position_for[HEAP_SIZE_VALUE_ID] = next_disabled_pos++;
449
+ }
450
+ heap_recorder_set_size_enabled(state->heap_recorder, heap_size_enabled);
451
+
452
+ if (heap_samples_enabled == Qfalse && heap_size_enabled == Qfalse) {
453
+ // Turns out heap sampling is disabled but we initialized everything in _native_new
454
+ // assuming all samples were enabled. We need to deinitialize the heap recorder.
455
+ heap_recorder_free(state->heap_recorder);
456
+ state->heap_recorder = NULL;
457
+ }
458
+
459
+ if (timeline_enabled == Qtrue) {
460
+ enabled_value_types[next_enabled_pos] = (ddog_prof_ValueType) TIMELINE_VALUE;
461
+ state->position_for[TIMELINE_VALUE_ID] = next_enabled_pos++;
462
+ } else {
463
+ state->position_for[TIMELINE_VALUE_ID] = next_disabled_pos++;
464
+ }
465
+
466
+ ddog_prof_Profile_drop(&state->slot_one_profile);
467
+ ddog_prof_Profile_drop(&state->slot_two_profile);
468
+
469
+ ddog_prof_Slice_ValueType sample_types = {.ptr = enabled_value_types, .len = state->enabled_values_count};
470
+ initialize_profiles(state, sample_types);
471
+
472
+ return Qtrue;
473
+ }
474
+
475
+ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
476
+ struct stack_recorder_state *state;
477
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
478
+
479
+ ddog_Timespec finish_timestamp = system_epoch_now_timespec();
480
+ // Need to do this while still holding on to the Global VM Lock; see comments on method for why
481
+ serializer_set_start_timestamp_for_next_profile(state, finish_timestamp);
482
+
483
+ // Prepare the iteration on heap recorder we'll be doing outside the GVL. The preparation needs to
484
+ // happen while holding on to the GVL.
485
+ heap_recorder_prepare_iteration(state->heap_recorder);
486
+
487
+ // We'll release the Global VM Lock while we're calling serialize, so that the Ruby VM can continue to work while this
488
+ // is pending
489
+ struct call_serialize_without_gvl_arguments args = {
490
+ .state = state,
491
+ .finish_timestamp = finish_timestamp,
492
+ .gc_count_before_serialize = rb_gc_count(),
493
+ .serialize_ran = false
494
+ };
495
+
496
+ while (!args.serialize_ran) {
497
+ // Give the Ruby VM an opportunity to process any pending interruptions (including raising exceptions).
498
+ // Note that it's OK to do this BEFORE call_serialize_without_gvl runs BUT NOT AFTER because afterwards
499
+ // there's heap-allocated memory that MUST be cleaned before raising any exception.
500
+ //
501
+ // Note that we run this in a loop because `rb_thread_call_without_gvl2` may return multiple times due to
502
+ // pending interrupts until it actually runs our code.
503
+ process_pending_interruptions(Qnil);
504
+
505
+ // We use rb_thread_call_without_gvl2 here because unlike the regular _gvl variant, gvl2 does not process
506
+ // interruptions and thus does not raise exceptions after running our code.
507
+ rb_thread_call_without_gvl2(call_serialize_without_gvl, &args, NULL /* No interruption function needed in this case */, NULL /* Not needed */);
508
+ }
509
+
510
+ // Cleanup after heap recorder iteration. This needs to happen while holding on to the GVL.
511
+ heap_recorder_finish_iteration(state->heap_recorder);
512
+
513
+ ddog_prof_Profile_SerializeResult serialized_profile = args.result;
514
+
515
+ if (serialized_profile.tag == DDOG_PROF_PROFILE_SERIALIZE_RESULT_ERR) {
516
+ return rb_ary_new_from_args(2, error_symbol, get_error_details_and_drop(&serialized_profile.err));
517
+ }
518
+
519
+ VALUE encoded_pprof = ruby_string_from_vec_u8(serialized_profile.ok.buffer);
520
+
521
+ ddog_Timespec ddprof_start = serialized_profile.ok.start;
522
+ ddog_Timespec ddprof_finish = serialized_profile.ok.end;
523
+
524
+ ddog_prof_EncodedProfile_drop(&serialized_profile.ok);
525
+
526
+ VALUE start = ruby_time_from(ddprof_start);
527
+ VALUE finish = ruby_time_from(ddprof_finish);
528
+
529
+ return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(3, start, finish, encoded_pprof));
530
+ }
531
+
532
+ static VALUE ruby_time_from(ddog_Timespec ddprof_time) {
533
+ const int utc = INT_MAX - 1; // From Ruby sources
534
+ struct timespec time = {.tv_sec = ddprof_time.seconds, .tv_nsec = ddprof_time.nanoseconds};
535
+ return rb_time_timespec_new(&time, utc);
536
+ }
537
+
538
+ void record_sample(VALUE recorder_instance, ddog_prof_Slice_Location locations, sample_values values, sample_labels labels) {
539
+ struct stack_recorder_state *state;
540
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
541
+
542
+ struct active_slot_pair active_slot = sampler_lock_active_profile(state);
543
+
544
+ // Note: We initialize this array to have ALL_VALUE_TYPES_COUNT but only tell libdatadog to use the first
545
+ // state->enabled_values_count values. This simplifies handling disabled value types -- we still put them on the
546
+ // array, but in _native_initialize we arrange so their position starts from state->enabled_values_count and thus
547
+ // libdatadog doesn't touch them.
548
+ int64_t metric_values[ALL_VALUE_TYPES_COUNT] = {0};
549
+ uint8_t *position_for = state->position_for;
550
+
551
+ metric_values[position_for[CPU_TIME_VALUE_ID]] = values.cpu_time_ns;
552
+ metric_values[position_for[CPU_SAMPLES_VALUE_ID]] = values.cpu_or_wall_samples;
553
+ metric_values[position_for[WALL_TIME_VALUE_ID]] = values.wall_time_ns;
554
+ metric_values[position_for[ALLOC_SAMPLES_VALUE_ID]] = values.alloc_samples;
555
+ metric_values[position_for[TIMELINE_VALUE_ID]] = values.timeline_wall_time_ns;
556
+
557
+ if (values.alloc_samples != 0) {
558
+ // If we got an allocation sample end the heap allocation recording to commit the heap sample.
559
+ // FIXME: Heap sampling currently has to be done in 2 parts because the construction of locations is happening
560
+ // very late in the allocation-sampling path (which is shared with the cpu sampling path). This can
561
+ // be fixed with some refactoring but for now this leads to a less impactful change.
562
+ end_heap_allocation_recording(state->heap_recorder, locations);
563
+ }
564
+
565
+ ddog_prof_Profile_Result result = ddog_prof_Profile_add(
566
+ active_slot.profile,
567
+ (ddog_prof_Sample) {
568
+ .locations = locations,
569
+ .values = (ddog_Slice_I64) {.ptr = metric_values, .len = state->enabled_values_count},
570
+ .labels = labels.labels
571
+ },
572
+ labels.end_timestamp_ns
573
+ );
574
+
575
+ sampler_unlock_active_profile(active_slot);
576
+
577
+ if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
578
+ rb_raise(rb_eArgError, "Failed to record sample: %"PRIsVALUE, get_error_details_and_drop(&result.err));
579
+ }
580
+ }
581
+
582
+ void track_object(VALUE recorder_instance, VALUE new_object, unsigned int sample_weight, ddog_CharSlice *alloc_class) {
583
+ struct stack_recorder_state *state;
584
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
585
+ // FIXME: Heap sampling currently has to be done in 2 parts because the construction of locations is happening
586
+ // very late in the allocation-sampling path (which is shared with the cpu sampling path). This can
587
+ // be fixed with some refactoring but for now this leads to a less impactful change.
588
+ start_heap_allocation_recording(state->heap_recorder, new_object, sample_weight, alloc_class);
589
+ }
590
+
591
+ void record_endpoint(VALUE recorder_instance, uint64_t local_root_span_id, ddog_CharSlice endpoint) {
592
+ struct stack_recorder_state *state;
593
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
594
+
595
+ struct active_slot_pair active_slot = sampler_lock_active_profile(state);
596
+
597
+ ddog_prof_Profile_Result result = ddog_prof_Profile_set_endpoint(active_slot.profile, local_root_span_id, endpoint);
598
+
599
+ sampler_unlock_active_profile(active_slot);
600
+
601
+ if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
602
+ rb_raise(rb_eArgError, "Failed to record endpoint: %"PRIsVALUE, get_error_details_and_drop(&result.err));
603
+ }
604
+ }
605
+
606
+ #define MAX_LEN_HEAP_ITERATION_ERROR_MSG 256
607
+
608
+ // Heap recorder iteration context allows us access to stack recorder state and profile being serialized
609
+ // during iteration of heap recorder live objects.
610
+ typedef struct heap_recorder_iteration_context {
611
+ struct stack_recorder_state *state;
612
+ ddog_prof_Profile *profile;
613
+
614
+ bool error;
615
+ char error_msg[MAX_LEN_HEAP_ITERATION_ERROR_MSG];
616
+
617
+ size_t profile_gen;
618
+ } heap_recorder_iteration_context;
619
+
620
+ static bool add_heap_sample_to_active_profile_without_gvl(heap_recorder_iteration_data iteration_data, void *extra_arg) {
621
+ heap_recorder_iteration_context *context = (heap_recorder_iteration_context*) extra_arg;
622
+
623
+ live_object_data *object_data = &iteration_data.object_data;
624
+
625
+ int64_t metric_values[ALL_VALUE_TYPES_COUNT] = {0};
626
+ uint8_t *position_for = context->state->position_for;
627
+
628
+ metric_values[position_for[HEAP_SAMPLES_VALUE_ID]] = object_data->weight;
629
+ metric_values[position_for[HEAP_SIZE_VALUE_ID]] = object_data->size * object_data->weight;
630
+
631
+ ddog_prof_Label labels[2];
632
+ size_t label_offset = 0;
633
+
634
+ if (object_data->class != NULL) {
635
+ labels[label_offset++] = (ddog_prof_Label) {
636
+ .key = DDOG_CHARSLICE_C("allocation class"),
637
+ .str = (ddog_CharSlice) {
638
+ .ptr = object_data->class,
639
+ .len = strlen(object_data->class),
640
+ },
641
+ .num = 0, // This shouldn't be needed but the tracer-2.7 docker image ships a buggy gcc that complains about this
642
+ };
643
+ }
644
+ labels[label_offset++] = (ddog_prof_Label) {
645
+ .key = DDOG_CHARSLICE_C("gc gen age"),
646
+ .num = context->profile_gen - object_data->alloc_gen,
647
+ };
648
+
649
+ ddog_prof_Profile_Result result = ddog_prof_Profile_add(
650
+ context->profile,
651
+ (ddog_prof_Sample) {
652
+ .locations = iteration_data.locations,
653
+ .values = (ddog_Slice_I64) {.ptr = metric_values, .len = context->state->enabled_values_count},
654
+ .labels = (ddog_prof_Slice_Label) {
655
+ .ptr = labels,
656
+ .len = label_offset,
657
+ }
658
+ },
659
+ 0
660
+ );
661
+
662
+ if (result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
663
+ read_ddogerr_string_and_drop(&result.err, context->error_msg, MAX_LEN_HEAP_ITERATION_ERROR_MSG);
664
+ context->error = true;
665
+ // By returning false we cancel the iteration
666
+ return false;
667
+ }
668
+
669
+ // Keep on iterating to next item!
670
+ return true;
671
+ }
672
+
673
+ static void build_heap_profile_without_gvl(struct stack_recorder_state *state, ddog_prof_Profile *profile, size_t gc_count_before_serialize) {
674
+ heap_recorder_iteration_context iteration_context = {
675
+ .state = state,
676
+ .profile = profile,
677
+ .error = false,
678
+ .error_msg = {0},
679
+ .profile_gen = gc_count_before_serialize,
680
+ };
681
+ bool iterated = heap_recorder_for_each_live_object(state->heap_recorder, add_heap_sample_to_active_profile_without_gvl, (void*) &iteration_context);
682
+ // We wait until we're out of the iteration to grab the gvl and raise. This is important because during
683
+ // iteration we may potentially acquire locks in the heap recorder and we could reach a deadlock if the
684
+ // same locks are acquired by the heap recorder while holding the gvl (since we'd be operating on the
685
+ // same locks but acquiring them in different order).
686
+ if (!iterated) {
687
+ grab_gvl_and_raise(rb_eRuntimeError, "Failure during heap profile building: iteration cancelled");
688
+ }
689
+ else if (iteration_context.error) {
690
+ grab_gvl_and_raise(rb_eRuntimeError, "Failure during heap profile building: %s", iteration_context.error_msg);
691
+ }
692
+ }
693
+
694
+ static void *call_serialize_without_gvl(void *call_args) {
695
+ struct call_serialize_without_gvl_arguments *args = (struct call_serialize_without_gvl_arguments *) call_args;
696
+
697
+ args->profile = serializer_flip_active_and_inactive_slots(args->state);
698
+
699
+ // Now that we have the inactive profile with all but heap samples, lets fill it with heap data
700
+ // without needing to race with the active sampler
701
+ build_heap_profile_without_gvl(args->state, args->profile, args->gc_count_before_serialize);
702
+
703
+ // Note: The profile gets reset by the serialize call
704
+ args->result = ddog_prof_Profile_serialize(args->profile, &args->finish_timestamp, NULL /* duration_nanos is optional */, NULL /* start_time is optional */);
705
+ args->serialize_ran = true;
706
+
707
+ return NULL; // Unused
708
+ }
709
+
710
+ VALUE enforce_recorder_instance(VALUE object) {
711
+ Check_TypedStruct(object, &stack_recorder_typed_data);
712
+ return object;
713
+ }
714
+
715
+ static struct active_slot_pair sampler_lock_active_profile(struct stack_recorder_state *state) {
716
+ int error;
717
+
718
+ for (int attempts = 0; attempts < 2; attempts++) {
719
+ error = pthread_mutex_trylock(&state->slot_one_mutex);
720
+ if (error && error != EBUSY) ENFORCE_SUCCESS_GVL(error);
721
+
722
+ // Slot one is active
723
+ if (!error) return (struct active_slot_pair) {.mutex = &state->slot_one_mutex, .profile = &state->slot_one_profile};
724
+
725
+ // If we got here, slot one was not active, let's try slot two
726
+
727
+ error = pthread_mutex_trylock(&state->slot_two_mutex);
728
+ if (error && error != EBUSY) ENFORCE_SUCCESS_GVL(error);
729
+
730
+ // Slot two is active
731
+ if (!error) return (struct active_slot_pair) {.mutex = &state->slot_two_mutex, .profile = &state->slot_two_profile};
732
+ }
733
+
734
+ // We already tried both multiple times, and we did not succeed. This is not expected to happen. Let's stop sampling.
735
+ rb_raise(rb_eRuntimeError, "Failed to grab either mutex in sampler_lock_active_profile");
736
+ }
737
+
738
+ static void sampler_unlock_active_profile(struct active_slot_pair active_slot) {
739
+ ENFORCE_SUCCESS_GVL(pthread_mutex_unlock(active_slot.mutex));
740
+ }
741
+
742
+ static ddog_prof_Profile *serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state) {
743
+ int previously_active_slot = state->active_slot;
744
+
745
+ if (previously_active_slot != 1 && previously_active_slot != 2) {
746
+ grab_gvl_and_raise(rb_eRuntimeError, "Unexpected active_slot state %d in serializer_flip_active_and_inactive_slots", previously_active_slot);
747
+ }
748
+
749
+ pthread_mutex_t *previously_active = (previously_active_slot == 1) ? &state->slot_one_mutex : &state->slot_two_mutex;
750
+ pthread_mutex_t *previously_inactive = (previously_active_slot == 1) ? &state->slot_two_mutex : &state->slot_one_mutex;
751
+
752
+ // Release the lock, thus making this slot active
753
+ ENFORCE_SUCCESS_NO_GVL(pthread_mutex_unlock(previously_inactive));
754
+
755
+ // Grab the lock, thus making this slot inactive
756
+ ENFORCE_SUCCESS_NO_GVL(pthread_mutex_lock(previously_active));
757
+
758
+ // Update active_slot
759
+ state->active_slot = (previously_active_slot == 1) ? 2 : 1;
760
+
761
+ // Return profile for previously active slot (now inactive)
762
+ return (previously_active_slot == 1) ? &state->slot_one_profile : &state->slot_two_profile;
763
+ }
764
+
765
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
766
+ // It SHOULD NOT be used for other purposes.
767
+ static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
768
+ struct stack_recorder_state *state;
769
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
770
+
771
+ return INT2NUM(state->active_slot);
772
+ }
773
+
774
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
775
+ // It SHOULD NOT be used for other purposes.
776
+ static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { return test_slot_mutex_state(recorder_instance, 1); }
777
+
778
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
779
+ // It SHOULD NOT be used for other purposes.
780
+ static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { return test_slot_mutex_state(recorder_instance, 2); }
781
+
782
+ static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot) {
783
+ struct stack_recorder_state *state;
784
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
785
+
786
+ pthread_mutex_t *slot_mutex = (slot == 1) ? &state->slot_one_mutex : &state->slot_two_mutex;
787
+
788
+ // Like Heisenberg's uncertainty principle, we can't observe without affecting...
789
+ int error = pthread_mutex_trylock(slot_mutex);
790
+
791
+ if (error == 0) {
792
+ // Mutex was unlocked
793
+ ENFORCE_SUCCESS_GVL(pthread_mutex_unlock(slot_mutex));
794
+ return Qfalse;
795
+ } else if (error == EBUSY) {
796
+ // Mutex was locked
797
+ return Qtrue;
798
+ } else {
799
+ ENFORCE_SUCCESS_GVL(error);
800
+ rb_raise(rb_eRuntimeError, "Failed to raise exception in test_slot_mutex_state; this should never happen");
801
+ }
802
+ }
803
+
804
+ static ddog_Timespec system_epoch_now_timespec(void) {
805
+ long now_ns = system_epoch_time_now_ns(RAISE_ON_FAILURE);
806
+ return (ddog_Timespec) {.seconds = now_ns / SECONDS_AS_NS(1), .nanoseconds = now_ns % SECONDS_AS_NS(1)};
807
+ }
808
+
809
+ // After the Ruby VM forks, this method gets called in the child process to clean up any leftover state from the parent.
810
+ //
811
+ // Assumption: This method gets called BEFORE restarting profiling -- e.g. there are no components attempting to
812
+ // trigger samples at the same time.
813
+ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE recorder_instance) {
814
+ struct stack_recorder_state *state;
815
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
816
+
817
+ // In case the fork happened halfway through `serializer_flip_active_and_inactive_slots` execution and the
818
+ // resulting state is inconsistent, we make sure to reset it back to the initial state.
819
+ initialize_slot_concurrency_control(state);
820
+
821
+ reset_profile(&state->slot_one_profile, /* start_time: */ NULL);
822
+ reset_profile(&state->slot_two_profile, /* start_time: */ NULL);
823
+
824
+ heap_recorder_after_fork(state->heap_recorder);
825
+
826
+ return Qtrue;
827
+ }
828
+
829
+ // Assumption 1: This method is called with the GVL being held, because `ddog_prof_Profile_reset` mutates the profile and must
830
+ // not be interrupted part-way through by a VM fork.
831
+ static void serializer_set_start_timestamp_for_next_profile(struct stack_recorder_state *state, ddog_Timespec start_time) {
832
+ // Before making this profile active, we reset it so that it uses the correct start_time for its start
833
+ ddog_prof_Profile *next_profile = (state->active_slot == 1) ? &state->slot_two_profile : &state->slot_one_profile;
834
+ reset_profile(next_profile, &start_time);
835
+ }
836
+
837
+ static VALUE _native_record_endpoint(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE local_root_span_id, VALUE endpoint) {
838
+ ENFORCE_TYPE(local_root_span_id, T_FIXNUM);
839
+ record_endpoint(recorder_instance, NUM2ULL(local_root_span_id), char_slice_from_ruby_string(endpoint));
840
+ return Qtrue;
841
+ }
842
+
843
+ static VALUE _native_track_object(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance, VALUE new_obj, VALUE weight, VALUE alloc_class) {
844
+ ENFORCE_TYPE(weight, T_FIXNUM);
845
+ ddog_CharSlice alloc_class_slice = char_slice_from_ruby_string(alloc_class);
846
+ track_object(recorder_instance, new_obj, NUM2UINT(weight), &alloc_class_slice);
847
+ return Qtrue;
848
+ }
849
+
850
+ static VALUE _native_check_heap_hashes(DDTRACE_UNUSED VALUE _self, VALUE locations) {
851
+ ENFORCE_TYPE(locations, T_ARRAY);
852
+ size_t locations_len = rb_array_len(locations);
853
+ ddog_prof_Location locations_arr[locations_len];
854
+ for (size_t i = 0; i < locations_len; i++) {
855
+ VALUE location = rb_ary_entry(locations, i);
856
+ ENFORCE_TYPE(location, T_ARRAY);
857
+ VALUE name = rb_ary_entry(location, 0);
858
+ VALUE filename = rb_ary_entry(location, 1);
859
+ VALUE line = rb_ary_entry(location, 2);
860
+ ENFORCE_TYPE(name, T_STRING);
861
+ ENFORCE_TYPE(filename, T_STRING);
862
+ ENFORCE_TYPE(line, T_FIXNUM);
863
+ locations_arr[i] = (ddog_prof_Location) {
864
+ .line = line,
865
+ .function = (ddog_prof_Function) {
866
+ .name = char_slice_from_ruby_string(name),
867
+ .filename = char_slice_from_ruby_string(filename),
868
+ }
869
+ };
870
+ }
871
+ ddog_prof_Slice_Location ddog_locations = {
872
+ .len = locations_len,
873
+ .ptr = locations_arr,
874
+ };
875
+ heap_recorder_testonly_assert_hash_matches(ddog_locations);
876
+
877
+ return Qnil;
878
+ }
879
+
880
+ static void reset_profile(ddog_prof_Profile *profile, ddog_Timespec *start_time /* Can be null */) {
881
+ ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(profile, start_time);
882
+ if (reset_result.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
883
+ rb_raise(rb_eRuntimeError, "Failed to reset profile: %"PRIsVALUE, get_error_details_and_drop(&reset_result.err));
884
+ }
885
+ }
886
+
887
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
888
+ // It SHOULD NOT be used for other purposes.
889
+ static VALUE _native_start_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
890
+ struct stack_recorder_state *state;
891
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
892
+
893
+ heap_recorder_prepare_iteration(state->heap_recorder);
894
+
895
+ return Qnil;
896
+ }
897
+
898
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
899
+ // It SHOULD NOT be used for other purposes.
900
+ static VALUE _native_end_fake_slow_heap_serialization(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
901
+ struct stack_recorder_state *state;
902
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
903
+
904
+ heap_recorder_finish_iteration(state->heap_recorder);
905
+
906
+ return Qnil;
907
+ }
908
+
909
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
910
+ // It SHOULD NOT be used for other purposes.
911
+ static VALUE _native_debug_heap_recorder(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
912
+ struct stack_recorder_state *state;
913
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
914
+
915
+ return heap_recorder_testonly_debug(state->heap_recorder);
916
+ }
917
+
918
+ #pragma GCC diagnostic push
919
+ // rb_gc_force_recycle was deprecated in latest versions of Ruby and is a noop.
920
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
921
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
922
+ // It SHOULD NOT be used for other purposes.
923
+ static VALUE _native_gc_force_recycle(DDTRACE_UNUSED VALUE _self, VALUE obj) {
924
+ rb_gc_force_recycle(obj);
925
+ return Qnil;
926
+ }
927
+ #pragma GCC diagnostic pop
928
+
929
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
930
+ // It SHOULD NOT be used for other purposes.
931
+ static VALUE _native_has_seen_id_flag(DDTRACE_UNUSED VALUE _self, VALUE obj) {
932
+ #ifndef NO_SEEN_OBJ_ID_FLAG
933
+ if (RB_FL_TEST(obj, RUBY_FL_SEEN_OBJ_ID)) {
934
+ return Qtrue;
935
+ } else {
936
+ return Qfalse;
937
+ }
938
+ #else
939
+ return Qfalse;
940
+ #endif
941
+ }