ddtrace 1.2.0 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (766) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +442 -2
  3. data/LICENSE-3rdparty.csv +4 -0
  4. data/README.md +2 -2
  5. data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +20 -4
  6. data/ext/ddtrace_profiling_loader/extconf.rb +21 -3
  7. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +46 -3
  8. data/ext/ddtrace_profiling_native_extension/clock_id.h +21 -0
  9. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +33 -2
  10. data/ext/ddtrace_profiling_native_extension/clock_id_noop.c +10 -1
  11. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +821 -0
  12. data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.c +142 -0
  13. data/ext/ddtrace_profiling_native_extension/collectors_dynamic_sampling_rate.h +14 -0
  14. data/ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.c +241 -0
  15. data/ext/ddtrace_profiling_native_extension/collectors_idle_sampling_helper.h +3 -0
  16. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +186 -85
  17. data/ext/ddtrace_profiling_native_extension/collectors_stack.h +13 -2
  18. data/ext/ddtrace_profiling_native_extension/collectors_thread_context.c +978 -0
  19. data/ext/ddtrace_profiling_native_extension/collectors_thread_context.h +14 -0
  20. data/ext/ddtrace_profiling_native_extension/extconf.rb +54 -34
  21. data/ext/ddtrace_profiling_native_extension/helpers.h +17 -0
  22. data/ext/ddtrace_profiling_native_extension/http_transport.c +127 -121
  23. data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.h +25 -0
  24. data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +82 -37
  25. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +189 -139
  26. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +15 -6
  27. data/ext/ddtrace_profiling_native_extension/profiling.c +221 -5
  28. data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +110 -0
  29. data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +57 -1
  30. data/ext/ddtrace_profiling_native_extension/setup_signal_handler.c +115 -0
  31. data/ext/ddtrace_profiling_native_extension/setup_signal_handler.h +11 -0
  32. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +489 -45
  33. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +12 -35
  34. data/ext/ddtrace_profiling_native_extension/time_helpers.c +17 -0
  35. data/ext/ddtrace_profiling_native_extension/time_helpers.h +10 -0
  36. data/lib/datadog/appsec/assets/blocked.html +98 -3
  37. data/lib/datadog/appsec/assets/blocked.json +1 -0
  38. data/lib/datadog/appsec/assets/blocked.text +5 -0
  39. data/lib/datadog/appsec/assets/waf_rules/recommended.json +1722 -636
  40. data/lib/datadog/appsec/assets/waf_rules/strict.json +366 -74
  41. data/lib/datadog/appsec/assets.rb +2 -4
  42. data/lib/datadog/appsec/autoload.rb +5 -10
  43. data/lib/datadog/appsec/component.rb +41 -0
  44. data/lib/datadog/appsec/configuration/settings.rb +46 -24
  45. data/lib/datadog/appsec/configuration.rb +12 -4
  46. data/lib/datadog/appsec/contrib/auto_instrument.rb +0 -4
  47. data/lib/datadog/appsec/contrib/configuration/settings.rb +1 -3
  48. data/lib/datadog/appsec/contrib/integration.rb +0 -2
  49. data/lib/datadog/appsec/contrib/patcher.rb +0 -2
  50. data/lib/datadog/appsec/contrib/rack/configuration/settings.rb +2 -4
  51. data/lib/datadog/appsec/contrib/rack/ext.rb +0 -2
  52. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +97 -0
  53. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +30 -0
  54. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +117 -110
  55. data/lib/datadog/appsec/contrib/rack/integration.rb +5 -7
  56. data/lib/datadog/appsec/contrib/rack/patcher.rb +4 -4
  57. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +31 -38
  58. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +21 -22
  59. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +21 -22
  60. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +9 -7
  61. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +80 -39
  62. data/lib/datadog/appsec/contrib/rails/configuration/settings.rb +2 -4
  63. data/lib/datadog/appsec/contrib/rails/ext.rb +0 -2
  64. data/lib/datadog/appsec/contrib/rails/framework.rb +0 -2
  65. data/lib/datadog/appsec/contrib/rails/gateway/request.rb +67 -0
  66. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +45 -40
  67. data/lib/datadog/appsec/contrib/rails/integration.rb +5 -7
  68. data/lib/datadog/appsec/contrib/rails/patcher.rb +17 -16
  69. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +24 -23
  70. data/lib/datadog/appsec/contrib/rails/request.rb +3 -2
  71. data/lib/datadog/appsec/contrib/rails/request_middleware.rb +0 -2
  72. data/lib/datadog/appsec/contrib/sinatra/configuration/settings.rb +2 -4
  73. data/lib/datadog/appsec/contrib/sinatra/ext.rb +1 -2
  74. data/lib/datadog/appsec/contrib/sinatra/framework.rb +0 -2
  75. data/lib/datadog/appsec/contrib/sinatra/gateway/request.rb +17 -0
  76. data/lib/datadog/appsec/contrib/sinatra/gateway/route_params.rb +23 -0
  77. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +82 -75
  78. data/lib/datadog/appsec/contrib/sinatra/integration.rb +4 -6
  79. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +33 -18
  80. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +21 -20
  81. data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +0 -2
  82. data/lib/datadog/appsec/event.rb +8 -16
  83. data/lib/datadog/appsec/ext.rb +9 -0
  84. data/lib/datadog/appsec/extensions.rb +51 -23
  85. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +24 -0
  86. data/lib/datadog/appsec/instrumentation/gateway.rb +26 -6
  87. data/lib/datadog/appsec/instrumentation.rb +9 -0
  88. data/lib/datadog/appsec/monitor/gateway/watcher.rb +86 -0
  89. data/lib/datadog/appsec/monitor/reactive/set_user.rb +61 -0
  90. data/lib/datadog/appsec/monitor.rb +11 -0
  91. data/lib/datadog/appsec/processor.rb +110 -31
  92. data/lib/datadog/appsec/rate_limiter.rb +0 -2
  93. data/lib/datadog/appsec/reactive/address_hash.rb +6 -2
  94. data/lib/datadog/appsec/reactive/engine.rb +12 -9
  95. data/lib/datadog/appsec/reactive/operation.rb +22 -5
  96. data/lib/datadog/appsec/reactive/subscriber.rb +2 -1
  97. data/lib/datadog/appsec/response.rb +61 -0
  98. data/lib/datadog/appsec/utils/http/media_range.rb +199 -0
  99. data/lib/datadog/appsec/utils/http/media_type.rb +85 -0
  100. data/lib/datadog/appsec/utils/http.rb +9 -0
  101. data/lib/datadog/appsec/utils.rb +7 -0
  102. data/lib/datadog/appsec.rb +25 -7
  103. data/lib/datadog/ci/configuration/components.rb +1 -3
  104. data/lib/datadog/ci/configuration/settings.rb +1 -3
  105. data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +2 -4
  106. data/lib/datadog/ci/contrib/cucumber/ext.rb +0 -2
  107. data/lib/datadog/ci/contrib/cucumber/formatter.rb +5 -7
  108. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +1 -3
  109. data/lib/datadog/ci/contrib/cucumber/integration.rb +4 -6
  110. data/lib/datadog/ci/contrib/cucumber/patcher.rb +2 -4
  111. data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +2 -4
  112. data/lib/datadog/ci/contrib/rspec/example.rb +5 -7
  113. data/lib/datadog/ci/contrib/rspec/ext.rb +0 -2
  114. data/lib/datadog/ci/contrib/rspec/integration.rb +4 -6
  115. data/lib/datadog/ci/contrib/rspec/patcher.rb +2 -4
  116. data/lib/datadog/ci/ext/app_types.rb +0 -2
  117. data/lib/datadog/ci/ext/environment.rb +77 -41
  118. data/lib/datadog/ci/ext/settings.rb +0 -2
  119. data/lib/datadog/ci/ext/test.rb +0 -2
  120. data/lib/datadog/ci/extensions.rb +4 -6
  121. data/lib/datadog/ci/flush.rb +2 -4
  122. data/lib/datadog/ci/test.rb +3 -5
  123. data/lib/datadog/ci.rb +6 -8
  124. data/lib/datadog/core/buffer/cruby.rb +1 -3
  125. data/lib/datadog/core/buffer/random.rb +0 -2
  126. data/lib/datadog/core/buffer/thread_safe.rb +1 -3
  127. data/lib/datadog/core/chunker.rb +0 -2
  128. data/lib/datadog/core/configuration/agent_settings_resolver.rb +8 -28
  129. data/lib/datadog/core/configuration/base.rb +14 -4
  130. data/lib/datadog/core/configuration/components.rb +31 -299
  131. data/lib/datadog/core/configuration/dependency_resolver.rb +0 -2
  132. data/lib/datadog/core/configuration/ext.rb +24 -0
  133. data/lib/datadog/core/configuration/option.rb +0 -2
  134. data/lib/datadog/core/configuration/option_definition.rb +12 -5
  135. data/lib/datadog/core/configuration/option_definition_set.rb +1 -3
  136. data/lib/datadog/core/configuration/option_set.rb +0 -2
  137. data/lib/datadog/core/configuration/options.rb +3 -5
  138. data/lib/datadog/core/configuration/settings.rb +87 -257
  139. data/lib/datadog/core/configuration.rb +9 -10
  140. data/lib/datadog/core/diagnostics/environment_logger.rb +10 -7
  141. data/lib/datadog/core/diagnostics/health.rb +4 -24
  142. data/lib/datadog/core/encoding.rb +0 -4
  143. data/lib/datadog/core/environment/cgroup.rb +1 -5
  144. data/lib/datadog/core/environment/class_count.rb +0 -2
  145. data/lib/datadog/core/environment/container.rb +1 -5
  146. data/lib/datadog/core/environment/ext.rb +1 -3
  147. data/lib/datadog/core/environment/gc.rb +0 -2
  148. data/lib/datadog/core/environment/identity.rb +2 -4
  149. data/lib/datadog/core/environment/platform.rb +1 -3
  150. data/lib/datadog/core/environment/socket.rb +1 -3
  151. data/lib/datadog/core/environment/thread_count.rb +0 -2
  152. data/lib/datadog/core/environment/variable_helpers.rb +58 -12
  153. data/lib/datadog/core/environment/vm_cache.rb +17 -2
  154. data/lib/datadog/core/error.rb +1 -3
  155. data/lib/datadog/core/extensions.rb +1 -3
  156. data/lib/datadog/core/git/ext.rb +0 -2
  157. data/lib/datadog/core/header_collection.rb +41 -0
  158. data/lib/datadog/core/logger.rb +0 -2
  159. data/lib/datadog/core/metrics/client.rb +10 -11
  160. data/lib/datadog/core/metrics/ext.rb +0 -4
  161. data/lib/datadog/core/metrics/helpers.rb +0 -2
  162. data/lib/datadog/core/metrics/logging.rb +0 -2
  163. data/lib/datadog/core/metrics/metric.rb +0 -2
  164. data/lib/datadog/core/metrics/options.rb +3 -5
  165. data/lib/datadog/core/pin.rb +0 -2
  166. data/lib/datadog/core/runtime/ext.rb +3 -3
  167. data/lib/datadog/core/runtime/metrics.rb +27 -13
  168. data/lib/datadog/core/telemetry/client.rb +77 -0
  169. data/lib/datadog/core/telemetry/collector.rb +231 -0
  170. data/lib/datadog/core/telemetry/emitter.rb +46 -0
  171. data/lib/datadog/core/telemetry/event.rb +67 -0
  172. data/lib/datadog/core/telemetry/ext.rb +9 -0
  173. data/lib/datadog/core/telemetry/heartbeat.rb +35 -0
  174. data/lib/datadog/core/telemetry/http/adapters/net.rb +111 -0
  175. data/lib/datadog/core/telemetry/http/env.rb +18 -0
  176. data/lib/datadog/core/telemetry/http/ext.rb +20 -0
  177. data/lib/datadog/core/telemetry/http/response.rb +64 -0
  178. data/lib/datadog/core/telemetry/http/transport.rb +51 -0
  179. data/lib/datadog/core/telemetry/v1/app_event.rb +50 -0
  180. data/lib/datadog/core/telemetry/v1/application.rb +86 -0
  181. data/lib/datadog/core/telemetry/v1/configuration.rb +25 -0
  182. data/lib/datadog/core/telemetry/v1/dependency.rb +36 -0
  183. data/lib/datadog/core/telemetry/v1/host.rb +51 -0
  184. data/lib/datadog/core/telemetry/v1/integration.rb +58 -0
  185. data/lib/datadog/core/telemetry/v1/product.rb +28 -0
  186. data/lib/datadog/core/telemetry/v1/telemetry_request.rb +100 -0
  187. data/lib/datadog/core/utils/compression.rb +5 -3
  188. data/lib/datadog/core/utils/forking.rb +0 -2
  189. data/lib/datadog/core/utils/network.rb +140 -0
  190. data/lib/datadog/core/utils/object_set.rb +1 -3
  191. data/lib/datadog/core/utils/only_once.rb +0 -2
  192. data/lib/datadog/core/utils/safe_dup.rb +0 -2
  193. data/lib/datadog/core/utils/sequence.rb +5 -2
  194. data/lib/datadog/core/utils/string_table.rb +1 -3
  195. data/lib/datadog/core/utils/time.rb +3 -7
  196. data/lib/datadog/core/utils.rb +1 -24
  197. data/lib/datadog/core/vendor/ipaddr.rb +78 -0
  198. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +0 -2
  199. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +2 -4
  200. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +0 -2
  201. data/lib/datadog/core/vendor/multipart-post/multipart/post/version.rb +0 -2
  202. data/lib/datadog/core/vendor/multipart-post/multipart/post.rb +0 -2
  203. data/lib/datadog/core/vendor/multipart-post/multipart.rb +0 -2
  204. data/lib/datadog/core/vendor/multipart-post/net/http/post/multipart.rb +3 -5
  205. data/lib/datadog/core/worker.rb +0 -2
  206. data/lib/datadog/core/workers/async.rb +1 -5
  207. data/lib/datadog/core/workers/interval_loop.rb +0 -2
  208. data/lib/datadog/core/workers/polling.rb +2 -4
  209. data/lib/datadog/core/workers/queue.rb +0 -2
  210. data/lib/datadog/core/workers/runtime_metrics.rb +4 -6
  211. data/lib/datadog/core.rb +21 -56
  212. data/lib/datadog/kit/appsec/events.rb +74 -0
  213. data/lib/datadog/kit/enable_core_dumps.rb +6 -6
  214. data/lib/datadog/kit/identity.rb +15 -8
  215. data/lib/datadog/kit.rb +1 -3
  216. data/lib/datadog/opentelemetry/api/context.rb +186 -0
  217. data/lib/datadog/opentelemetry/api/trace/span.rb +14 -0
  218. data/lib/datadog/opentelemetry/sdk/configurator.rb +37 -0
  219. data/lib/datadog/opentelemetry/sdk/id_generator.rb +26 -0
  220. data/lib/datadog/opentelemetry/sdk/propagator.rb +90 -0
  221. data/lib/datadog/opentelemetry/sdk/span_processor.rb +91 -0
  222. data/lib/datadog/opentelemetry.rb +47 -0
  223. data/lib/datadog/opentracer/binary_propagator.rb +0 -2
  224. data/lib/datadog/opentracer/carrier.rb +0 -2
  225. data/lib/datadog/opentracer/distributed_headers.rb +7 -11
  226. data/lib/datadog/opentracer/global_tracer.rb +0 -2
  227. data/lib/datadog/opentracer/propagator.rb +0 -2
  228. data/lib/datadog/opentracer/rack_propagator.rb +10 -11
  229. data/lib/datadog/opentracer/scope.rb +0 -2
  230. data/lib/datadog/opentracer/scope_manager.rb +0 -2
  231. data/lib/datadog/opentracer/span.rb +1 -3
  232. data/lib/datadog/opentracer/span_context.rb +0 -2
  233. data/lib/datadog/opentracer/span_context_factory.rb +0 -2
  234. data/lib/datadog/opentracer/text_map_propagator.rb +13 -14
  235. data/lib/datadog/opentracer/thread_local_scope.rb +0 -2
  236. data/lib/datadog/opentracer/thread_local_scope_manager.rb +1 -3
  237. data/lib/datadog/opentracer/tracer.rb +23 -23
  238. data/lib/datadog/opentracer.rb +16 -18
  239. data/lib/datadog/profiling/backtrace_location.rb +0 -2
  240. data/lib/datadog/profiling/buffer.rb +3 -5
  241. data/lib/datadog/profiling/collectors/code_provenance.rb +0 -2
  242. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +96 -0
  243. data/lib/datadog/profiling/collectors/dynamic_sampling_rate.rb +12 -0
  244. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +66 -0
  245. data/lib/datadog/profiling/collectors/old_stack.rb +16 -13
  246. data/lib/datadog/profiling/collectors/stack.rb +3 -10
  247. data/lib/datadog/profiling/collectors/thread_context.rb +46 -0
  248. data/lib/datadog/profiling/component.rb +161 -0
  249. data/lib/datadog/profiling/encoding/profile.rb +1 -3
  250. data/lib/datadog/profiling/event.rb +0 -2
  251. data/lib/datadog/profiling/events/stack.rb +1 -3
  252. data/lib/datadog/profiling/exporter.rb +23 -14
  253. data/lib/datadog/profiling/ext/forking.rb +36 -39
  254. data/lib/datadog/profiling/ext.rb +1 -2
  255. data/lib/datadog/profiling/flush.rb +0 -5
  256. data/lib/datadog/profiling/http_transport.rb +5 -6
  257. data/lib/datadog/profiling/load_native_extension.rb +0 -2
  258. data/lib/datadog/profiling/native_extension.rb +0 -2
  259. data/lib/datadog/profiling/old_recorder.rb +8 -7
  260. data/lib/datadog/profiling/pprof/builder.rb +4 -6
  261. data/lib/datadog/profiling/pprof/converter.rb +1 -3
  262. data/lib/datadog/profiling/pprof/message_set.rb +1 -3
  263. data/lib/datadog/profiling/pprof/payload.rb +0 -2
  264. data/lib/datadog/profiling/pprof/pprof_pb.rb +0 -2
  265. data/lib/datadog/profiling/pprof/stack_sample.rb +4 -6
  266. data/lib/datadog/profiling/pprof/string_table.rb +1 -3
  267. data/lib/datadog/profiling/pprof/template.rb +5 -7
  268. data/lib/datadog/profiling/preload.rb +1 -3
  269. data/lib/datadog/profiling/profiler.rb +7 -2
  270. data/lib/datadog/profiling/scheduler.rb +8 -12
  271. data/lib/datadog/profiling/stack_recorder.rb +49 -8
  272. data/lib/datadog/profiling/tag_builder.rb +5 -2
  273. data/lib/datadog/profiling/tasks/exec.rb +0 -2
  274. data/lib/datadog/profiling/tasks/help.rb +0 -2
  275. data/lib/datadog/profiling/tasks/setup.rb +2 -11
  276. data/lib/datadog/profiling/trace_identifiers/ddtrace.rb +2 -4
  277. data/lib/datadog/profiling/trace_identifiers/helper.rb +1 -3
  278. data/lib/datadog/profiling.rb +67 -27
  279. data/lib/datadog/tracing/analytics.rb +1 -3
  280. data/lib/datadog/tracing/buffer.rb +5 -9
  281. data/lib/datadog/tracing/client_ip.rb +61 -0
  282. data/lib/datadog/tracing/component.rb +176 -0
  283. data/lib/datadog/tracing/configuration/ext.rb +49 -6
  284. data/lib/datadog/tracing/configuration/settings.rb +451 -0
  285. data/lib/datadog/tracing/context.rb +1 -3
  286. data/lib/datadog/tracing/context_provider.rb +2 -4
  287. data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +2 -4
  288. data/lib/datadog/tracing/contrib/action_cable/event.rb +4 -7
  289. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +4 -6
  290. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +3 -5
  291. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +4 -6
  292. data/lib/datadog/tracing/contrib/action_cable/events.rb +4 -6
  293. data/lib/datadog/tracing/contrib/action_cable/ext.rb +0 -2
  294. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +3 -6
  295. data/lib/datadog/tracing/contrib/action_cable/integration.rb +4 -6
  296. data/lib/datadog/tracing/contrib/action_cable/patcher.rb +4 -6
  297. data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +2 -4
  298. data/lib/datadog/tracing/contrib/action_mailer/event.rb +3 -5
  299. data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +3 -5
  300. data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +3 -5
  301. data/lib/datadog/tracing/contrib/action_mailer/events.rb +2 -4
  302. data/lib/datadog/tracing/contrib/action_mailer/ext.rb +0 -2
  303. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +4 -6
  304. data/lib/datadog/tracing/contrib/action_mailer/patcher.rb +3 -5
  305. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +6 -8
  306. data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +2 -4
  307. data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +2 -4
  308. data/lib/datadog/tracing/contrib/action_pack/ext.rb +0 -2
  309. data/lib/datadog/tracing/contrib/action_pack/integration.rb +4 -6
  310. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +2 -4
  311. data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -3
  312. data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +2 -4
  313. data/lib/datadog/tracing/contrib/action_view/event.rb +1 -3
  314. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +5 -7
  315. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +5 -7
  316. data/lib/datadog/tracing/contrib/action_view/events.rb +2 -4
  317. data/lib/datadog/tracing/contrib/action_view/ext.rb +0 -2
  318. data/lib/datadog/tracing/contrib/action_view/instrumentation/partial_renderer.rb +2 -4
  319. data/lib/datadog/tracing/contrib/action_view/instrumentation/template_renderer.rb +2 -4
  320. data/lib/datadog/tracing/contrib/action_view/integration.rb +4 -6
  321. data/lib/datadog/tracing/contrib/action_view/patcher.rb +7 -9
  322. data/lib/datadog/tracing/contrib/action_view/utils.rb +1 -3
  323. data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +3 -5
  324. data/lib/datadog/tracing/contrib/active_job/event.rb +3 -5
  325. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +4 -6
  326. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +4 -6
  327. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +4 -6
  328. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +4 -6
  329. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +4 -6
  330. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +4 -6
  331. data/lib/datadog/tracing/contrib/active_job/events.rb +6 -8
  332. data/lib/datadog/tracing/contrib/active_job/ext.rb +0 -2
  333. data/lib/datadog/tracing/contrib/active_job/integration.rb +4 -6
  334. data/lib/datadog/tracing/contrib/active_job/log_injection.rb +0 -4
  335. data/lib/datadog/tracing/contrib/active_job/patcher.rb +4 -6
  336. data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +2 -4
  337. data/lib/datadog/tracing/contrib/active_model_serializers/event.rb +4 -7
  338. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +3 -5
  339. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +2 -4
  340. data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +2 -4
  341. data/lib/datadog/tracing/contrib/active_model_serializers/ext.rb +0 -2
  342. data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +3 -5
  343. data/lib/datadog/tracing/contrib/active_model_serializers/patcher.rb +3 -6
  344. data/lib/datadog/tracing/contrib/active_record/configuration/makara_resolver.rb +0 -2
  345. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -4
  346. data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +3 -5
  347. data/lib/datadog/tracing/contrib/active_record/event.rb +1 -3
  348. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +4 -6
  349. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +6 -8
  350. data/lib/datadog/tracing/contrib/active_record/events.rb +2 -4
  351. data/lib/datadog/tracing/contrib/active_record/ext.rb +0 -2
  352. data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -8
  353. data/lib/datadog/tracing/contrib/active_record/patcher.rb +2 -4
  354. data/lib/datadog/tracing/contrib/active_record/utils.rb +2 -4
  355. data/lib/datadog/tracing/contrib/active_record/vendor/connection_specification.rb +0 -2
  356. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +19 -11
  357. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +2 -4
  358. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +1 -3
  359. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +2 -4
  360. data/lib/datadog/tracing/contrib/active_support/ext.rb +0 -2
  361. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -7
  362. data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +1 -3
  363. data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +1 -3
  364. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +0 -2
  365. data/lib/datadog/tracing/contrib/active_support/patcher.rb +2 -4
  366. data/lib/datadog/tracing/contrib/analytics.rb +1 -3
  367. data/lib/datadog/tracing/contrib/auto_instrument.rb +4 -6
  368. data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +6 -5
  369. data/lib/datadog/tracing/contrib/aws/ext.rb +1 -2
  370. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +5 -6
  371. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -5
  372. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +0 -2
  373. data/lib/datadog/tracing/contrib/aws/patcher.rb +5 -7
  374. data/lib/datadog/tracing/contrib/aws/services.rb +0 -4
  375. data/lib/datadog/tracing/contrib/concurrent_ruby/configuration/settings.rb +2 -4
  376. data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +0 -2
  377. data/lib/datadog/tracing/contrib/concurrent_ruby/ext.rb +0 -2
  378. data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +1 -3
  379. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -5
  380. data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +2 -5
  381. data/lib/datadog/tracing/contrib/configurable.rb +2 -4
  382. data/lib/datadog/tracing/contrib/configuration/resolver.rb +0 -2
  383. data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +1 -3
  384. data/lib/datadog/tracing/contrib/configuration/settings.rb +2 -6
  385. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +6 -5
  386. data/lib/datadog/tracing/contrib/dalli/ext.rb +2 -2
  387. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +10 -7
  388. data/lib/datadog/tracing/contrib/dalli/integration.rb +3 -5
  389. data/lib/datadog/tracing/contrib/dalli/patcher.rb +3 -5
  390. data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -3
  391. data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +3 -5
  392. data/lib/datadog/tracing/contrib/delayed_job/ext.rb +2 -2
  393. data/lib/datadog/tracing/contrib/delayed_job/integration.rb +3 -5
  394. data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +8 -4
  395. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +11 -6
  396. data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +32 -0
  397. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +7 -5
  398. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +3 -2
  399. data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +3 -5
  400. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +10 -9
  401. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +1 -5
  402. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +8 -5
  403. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +6 -9
  404. data/lib/datadog/tracing/contrib/ethon/ext.rb +1 -2
  405. data/lib/datadog/tracing/contrib/ethon/integration.rb +4 -6
  406. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +5 -6
  407. data/lib/datadog/tracing/contrib/ethon/patcher.rb +3 -6
  408. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +7 -5
  409. data/lib/datadog/tracing/contrib/excon/ext.rb +1 -2
  410. data/lib/datadog/tracing/contrib/excon/integration.rb +4 -6
  411. data/lib/datadog/tracing/contrib/excon/middleware.rb +8 -9
  412. data/lib/datadog/tracing/contrib/excon/patcher.rb +2 -4
  413. data/lib/datadog/tracing/contrib/ext.rb +30 -0
  414. data/lib/datadog/tracing/contrib/extensions.rb +5 -5
  415. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +7 -5
  416. data/lib/datadog/tracing/contrib/faraday/connection.rb +0 -2
  417. data/lib/datadog/tracing/contrib/faraday/ext.rb +1 -2
  418. data/lib/datadog/tracing/contrib/faraday/integration.rb +4 -6
  419. data/lib/datadog/tracing/contrib/faraday/middleware.rb +8 -10
  420. data/lib/datadog/tracing/contrib/faraday/patcher.rb +5 -7
  421. data/lib/datadog/tracing/contrib/faraday/rack_builder.rb +0 -2
  422. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +3 -5
  423. data/lib/datadog/tracing/contrib/grape/endpoint.rb +4 -9
  424. data/lib/datadog/tracing/contrib/grape/ext.rb +0 -2
  425. data/lib/datadog/tracing/contrib/grape/instrumentation.rb +0 -2
  426. data/lib/datadog/tracing/contrib/grape/integration.rb +3 -5
  427. data/lib/datadog/tracing/contrib/grape/patcher.rb +4 -6
  428. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +3 -5
  429. data/lib/datadog/tracing/contrib/graphql/ext.rb +0 -2
  430. data/lib/datadog/tracing/contrib/graphql/integration.rb +3 -5
  431. data/lib/datadog/tracing/contrib/graphql/patcher.rb +2 -5
  432. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +9 -6
  433. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +20 -7
  434. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +17 -19
  435. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +3 -6
  436. data/lib/datadog/tracing/contrib/grpc/distributed/fetcher.rb +26 -0
  437. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +42 -0
  438. data/lib/datadog/tracing/contrib/grpc/ext.rb +4 -2
  439. data/lib/datadog/tracing/contrib/grpc/integration.rb +11 -6
  440. data/lib/datadog/tracing/contrib/grpc/intercept_with_datadog.rb +0 -2
  441. data/lib/datadog/tracing/contrib/grpc/patcher.rb +3 -8
  442. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +45 -0
  443. data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +20 -0
  444. data/lib/datadog/tracing/contrib/hanami/ext.rb +22 -0
  445. data/lib/datadog/tracing/contrib/hanami/integration.rb +42 -0
  446. data/lib/datadog/tracing/contrib/hanami/patcher.rb +31 -0
  447. data/lib/datadog/tracing/contrib/hanami/plugin.rb +21 -0
  448. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +39 -0
  449. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +42 -0
  450. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +1 -4
  451. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +13 -5
  452. data/lib/datadog/tracing/contrib/http/distributed/fetcher.rb +38 -0
  453. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +37 -0
  454. data/lib/datadog/tracing/contrib/http/ext.rb +2 -2
  455. data/lib/datadog/tracing/contrib/http/instrumentation.rb +8 -12
  456. data/lib/datadog/tracing/contrib/http/integration.rb +6 -8
  457. data/lib/datadog/tracing/contrib/http/patcher.rb +3 -5
  458. data/lib/datadog/tracing/contrib/http_annotation_helper.rb +0 -2
  459. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +13 -5
  460. data/lib/datadog/tracing/contrib/httpclient/ext.rb +2 -2
  461. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +9 -11
  462. data/lib/datadog/tracing/contrib/httpclient/integration.rb +4 -6
  463. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +3 -5
  464. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +13 -5
  465. data/lib/datadog/tracing/contrib/httprb/ext.rb +2 -2
  466. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +9 -11
  467. data/lib/datadog/tracing/contrib/httprb/integration.rb +4 -6
  468. data/lib/datadog/tracing/contrib/httprb/patcher.rb +3 -5
  469. data/lib/datadog/tracing/contrib/integration.rb +3 -5
  470. data/lib/datadog/tracing/contrib/kafka/configuration/settings.rb +2 -4
  471. data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +1 -2
  472. data/lib/datadog/tracing/contrib/kafka/consumer_group_event.rb +0 -2
  473. data/lib/datadog/tracing/contrib/kafka/event.rb +4 -5
  474. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +2 -4
  475. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +3 -5
  476. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +3 -5
  477. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +4 -6
  478. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +4 -6
  479. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +4 -6
  480. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +4 -6
  481. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +3 -4
  482. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +3 -4
  483. data/lib/datadog/tracing/contrib/kafka/events.rb +9 -11
  484. data/lib/datadog/tracing/contrib/kafka/ext.rb +1 -2
  485. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -5
  486. data/lib/datadog/tracing/contrib/kafka/patcher.rb +3 -5
  487. data/lib/datadog/tracing/contrib/lograge/configuration/settings.rb +2 -4
  488. data/lib/datadog/tracing/contrib/lograge/ext.rb +0 -2
  489. data/lib/datadog/tracing/contrib/lograge/instrumentation.rb +1 -4
  490. data/lib/datadog/tracing/contrib/lograge/integration.rb +3 -5
  491. data/lib/datadog/tracing/contrib/lograge/patcher.rb +2 -4
  492. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +7 -5
  493. data/lib/datadog/tracing/contrib/mongodb/ext.rb +8 -2
  494. data/lib/datadog/tracing/contrib/mongodb/instrumentation.rb +3 -5
  495. data/lib/datadog/tracing/contrib/mongodb/integration.rb +4 -6
  496. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -3
  497. data/lib/datadog/tracing/contrib/mongodb/patcher.rb +3 -5
  498. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +10 -6
  499. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +17 -4
  500. data/lib/datadog/tracing/contrib/mysql2/ext.rb +2 -2
  501. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +20 -7
  502. data/lib/datadog/tracing/contrib/mysql2/integration.rb +3 -5
  503. data/lib/datadog/tracing/contrib/mysql2/patcher.rb +2 -4
  504. data/lib/datadog/tracing/contrib/patchable.rb +0 -2
  505. data/lib/datadog/tracing/contrib/patcher.rb +16 -6
  506. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +17 -4
  507. data/lib/datadog/tracing/contrib/pg/ext.rb +3 -3
  508. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +78 -41
  509. data/lib/datadog/tracing/contrib/pg/integration.rb +3 -5
  510. data/lib/datadog/tracing/contrib/pg/patcher.rb +2 -4
  511. data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +6 -5
  512. data/lib/datadog/tracing/contrib/presto/ext.rb +2 -2
  513. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +5 -5
  514. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -5
  515. data/lib/datadog/tracing/contrib/presto/patcher.rb +4 -6
  516. data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +41 -0
  517. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +31 -0
  518. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +26 -0
  519. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +45 -0
  520. data/lib/datadog/tracing/contrib/qless/configuration/settings.rb +2 -4
  521. data/lib/datadog/tracing/contrib/qless/ext.rb +0 -2
  522. data/lib/datadog/tracing/contrib/qless/integration.rb +3 -5
  523. data/lib/datadog/tracing/contrib/qless/patcher.rb +1 -5
  524. data/lib/datadog/tracing/contrib/qless/qless_job.rb +5 -5
  525. data/lib/datadog/tracing/contrib/qless/tracer_cleaner.rb +0 -4
  526. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +3 -5
  527. data/lib/datadog/tracing/contrib/que/ext.rb +0 -2
  528. data/lib/datadog/tracing/contrib/que/integration.rb +4 -6
  529. data/lib/datadog/tracing/contrib/que/patcher.rb +1 -3
  530. data/lib/datadog/tracing/contrib/que/tracer.rb +5 -3
  531. data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +2 -4
  532. data/lib/datadog/tracing/contrib/racecar/event.rb +5 -7
  533. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +6 -5
  534. data/lib/datadog/tracing/contrib/racecar/events/consume.rb +2 -4
  535. data/lib/datadog/tracing/contrib/racecar/events/message.rb +6 -5
  536. data/lib/datadog/tracing/contrib/racecar/events.rb +3 -5
  537. data/lib/datadog/tracing/contrib/racecar/ext.rb +1 -2
  538. data/lib/datadog/tracing/contrib/racecar/integration.rb +3 -5
  539. data/lib/datadog/tracing/contrib/racecar/patcher.rb +3 -5
  540. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +2 -4
  541. data/lib/datadog/tracing/contrib/rack/ext.rb +5 -2
  542. data/lib/datadog/tracing/contrib/rack/header_collection.rb +35 -0
  543. data/lib/datadog/tracing/contrib/rack/integration.rb +4 -6
  544. data/lib/datadog/tracing/contrib/rack/middlewares.rb +170 -78
  545. data/lib/datadog/tracing/contrib/rack/patcher.rb +12 -4
  546. data/lib/datadog/tracing/contrib/rack/request_queue.rb +0 -2
  547. data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +1 -3
  548. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +1 -3
  549. data/lib/datadog/tracing/contrib/rails/ext.rb +0 -2
  550. data/lib/datadog/tracing/contrib/rails/framework.rb +16 -23
  551. data/lib/datadog/tracing/contrib/rails/integration.rb +4 -6
  552. data/lib/datadog/tracing/contrib/rails/log_injection.rb +0 -4
  553. data/lib/datadog/tracing/contrib/rails/middlewares.rb +1 -4
  554. data/lib/datadog/tracing/contrib/rails/patcher.rb +7 -10
  555. data/lib/datadog/tracing/contrib/rails/railtie.rb +3 -5
  556. data/lib/datadog/tracing/contrib/rails/utils.rb +1 -3
  557. data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +16 -3
  558. data/lib/datadog/tracing/contrib/rake/ext.rb +0 -2
  559. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +12 -9
  560. data/lib/datadog/tracing/contrib/rake/integration.rb +3 -5
  561. data/lib/datadog/tracing/contrib/rake/patcher.rb +3 -6
  562. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +1 -3
  563. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +6 -5
  564. data/lib/datadog/tracing/contrib/redis/ext.rb +3 -2
  565. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +36 -28
  566. data/lib/datadog/tracing/contrib/redis/integration.rb +37 -6
  567. data/lib/datadog/tracing/contrib/redis/patcher.rb +56 -14
  568. data/lib/datadog/tracing/contrib/redis/quantize.rb +11 -10
  569. data/lib/datadog/tracing/contrib/redis/tags.rb +12 -12
  570. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +70 -0
  571. data/lib/datadog/tracing/contrib/redis/vendor/resolver.rb +0 -2
  572. data/lib/datadog/tracing/contrib/registerable.rb +0 -2
  573. data/lib/datadog/tracing/contrib/registry.rb +0 -2
  574. data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +3 -5
  575. data/lib/datadog/tracing/contrib/resque/ext.rb +0 -2
  576. data/lib/datadog/tracing/contrib/resque/integration.rb +3 -5
  577. data/lib/datadog/tracing/contrib/resque/patcher.rb +2 -4
  578. data/lib/datadog/tracing/contrib/resque/resque_job.rb +7 -6
  579. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +8 -5
  580. data/lib/datadog/tracing/contrib/rest_client/ext.rb +1 -2
  581. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -5
  582. data/lib/datadog/tracing/contrib/rest_client/patcher.rb +2 -5
  583. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +6 -7
  584. data/lib/datadog/tracing/contrib/semantic_logger/configuration/settings.rb +2 -4
  585. data/lib/datadog/tracing/contrib/semantic_logger/ext.rb +0 -2
  586. data/lib/datadog/tracing/contrib/semantic_logger/instrumentation.rb +1 -4
  587. data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +3 -5
  588. data/lib/datadog/tracing/contrib/semantic_logger/patcher.rb +2 -4
  589. data/lib/datadog/tracing/contrib/sequel/configuration/settings.rb +2 -4
  590. data/lib/datadog/tracing/contrib/sequel/database.rb +4 -7
  591. data/lib/datadog/tracing/contrib/sequel/dataset.rb +4 -7
  592. data/lib/datadog/tracing/contrib/sequel/ext.rb +0 -2
  593. data/lib/datadog/tracing/contrib/sequel/integration.rb +3 -5
  594. data/lib/datadog/tracing/contrib/sequel/patcher.rb +3 -5
  595. data/lib/datadog/tracing/contrib/sequel/utils.rb +2 -4
  596. data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +3 -5
  597. data/lib/datadog/tracing/contrib/shoryuken/ext.rb +1 -2
  598. data/lib/datadog/tracing/contrib/shoryuken/integration.rb +4 -6
  599. data/lib/datadog/tracing/contrib/shoryuken/patcher.rb +1 -3
  600. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +5 -3
  601. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +11 -7
  602. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +3 -5
  603. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +6 -2
  604. data/lib/datadog/tracing/contrib/sidekiq/integration.rb +3 -5
  605. data/lib/datadog/tracing/contrib/sidekiq/patcher.rb +14 -9
  606. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +23 -3
  607. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/job_fetch.rb +2 -2
  608. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/{scheduled_push.rb → redis_info.rb} +7 -8
  609. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +55 -0
  610. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +12 -8
  611. data/lib/datadog/tracing/contrib/sidekiq/tracing.rb +2 -4
  612. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +2 -4
  613. data/lib/datadog/tracing/contrib/sinatra/env.rb +14 -27
  614. data/lib/datadog/tracing/contrib/sinatra/ext.rb +7 -5
  615. data/lib/datadog/tracing/contrib/sinatra/framework.rb +0 -4
  616. data/lib/datadog/tracing/contrib/sinatra/headers.rb +1 -3
  617. data/lib/datadog/tracing/contrib/sinatra/integration.rb +3 -5
  618. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +6 -9
  619. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +15 -90
  620. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +20 -18
  621. data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +2 -4
  622. data/lib/datadog/tracing/contrib/sneakers/ext.rb +1 -2
  623. data/lib/datadog/tracing/contrib/sneakers/integration.rb +4 -6
  624. data/lib/datadog/tracing/contrib/sneakers/patcher.rb +2 -4
  625. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +7 -5
  626. data/lib/datadog/tracing/contrib/status_code_matcher.rb +2 -4
  627. data/lib/datadog/tracing/contrib/stripe/configuration/settings.rb +33 -0
  628. data/lib/datadog/tracing/contrib/stripe/ext.rb +26 -0
  629. data/lib/datadog/tracing/contrib/stripe/integration.rb +43 -0
  630. data/lib/datadog/tracing/contrib/stripe/patcher.rb +28 -0
  631. data/lib/datadog/tracing/contrib/stripe/request.rb +67 -0
  632. data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +2 -4
  633. data/lib/datadog/tracing/contrib/sucker_punch/exception_handler.rb +0 -2
  634. data/lib/datadog/tracing/contrib/sucker_punch/ext.rb +0 -2
  635. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +3 -6
  636. data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +3 -5
  637. data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +4 -8
  638. data/lib/datadog/tracing/contrib/utils/database.rb +0 -2
  639. data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +0 -2
  640. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +92 -14
  641. data/lib/datadog/tracing/contrib.rb +50 -50
  642. data/lib/datadog/tracing/correlation.rb +16 -4
  643. data/lib/datadog/{core → tracing}/diagnostics/ext.rb +1 -8
  644. data/lib/datadog/tracing/diagnostics/health.rb +38 -0
  645. data/lib/datadog/tracing/distributed/b3_multi.rb +72 -0
  646. data/lib/datadog/tracing/distributed/b3_single.rb +68 -0
  647. data/lib/datadog/tracing/distributed/datadog.rb +200 -0
  648. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +84 -0
  649. data/lib/datadog/tracing/distributed/fetcher.rb +21 -0
  650. data/lib/datadog/tracing/distributed/headers/ext.rb +19 -16
  651. data/lib/datadog/tracing/distributed/helpers.rb +27 -40
  652. data/lib/datadog/tracing/distributed/none.rb +18 -0
  653. data/lib/datadog/tracing/distributed/propagation.rb +126 -0
  654. data/lib/datadog/tracing/distributed/trace_context.rb +373 -0
  655. data/lib/datadog/tracing/event.rb +1 -3
  656. data/lib/datadog/tracing/flush.rb +57 -37
  657. data/lib/datadog/tracing/metadata/analytics.rb +2 -4
  658. data/lib/datadog/tracing/metadata/errors.rb +2 -4
  659. data/lib/datadog/tracing/metadata/ext.rb +18 -12
  660. data/lib/datadog/tracing/metadata/tagging.rb +17 -4
  661. data/lib/datadog/tracing/metadata.rb +3 -5
  662. data/lib/datadog/tracing/pipeline/span_filter.rb +10 -8
  663. data/lib/datadog/tracing/pipeline/span_processor.rb +0 -2
  664. data/lib/datadog/tracing/pipeline.rb +3 -5
  665. data/lib/datadog/tracing/propagation/http.rb +3 -100
  666. data/lib/datadog/tracing/runtime/metrics.rb +1 -3
  667. data/lib/datadog/tracing/sampling/all_sampler.rb +1 -3
  668. data/lib/datadog/tracing/sampling/ext.rb +30 -1
  669. data/lib/datadog/tracing/sampling/matcher.rb +0 -2
  670. data/lib/datadog/tracing/sampling/priority_sampler.rb +62 -11
  671. data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +10 -13
  672. data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +32 -10
  673. data/lib/datadog/tracing/sampling/rate_limiter.rb +4 -3
  674. data/lib/datadog/tracing/sampling/rate_sampler.rb +27 -12
  675. data/lib/datadog/tracing/sampling/rule.rb +3 -5
  676. data/lib/datadog/tracing/sampling/rule_sampler.rb +8 -9
  677. data/lib/datadog/tracing/sampling/sampler.rb +0 -2
  678. data/lib/datadog/tracing/sampling/span/ext.rb +25 -0
  679. data/lib/datadog/tracing/sampling/span/matcher.rb +9 -0
  680. data/lib/datadog/tracing/sampling/span/rule.rb +82 -0
  681. data/lib/datadog/tracing/sampling/span/rule_parser.rb +104 -0
  682. data/lib/datadog/tracing/sampling/span/sampler.rb +75 -0
  683. data/lib/datadog/tracing/span.rb +6 -24
  684. data/lib/datadog/tracing/span_operation.rb +11 -14
  685. data/lib/datadog/tracing/sync_writer.rb +5 -7
  686. data/lib/datadog/tracing/trace_digest.rb +88 -4
  687. data/lib/datadog/tracing/trace_operation.rb +60 -17
  688. data/lib/datadog/tracing/trace_segment.rb +20 -10
  689. data/lib/datadog/tracing/tracer.rb +49 -23
  690. data/lib/datadog/tracing/utils.rb +81 -0
  691. data/lib/datadog/tracing/workers/trace_writer.rb +9 -11
  692. data/lib/datadog/tracing/workers.rb +3 -5
  693. data/lib/datadog/tracing/writer.rb +12 -7
  694. data/lib/datadog/tracing.rb +8 -10
  695. data/lib/ddtrace/auto_instrument.rb +9 -4
  696. data/lib/ddtrace/auto_instrument_base.rb +0 -2
  697. data/lib/ddtrace/profiling/preload.rb +0 -2
  698. data/lib/ddtrace/transport/ext.rb +7 -3
  699. data/lib/ddtrace/transport/http/adapters/net.rb +3 -4
  700. data/lib/ddtrace/transport/http/adapters/registry.rb +0 -2
  701. data/lib/ddtrace/transport/http/adapters/test.rb +1 -3
  702. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +2 -4
  703. data/lib/ddtrace/transport/http/api/endpoint.rb +0 -2
  704. data/lib/ddtrace/transport/http/api/fallbacks.rb +0 -2
  705. data/lib/ddtrace/transport/http/api/instance.rb +0 -2
  706. data/lib/ddtrace/transport/http/api/map.rb +1 -3
  707. data/lib/ddtrace/transport/http/api/spec.rb +0 -2
  708. data/lib/ddtrace/transport/http/api.rb +4 -6
  709. data/lib/ddtrace/transport/http/builder.rb +5 -7
  710. data/lib/ddtrace/transport/http/client.rb +2 -4
  711. data/lib/ddtrace/transport/http/env.rb +0 -2
  712. data/lib/ddtrace/transport/http/response.rb +1 -3
  713. data/lib/ddtrace/transport/http/statistics.rb +1 -3
  714. data/lib/ddtrace/transport/http/traces.rb +6 -8
  715. data/lib/ddtrace/transport/http.rb +11 -12
  716. data/lib/ddtrace/transport/io/client.rb +2 -4
  717. data/lib/ddtrace/transport/io/response.rb +1 -3
  718. data/lib/ddtrace/transport/io/traces.rb +3 -7
  719. data/lib/ddtrace/transport/io.rb +3 -5
  720. data/lib/ddtrace/transport/parcel.rb +0 -4
  721. data/lib/ddtrace/transport/request.rb +0 -2
  722. data/lib/ddtrace/transport/response.rb +0 -2
  723. data/lib/ddtrace/transport/serializable_trace.rb +9 -5
  724. data/lib/ddtrace/transport/statistics.rb +2 -4
  725. data/lib/ddtrace/transport/trace_formatter.rb +21 -12
  726. data/lib/ddtrace/transport/traces.rb +9 -9
  727. data/lib/ddtrace/version.rb +2 -4
  728. data/lib/ddtrace.rb +6 -10
  729. metadata +131 -50
  730. data/.editorconfig +0 -22
  731. data/.gitignore +0 -58
  732. data/CONTRIBUTING.md +0 -81
  733. data/ddtrace.gemspec +0 -71
  734. data/docs/0.x-trace.png +0 -0
  735. data/docs/1.0-trace.png +0 -0
  736. data/docs/AutoInstrumentation.md +0 -36
  737. data/docs/Deprecation.md +0 -8
  738. data/docs/DevelopmentGuide.md +0 -259
  739. data/docs/GettingStarted.md +0 -2712
  740. data/docs/ProfilingDevelopment.md +0 -109
  741. data/docs/PublicApi.md +0 -14
  742. data/docs/UpgradeGuide.md +0 -736
  743. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +0 -269
  744. data/ext/ddtrace_profiling_native_extension/libddprof_helpers.h +0 -13
  745. data/lib/datadog/appsec/assets/waf_rules/risky.json +0 -1499
  746. data/lib/datadog/appsec/contrib/rack/request.rb +0 -58
  747. data/lib/datadog/appsec/contrib/rack/response.rb +0 -24
  748. data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +0 -42
  749. data/lib/datadog/profiling/old_ext.rb +0 -42
  750. data/lib/datadog/profiling/transport/http/api/endpoint.rb +0 -85
  751. data/lib/datadog/profiling/transport/http/api/instance.rb +0 -38
  752. data/lib/datadog/profiling/transport/http/api/spec.rb +0 -42
  753. data/lib/datadog/profiling/transport/http/api.rb +0 -45
  754. data/lib/datadog/profiling/transport/http/builder.rb +0 -30
  755. data/lib/datadog/profiling/transport/http/client.rb +0 -37
  756. data/lib/datadog/profiling/transport/http/response.rb +0 -21
  757. data/lib/datadog/profiling/transport/http.rb +0 -112
  758. data/lib/datadog/tracing/distributed/headers/b3.rb +0 -55
  759. data/lib/datadog/tracing/distributed/headers/b3_single.rb +0 -67
  760. data/lib/datadog/tracing/distributed/headers/datadog.rb +0 -52
  761. data/lib/datadog/tracing/distributed/headers/parser.rb +0 -37
  762. data/lib/datadog/tracing/distributed/metadata/b3.rb +0 -55
  763. data/lib/datadog/tracing/distributed/metadata/b3_single.rb +0 -66
  764. data/lib/datadog/tracing/distributed/metadata/datadog.rb +0 -73
  765. data/lib/datadog/tracing/distributed/metadata/parser.rb +0 -34
  766. data/lib/datadog/tracing/propagation/grpc.rb +0 -98
