ddtrace 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (484) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -1
  3. data/LICENSE-3rdparty.csv +2 -0
  4. data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +1 -1
  5. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +9 -2
  6. data/ext/ddtrace_profiling_native_extension/clock_id.h +20 -0
  7. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +30 -1
  8. data/ext/ddtrace_profiling_native_extension/clock_id_noop.c +10 -1
  9. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +148 -28
  10. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +6 -0
  11. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +11 -7
  12. data/ext/ddtrace_profiling_native_extension/extconf.rb +24 -19
  13. data/ext/ddtrace_profiling_native_extension/helpers.h +12 -0
  14. data/ext/ddtrace_profiling_native_extension/http_transport.c +40 -47
  15. data/ext/ddtrace_profiling_native_extension/{libddprof_helpers.h → libdatadog_helpers.h} +2 -1
  16. data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +36 -20
  17. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +30 -29
  18. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +2 -5
  19. data/ext/ddtrace_profiling_native_extension/profiling.c +2 -3
  20. data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +25 -0
  21. data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +33 -1
  22. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +292 -18
  23. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +1 -1
  24. data/lib/datadog/appsec/autoload.rb +4 -2
  25. data/lib/datadog/appsec/configuration.rb +1 -1
  26. data/lib/datadog/appsec/contrib/auto_instrument.rb +0 -2
  27. data/lib/datadog/appsec/contrib/configuration/settings.rb +1 -1
  28. data/lib/datadog/appsec/contrib/rack/configuration/settings.rb +2 -2
  29. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +6 -6
  30. data/lib/datadog/appsec/contrib/rack/integration.rb +5 -5
  31. data/lib/datadog/appsec/contrib/rack/patcher.rb +2 -2
  32. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +1 -1
  33. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +1 -1
  34. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +1 -1
  35. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +2 -2
  36. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +3 -3
  37. data/lib/datadog/appsec/contrib/rails/configuration/settings.rb +2 -2
  38. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +4 -4
  39. data/lib/datadog/appsec/contrib/rails/integration.rb +4 -4
  40. data/lib/datadog/appsec/contrib/rails/patcher.rb +16 -12
  41. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +1 -1
  42. data/lib/datadog/appsec/contrib/sinatra/configuration/settings.rb +2 -2
  43. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +5 -5
  44. data/lib/datadog/appsec/contrib/sinatra/integration.rb +4 -4
  45. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +16 -12
  46. data/lib/datadog/appsec/event.rb +3 -3
  47. data/lib/datadog/appsec/extensions.rb +1 -1
  48. data/lib/datadog/appsec/processor.rb +1 -1
  49. data/lib/datadog/appsec/reactive/engine.rb +2 -2
  50. data/lib/datadog/appsec/reactive/operation.rb +3 -3
  51. data/lib/datadog/appsec.rb +5 -5
  52. data/lib/datadog/ci/configuration/components.rb +1 -1
  53. data/lib/datadog/ci/configuration/settings.rb +1 -1
  54. data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +2 -2
  55. data/lib/datadog/ci/contrib/cucumber/formatter.rb +5 -5
  56. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +1 -1
  57. data/lib/datadog/ci/contrib/cucumber/integration.rb +3 -3
  58. data/lib/datadog/ci/contrib/cucumber/patcher.rb +2 -2
  59. data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +2 -2
  60. data/lib/datadog/ci/contrib/rspec/example.rb +5 -5
  61. data/lib/datadog/ci/contrib/rspec/integration.rb +3 -3
  62. data/lib/datadog/ci/contrib/rspec/patcher.rb +2 -2
  63. data/lib/datadog/ci/ext/environment.rb +8 -6
  64. data/lib/datadog/ci/extensions.rb +4 -4
  65. data/lib/datadog/ci/flush.rb +2 -2
  66. data/lib/datadog/ci/test.rb +3 -3
  67. data/lib/datadog/ci.rb +6 -6
  68. data/lib/datadog/core/buffer/cruby.rb +1 -1
  69. data/lib/datadog/core/buffer/thread_safe.rb +1 -1
  70. data/lib/datadog/core/configuration/agent_settings_resolver.rb +6 -6
  71. data/lib/datadog/core/configuration/base.rb +2 -2
  72. data/lib/datadog/core/configuration/components.rb +26 -43
  73. data/lib/datadog/core/configuration/option_definition.rb +1 -1
  74. data/lib/datadog/core/configuration/option_definition_set.rb +1 -1
  75. data/lib/datadog/core/configuration/options.rb +3 -3
  76. data/lib/datadog/core/configuration/settings.rb +9 -7
  77. data/lib/datadog/core/configuration.rb +4 -4
  78. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  79. data/lib/datadog/core/diagnostics/health.rb +2 -2
  80. data/lib/datadog/core/environment/cgroup.rb +1 -1
  81. data/lib/datadog/core/environment/container.rb +1 -1
  82. data/lib/datadog/core/environment/ext.rb +1 -1
  83. data/lib/datadog/core/environment/identity.rb +2 -2
  84. data/lib/datadog/core/environment/platform.rb +1 -1
  85. data/lib/datadog/core/environment/socket.rb +1 -1
  86. data/lib/datadog/core/error.rb +1 -1
  87. data/lib/datadog/core/extensions.rb +1 -1
  88. data/lib/datadog/core/metrics/client.rb +8 -8
  89. data/lib/datadog/core/metrics/options.rb +3 -3
  90. data/lib/datadog/core/runtime/metrics.rb +6 -6
  91. data/lib/datadog/core/utils/object_set.rb +1 -1
  92. data/lib/datadog/core/utils/string_table.rb +1 -1
  93. data/lib/datadog/core/utils/time.rb +3 -3
  94. data/lib/datadog/core/utils.rb +2 -2
  95. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +2 -2
  96. data/lib/datadog/core/vendor/multipart-post/net/http/post/multipart.rb +3 -3
  97. data/lib/datadog/core/workers/async.rb +1 -1
  98. data/lib/datadog/core/workers/polling.rb +2 -2
  99. data/lib/datadog/core/workers/runtime_metrics.rb +4 -4
  100. data/lib/datadog/core.rb +50 -50
  101. data/lib/datadog/kit.rb +1 -1
  102. data/lib/datadog/opentracer/distributed_headers.rb +2 -2
  103. data/lib/datadog/opentracer/rack_propagator.rb +11 -7
  104. data/lib/datadog/opentracer/span.rb +1 -1
  105. data/lib/datadog/opentracer/text_map_propagator.rb +9 -6
  106. data/lib/datadog/opentracer/thread_local_scope_manager.rb +1 -1
  107. data/lib/datadog/opentracer/tracer.rb +19 -15
  108. data/lib/datadog/opentracer.rb +16 -16
  109. data/lib/datadog/profiling/buffer.rb +3 -3
  110. data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +4 -19
  111. data/lib/datadog/profiling/collectors/old_stack.rb +7 -7
  112. data/lib/datadog/profiling/collectors/stack.rb +3 -8
  113. data/lib/datadog/profiling/encoding/profile.rb +1 -1
  114. data/lib/datadog/profiling/events/stack.rb +1 -1
  115. data/lib/datadog/profiling/exporter.rb +17 -9
  116. data/lib/datadog/profiling/ext/forking.rb +36 -37
  117. data/lib/datadog/profiling/ext.rb +1 -0
  118. data/lib/datadog/profiling/flush.rb +0 -3
  119. data/lib/datadog/profiling/http_transport.rb +4 -3
  120. data/lib/datadog/profiling/old_recorder.rb +2 -7
  121. data/lib/datadog/profiling/pprof/builder.rb +4 -4
  122. data/lib/datadog/profiling/pprof/converter.rb +1 -1
  123. data/lib/datadog/profiling/pprof/message_set.rb +1 -1
  124. data/lib/datadog/profiling/pprof/stack_sample.rb +4 -4
  125. data/lib/datadog/profiling/pprof/string_table.rb +1 -1
  126. data/lib/datadog/profiling/pprof/template.rb +5 -5
  127. data/lib/datadog/profiling/preload.rb +1 -1
  128. data/lib/datadog/profiling/scheduler.rb +5 -4
  129. data/lib/datadog/profiling/stack_recorder.rb +14 -4
  130. data/lib/datadog/profiling/tag_builder.rb +6 -1
  131. data/lib/datadog/profiling/tasks/setup.rb +2 -2
  132. data/lib/datadog/profiling/trace_identifiers/ddtrace.rb +2 -2
  133. data/lib/datadog/profiling/trace_identifiers/helper.rb +1 -1
  134. data/lib/datadog/profiling/transport/http/api/endpoint.rb +5 -5
  135. data/lib/datadog/profiling/transport/http/api/instance.rb +2 -2
  136. data/lib/datadog/profiling/transport/http/api/spec.rb +1 -1
  137. data/lib/datadog/profiling/transport/http/api.rb +5 -5
  138. data/lib/datadog/profiling/transport/http/builder.rb +3 -3
  139. data/lib/datadog/profiling/transport/http/client.rb +2 -2
  140. data/lib/datadog/profiling/transport/http/response.rb +1 -1
  141. data/lib/datadog/profiling/transport/http.rb +21 -15
  142. data/lib/datadog/profiling.rb +20 -20
  143. data/lib/datadog/tracing/analytics.rb +1 -1
  144. data/lib/datadog/tracing/buffer.rb +5 -5
  145. data/lib/datadog/tracing/context.rb +1 -1
  146. data/lib/datadog/tracing/context_provider.rb +2 -2
  147. data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +2 -2
  148. data/lib/datadog/tracing/contrib/action_cable/event.rb +4 -5
  149. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +4 -4
  150. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +3 -3
  151. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +4 -4
  152. data/lib/datadog/tracing/contrib/action_cable/events.rb +4 -4
  153. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +3 -4
  154. data/lib/datadog/tracing/contrib/action_cable/integration.rb +4 -4
  155. data/lib/datadog/tracing/contrib/action_cable/patcher.rb +4 -4
  156. data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +2 -2
  157. data/lib/datadog/tracing/contrib/action_mailer/event.rb +3 -3
  158. data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +3 -3
  159. data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +3 -3
  160. data/lib/datadog/tracing/contrib/action_mailer/events.rb +2 -2
  161. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +4 -4
  162. data/lib/datadog/tracing/contrib/action_mailer/patcher.rb +3 -3
  163. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +6 -6
  164. data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +2 -2
  165. data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +2 -2
  166. data/lib/datadog/tracing/contrib/action_pack/integration.rb +4 -4
  167. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +2 -2
  168. data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -1
  169. data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +2 -2
  170. data/lib/datadog/tracing/contrib/action_view/event.rb +1 -1
  171. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +5 -5
  172. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +5 -5
  173. data/lib/datadog/tracing/contrib/action_view/events.rb +2 -2
  174. data/lib/datadog/tracing/contrib/action_view/instrumentation/partial_renderer.rb +2 -2
  175. data/lib/datadog/tracing/contrib/action_view/instrumentation/template_renderer.rb +2 -2
  176. data/lib/datadog/tracing/contrib/action_view/integration.rb +4 -4
  177. data/lib/datadog/tracing/contrib/action_view/patcher.rb +7 -7
  178. data/lib/datadog/tracing/contrib/action_view/utils.rb +1 -1
  179. data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +3 -3
  180. data/lib/datadog/tracing/contrib/active_job/event.rb +3 -3
  181. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +4 -4
  182. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +4 -4
  183. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +4 -4
  184. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +4 -4
  185. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +4 -4
  186. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +4 -4
  187. data/lib/datadog/tracing/contrib/active_job/events.rb +6 -6
  188. data/lib/datadog/tracing/contrib/active_job/integration.rb +4 -4
  189. data/lib/datadog/tracing/contrib/active_job/log_injection.rb +0 -2
  190. data/lib/datadog/tracing/contrib/active_job/patcher.rb +4 -4
  191. data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +2 -2
  192. data/lib/datadog/tracing/contrib/active_model_serializers/event.rb +4 -5
  193. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +3 -3
  194. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +2 -2
  195. data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +2 -2
  196. data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +3 -3
  197. data/lib/datadog/tracing/contrib/active_model_serializers/patcher.rb +3 -4
  198. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
  199. data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +3 -3
  200. data/lib/datadog/tracing/contrib/active_record/event.rb +1 -1
  201. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +4 -4
  202. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +6 -6
  203. data/lib/datadog/tracing/contrib/active_record/events.rb +2 -2
  204. data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -6
  205. data/lib/datadog/tracing/contrib/active_record/patcher.rb +2 -2
  206. data/lib/datadog/tracing/contrib/active_record/utils.rb +2 -2
  207. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +19 -9
  208. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +2 -2
  209. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +1 -1
  210. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +2 -2
  211. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -5
  212. data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +1 -1
  213. data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +1 -1
  214. data/lib/datadog/tracing/contrib/active_support/patcher.rb +2 -2
  215. data/lib/datadog/tracing/contrib/analytics.rb +1 -1
  216. data/lib/datadog/tracing/contrib/auto_instrument.rb +4 -4
  217. data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +2 -2
  218. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +3 -4
  219. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -3
  220. data/lib/datadog/tracing/contrib/aws/patcher.rb +5 -5
  221. data/lib/datadog/tracing/contrib/concurrent_ruby/configuration/settings.rb +2 -2
  222. data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +1 -1
  223. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -3
  224. data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +2 -2
  225. data/lib/datadog/tracing/contrib/configurable.rb +2 -2
  226. data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +1 -1
  227. data/lib/datadog/tracing/contrib/configuration/settings.rb +2 -2
  228. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +2 -2
  229. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +4 -5
  230. data/lib/datadog/tracing/contrib/dalli/integration.rb +3 -3
  231. data/lib/datadog/tracing/contrib/dalli/patcher.rb +3 -3
  232. data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -1
  233. data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +3 -3
  234. data/lib/datadog/tracing/contrib/delayed_job/ext.rb +2 -0
  235. data/lib/datadog/tracing/contrib/delayed_job/integration.rb +3 -3
  236. data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +8 -2
  237. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +3 -4
  238. data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +32 -0
  239. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +2 -2
  240. data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +3 -3
  241. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -7
  242. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +1 -1
  243. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +2 -2
  244. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
  245. data/lib/datadog/tracing/contrib/ethon/integration.rb +4 -4
  246. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +3 -4
  247. data/lib/datadog/tracing/contrib/ethon/patcher.rb +3 -3
  248. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +2 -2
  249. data/lib/datadog/tracing/contrib/excon/integration.rb +4 -4
  250. data/lib/datadog/tracing/contrib/excon/middleware.rb +6 -7
  251. data/lib/datadog/tracing/contrib/excon/patcher.rb +2 -2
  252. data/lib/datadog/tracing/contrib/extensions.rb +3 -3
  253. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +2 -2
  254. data/lib/datadog/tracing/contrib/faraday/integration.rb +4 -4
  255. data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -6
  256. data/lib/datadog/tracing/contrib/faraday/patcher.rb +5 -5
  257. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +3 -3
  258. data/lib/datadog/tracing/contrib/grape/endpoint.rb +4 -5
  259. data/lib/datadog/tracing/contrib/grape/integration.rb +3 -3
  260. data/lib/datadog/tracing/contrib/grape/patcher.rb +4 -4
  261. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +2 -2
  262. data/lib/datadog/tracing/contrib/graphql/integration.rb +3 -3
  263. data/lib/datadog/tracing/contrib/graphql/patcher.rb +2 -3
  264. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +3 -3
  265. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +4 -4
  266. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +6 -6
  267. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +3 -4
  268. data/lib/datadog/tracing/contrib/grpc/integration.rb +3 -3
  269. data/lib/datadog/tracing/contrib/grpc/patcher.rb +5 -5
  270. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +1 -2
  271. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +2 -2
  272. data/lib/datadog/tracing/contrib/http/instrumentation.rb +3 -4
  273. data/lib/datadog/tracing/contrib/http/integration.rb +6 -6
  274. data/lib/datadog/tracing/contrib/http/patcher.rb +3 -3
  275. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +2 -2
  276. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +4 -5
  277. data/lib/datadog/tracing/contrib/httpclient/integration.rb +4 -4
  278. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +3 -3
  279. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +2 -2
  280. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +4 -5
  281. data/lib/datadog/tracing/contrib/httprb/integration.rb +4 -4
  282. data/lib/datadog/tracing/contrib/httprb/patcher.rb +3 -3
  283. data/lib/datadog/tracing/contrib/integration.rb +3 -3
  284. data/lib/datadog/tracing/contrib/kafka/configuration/settings.rb +2 -2
  285. data/lib/datadog/tracing/contrib/kafka/event.rb +3 -3
  286. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +2 -2
  287. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +3 -3
  288. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +3 -3
  289. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +4 -4
  290. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +4 -4
  291. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +4 -4
  292. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +4 -4
  293. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +2 -2
  294. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +2 -2
  295. data/lib/datadog/tracing/contrib/kafka/events.rb +9 -9
  296. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -3
  297. data/lib/datadog/tracing/contrib/kafka/patcher.rb +3 -3
  298. data/lib/datadog/tracing/contrib/lograge/configuration/settings.rb +2 -2
  299. data/lib/datadog/tracing/contrib/lograge/instrumentation.rb +1 -2
  300. data/lib/datadog/tracing/contrib/lograge/integration.rb +3 -3
  301. data/lib/datadog/tracing/contrib/lograge/patcher.rb +2 -2
  302. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +2 -2
  303. data/lib/datadog/tracing/contrib/mongodb/instrumentation.rb +3 -3
  304. data/lib/datadog/tracing/contrib/mongodb/integration.rb +4 -4
  305. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -1
  306. data/lib/datadog/tracing/contrib/mongodb/patcher.rb +3 -3
  307. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +4 -4
  308. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +2 -2
  309. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +3 -4
  310. data/lib/datadog/tracing/contrib/mysql2/integration.rb +3 -3
  311. data/lib/datadog/tracing/contrib/mysql2/patcher.rb +2 -2
  312. data/lib/datadog/tracing/contrib/patcher.rb +2 -2
  313. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +2 -2
  314. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +3 -4
  315. data/lib/datadog/tracing/contrib/pg/integration.rb +3 -3
  316. data/lib/datadog/tracing/contrib/pg/patcher.rb +2 -2
  317. data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +2 -2
  318. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +2 -3
  319. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -3
  320. data/lib/datadog/tracing/contrib/presto/patcher.rb +4 -4
  321. data/lib/datadog/tracing/contrib/qless/configuration/settings.rb +2 -2
  322. data/lib/datadog/tracing/contrib/qless/integration.rb +3 -3
  323. data/lib/datadog/tracing/contrib/qless/patcher.rb +1 -2
  324. data/lib/datadog/tracing/contrib/qless/qless_job.rb +2 -3
  325. data/lib/datadog/tracing/contrib/qless/tracer_cleaner.rb +0 -2
  326. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +3 -3
  327. data/lib/datadog/tracing/contrib/que/integration.rb +4 -4
  328. data/lib/datadog/tracing/contrib/que/patcher.rb +1 -1
  329. data/lib/datadog/tracing/contrib/que/tracer.rb +1 -1
  330. data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +2 -2
  331. data/lib/datadog/tracing/contrib/racecar/event.rb +4 -5
  332. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +2 -2
  333. data/lib/datadog/tracing/contrib/racecar/events/consume.rb +2 -2
  334. data/lib/datadog/tracing/contrib/racecar/events/message.rb +2 -2
  335. data/lib/datadog/tracing/contrib/racecar/events.rb +3 -3
  336. data/lib/datadog/tracing/contrib/racecar/integration.rb +3 -3
  337. data/lib/datadog/tracing/contrib/racecar/patcher.rb +3 -3
  338. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +2 -2
  339. data/lib/datadog/tracing/contrib/rack/integration.rb +4 -4
  340. data/lib/datadog/tracing/contrib/rack/middlewares.rb +24 -20
  341. data/lib/datadog/tracing/contrib/rack/patcher.rb +4 -2
  342. data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +1 -1
  343. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +1 -1
  344. data/lib/datadog/tracing/contrib/rails/framework.rb +16 -21
  345. data/lib/datadog/tracing/contrib/rails/integration.rb +4 -4
  346. data/lib/datadog/tracing/contrib/rails/log_injection.rb +0 -2
  347. data/lib/datadog/tracing/contrib/rails/middlewares.rb +1 -2
  348. data/lib/datadog/tracing/contrib/rails/patcher.rb +7 -8
  349. data/lib/datadog/tracing/contrib/rails/railtie.rb +3 -3
  350. data/lib/datadog/tracing/contrib/rails/utils.rb +1 -1
  351. data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +17 -2
  352. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +12 -7
  353. data/lib/datadog/tracing/contrib/rake/integration.rb +3 -3
  354. data/lib/datadog/tracing/contrib/rake/patcher.rb +3 -4
  355. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +1 -1
  356. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +2 -2
  357. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +6 -7
  358. data/lib/datadog/tracing/contrib/redis/integration.rb +3 -3
  359. data/lib/datadog/tracing/contrib/redis/patcher.rb +6 -6
  360. data/lib/datadog/tracing/contrib/redis/tags.rb +3 -4
  361. data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +3 -3
  362. data/lib/datadog/tracing/contrib/resque/integration.rb +3 -3
  363. data/lib/datadog/tracing/contrib/resque/patcher.rb +2 -2
  364. data/lib/datadog/tracing/contrib/resque/resque_job.rb +3 -4
  365. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +2 -2
  366. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -3
  367. data/lib/datadog/tracing/contrib/rest_client/patcher.rb +2 -2
  368. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +4 -5
  369. data/lib/datadog/tracing/contrib/semantic_logger/configuration/settings.rb +2 -2
  370. data/lib/datadog/tracing/contrib/semantic_logger/instrumentation.rb +1 -2
  371. data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +3 -3
  372. data/lib/datadog/tracing/contrib/semantic_logger/patcher.rb +2 -2
  373. data/lib/datadog/tracing/contrib/sequel/configuration/settings.rb +2 -2
  374. data/lib/datadog/tracing/contrib/sequel/database.rb +4 -5
  375. data/lib/datadog/tracing/contrib/sequel/dataset.rb +4 -5
  376. data/lib/datadog/tracing/contrib/sequel/integration.rb +3 -3
  377. data/lib/datadog/tracing/contrib/sequel/patcher.rb +3 -3
  378. data/lib/datadog/tracing/contrib/sequel/utils.rb +2 -2
  379. data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +3 -3
  380. data/lib/datadog/tracing/contrib/shoryuken/integration.rb +4 -4
  381. data/lib/datadog/tracing/contrib/shoryuken/patcher.rb +1 -1
  382. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +1 -1
  383. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +4 -5
  384. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +3 -3
  385. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +6 -0
  386. data/lib/datadog/tracing/contrib/sidekiq/integration.rb +3 -3
  387. data/lib/datadog/tracing/contrib/sidekiq/patcher.rb +14 -7
  388. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +19 -1
  389. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/{scheduled_push.rb → redis_info.rb} +5 -6
  390. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +53 -0
  391. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -6
  392. data/lib/datadog/tracing/contrib/sidekiq/tracing.rb +2 -2
  393. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +2 -2
  394. data/lib/datadog/tracing/contrib/sinatra/env.rb +2 -2
  395. data/lib/datadog/tracing/contrib/sinatra/framework.rb +0 -2
  396. data/lib/datadog/tracing/contrib/sinatra/headers.rb +1 -1
  397. data/lib/datadog/tracing/contrib/sinatra/integration.rb +3 -3
  398. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +5 -5
  399. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +7 -8
  400. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +6 -7
  401. data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +2 -2
  402. data/lib/datadog/tracing/contrib/sneakers/integration.rb +4 -4
  403. data/lib/datadog/tracing/contrib/sneakers/patcher.rb +2 -2
  404. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +2 -3
  405. data/lib/datadog/tracing/contrib/status_code_matcher.rb +2 -2
  406. data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +2 -2
  407. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +3 -4
  408. data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +3 -3
  409. data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +4 -5
  410. data/lib/datadog/tracing/contrib.rb +48 -48
  411. data/lib/datadog/tracing/correlation.rb +1 -1
  412. data/lib/datadog/tracing/distributed/headers/b3.rb +4 -4
  413. data/lib/datadog/tracing/distributed/headers/b3_single.rb +4 -4
  414. data/lib/datadog/tracing/distributed/headers/datadog.rb +3 -3
  415. data/lib/datadog/tracing/distributed/headers/parser.rb +1 -1
  416. data/lib/datadog/tracing/distributed/helpers.rb +2 -2
  417. data/lib/datadog/tracing/distributed/metadata/b3.rb +4 -4
  418. data/lib/datadog/tracing/distributed/metadata/b3_single.rb +4 -4
  419. data/lib/datadog/tracing/distributed/metadata/datadog.rb +2 -2
  420. data/lib/datadog/tracing/distributed/metadata/parser.rb +1 -1
  421. data/lib/datadog/tracing/event.rb +1 -1
  422. data/lib/datadog/tracing/metadata/analytics.rb +2 -2
  423. data/lib/datadog/tracing/metadata/errors.rb +2 -2
  424. data/lib/datadog/tracing/metadata/tagging.rb +2 -2
  425. data/lib/datadog/tracing/metadata.rb +3 -3
  426. data/lib/datadog/tracing/pipeline/span_filter.rb +10 -6
  427. data/lib/datadog/tracing/pipeline.rb +3 -3
  428. data/lib/datadog/tracing/propagation/grpc.rb +6 -6
  429. data/lib/datadog/tracing/propagation/http.rb +8 -8
  430. data/lib/datadog/tracing/runtime/metrics.rb +1 -1
  431. data/lib/datadog/tracing/sampling/all_sampler.rb +1 -1
  432. data/lib/datadog/tracing/sampling/priority_sampler.rb +5 -5
  433. data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +2 -2
  434. data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +3 -3
  435. data/lib/datadog/tracing/sampling/rate_limiter.rb +1 -1
  436. data/lib/datadog/tracing/sampling/rate_sampler.rb +5 -5
  437. data/lib/datadog/tracing/sampling/rule.rb +3 -3
  438. data/lib/datadog/tracing/sampling/rule_sampler.rb +4 -4
  439. data/lib/datadog/tracing/span.rb +4 -4
  440. data/lib/datadog/tracing/span_operation.rb +9 -9
  441. data/lib/datadog/tracing/sync_writer.rb +5 -5
  442. data/lib/datadog/tracing/trace_operation.rb +16 -9
  443. data/lib/datadog/tracing/trace_segment.rb +5 -5
  444. data/lib/datadog/tracing/tracer.rb +15 -15
  445. data/lib/datadog/tracing/workers/trace_writer.rb +9 -9
  446. data/lib/datadog/tracing/workers.rb +3 -3
  447. data/lib/datadog/tracing/writer.rb +5 -5
  448. data/lib/datadog/tracing.rb +8 -8
  449. data/lib/ddtrace/auto_instrument.rb +2 -2
  450. data/lib/ddtrace/transport/ext.rb +7 -0
  451. data/lib/ddtrace/transport/http/adapters/net.rb +2 -2
  452. data/lib/ddtrace/transport/http/adapters/test.rb +1 -1
  453. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +2 -2
  454. data/lib/ddtrace/transport/http/api/map.rb +1 -1
  455. data/lib/ddtrace/transport/http/api.rb +4 -4
  456. data/lib/ddtrace/transport/http/builder.rb +5 -5
  457. data/lib/ddtrace/transport/http/client.rb +2 -2
  458. data/lib/ddtrace/transport/http/response.rb +1 -1
  459. data/lib/ddtrace/transport/http/statistics.rb +1 -1
  460. data/lib/ddtrace/transport/http/traces.rb +5 -5
  461. data/lib/ddtrace/transport/http.rb +12 -9
  462. data/lib/ddtrace/transport/io/client.rb +2 -2
  463. data/lib/ddtrace/transport/io/response.rb +1 -1
  464. data/lib/ddtrace/transport/io/traces.rb +3 -3
  465. data/lib/ddtrace/transport/io.rb +3 -3
  466. data/lib/ddtrace/transport/statistics.rb +2 -2
  467. data/lib/ddtrace/transport/trace_formatter.rb +5 -5
  468. data/lib/ddtrace/transport/traces.rb +5 -5
  469. data/lib/ddtrace/version.rb +1 -1
  470. data/lib/ddtrace.rb +6 -6
  471. metadata +14 -22
  472. data/.editorconfig +0 -22
  473. data/.gitignore +0 -58
  474. data/CONTRIBUTING.md +0 -81
  475. data/ddtrace.gemspec +0 -71
  476. data/docs/0.x-trace.png +0 -0
  477. data/docs/1.0-trace.png +0 -0
  478. data/docs/AutoInstrumentation.md +0 -36
  479. data/docs/Deprecation.md +0 -8
  480. data/docs/DevelopmentGuide.md +0 -259
  481. data/docs/GettingStarted.md +0 -2712
  482. data/docs/ProfilingDevelopment.md +0 -109
  483. data/docs/PublicApi.md +0 -14
  484. data/docs/UpgradeGuide.md +0 -736
@@ -2,13 +2,20 @@
2
2
 
3
3
  #include <ruby.h>
4
4
 
5
+ #include "helpers.h"
6
+
5
7
  // Processes any pending interruptions, including exceptions to be raised.
6
8
  // If there's an exception to be raised, it raises it. In that case, this function does not return.
7
- static inline VALUE process_pending_interruptions(VALUE _unused) {
9
+ static inline VALUE process_pending_interruptions(DDTRACE_UNUSED VALUE _) {
8
10
  rb_thread_check_ints();
9
11
  return Qnil;
10
12
  }
11
13
 
14
+ // RB_UNLIKELY is not supported on Ruby 2.2 and 2.3
15
+ #ifndef RB_UNLIKELY
16
+ #define RB_UNLIKELY(x) x
17
+ #endif
18
+
12
19
  // Calls process_pending_interruptions BUT "rescues" any exceptions to be raised, returning them instead as
13
20
  // a non-zero `pending_exception`.
14
21
  //
@@ -31,3 +38,28 @@ static inline int check_if_pending_exception(void) {
31
38
  rb_protect(process_pending_interruptions, Qnil, &pending_exception);
32
39
  return pending_exception;
33
40
  }
41
+
42
+ #define ADD_QUOTES_HELPER(x) #x
43
+ #define ADD_QUOTES(x) ADD_QUOTES_HELPER(x)
44
+
45
+ // Ruby has a Check_Type(value, type) that is roughly equivalent to this BUT Ruby's version is rather cryptic when it fails
46
+ // e.g. "wrong argument type nil (expected String)". This is a replacement that prints more information to help debugging.
47
+ #define ENFORCE_TYPE(value, type) \
48
+ { if (RB_UNLIKELY(!RB_TYPE_P(value, type))) raise_unexpected_type(value, type, ADD_QUOTES(value), ADD_QUOTES(type), __FILE__, __LINE__, __func__); }
49
+
50
+ // Called by ENFORCE_TYPE; should not be used directly
51
+ NORETURN(void raise_unexpected_type(
52
+ VALUE value,
53
+ enum ruby_value_type type,
54
+ const char *value_name,
55
+ const char *type_name,
56
+ const char *file,
57
+ int line,
58
+ const char* function_name
59
+ ));
60
+
61
+ // This API is exported as a public symbol by the VM BUT the function header is not defined in any public header, so we
62
+ // repeat it here to be able to use in our code.
63
+ //
64
+ // Queries if the current thread is the owner of the global VM lock.
65
+ int ruby_thread_has_gvl_p(void);
@@ -1,12 +1,130 @@
1
1
  #include <ruby.h>
2
2
  #include <ruby/thread.h>
3
+ #include <pthread.h>
4
+ #include <errno.h>
5
+ #include "helpers.h"
3
6
  #include "stack_recorder.h"
4
- #include "libddprof_helpers.h"
7
+ #include "libdatadog_helpers.h"
5
8
  #include "ruby_helpers.h"
6
9
 
7
10
  // Used to wrap a ddprof_ffi_Profile in a Ruby object and expose Ruby-level serialization APIs
8
11
  // This file implements the native bits of the Datadog::Profiling::StackRecorder class
9
12
 
13
+ // ---
14
+ // ## Synchronization mechanism for safe parallel access design notes
15
+ //
16
+ // The state of the StackRecorder is managed using a set of locks to avoid concurrency issues.
17
+ //
18
+ // This is needed because the state is expected to be accessed, in parallel, by two different threads.
19
+ //
20
+ // 1. The thread that is taking a stack sample and that called `record_sample`, let's call it the **sampler thread**.
21
+ // In the current implementation of the profiler, there can only exist one **sampler thread** at a time; if this
22
+ // constraint changes, we should revise the design of the StackRecorder.
23
+ //
24
+ // 2. The thread that serializes and reports profiles, let's call it the **serializer thread**. We enforce that there
25
+ // cannot be more than one thread attempting to serialize profiles at a time.
26
+ //
27
+ // If both the sampler and serializer threads are trying to access the same `ddprof_ffi_Profile` in parallel, we will
28
+ // have a concurrency issue. Thus, the StackRecorder has an added mechanism to avoid this.
29
+ //
30
+ // As an additional constraint, the **sampler thread** has absolute priority and must never block while
31
+ // recording a sample.
32
+ //
33
+ // ### The solution: Keep two profiles at the same time
34
+ //
35
+ // To solve for the constraints above, the StackRecorder keeps two `ddprof_ffi_Profile` profile instances inside itself.
36
+ // They are called the `slot_one_profile` and `slot_two_profile`.
37
+ //
38
+ // Each profile is paired with its own mutex. `slot_one_profile` is protected by `slot_one_mutex` and `slot_two_profile`
39
+ // is protected by `slot_two_mutex`.
40
+ //
41
+ // We additionally introduce the concept of **active** and **inactive** profile slots. At any point, the sampler thread
42
+ // can probe the mutexes to discover which of the profiles corresponds to the active slot, and then records samples in it.
43
+ // When the serializer thread is ready to serialize data, it flips the active and inactive slots; it reports the data
44
+ // on the previously-active profile slot, and the sampler thread can continue to record in the previously-inactive
45
+ // profile slot.
46
+ //
47
+ // Thus, the sampler and serializer threads never cross paths, avoiding concurrency issues. The sampler thread writes to
48
+ // the active profile slot, and the serializer thread reads from the inactive profile slot.
49
+ //
50
+ // ### Locking protocol, high-level
51
+ //
52
+ // The active profile slot is the slot for which its corresponding mutex **is unlocked**. That is, if the sampler
53
+ // thread can grab a lock for a profile slot, then that slot is the active one. (Here you see where the constraint
54
+ // stated above that only one sampler thread can exist kicks in -- this part would need to be more complex if multiple
55
+ // sampler threads were in play.)
56
+ //
57
+ // As a counterpart, the inactive profile slot mutex is **kept locked** until such time the serializer
58
+ // thread is ready to work and decides to flip the slots.
59
+ //
60
+ // When a new StackRecorder is initialized, the `slot_one_mutex` is unlocked, and the `slot_two_mutex` is kept locked,
61
+ // that is, a new instance always starts with slot one active.
62
+ //
63
+ // Additionally, an `active_slot` field is kept, containing a `1` or `2`; this is only kept for the serializer thread
64
+ // to use as a simplification, as well as for testing and debugging; the **sampler thread must never use the `active_slot`
65
+ // field**.
66
+ //
67
+ // ### Locking protocol, from the sampler thread side
68
+ //
69
+ // When the sampler thread wants to record a sample, it goes through the following steps to discover which is the
70
+ // active profile slot:
71
+ //
72
+ // 1. `pthread_mutex_trylock(slot_one_mutex)`. If it succeeds to grab the lock, this means the active profile slot is
73
+ // slot one. If it fails, we move to the next step.
74
+ //
75
+ // 2. `pthread_mutex_trylock(slot_two_mutex)`. If it succeeds to grab the lock, this means the active profile slot is
76
+ // slot two. If it fails, we move to the next step.
77
+ //
78
+ // 3. What does it mean for the sampler thread to have observed both `slot_one_mutex` as well as `slot_two_mutex` as
79
+ // being locked? There are two options:
80
+ // a. The sampler thread got really unlucky. When it tried to grab the `slot_one_mutex`, the active profile slot was
81
+ // the second one BUT then the serializer thread flipped the slots, and by the time the sampler thread probed the
82
+ // `slot_two_mutex`, that one was taken. Since the serializer thread is expected only to work once a minute,
83
+ // we retry steps 1. and 2. and should be able to find an active slot.
84
+ // b. Something is incorrect in the StackRecorder state. In this situation, the sampler thread should give up on
85
+ // sampling and enter an error state.
86
+ //
87
+ // Note that in the steps above, and because the sampler thread uses `trylock` to probe the mutexes, that the
88
+ // sampler thread never blocks. It either is able to find an active profile slot in a bounded amount of steps or it
89
+ // enters an error state.
90
+ //
91
+ // This guarantees that sampler performance is never constrained by serializer performance.
92
+ //
93
+ // ### Locking protocol, from the serializer thread side
94
+ //
95
+ // When the serializer thread wants to serialize a profile, it first flips the active and inactive profile slots.
96
+ //
97
+ // The flipping action is described below. Consider previously-inactive and previously-active as the state of the slots
98
+ // before the flipping happens.
99
+ //
100
+ // The flipping steps are the following:
101
+ //
102
+ // 1. Release the mutex for the previously-inactive profile slot. That slot, as seen by the sampler thread, is now
103
+ // active.
104
+ //
105
+ // 2. Grab the mutex for the previously-active profile slot. Note that this can lead to the serializer thread blocking,
106
+ // if the sampler thread is holding this mutex. After the mutex is grabbed, the previously-active slot becomes inactive,
107
+ // as seen by the sampler thread.
108
+ //
109
+ // 3. Update `active_slot`.
110
+ //
111
+ // After flipping the profile slots, the serializer thread is now free to serialize the inactive profile slot. The slot
112
+ // is kept inactive until the next time the serializer thread wants to serialize data.
113
+ //
114
+ // Note there can be a brief period between steps 1 and 2 where the serializer thread holds no lock, which means that
115
+ // the sampler thread can pick either slot. This is OK: if the sampler thread picks the previously-inactive slot, the
116
+ // samples will be reported on the next serialization; if the sampler thread picks the previously-active slot, the
117
+ // samples are still included in the current serialization. Either option is correct.
118
+ //
119
+ // ### Additional notes
120
+ //
121
+ // Q: Can the sampler thread and the serializer thread ever be the same thread? (E.g. sampling in interrupt handler)
122
+ // A: No; the current profiler design requires that sampling happens only on the thread that is holding the Global VM
123
+ // Lock (GVL). The serializer thread flipping occurs after the serializer thread releases the GVL, and thus the
124
+ // serializer thread will not be able to host the sampling process.
125
+ //
126
+ // ---
127
+
10
128
  static VALUE ok_symbol = Qnil; // :ok in Ruby
11
129
  static VALUE error_symbol = Qnil; // :error in Ruby
12
130
 
@@ -14,9 +132,32 @@ static ID ruby_time_from_id; // id of :ruby_time_from in Ruby
14
132
 
15
133
  static VALUE stack_recorder_class = Qnil;
16
134
 
135
+ // Contains native state for each instance
136
+ struct stack_recorder_state {
137
+ pthread_mutex_t slot_one_mutex;
138
+ ddprof_ffi_Profile *slot_one_profile;
139
+
140
+ pthread_mutex_t slot_two_mutex;
141
+ ddprof_ffi_Profile *slot_two_profile;
142
+
143
+ short active_slot; // MUST NEVER BE ACCESSED FROM record_sample; this is NOT for the sampler thread to use.
144
+ };
145
+
146
+ // Used to return a pair of values from sampler_lock_active_profile()
147
+ struct active_slot_pair {
148
+ pthread_mutex_t *mutex;
149
+ ddprof_ffi_Profile *profile;
150
+ };
151
+
17
152
  struct call_serialize_without_gvl_arguments {
153
+ // Set by caller
154
+ struct stack_recorder_state *state;
155
+
156
+ // Set by callee
18
157
  ddprof_ffi_Profile *profile;
19
158
  ddprof_ffi_SerializeResult result;
159
+
160
+ // Set by both
20
161
  bool serialize_ran;
21
162
  };
22
163
 
@@ -25,21 +166,33 @@ static void stack_recorder_typed_data_free(void *data);
25
166
  static VALUE _native_serialize(VALUE self, VALUE recorder_instance);
26
167
  static VALUE ruby_time_from(ddprof_ffi_Timespec ddprof_time);
27
168
  static void *call_serialize_without_gvl(void *call_args);
169
+ static struct active_slot_pair sampler_lock_active_profile();
170
+ static void sampler_unlock_active_profile(struct active_slot_pair active_slot);
171
+ static ddprof_ffi_Profile *serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state);
172
+ static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
173
+ static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
174
+ static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance);
175
+ static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot);
28
176
 