@@ -0,0 +1,821 @@
1
+ #include <ruby.h>
2
+ #include <ruby/thread.h>
3
+ #include <ruby/thread_native.h>
4
+ #include <ruby/debug.h>
5
+ #include <stdbool.h>
6
+ #include <stdatomic.h>
7
+ #include <signal.h>
8
+ #include <errno.h>
9
+
10
+ #include "helpers.h"
11
+ #include "ruby_helpers.h"
12
+ #include "collectors_thread_context.h"
13
+ #include "collectors_dynamic_sampling_rate.h"
14
+ #include "collectors_idle_sampling_helper.h"
15
+ #include "private_vm_api_access.h"
16
+ #include "setup_signal_handler.h"
17
+ #include "time_helpers.h"
18
+
19
+ // Used to trigger the execution of Collectors::ThreadState, which implements all of the sampling logic
20
+ // itself; this class only implements the "when to do it" part.
21
+ //
22
+ // This file implements the native bits of the Datadog::Profiling::Collectors::CpuAndWallTimeWorker class
23
+
24
+ // ---
25
+ // Here be dragons: This component is quite fiddly and probably one of the more complex in the profiler as it deals with
26
+ // multiple threads, signal handlers, global state, etc.
27
+ //
28
+ // ## Design notes for this class:
29
+ //
30
+ // ### Constraints
31
+ //
32
+ // Currently, sampling Ruby threads requires calling Ruby VM APIs that are only safe to call while holding on to the
33
+ // global VM lock (and are not async-signal safe -- cannot be called from a signal handler).
34
+ //
35
+ // @ivoanjo: As a note, I don't think we should think of this constraint as set in stone. Since can reach into the Ruby
36
+ // internals, we may be able to figure out a way of overcoming it. But it's definitely going to be hard so for now
37
+ // we're considering it as a given.
38
+ //
39
+ // ### Flow for triggering CPU/Wall-time samples
40
+ //
41
+ // The flow for triggering samples is as follows:
42
+ //
43
+ // 1. Inside the `run_sampling_trigger_loop` function (running in the `CpuAndWallTimeWorker` background thread),
44
+ // a `SIGPROF` signal gets sent to the current process.
45
+ //
46
+ // 2. The `handle_sampling_signal` signal handler function gets called to handle the `SIGPROF` signal.
47
+ //
48
+ // Which thread the signal handler function gets called on by the operating system is quite important. We need to perform
49
+ // an operation -- calling the `rb_postponed_job_register_one` API -- that can only be called from the thread that
50
+ // is holding on to the global VM lock. So this is the thread we're "hoping" our signal lands on.
51
+ //
52
+ // The signal never lands on the `CpuAndWallTimeWorker` background thread because we explicitly block it off from that
53
+ // thread in `block_sigprof_signal_handler_from_running_in_current_thread`.
54
+ //
55
+ // If the signal lands on a thread that is not holding onto the global VM lock, we can't proceed to the next step,
56
+ // and we need to restart the sampling flow from step 1. (There's still quite a few improvements we can make here,
57
+ // but this is the current state of the implementation).
58
+ //
59
+ // 3. Inside `handle_sampling_signal`, if it's getting executed by the Ruby thread that is holding the global VM lock,
60
+ // we can call `rb_postponed_job_register_one` to ask the Ruby VM to call our `sample_from_postponed_job` function
61
+ // "as soon as it can".
62
+ //
63
+ // 4. The Ruby VM calls our `sample_from_postponed_job` from a thread holding the global VM lock. A sample is recorded by
64
+ // calling `thread_context_collector_sample`.
65
+ //
66
+ // ### TracePoints and Forking
67
+ //
68
+ // When the Ruby VM forks, the CPU/Wall-time profiling stops naturally because it's triggered by a background thread
69
+ // that doesn't get automatically restarted by the VM on the child process. (The profiler does trigger its restart at
70
+ // some point -- see `Profiling::Tasks::Setup` for details).
71
+ //
72
+ // But this doesn't apply to any `TracePoint`s this class may use, which will continue to be active. Thus, we need to
73
+ // always remember consider this case of -- the worker thread may not be alive but the `TracePoint`s can continue to
74
+ // trigger samples.
75
+ //
76
+ // ---
77
+
78
+ // Contains state for a single CpuAndWallTimeWorker instance
79
+ struct cpu_and_wall_time_worker_state {
80
+ atomic_bool should_run;
81
+
82
+ bool gc_profiling_enabled;
83
+ bool allocation_counting_enabled;
84
+ VALUE self_instance;
85
+ VALUE thread_context_collector_instance;
86
+ VALUE idle_sampling_helper_instance;
87
+ VALUE owner_thread;
88
+ dynamic_sampling_rate_state dynamic_sampling_rate;
89
+
90
+ // When something goes wrong during sampling, we record the Ruby exception here, so that it can be "re-raised" on
91
+ // the CpuAndWallTimeWorker thread
92
+ VALUE failure_exception;
93
+ // Used by `_native_stop` to flag the worker thread to start (see comment on `_native_sampling_loop`)
94
+ VALUE stop_thread;
95
+
96
+ // Used to get gc start/finish information
97
+ VALUE gc_tracepoint;
98
+
99
+ VALUE object_allocation_tracepoint;
100
+
101
+ struct stats {
102
+ // How many times we tried to trigger a sample
103
+ unsigned int trigger_sample_attempts;
104
+ // How many times we tried to simulate signal delivery
105
+ unsigned int trigger_simulated_signal_delivery_attempts;
106
+ // How many times we actually simulated signal delivery
107
+ unsigned int simulated_signal_delivery;
108
+ // How many times we actually called rb_postponed_job_register_one from a signal handler
109
+ unsigned int signal_handler_enqueued_sample;
110
+ // How many times the signal handler was called from the wrong thread
111
+ unsigned int signal_handler_wrong_thread;
112
+ // How many times we actually sampled (except GC samples)
113
+ unsigned int sampled;
114
+ // Min/max/total wall-time spent sampling (except GC samples)
115
+ uint64_t sampling_time_ns_min;
116
+ uint64_t sampling_time_ns_max;
117
+ uint64_t sampling_time_ns_total;
118
+ } stats;
119
+ };
120
+
121
+ static VALUE _native_new(VALUE klass);
122
+ static VALUE _native_initialize(
123
+ DDTRACE_UNUSED VALUE _self,
124
+ VALUE self_instance,
125
+ VALUE thread_context_collector_instance,
126
+ VALUE gc_profiling_enabled,
127
+ VALUE idle_sampling_helper_instance,
128
+ VALUE allocation_counting_enabled
129
+ );
130
+ static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr);
131
+ static VALUE _native_sampling_loop(VALUE self, VALUE instance);
132
+ static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread);
133
+ static VALUE stop(VALUE self_instance, VALUE optional_exception);
134
+ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext);
135
+ static void *run_sampling_trigger_loop(void *state_ptr);
136
+ static void interrupt_sampling_trigger_loop(void *state_ptr);
137
+ static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused);
138
+ static VALUE rescued_sample_from_postponed_job(VALUE self_instance);
139
+ static VALUE handle_sampling_failure(VALUE self_instance, VALUE exception);
140
+ static VALUE _native_current_sigprof_signal_handler(DDTRACE_UNUSED VALUE self);
141
+ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance);
142
+ static VALUE _native_is_running(DDTRACE_UNUSED VALUE self, VALUE instance);
143
+ static void testing_signal_handler(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext);
144
+ static VALUE _native_install_testing_signal_handler(DDTRACE_UNUSED VALUE self);
145
+ static VALUE _native_remove_testing_signal_handler(DDTRACE_UNUSED VALUE self);
146
+ static VALUE _native_trigger_sample(DDTRACE_UNUSED VALUE self);
147
+ static VALUE _native_gc_tracepoint(DDTRACE_UNUSED VALUE self, VALUE instance);
148
+ static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused);
149
+ static void after_gc_from_postponed_job(DDTRACE_UNUSED void *_unused);
150
+ static VALUE safely_call(VALUE (*function_to_call_safely)(VALUE), VALUE function_to_call_safely_arg, VALUE instance);
151
+ static VALUE _native_simulate_handle_sampling_signal(DDTRACE_UNUSED VALUE self);
152
+ static VALUE _native_simulate_sample_from_postponed_job(DDTRACE_UNUSED VALUE self);
153
+ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE instance);
154
+ static VALUE _native_is_sigprof_blocked_in_current_thread(DDTRACE_UNUSED VALUE self);
155
+ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance);
156
+ void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused);
157
+ static void grab_gvl_and_sample(void);
158
+ static void reset_stats(struct cpu_and_wall_time_worker_state *state);
159
+ static void sleep_for(uint64_t time_ns);
160
+ static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self);
161
+ static void on_newobj_event(DDTRACE_UNUSED VALUE tracepoint_data, DDTRACE_UNUSED void *unused);
162
+ static void disable_tracepoints(struct cpu_and_wall_time_worker_state *state);
163
+
164
+ // Note on sampler global state safety:
165
+ //
166
+ // Both `active_sampler_instance` and `active_sampler_instance_state` are **GLOBAL** state. Be careful when accessing
167
+ // or modifying them.
168
+ // In particular, it's important to only mutate them while holding the global VM lock, to ensure correctness.
169
+ //
170
+ // This global state is needed because a bunch of functions on this file need to access it from situations
171
+ // (e.g. signal handler) where it's impossible or just awkward to pass it as an argument.
172
+ static VALUE active_sampler_instance = Qnil;
173
+ static struct cpu_and_wall_time_worker_state *active_sampler_instance_state = NULL;
174
+
175
+ // Used to implement CpuAndWallTimeWorker._native_allocation_count . To be able to use cheap thread-local variables
176
+ // (here with `__thread`, see https://gcc.gnu.org/onlinedocs/gcc/Thread-Local.html), this needs to be global.
177
+ //
178
+ // Carryover of state between profiler instances can happen and is not considered to be a problem -- see expectations for this
179
+ // API documented in profiling.rb .
180
+ __thread uint64_t allocation_count = 0;
181
+
182
+ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
183
+ rb_global_variable(&active_sampler_instance);
184
+
185
+ VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
186
+ VALUE collectors_cpu_and_wall_time_worker_class = rb_define_class_under(collectors_module, "CpuAndWallTimeWorker", rb_cObject);
187
+ // Hosts methods used for testing the native code using RSpec
188
+ VALUE testing_module = rb_define_module_under(collectors_cpu_and_wall_time_worker_class, "Testing");
189
+
190
+ // Instances of the CpuAndWallTimeWorker class are "TypedData" objects.
191
+ // "TypedData" objects are special objects in the Ruby VM that can wrap C structs.
192
+ // In this case, it wraps the cpu_and_wall_time_worker_state.
193
+ //
194
+ // Because Ruby doesn't know how to initialize native-level structs, we MUST override the allocation function for objects
195
+ // of this class so that we can manage this part. Not overriding or disabling the allocation function is a common
196
+ // gotcha for "TypedData" objects that can very easily lead to VM crashes, see for instance
197
+ // https://bugs.ruby-lang.org/issues/18007 for a discussion around this.
198
+ rb_define_alloc_func(collectors_cpu_and_wall_time_worker_class, _native_new);
199
+
200
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_initialize", _native_initialize, 5);
201
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_sampling_loop", _native_sampling_loop, 1);
202
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stop", _native_stop, 2);
203
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_reset_after_fork", _native_reset_after_fork, 1);
204
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stats", _native_stats, 1);
205
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_allocation_count", _native_allocation_count, 0);
206
+ rb_define_singleton_method(testing_module, "_native_current_sigprof_signal_handler", _native_current_sigprof_signal_handler, 0);
207
+ rb_define_singleton_method(testing_module, "_native_is_running?", _native_is_running, 1);
208
+ rb_define_singleton_method(testing_module, "_native_install_testing_signal_handler", _native_install_testing_signal_handler, 0);
209
+ rb_define_singleton_method(testing_module, "_native_remove_testing_signal_handler", _native_remove_testing_signal_handler, 0);
210
+ rb_define_singleton_method(testing_module, "_native_trigger_sample", _native_trigger_sample, 0);
211
+ rb_define_singleton_method(testing_module, "_native_gc_tracepoint", _native_gc_tracepoint, 1);
212
+ rb_define_singleton_method(testing_module, "_native_simulate_handle_sampling_signal", _native_simulate_handle_sampling_signal, 0);
213
+ rb_define_singleton_method(testing_module, "_native_simulate_sample_from_postponed_job", _native_simulate_sample_from_postponed_job, 0);
214
+ rb_define_singleton_method(testing_module, "_native_is_sigprof_blocked_in_current_thread", _native_is_sigprof_blocked_in_current_thread, 0);
215
+ }
216
+
217
+ // This structure is used to define a Ruby object that stores a pointer to a struct cpu_and_wall_time_worker_state
218
+ // See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works
219
+ static const rb_data_type_t cpu_and_wall_time_worker_typed_data = {
220
+ .wrap_struct_name = "Datadog::Profiling::Collectors::CpuAndWallTimeWorker",
221
+ .function = {
222
+ .dmark = cpu_and_wall_time_worker_typed_data_mark,
223
+ .dfree = RUBY_DEFAULT_FREE,
224
+ .dsize = NULL, // We don't track memory usage (although it'd be cool if we did!)
225
+ //.dcompact = NULL, // FIXME: Add support for compaction
226
+ },
227
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
228
+ };
229
+
230
+ static VALUE _native_new(VALUE klass) {
231
+ struct cpu_and_wall_time_worker_state *state = ruby_xcalloc(1, sizeof(struct cpu_and_wall_time_worker_state));
232
+
233
+ atomic_init(&state->should_run, false);
234
+ state->gc_profiling_enabled = false;
235
+ state->allocation_counting_enabled = false;
236
+ state->thread_context_collector_instance = Qnil;
237
+ state->idle_sampling_helper_instance = Qnil;
238
+ state->owner_thread = Qnil;
239
+ dynamic_sampling_rate_init(&state->dynamic_sampling_rate);
240
+ state->failure_exception = Qnil;
241
+ state->stop_thread = Qnil;
242
+ state->gc_tracepoint = Qnil;
243
+ state->object_allocation_tracepoint = Qnil;
244
+ reset_stats(state);
245
+
246
+ return state->self_instance = TypedData_Wrap_Struct(klass, &cpu_and_wall_time_worker_typed_data, state);
247
+ }
248
+
249
+ static VALUE _native_initialize(
250
+ DDTRACE_UNUSED VALUE _self,
251
+ VALUE self_instance,
252
+ VALUE thread_context_collector_instance,
253
+ VALUE gc_profiling_enabled,
254
+ VALUE idle_sampling_helper_instance,
255
+ VALUE allocation_counting_enabled
256
+ ) {
257
+ ENFORCE_BOOLEAN(gc_profiling_enabled);
258
+ ENFORCE_BOOLEAN(allocation_counting_enabled);
259
+
260
+ struct cpu_and_wall_time_worker_state *state;
261
+ TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
262
+
263
+ state->gc_profiling_enabled = (gc_profiling_enabled == Qtrue);
264
+ state->allocation_counting_enabled = (allocation_counting_enabled == Qtrue);
265
+ state->thread_context_collector_instance = enforce_thread_context_collector_instance(thread_context_collector_instance);
266
+ state->idle_sampling_helper_instance = idle_sampling_helper_instance;
267
+ state->gc_tracepoint = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_GC_ENTER | RUBY_INTERNAL_EVENT_GC_EXIT, on_gc_event, NULL /* unused */);
268
+ state->object_allocation_tracepoint = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_NEWOBJ, on_newobj_event, NULL /* unused */);
269
+
270
+ return Qtrue;
271
+ }
272
+
273
+ // Since our state contains references to Ruby objects, we need to tell the Ruby GC about them
274
+ static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr) {
275
+ struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr;
276
+
277
+ rb_gc_mark(state->thread_context_collector_instance);
278
+ rb_gc_mark(state->idle_sampling_helper_instance);
279
+ rb_gc_mark(state->owner_thread);
280
+ rb_gc_mark(state->failure_exception);
281
+ rb_gc_mark(state->stop_thread);
282
+ rb_gc_mark(state->gc_tracepoint);
283
+ rb_gc_mark(state->object_allocation_tracepoint);
284
+ }
285
+
286
+ // Called in a background thread created in CpuAndWallTimeWorker#start
287
+ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
288
+ struct cpu_and_wall_time_worker_state *state;
289
+ TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
290
+
291
+ struct cpu_and_wall_time_worker_state *old_state = active_sampler_instance_state;
292
+ if (old_state != NULL) {
293
+ if (is_thread_alive(old_state->owner_thread)) {
294
+ rb_raise(
295
+ rb_eRuntimeError,
296
+ "Could not start CpuAndWallTimeWorker: There's already another instance of CpuAndWallTimeWorker active in a different thread"
297
+ );
298
+ } else {
299
+ // The previously active thread seems to have died without cleaning up after itself.
300
+ // In this case, we can still go ahead and start the profiler BUT we make sure to disable any existing tracepoint
301
+ // first as:
302
+ // a) If this is a new instance of the CpuAndWallTimeWorker, we don't want the tracepoint from the old instance
303
+ // being kept around
304
+ // b) If this is the same instance of the CpuAndWallTimeWorker if we call enable on a tracepoint that is already
305
+ // enabled, it will start firing more than once, see https://bugs.ruby-lang.org/issues/19114 for details.
306
+ disable_tracepoints(old_state);
307
+ }
308
+ }
309
+
310
+ // We use `stop_thread` to distinguish when `_native_stop` was called before we actually had a chance to start. In this
311
+ // situation we stop immediately and never even start the sampling trigger loop.
312
+ if (state->stop_thread == rb_thread_current()) return Qnil;
313
+
314
+ // Reset the dynamic sampling rate state, if any (reminder: the monotonic clock reference may change after a fork)
315
+ dynamic_sampling_rate_reset(&state->dynamic_sampling_rate);
316
+
317
+ // This write to a global is thread-safe BECAUSE we're still holding on to the global VM lock at this point
318
+ active_sampler_instance_state = state;
319
+ active_sampler_instance = instance;
320
+ state->owner_thread = rb_thread_current();
321
+
322
+ atomic_store(&state->should_run, true);
323
+
324
+ block_sigprof_signal_handler_from_running_in_current_thread(); // We want to interrupt the thread with the global VM lock, never this one
325
+
326
+ // Release GVL, get to the actual work!
327
+ int exception_state;
328
+ rb_protect(release_gvl_and_run_sampling_trigger_loop, instance, &exception_state);
329
+
330
+ // The sample trigger loop finished (either cleanly or with an error); let's clean up
331
+
332
+ disable_tracepoints(state);
333
+
334
+ active_sampler_instance_state = NULL;
335
+ active_sampler_instance = Qnil;
336
+ state->owner_thread = Qnil;
337
+
338
+ // If this `Thread` is about to die, why is this important? It's because Ruby caches native threads for a period after
339
+ // the `Thread` dies, and reuses them if a new Ruby `Thread` gets created. This means that while conceptually the
340
+ // worker background `Thread` is about to die, the low-level native OS thread can be reused for something else in the Ruby app.
341
+ // Then, the reused thread would "inherit" the SIGPROF blocking, which is... really unexpected.
342
+ // This actually caused a flaky test -- the `native_extension_spec.rb` creates a `Thread` and tries to specifically
343
+ // send SIGPROF signals to it, and oops it could fail if it got the reused native thread from the worker which still
344
+ // had SIGPROF delivery blocked. :hide_the_pain_harold:
345
+ unblock_sigprof_signal_handler_from_running_in_current_thread();
346
+
347
+ // Why replace and not use remove the signal handler? We do this because when a process receives a SIGPROF without
348
+ // having an explicit signal handler set up, the process will instantly terminate with a confusing
349
+ // "Profiling timer expired" message left behind. (This message doesn't come from us -- it's the default message for
350
+ // an unhandled SIGPROF. Pretty confusing UNIX/POSIX behavior...)
351
+ //
352
+ // Unfortunately, because signal delivery is asynchronous, there's no way to guarantee that there are no pending
353
+ // profiler-sent signals by the time we get here and want to clean up.
354
+ // @ivoanjo: I suspect this will never happen, but the cost of getting it wrong is really high (VM terminates) so this
355
+ // is a just-in-case situation.
356
+ //
357
+ // Note 2: This can raise exceptions as well, so make sure that all cleanups are done by the time we get here.
358
+ replace_sigprof_signal_handler_with_empty_handler(handle_sampling_signal);
359
+
360
+ // Ensure that instance is not garbage collected while the native sampling loop is running; this is probably not needed, but just in case
361
+ RB_GC_GUARD(instance);
362
+
363
+ if (exception_state) rb_jump_tag(exception_state); // Re-raise any exception that happened
364
+
365
+ return Qnil;
366
+ }
367
+
368
+ static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE worker_thread) {
369
+ struct cpu_and_wall_time_worker_state *state;
370
+ TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
371
+
372
+ state->stop_thread = worker_thread;
373
+
374
+ return stop(self_instance, /* optional_exception: */ Qnil);
375
+ }
376
+
377
+ static VALUE stop(VALUE self_instance, VALUE optional_exception) {
378
+ struct cpu_and_wall_time_worker_state *state;
379
+ TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
380
+
381
+ atomic_store(&state->should_run, false);
382
+ state->failure_exception = optional_exception;
383
+
384
+ // Disable the tracepoints as soon as possible, so the VM doesn't keep on calling them
385
+ disable_tracepoints(state);
386
+
387
+ return Qtrue;
388
+ }
389
+
390
+ // NOTE: Remember that this will run in the thread and within the scope of user code, including user C code.
391
+ // We need to be careful not to change any state that may be observed OR to restore it if we do. For instance, if anything
392
+ // we do here can set `errno`, then we must be careful to restore the old `errno` after the fact.
393
+ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) {
394
+ struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
395
+
396
+ // This can potentially happen if the CpuAndWallTimeWorker was stopped while the signal delivery was happening; nothing to do
397
+ if (state == NULL) return;
398
+
399
+ if (
400
+ !ruby_native_thread_p() || // Not a Ruby thread
401
+ !is_current_thread_holding_the_gvl() || // Not safe to enqueue a sample from this thread
402
+ !ddtrace_rb_ractor_main_p() // We're not on the main Ractor; we currently don't support profiling non-main Ractors
403
+ ) {
404
+ state->stats.signal_handler_wrong_thread++;
405
+ return;
406
+ }
407
+
408
+ // We implicitly assume there can be no concurrent nor nested calls to handle_sampling_signal because
409
+ // a) we get triggered using SIGPROF, and the docs state second SIGPROF will not interrupt an existing one
410
+ // b) we validate we are in the thread that has the global VM lock; if a different thread gets a signal, it will return early
411
+ // because it will not have the global VM lock
412
+
413
+ // Note: rb_postponed_job_register_one ensures that if there's a previous sample_from_postponed_job queued for execution
414
+ // then we will not queue a second one. It does this by doing a linear scan on the existing jobs; in the future we
415
+ // may want to implement that check ourselves.
416
+
417
+ state->stats.signal_handler_enqueued_sample++;
418
+
419
+ // Note: If we ever want to get rid of rb_postponed_job_register_one, remember not to clobber Ruby exceptions, as
420
+ // this function does this helpful job for us now -- https://github.com/ruby/ruby/commit/a98e343d39c4d7bf1e2190b076720f32d9f298b3.
421
+ /*int result =*/ rb_postponed_job_register_one(0, sample_from_postponed_job, NULL);
422
+ // TODO: Do something with result (potentially update tracking counters?)
423
+ }
424
+
425
+ // The actual sampling trigger loop always runs **without** the global vm lock.
426
+ static void *run_sampling_trigger_loop(void *state_ptr) {
427
+ struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr;
428
+
429
+ uint64_t minimum_time_between_signals = MILLIS_AS_NS(10);
430
+
431
+ while (atomic_load(&state->should_run)) {
432
+ state->stats.trigger_sample_attempts++;
433
+
434
+ // TODO: This is still a placeholder for a more complex mechanism. In particular:
435
+ // * We want to do more than having a fixed sampling rate
436
+
437
+ current_gvl_owner owner = gvl_owner();
438
+ if (owner.valid) {
439
+ // Note that reading the GVL owner and sending them a signal is a race -- the Ruby VM keeps on executing while
440
+ // we're doing this, so we may still not signal the correct thread from time to time, but our signal handler
441
+ // includes a check to see if it got called in the right thread
442
+ pthread_kill(owner.owner, SIGPROF);
443
+ } else {
444
+ // If no thread owns the Global VM Lock, the application is probably idle at the moment. We still want to sample
445
+ // so we "ask a friend" (the IdleSamplingHelper component) to grab the GVL and simulate getting a SIGPROF.
446
+ //
447
+ // In a previous version of the code, we called `grab_gvl_and_sample` directly BUT this was problematic because
448
+ // Ruby may concurrently get busy and so the CpuAndWallTimeWorker would be blocked in line to acquire the GVL
449
+ // for an uncontrolled amount of time. (This can still happen to the IdleSamplingHelper, but the
450
+ // CpuAndWallTimeWorker will still be free to interrupt the Ruby VM and keep sampling for the entire blocking period).
451
+ state->stats.trigger_simulated_signal_delivery_attempts++;
452
+ idle_sampling_helper_request_action(state->idle_sampling_helper_instance, grab_gvl_and_sample);
453
+ }
454
+
455
+ sleep_for(minimum_time_between_signals);
456
+
457
+ // The dynamic sampling rate module keeps track of how long samples are taking, and in here we extend our sleep time
458
+ // to take that into account.
459
+ // Note that we deliberately should NOT combine this sleep_for with the one above because the result of
460
+ // `dynamic_sampling_rate_get_sleep` may have changed while the above sleep was ongoing.
461
+ uint64_t extra_sleep =
462
+ dynamic_sampling_rate_get_sleep(&state->dynamic_sampling_rate, monotonic_wall_time_now_ns(DO_NOT_RAISE_ON_FAILURE));
463
+ if (extra_sleep > 0) sleep_for(extra_sleep);
464
+ }
465
+
466
+ return NULL; // Unused
467
+ }
468
+
469
+ // This is called by the Ruby VM when it wants to shut down the background thread
470
+ static void interrupt_sampling_trigger_loop(void *state_ptr) {
471
+ struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr;
472
+
473
+ atomic_store(&state->should_run, false);
474
+ }
475
+
476
+ static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused) {
477
+ struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
478
+
479
+ // This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do
480
+ if (state == NULL) return;
481
+
482
+ // @ivoanjo: I'm not sure this can ever happen because `handle_sampling_signal` only enqueues this callback if
483
+ // it's running on the main Ractor, but just in case...
484
+ if (!ddtrace_rb_ractor_main_p()) {
485
+ return; // We're not on the main Ractor; we currently don't support profiling non-main Ractors
486
+ }
487
+
488
+ // Rescue against any exceptions that happen during sampling
489
+ safely_call(rescued_sample_from_postponed_job, state->self_instance, state->self_instance);
490
+ }
491
+
492
+ static VALUE rescued_sample_from_postponed_job(VALUE self_instance) {
493
+ struct cpu_and_wall_time_worker_state *state;
494
+ TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
495
+
496
+ long wall_time_ns_before_sample = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
497
+
498
+ if (!dynamic_sampling_rate_should_sample(&state->dynamic_sampling_rate, wall_time_ns_before_sample)) {
499
+ // TODO: Add a counter for this
500
+ return Qnil;
501
+ }
502
+
503
+ state->stats.sampled++;
504
+
505
+ VALUE profiler_overhead_stack_thread = state->owner_thread; // Used to attribute profiler overhead to a different stack
506
+ thread_context_collector_sample(state->thread_context_collector_instance, wall_time_ns_before_sample, profiler_overhead_stack_thread);
507
+
508
+ long wall_time_ns_after_sample = monotonic_wall_time_now_ns(RAISE_ON_FAILURE);
509
+ long delta_ns = wall_time_ns_after_sample - wall_time_ns_before_sample;
510
+
511
+ // Guard against wall-time going backwards, see https://github.com/DataDog/dd-trace-rb/pull/2336 for discussion.
512
+ uint64_t sampling_time_ns = delta_ns < 0 ? 0 : delta_ns;
513
+
514
+ state->stats.sampling_time_ns_min = uint64_min_of(sampling_time_ns, state->stats.sampling_time_ns_min);
515
+ state->stats.sampling_time_ns_max = uint64_max_of(sampling_time_ns, state->stats.sampling_time_ns_max);
516
+ state->stats.sampling_time_ns_total += sampling_time_ns;
517
+
518
+ dynamic_sampling_rate_after_sample(&state->dynamic_sampling_rate, wall_time_ns_after_sample, sampling_time_ns);
519
+
520
+ // Return a dummy VALUE because we're called from rb_rescue2 which requires it
521
+ return Qnil;
522
+ }
523
+
524
+ static VALUE handle_sampling_failure(VALUE self_instance, VALUE exception) {
525
+ stop(self_instance, exception);
526
+ return Qnil;
527
+ }
528
+
529
+ // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
530
+ // It SHOULD NOT be used for other purposes.
531
+ static VALUE _native_current_sigprof_signal_handler(DDTRACE_UNUSED VALUE self) {
532
+ struct sigaction existing_signal_handler_config = {.sa_sigaction = NULL};
533
+ if (sigaction(SIGPROF, NULL, &existing_signal_handler_config) != 0) {
534
+ rb_sys_fail("Failed to probe existing handler");
535
+ }
536
+
537
+ if (existing_signal_handler_config.sa_sigaction == handle_sampling_signal) {
538
+ return ID2SYM(rb_intern("profiling"));
539
+ } else if (existing_signal_handler_config.sa_sigaction == empty_signal_handler) {
540
+ return ID2SYM(rb_intern("empty"));
541
+ } else if (existing_signal_handler_config.sa_sigaction != NULL) {
542
+ return ID2SYM(rb_intern("other"));
543
+ } else {
544
+ return Qnil;
545
+ }
546
+ }
547
+
548
+ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
549
+ struct cpu_and_wall_time_worker_state *state;
550
+ TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
551
+
552
+ // Final preparations: Setup signal handler and enable tracepoints. We run these here and not in `_native_sampling_loop`
553
+ // because they may raise exceptions.
554
+ install_sigprof_signal_handler(handle_sampling_signal, "handle_sampling_signal");
555
+ if (state->gc_profiling_enabled) rb_tracepoint_enable(state->gc_tracepoint);
556
+ if (state->allocation_counting_enabled) rb_tracepoint_enable(state->object_allocation_tracepoint);
557
+
558
+ rb_thread_call_without_gvl(run_sampling_trigger_loop, state, interrupt_sampling_trigger_loop, state);
559
+
560
+ // If we stopped sampling due to an exception, re-raise it (now in the worker thread)
561
+ if (state->failure_exception != Qnil) rb_exc_raise(state->failure_exception);
562
+
563
+ return Qnil;
564
+ }
565
+
566
+ // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
567
+ // It SHOULD NOT be used for other purposes.
568
+ static VALUE _native_is_running(DDTRACE_UNUSED VALUE self, VALUE instance) {
569
+ struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
570
+
571
+ return (state != NULL && is_thread_alive(state->owner_thread) && state->self_instance == instance) ? Qtrue : Qfalse;
572
+ }
573
+
574
+ static void testing_signal_handler(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) {
575
+ /* Does nothing on purpose */
576
+ }
577
+
578
+ // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
579
+ // It SHOULD NOT be used for other purposes.
580
+ static VALUE _native_install_testing_signal_handler(DDTRACE_UNUSED VALUE self) {
581
+ install_sigprof_signal_handler(testing_signal_handler, "testing_signal_handler");
582
+ return Qtrue;
583
+ }
584
+
585
+ // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
586
+ // It SHOULD NOT be used for other purposes.
587
+ static VALUE _native_remove_testing_signal_handler(DDTRACE_UNUSED VALUE self) {
588
+ remove_sigprof_signal_handler();
589
+ return Qtrue;
590
+ }
591
+
592
+ // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
593
+ // It SHOULD NOT be used for other purposes.
594
+ static VALUE _native_trigger_sample(DDTRACE_UNUSED VALUE self) {
595
+ sample_from_postponed_job(NULL);
596
+ return Qtrue;
597
+ }
598
+
599
+ // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
600
+ // It SHOULD NOT be used for other purposes.
601
+ static VALUE _native_gc_tracepoint(DDTRACE_UNUSED VALUE self, VALUE instance) {
602
+ struct cpu_and_wall_time_worker_state *state;
603
+ TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
604
+
605
+ return state->gc_tracepoint;
606
+ }
607
+
608
+ // Implements tracking of cpu-time and wall-time spent doing GC. This function is called by Ruby from the `gc_tracepoint`
609
+ // when the RUBY_INTERNAL_EVENT_GC_ENTER and RUBY_INTERNAL_EVENT_GC_EXIT events are triggered.
610
+ //
611
+ // See the comments on
612
+ // * thread_context_collector_on_gc_start
613
+ // * thread_context_collector_on_gc_finish
614
+ // * thread_context_collector_sample_after_gc
615
+ //
616
+ // For the expected times in which to call them, and their assumptions.
617
+ //
618
+ // Safety: This function gets called while Ruby is doing garbage collection. While Ruby is doing garbage collection,
619
+ // *NO ALLOCATION* is allowed. This function, and any it calls must never trigger memory or object allocation.
620
+ // This includes exceptions and use of ruby_xcalloc (because xcalloc can trigger GC)!
621
+ static void on_gc_event(VALUE tracepoint_data, DDTRACE_UNUSED void *unused) {
622
+ if (!ddtrace_rb_ractor_main_p()) {
623
+ return; // We're not on the main Ractor; we currently don't support profiling non-main Ractors
624
+ }
625
+
626
+ int event = rb_tracearg_event_flag(rb_tracearg_from_tracepoint(tracepoint_data));
627
+ if (event != RUBY_INTERNAL_EVENT_GC_ENTER && event != RUBY_INTERNAL_EVENT_GC_EXIT) return; // Unknown event
628
+
629
+ struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
630
+
631
+ // This should not happen in a normal situation because the tracepoint is always enabled after the instance is set
632
+ // and disabled before it is cleared, but just in case...
633
+ if (state == NULL) return;
634
+
635
+ if (event == RUBY_INTERNAL_EVENT_GC_ENTER) {
636
+ thread_context_collector_on_gc_start(state->thread_context_collector_instance);
637
+ } else if (event == RUBY_INTERNAL_EVENT_GC_EXIT) {
638
+ // Design: In an earlier iteration of this feature (see https://github.com/DataDog/dd-trace-rb/pull/2308) we
639
+ // actually had a single method to implement the behavior of both thread_context_collector_on_gc_finish
640
+ // and thread_context_collector_sample_after_gc (the latter is called via after_gc_from_postponed_job).
641
+ //
642
+ // Unfortunately, then we discovered the safety issue around no allocations, and thus decided to separate them -- so that
643
+ // the sampling could run outside the tight safety constraints of the garbage collection process.
644
+ //
645
+ // There is a downside: The sample is now taken very very shortly afterwards the GC finishes, and not immediately
646
+ // as the GC finishes, which means the stack captured may by affected by "skid", e.g. point slightly after where
647
+ // it should be pointing at.
648
+ // Alternatives to solve this would be to capture no stack for garbage collection (as we do for Java and .net);
649
+ // making the sampling process allocation-safe (very hard); or separate stack sampling from sample recording,
650
+ // e.g. enabling us to capture the stack in thread_context_collector_on_gc_finish and do the rest later
651
+ // (medium hard).
652
+
653
+ thread_context_collector_on_gc_finish(state->thread_context_collector_instance);
654
+ // We use rb_postponed_job_register_one to ask Ruby to run thread_context_collector_sample_after_gc after if
655
+ // fully finishes the garbage collection, so that one is allowed to do allocations and throw exceptions as usual.
656
+ //
657
+ // Note: If we ever want to get rid of rb_postponed_job_register_one, remember not to clobber Ruby exceptions, as
658
+ // this function does this helpful job for us now -- https://github.com/ruby/ruby/commit/a98e343d39c4d7bf1e2190b076720f32d9f298b3.
659
+ rb_postponed_job_register_one(0, after_gc_from_postponed_job, NULL);
660
+ }
661
+ }
662
+
663
+ static void after_gc_from_postponed_job(DDTRACE_UNUSED void *_unused) {
664
+ struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
665
+
666
+ // This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do
667
+ if (state == NULL) return;
668
+
669
+ // @ivoanjo: I'm not sure this can ever happen because `on_gc_event` only enqueues this callback if
670
+ // it's running on the main Ractor, but just in case...
671
+ if (!ddtrace_rb_ractor_main_p()) {
672
+ return; // We're not on the main Ractor; we currently don't support profiling non-main Ractors
673
+ }
674
+
675
+ // Trigger sampling using the Collectors::ThreadState; rescue against any exceptions that happen during sampling
676
+ safely_call(thread_context_collector_sample_after_gc, state->thread_context_collector_instance, state->self_instance);
677
+ }
678
+
679
+ // Equivalent to Ruby begin/rescue call, where we call a C function and jump to the exception handler if an
680
+ // exception gets raised within
681
+ static VALUE safely_call(VALUE (*function_to_call_safely)(VALUE), VALUE function_to_call_safely_arg, VALUE instance) {
682
+ VALUE exception_handler_function_arg = instance;
683
+ return rb_rescue2(
684
+ function_to_call_safely,
685
+ function_to_call_safely_arg,
686
+ handle_sampling_failure,
687
+ exception_handler_function_arg,
688
+ rb_eException, // rb_eException is the base class of all Ruby exceptions
689
+ 0 // Required by API to be the last argument
690
+ );
691
+ }
692
+
693
+ // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
694
+ // It SHOULD NOT be used for other purposes.
695
+ static VALUE _native_simulate_handle_sampling_signal(DDTRACE_UNUSED VALUE self) {
696
+ handle_sampling_signal(0, NULL, NULL);
697
+ return Qtrue;
698
+ }
699
+
700
+ // This method exists only to enable testing Datadog::Profiling::Collectors::CpuAndWallTimeWorker behavior using RSpec.
701
+ // It SHOULD NOT be used for other purposes.
702
+ static VALUE _native_simulate_sample_from_postponed_job(DDTRACE_UNUSED VALUE self) {
703
+ sample_from_postponed_job(NULL);
704
+ return Qtrue;
705
+ }
706
+
707
+ // After the Ruby VM forks, this method gets called in the child process to clean up any leftover state from the parent.
708
+ //
709
+ // Assumption: This method gets called BEFORE restarting profiling. Note that profiling-related tracepoints may still
710
+ // be active, so we make sure to disable them before calling into anything else, so that there are no components
711
+ // attempting to trigger samples at the same time as the reset is done.
712
+ //
713
+ // In the future, if we add more other components with tracepoints, we will need to coordinate stopping all such
714
+ // tracepoints before doing the other cleaning steps.
715
+ static VALUE _native_reset_after_fork(DDTRACE_UNUSED VALUE self, VALUE instance) {
716
+ struct cpu_and_wall_time_worker_state *state;
717
+ TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
718
+
719
+ // Disable all tracepoints, so that there are no more attempts to mutate the profile
720
+ disable_tracepoints(state);
721
+
722
+ reset_stats(state);
723
+
724
+ // Remove all state from the `Collectors::ThreadState` and connected downstream components
725
+ rb_funcall(state->thread_context_collector_instance, rb_intern("reset_after_fork"), 0);
726
+
727
+ return Qtrue;
728
+ }
729
+
730
+ static VALUE _native_is_sigprof_blocked_in_current_thread(DDTRACE_UNUSED VALUE self) {
731
+ return is_sigprof_blocked_in_current_thread();
732
+ }
733
+
734
+ static VALUE _native_stats(DDTRACE_UNUSED VALUE self, VALUE instance) {
735
+ struct cpu_and_wall_time_worker_state *state;
736
+ TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
737
+
738
+ VALUE pretty_sampling_time_ns_min = state->stats.sampling_time_ns_min == UINT64_MAX ? Qnil : ULL2NUM(state->stats.sampling_time_ns_min);
739
+ VALUE pretty_sampling_time_ns_max = state->stats.sampling_time_ns_max == 0 ? Qnil : ULL2NUM(state->stats.sampling_time_ns_max);
740
+ VALUE pretty_sampling_time_ns_total = state->stats.sampling_time_ns_total == 0 ? Qnil : ULL2NUM(state->stats.sampling_time_ns_total);
741
+ VALUE pretty_sampling_time_ns_avg =
742
+ state->stats.sampled == 0 ? Qnil : DBL2NUM(((double) state->stats.sampling_time_ns_total) / state->stats.sampled);
743
+
744
+ VALUE stats_as_hash = rb_hash_new();
745
+ VALUE arguments[] = {
746
+ ID2SYM(rb_intern("trigger_sample_attempts")), /* => */ UINT2NUM(state->stats.trigger_sample_attempts),
747
+ ID2SYM(rb_intern("trigger_simulated_signal_delivery_attempts")), /* => */ UINT2NUM(state->stats.trigger_simulated_signal_delivery_attempts),
748
+ ID2SYM(rb_intern("simulated_signal_delivery")), /* => */ UINT2NUM(state->stats.simulated_signal_delivery),
749
+ ID2SYM(rb_intern("signal_handler_enqueued_sample")), /* => */ UINT2NUM(state->stats.signal_handler_enqueued_sample),
750
+ ID2SYM(rb_intern("signal_handler_wrong_thread")), /* => */ UINT2NUM(state->stats.signal_handler_wrong_thread),
751
+ ID2SYM(rb_intern("sampled")), /* => */ UINT2NUM(state->stats.sampled),
752
+ ID2SYM(rb_intern("sampling_time_ns_min")), /* => */ pretty_sampling_time_ns_min,
753
+ ID2SYM(rb_intern("sampling_time_ns_max")), /* => */ pretty_sampling_time_ns_max,
754
+ ID2SYM(rb_intern("sampling_time_ns_total")), /* => */ pretty_sampling_time_ns_total,
755
+ ID2SYM(rb_intern("sampling_time_ns_avg")), /* => */ pretty_sampling_time_ns_avg,
756
+ };
757
+ for (long unsigned int i = 0; i < VALUE_COUNT(arguments); i += 2) rb_hash_aset(stats_as_hash, arguments[i], arguments[i+1]);
758
+ return stats_as_hash;
759
+ }
760
+
761
+ void *simulate_sampling_signal_delivery(DDTRACE_UNUSED void *_unused) {
762
+ struct cpu_and_wall_time_worker_state *state = active_sampler_instance_state; // Read from global variable, see "sampler global state safety" note above
763
+
764
+ // This can potentially happen if the CpuAndWallTimeWorker was stopped while the IdleSamplingHelper was trying to execute this action
765
+ if (state == NULL) return NULL;
766
+
767
+ state->stats.simulated_signal_delivery++;
768
+
769
+ // @ivoanjo: We could instead directly call sample_from_postponed_job, but I chose to go through the signal handler
770
+ // so that the simulated case is as close to the original one as well (including any metrics increases, etc).
771
+ handle_sampling_signal(0, NULL, NULL);
772
+
773
+ return NULL; // Unused
774
+ }
775
+
776
+ static void grab_gvl_and_sample(void) { rb_thread_call_with_gvl(simulate_sampling_signal_delivery, NULL); }
777
+
778
+ static void reset_stats(struct cpu_and_wall_time_worker_state *state) {
779
+ state->stats = (struct stats) {}; // Resets all stats back to zero
780
+ state->stats.sampling_time_ns_min = UINT64_MAX; // Since we always take the min between existing and latest sample
781
+ }
782
+
783
+ static void sleep_for(uint64_t time_ns) {
784
+ // As a simplification, we currently only support setting .tv_nsec
785
+ if (time_ns >= SECONDS_AS_NS(1)) {
786
+ grab_gvl_and_raise(rb_eArgError, "sleep_for can only sleep for less than 1 second, time_ns: %"PRIu64, time_ns);
787
+ }
788
+
789
+ struct timespec time_to_sleep = {.tv_nsec = time_ns};
790
+
791
+ while (nanosleep(&time_to_sleep, &time_to_sleep) != 0) {
792
+ if (errno == EINTR) {
793
+ // We were interrupted. nanosleep updates "time_to_sleep" to contain only the remaining time, so we just let the
794
+ // loop keep going.
795
+ } else {
796
+ ENFORCE_SUCCESS_NO_GVL(errno);
797
+ }
798
+ }
799
+ }
800
+
801
+ static VALUE _native_allocation_count(DDTRACE_UNUSED VALUE self) {
802
+ bool is_profiler_running = active_sampler_instance_state != NULL;
803
+
804
+ return is_profiler_running ? ULL2NUM(allocation_count) : Qnil;
805
+ }
806
+
807
+ // Implements memory-related profiling events. This function is called by Ruby via the `object_allocation_tracepoint`
808
+ // when the RUBY_INTERNAL_EVENT_NEWOBJ event is triggered.
809
+ static void on_newobj_event(DDTRACE_UNUSED VALUE tracepoint_data, DDTRACE_UNUSED void *unused) {
810
+ // Update thread-local allocation count
811
+ if (RB_UNLIKELY(allocation_count == UINT64_MAX)) {
812
+ allocation_count = 0;
813
+ } else {
814
+ allocation_count++;
815
+ }
816
+ }
817
+
818
+ static void disable_tracepoints(struct cpu_and_wall_time_worker_state *state) {
819
+ rb_tracepoint_disable(state->gc_tracepoint);
820
+ rb_tracepoint_disable(state->object_allocation_tracepoint);
821
+ }