29
177
  void stack_recorder_init(VALUE profiling_module) {
30
178
  stack_recorder_class = rb_define_class_under(profiling_module, "StackRecorder", rb_cObject);
179
+ // Hosts methods used for testing the native code using RSpec
180
+ VALUE testing_module = rb_define_module_under(stack_recorder_class, "Testing");
31
181
 
32
182
  // Instances of the StackRecorder class are "TypedData" objects.
33
183
  // "TypedData" objects are special objects in the Ruby VM that can wrap C structs.
34
- // In our case, we're going to keep a libddprof profile reference inside our object.
184
+ // In this case, it wraps the stack_recorder_state.
35
185
  //
36
- // Because Ruby doesn't know how to initialize libddprof profiles, we MUST override the allocation function for objects
186
+ // Because Ruby doesn't know how to initialize native-level structs, we MUST override the allocation function for objects
37
187
  // of this class so that we can manage this part. Not overriding or disabling the allocation function is a common
38
188
  // gotcha for "TypedData" objects that can very easily lead to VM crashes, see for instance
39
189
  // https://bugs.ruby-lang.org/issues/18007 for a discussion around this.
40
190
  rb_define_alloc_func(stack_recorder_class, _native_new);
41
191
 
42
192
  rb_define_singleton_method(stack_recorder_class, "_native_serialize", _native_serialize, 1);
193
+ rb_define_singleton_method(testing_module, "_native_active_slot", _native_active_slot, 1);
194
+ rb_define_singleton_method(testing_module, "_native_slot_one_mutex_locked?", _native_is_slot_one_mutex_locked, 1);
195
+ rb_define_singleton_method(testing_module, "_native_slot_two_mutex_locked?", _native_is_slot_two_mutex_locked, 1);
43
196
 
44
197
  ok_symbol = ID2SYM(rb_intern_const("ok"));
45
198
  error_symbol = ID2SYM(rb_intern_const("error"));
@@ -59,24 +212,46 @@ static const rb_data_type_t stack_recorder_typed_data = {
59
212
  };
60
213
 
61
214
  static VALUE _native_new(VALUE klass) {
215
+ struct stack_recorder_state *state = ruby_xcalloc(1, sizeof(struct stack_recorder_state));
216
+
62
217
  ddprof_ffi_Slice_value_type sample_types = {.ptr = enabled_value_types, .len = ENABLED_VALUE_TYPES_COUNT};
63
218
 
64
- ddprof_ffi_Profile *profile = ddprof_ffi_Profile_new(sample_types, NULL /* Period is optional */);
219
+ state->slot_one_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
220
+ state->slot_two_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
221
+
222
+ // A newly-created StackRecorder starts with slot one being active for samples, so let's lock slot two
223
+ int error = pthread_mutex_lock(&state->slot_two_mutex);
224
+ if (error) rb_syserr_fail(error, "Unexpected failure during pthread_mutex_lock");
225
+
226
+ state->active_slot = 1;
227
+
228
+ // Note: Don't raise exceptions after this point, since it'll lead to libdatadog memory leaking!
65
229
 
66
- return TypedData_Wrap_Struct(klass, &stack_recorder_typed_data, profile);
230
+ state->slot_one_profile = ddprof_ffi_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
231
+ state->slot_two_profile = ddprof_ffi_Profile_new(sample_types, NULL /* period is optional */, NULL /* start_time is optional */);
232
+
233
+ return TypedData_Wrap_Struct(klass, &stack_recorder_typed_data, state);
67
234
  }
68
235
 
69
- static void stack_recorder_typed_data_free(void *data) {
70
- ddprof_ffi_Profile_free((ddprof_ffi_Profile *) data);
236
+ static void stack_recorder_typed_data_free(void *state_ptr) {
237
+ struct stack_recorder_state *state = (struct stack_recorder_state *) state_ptr;
238
+
239
+ pthread_mutex_destroy(&state->slot_one_mutex);
240
+ ddprof_ffi_Profile_free(state->slot_one_profile);
241
+
242
+ pthread_mutex_destroy(&state->slot_two_mutex);
243
+ ddprof_ffi_Profile_free(state->slot_two_profile);
244
+
245
+ ruby_xfree(state);
71
246
  }
72
247
 
73
- static VALUE _native_serialize(VALUE self, VALUE recorder_instance) {
74
- ddprof_ffi_Profile *profile;
75
- TypedData_Get_Struct(recorder_instance, ddprof_ffi_Profile, &stack_recorder_typed_data, profile);
248
+ static VALUE _native_serialize(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
249
+ struct stack_recorder_state *state;
250
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
76
251
 
77
252
  // We'll release the Global VM Lock while we're calling serialize, so that the Ruby VM can continue to work while this
78
253
  // is pending
79
- struct call_serialize_without_gvl_arguments args = {.profile = profile, .serialize_ran = false};
254
+ struct call_serialize_without_gvl_arguments args = {.state = state, .serialize_ran = false};
80
255
 
81
256
  while (!args.serialize_ran) {
82
257
  // Give the Ruby VM an opportunity to process any pending interruptions (including raising exceptions).
@@ -89,7 +264,7 @@ static VALUE _native_serialize(VALUE self, VALUE recorder_instance) {
89
264
 
90
265
  // We use rb_thread_call_without_gvl2 here because unlike the regular _gvl variant, gvl2 does not process
91
266
  // interruptions and thus does not raise exceptions after running our code.
92
- rb_thread_call_without_gvl2(call_serialize_without_gvl, &args, /* No interruption function supported */ NULL, NULL);
267
+ rb_thread_call_without_gvl2(call_serialize_without_gvl, &args, NULL /* No interruption function needed in this case */, NULL /* Not needed */);
93
268
  }
94
269
 
95
270
  ddprof_ffi_SerializeResult serialized_profile = args.result;
@@ -105,13 +280,15 @@ static VALUE _native_serialize(VALUE self, VALUE recorder_instance) {
105
280
  ddprof_ffi_Timespec ddprof_start = serialized_profile.ok.start;
106
281
  ddprof_ffi_Timespec ddprof_finish = serialized_profile.ok.end;
107
282
 
108
- // Clean up libddprof object to avoid leaking in case ruby_time_from raises an exception
283
+ // Clean up libdatadog object to avoid leaking in case ruby_time_from raises an exception
109
284
  ddprof_ffi_SerializeResult_drop(serialized_profile);
110
285
 
111
286
  VALUE start = ruby_time_from(ddprof_start);
112
287
  VALUE finish = ruby_time_from(ddprof_finish);
113
288
 
114
- if (!ddprof_ffi_Profile_reset(profile)) return rb_ary_new_from_args(2, error_symbol, rb_str_new_cstr("Failed to reset profile"));
289
+ if (!ddprof_ffi_Profile_reset(args.profile, NULL /* start_time is optional */ )) {
290
+ return rb_ary_new_from_args(2, error_symbol, rb_str_new_cstr("Failed to reset profile"));
291
+ }
115
292
 
116
293
  return rb_ary_new_from_args(2, ok_symbol, rb_ary_new_from_args(3, start, finish, encoded_pprof));
117
294
  }
@@ -127,16 +304,21 @@ static VALUE ruby_time_from(ddprof_ffi_Timespec ddprof_time) {
127
304
  }
128
305
 
129
306
  void record_sample(VALUE recorder_instance, ddprof_ffi_Sample sample) {
130
- ddprof_ffi_Profile *profile;
131
- TypedData_Get_Struct(recorder_instance, ddprof_ffi_Profile, &stack_recorder_typed_data, profile);
307
+ struct stack_recorder_state *state;
308
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
132
309
 
133
- ddprof_ffi_Profile_add(profile, sample);
310
+ struct active_slot_pair active_slot = sampler_lock_active_profile(state);
311
+
312
+ ddprof_ffi_Profile_add(active_slot.profile, sample);
313
+
314
+ sampler_unlock_active_profile(active_slot);
134
315
  }
135
316
 
136
317
  static void *call_serialize_without_gvl(void *call_args) {
137
318
  struct call_serialize_without_gvl_arguments *args = (struct call_serialize_without_gvl_arguments *) call_args;
138
319
 
139
- args->result = ddprof_ffi_Profile_serialize(args->profile);
320
+ args->profile = serializer_flip_active_and_inactive_slots(args->state);
321
+ args->result = ddprof_ffi_Profile_serialize(args->profile, NULL /* end_time is optional */, NULL /* duration_nanos is optional */);
140
322
  args->serialize_ran = true;
141
323
 
142
324
  return NULL; // Unused
@@ -145,3 +327,95 @@ static void *call_serialize_without_gvl(void *call_args) {
145
327
  void enforce_recorder_instance(VALUE object) {
146
328
  Check_TypedStruct(object, &stack_recorder_typed_data);
147
329
  }
330
+
331
+ static struct active_slot_pair sampler_lock_active_profile(struct stack_recorder_state *state) {
332
+ int error;
333
+
334
+ for (int attempts = 0; attempts < 2; attempts++) {
335
+ error = pthread_mutex_trylock(&state->slot_one_mutex);
336
+ if (error && error != EBUSY) rb_syserr_fail(error, "Unexpected failure during sampler_lock_active_profile for slot_one_mutex");
337
+
338
+ // Slot one is active
339
+ if (!error) return (struct active_slot_pair) {.mutex = &state->slot_one_mutex, .profile = state->slot_one_profile};
340
+
341
+ // If we got here, slot one was not active, let's try slot two
342
+
343
+ error = pthread_mutex_trylock(&state->slot_two_mutex);
344
+ if (error && error != EBUSY) rb_syserr_fail(error, "Unexpected failure during sampler_lock_active_profile for slot_two_mutex");
345
+
346
+ // Slot two is active
347
+ if (!error) return (struct active_slot_pair) {.mutex = &state->slot_two_mutex, .profile = state->slot_two_profile};
348
+ }
349
+
350
+ // We already tried both multiple times, and we did not succeed. This is not expected to happen. Let's stop sampling.
351
+ rb_raise(rb_eRuntimeError, "Failed to grab either mutex in sampler_lock_active_profile");
352
+ }
353
+
354
+ static void sampler_unlock_active_profile(struct active_slot_pair active_slot) {
355
+ int error = pthread_mutex_unlock(active_slot.mutex);
356
+ if (error != 0) rb_syserr_fail(error, "Unexpected failure in sampler_unlock_active_profile");
357
+ }
358
+
359
+ static ddprof_ffi_Profile *serializer_flip_active_and_inactive_slots(struct stack_recorder_state *state) {
360
+ int error;
361
+ int previously_active_slot = state->active_slot;
362
+
363
+ if (previously_active_slot != 1 && previously_active_slot != 2) {
364
+ rb_raise(rb_eRuntimeError, "Unexpected active_slot state %d in serializer_flip_active_and_inactive_slots", previously_active_slot);
365
+ }
366
+
367
+ pthread_mutex_t *previously_active = (previously_active_slot == 1) ? &state->slot_one_mutex : &state->slot_two_mutex;
368
+ pthread_mutex_t *previously_inactive = (previously_active_slot == 1) ? &state->slot_two_mutex : &state->slot_one_mutex;
369
+
370
+ // Release the lock, thus making this slot active
371
+ error = pthread_mutex_unlock(previously_inactive);
372
+ if (error) rb_syserr_fail(error, "Unexpected failure during serializer_flip_active_and_inactive_slots for previously_inactive");
373
+
374
+ // Grab the lock, thus making this slot inactive
375
+ error = pthread_mutex_lock(previously_active);
376
+ if (error) rb_syserr_fail(error, "Unexpected failure during serializer_flip_active_and_inactive_slots for previously_active");
377
+
378
+ // Update active_slot
379
+ state->active_slot = (previously_active_slot == 1) ? 2 : 1;
380
+
381
+ // Return profile for previously active slot (now inactive)
382
+ return (previously_active_slot == 1) ? state->slot_one_profile : state->slot_two_profile;
383
+ }
384
+
385
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
386
+ // It SHOULD NOT be used for other purposes.
387
+ static VALUE _native_active_slot(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) {
388
+ struct stack_recorder_state *state;
389
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
390
+
391
+ return INT2NUM(state->active_slot);
392
+ }
393
+
394
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
395
+ // It SHOULD NOT be used for other purposes.
396
+ static VALUE _native_is_slot_one_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { return test_slot_mutex_state(recorder_instance, 1); }
397
+
398
+ // This method exists only to enable testing Datadog::Profiling::StackRecorder behavior using RSpec.
399
+ // It SHOULD NOT be used for other purposes.
400
+ static VALUE _native_is_slot_two_mutex_locked(DDTRACE_UNUSED VALUE _self, VALUE recorder_instance) { return test_slot_mutex_state(recorder_instance, 2); }
401
+
402
+ static VALUE test_slot_mutex_state(VALUE recorder_instance, int slot) {
403
+ struct stack_recorder_state *state;
404
+ TypedData_Get_Struct(recorder_instance, struct stack_recorder_state, &stack_recorder_typed_data, state);
405
+
406
+ pthread_mutex_t *slot_mutex = (slot == 1) ? &state->slot_one_mutex : &state->slot_two_mutex;
407
+
408
+ // Like Heisenberg's uncertainty principle, we can't observe without affecting...
409
+ int error = pthread_mutex_trylock(slot_mutex);
410
+
411
+ if (error == 0) {
412
+ // Mutex was unlocked
413
+ pthread_mutex_unlock(slot_mutex);
414
+ return Qfalse;
415
+ } else if (error == EBUSY) {
416
+ // Mutex was locked
417
+ return Qtrue;
418
+ } else {
419
+ rb_syserr_fail(error, "Unexpected failure when checking mutex state");
420
+ }
421
+ }
@@ -3,7 +3,7 @@
3
3
  #include <ddprof/ffi.h>
4
4
 
5
5
  // Note: Please DO NOT use `VALUE_STRING` anywhere else, instead use `DDPROF_FFI_CHARSLICE_C`.
6
- // `VALUE_STRING` is only needed because older versions of gcc (4.9.2, used in our Ruby 2.1 and 2.2 CI test images)
6
+ // `VALUE_STRING` is only needed because older versions of gcc (4.9.2, used in our Ruby 2.2 CI test images)
7
7
  // tripped when compiling `enabled_value_types` using `-std=gnu99` due to the extra cast that is included in
8
8
  // `DDPROF_FFI_CHARSLICE_C` with the following error:
9
9
  //
@@ -1,14 +1,16 @@
1
1
  # typed: ignore
2
2
 
3
3
  if %w[1 true].include?((ENV['DD_APPSEC_ENABLED'] || '').downcase)
4
+ require_relative '../../ddtrace'
5
+
4
6
  begin
5
- require 'datadog/appsec'
7
+ require_relative '../appsec'
6
8
  rescue StandardError => e
7
9
  puts "AppSec failed to load. No security check will be performed. error: #{e.class.name} #{e.message}"
8
10
  end
9
11
 
10
12
  begin
11
- require 'datadog/appsec/contrib/auto_instrument'
13
+ require_relative 'contrib/auto_instrument'
12
14
  Datadog::AppSec::Contrib::AutoInstrument.patch_all
13
15
  rescue StandardError => e
14
16
  puts "AppSec failed to instrument. No security check will be performed. error: #{e.class.name} #{e.message}"
@@ -1,6 +1,6 @@
1
1
  # typed: true
2
2
 
3
- require 'datadog/appsec/configuration/settings'
3
+ require_relative 'configuration/settings'
4
4
 
5
5
  module Datadog
6
6
  module AppSec
@@ -1,7 +1,5 @@
1
1
  # typed: true
2
2
 
3
- require 'ddtrace'
4
-
5
3
  module Datadog
6
4
  module AppSec
7
5
  module Contrib
@@ -1,6 +1,6 @@
1
1
  # typed: false
2
2
 
3
- require 'datadog/core/configuration/base'
3
+ require_relative '../../../core/configuration/base'
4
4
 
5
5
  module Datadog
6
6
  module AppSec
@@ -1,7 +1,7 @@
1
1
  # typed: false
2
2
 
3
- require 'datadog/appsec/contrib/configuration/settings'
4
- require 'datadog/appsec/contrib/rack/ext'
3
+ require_relative '../../configuration/settings'
4
+ require_relative '../ext'
5
5
 
6
6
  module Datadog
7
7
  module AppSec
@@ -1,11 +1,11 @@
1
1
  # typed: false
2
2
 
3
- require 'datadog/appsec/instrumentation/gateway'
4
- require 'datadog/appsec/reactive/operation'
5
- require 'datadog/appsec/contrib/rack/reactive/request'
6
- require 'datadog/appsec/contrib/rack/reactive/request_body'
7
- require 'datadog/appsec/contrib/rack/reactive/response'
8
- require 'datadog/appsec/event'
3
+ require_relative '../../../instrumentation/gateway'
4
+ require_relative '../../../reactive/operation'
5
+ require_relative '../reactive/request'
6
+ require_relative '../reactive/request_body'
7
+ require_relative '../reactive/response'
8
+ require_relative '../../../event'
9
9
 
10
10
  module Datadog
11
11
  module AppSec
@@ -1,11 +1,11 @@
1
1
  # typed: ignore
2
2
 
3
- require 'datadog/appsec/contrib/integration'
3
+ require_relative '../integration'
4
4
 
5
- require 'datadog/appsec/contrib/rack/configuration/settings'
6
- require 'datadog/appsec/contrib/rack/patcher'
7
- require 'datadog/appsec/contrib/rack/request_middleware'
8
- require 'datadog/appsec/contrib/rack/request_body_middleware'
5
+ require_relative 'configuration/settings'
6
+ require_relative 'patcher'
7
+ require_relative 'request_middleware'
8
+ require_relative 'request_body_middleware'
9
9
 
10
10
  module Datadog
11
11
  module AppSec
@@ -1,7 +1,7 @@
1
1
  # typed: ignore
2
2
 
3
- require 'datadog/appsec/contrib/patcher'
4
- require 'datadog/appsec/contrib/rack/gateway/watcher'
3
+ require_relative '../patcher'
4
+ require_relative 'gateway/watcher'
5
5
 
6
6
  module Datadog
7
7
  module AppSec
@@ -1,6 +1,6 @@
1
1
  # typed: true
2
2
 
3
- require 'datadog/appsec/contrib/rack/request'
3
+ require_relative '../request'
4
4
 
5
5
  module Datadog
6
6
  module AppSec
@@ -1,6 +1,6 @@
1
1
  # typed: true
2
2
 
3
- require 'datadog/appsec/contrib/rack/request'
3
+ require_relative '../request'
4
4
 
5
5
  module Datadog
6
6
  module AppSec
@@ -1,6 +1,6 @@
1
1
  # typed: true
2
2
 
3
- require 'datadog/appsec/contrib/rack/response'
3
+ require_relative '../response'
4
4
 
5
5
  module Datadog
6
6
  module AppSec
@@ -1,7 +1,7 @@
1
1
  # typed: ignore
2
2
 
3
- require 'datadog/appsec/instrumentation/gateway'
4
- require 'datadog/appsec/assets'
3
+ require_relative '../../instrumentation/gateway'
4
+ require_relative '../../assets'
5
5
 
6
6
  module Datadog
7
7
  module AppSec
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'json'
4
4
 
5
- require 'datadog/appsec/instrumentation/gateway'
6
- require 'datadog/appsec/processor'
7
- require 'datadog/appsec/assets'
5
+ require_relative '../../instrumentation/gateway'
6
+ require_relative '../../processor'
7
+ require_relative '../../assets'
8
8
 
9
9
  module Datadog
10
10
  module AppSec
@@ -1,7 +1,7 @@
1
1
  # typed: false
2
2
 
3
- require 'datadog/appsec/contrib/configuration/settings'
4
- require 'datadog/appsec/contrib/rails/ext'
3
+ require_relative '../../configuration/settings'
4
+ require_relative '../ext'
5
5
 
6
6
  module Datadog
7
7
  module AppSec
@@ -1,9 +1,9 @@
1
1
  # typed: false
2
2
 
3
- require 'datadog/appsec/instrumentation/gateway'
4
- require 'datadog/appsec/reactive/operation'
5
- require 'datadog/appsec/contrib/rails/reactive/action'
6
- require 'datadog/appsec/event'
3
+ require_relative '../../../instrumentation/gateway'
4
+ require_relative '../../../reactive/operation'
5
+ require_relative '../reactive/action'
6
+ require_relative '../../../event'
7
7
 
8
8
  module Datadog
9
9
  module AppSec