ddtrace 0.40.0 → 0.54.1

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 (602) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +22 -0
  3. data/.gitignore +7 -1
  4. data/CHANGELOG.md +1667 -350
  5. data/CONTRIBUTING.md +3 -7
  6. data/LICENSE-3rdparty.csv +2 -0
  7. data/README.md +1 -0
  8. data/bin/ddtracerb +15 -0
  9. data/ddtrace.gemspec +21 -37
  10. data/docs/DevelopmentGuide.md +56 -8
  11. data/docs/GettingStarted.md +438 -92
  12. data/docs/ProfilingDevelopment.md +107 -0
  13. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +86 -0
  14. data/ext/ddtrace_profiling_native_extension/clock_id.h +4 -0
  15. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +52 -0
  16. data/ext/ddtrace_profiling_native_extension/clock_id_noop.c +14 -0
  17. data/ext/ddtrace_profiling_native_extension/extconf.rb +166 -0
  18. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +35 -0
  19. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +3 -0
  20. data/ext/ddtrace_profiling_native_extension/profiling.c +22 -0
  21. data/lib/datadog/ci/configuration/components.rb +31 -0
  22. data/lib/datadog/ci/configuration/settings.rb +37 -0
  23. data/lib/datadog/ci/context_flush.rb +29 -0
  24. data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +31 -0
  25. data/lib/datadog/ci/contrib/cucumber/ext.rb +20 -0
  26. data/lib/datadog/ci/contrib/cucumber/formatter.rb +99 -0
  27. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +27 -0
  28. data/lib/datadog/ci/contrib/cucumber/integration.rb +48 -0
  29. data/lib/datadog/ci/contrib/cucumber/patcher.rb +26 -0
  30. data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +31 -0
  31. data/lib/datadog/ci/contrib/rspec/example.rb +75 -0
  32. data/lib/datadog/ci/contrib/rspec/ext.rb +19 -0
  33. data/lib/datadog/ci/contrib/rspec/integration.rb +49 -0
  34. data/lib/datadog/ci/contrib/rspec/patcher.rb +26 -0
  35. data/lib/datadog/ci/ext/app_types.rb +10 -0
  36. data/lib/datadog/ci/ext/environment.rb +485 -0
  37. data/lib/datadog/ci/ext/settings.rb +11 -0
  38. data/lib/datadog/ci/ext/test.rb +36 -0
  39. data/lib/datadog/ci/extensions.rb +18 -0
  40. data/lib/datadog/ci/test.rb +81 -0
  41. data/lib/datadog/ci.rb +17 -0
  42. data/lib/datadog/contrib.rb +71 -0
  43. data/lib/datadog/core/environment/cgroup.rb +52 -0
  44. data/lib/datadog/core/environment/class_count.rb +20 -0
  45. data/lib/datadog/core/environment/container.rb +91 -0
  46. data/lib/datadog/core/environment/ext.rb +27 -0
  47. data/lib/datadog/core/environment/gc.rb +19 -0
  48. data/lib/datadog/core/environment/identity.rb +51 -0
  49. data/lib/datadog/core/environment/socket.rb +17 -0
  50. data/lib/datadog/core/environment/thread_count.rb +19 -0
  51. data/lib/datadog/core/environment/variable_helpers.rb +42 -0
  52. data/lib/datadog/core/environment/vm_cache.rb +46 -0
  53. data/lib/ddtrace/analytics.rb +3 -0
  54. data/lib/ddtrace/auto_instrument.rb +5 -0
  55. data/lib/ddtrace/auto_instrument_base.rb +7 -0
  56. data/lib/ddtrace/buffer.rb +278 -57
  57. data/lib/ddtrace/chunker.rb +1 -0
  58. data/lib/ddtrace/configuration/agent_settings_resolver.rb +309 -0
  59. data/lib/ddtrace/configuration/base.rb +9 -11
  60. data/lib/ddtrace/configuration/components.rb +167 -26
  61. data/lib/ddtrace/configuration/dependency_resolver.rb +1 -0
  62. data/lib/ddtrace/configuration/option.rb +1 -0
  63. data/lib/ddtrace/configuration/option_definition.rb +2 -3
  64. data/lib/ddtrace/configuration/option_definition_set.rb +1 -0
  65. data/lib/ddtrace/configuration/option_set.rb +1 -0
  66. data/lib/ddtrace/configuration/options.rb +10 -10
  67. data/lib/ddtrace/configuration/pin_setup.rb +1 -0
  68. data/lib/ddtrace/configuration/settings.rb +147 -13
  69. data/lib/ddtrace/configuration.rb +133 -22
  70. data/lib/ddtrace/context.rb +51 -22
  71. data/lib/ddtrace/context_flush.rb +15 -2
  72. data/lib/ddtrace/context_provider.rb +17 -5
  73. data/lib/ddtrace/contrib/action_cable/configuration/settings.rb +1 -0
  74. data/lib/ddtrace/contrib/action_cable/event.rb +6 -4
  75. data/lib/ddtrace/contrib/action_cable/events/broadcast.rb +1 -0
  76. data/lib/ddtrace/contrib/action_cable/events/perform_action.rb +1 -0
  77. data/lib/ddtrace/contrib/action_cable/events/transmit.rb +1 -0
  78. data/lib/ddtrace/contrib/action_cable/events.rb +1 -0
  79. data/lib/ddtrace/contrib/action_cable/ext.rb +1 -0
  80. data/lib/ddtrace/contrib/action_cable/instrumentation.rb +47 -0
  81. data/lib/ddtrace/contrib/action_cable/integration.rb +8 -0
  82. data/lib/ddtrace/contrib/action_cable/patcher.rb +2 -0
  83. data/lib/ddtrace/contrib/action_mailer/configuration/settings.rb +32 -0
  84. data/lib/ddtrace/contrib/action_mailer/event.rb +50 -0
  85. data/lib/ddtrace/contrib/action_mailer/events/deliver.rb +54 -0
  86. data/lib/ddtrace/contrib/action_mailer/events/process.rb +41 -0
  87. data/lib/ddtrace/contrib/action_mailer/events.rb +31 -0
  88. data/lib/ddtrace/contrib/action_mailer/ext.rb +32 -0
  89. data/lib/ddtrace/contrib/action_mailer/integration.rb +45 -0
  90. data/lib/ddtrace/contrib/action_mailer/patcher.rb +27 -0
  91. data/lib/ddtrace/contrib/action_pack/action_controller/instrumentation.rb +22 -13
  92. data/lib/ddtrace/contrib/action_pack/action_controller/patcher.rb +2 -1
  93. data/lib/ddtrace/contrib/action_pack/configuration/settings.rb +1 -0
  94. data/lib/ddtrace/contrib/action_pack/ext.rb +1 -0
  95. data/lib/ddtrace/contrib/action_pack/integration.rb +8 -0
  96. data/lib/ddtrace/contrib/action_pack/patcher.rb +1 -0
  97. data/lib/ddtrace/contrib/action_pack/utils.rb +2 -1
  98. data/lib/ddtrace/contrib/action_view/configuration/settings.rb +1 -0
  99. data/lib/ddtrace/contrib/action_view/event.rb +4 -7
  100. data/lib/ddtrace/contrib/action_view/events/render_partial.rb +2 -0
  101. data/lib/ddtrace/contrib/action_view/events/render_template.rb +2 -0
  102. data/lib/ddtrace/contrib/action_view/events.rb +1 -0
  103. data/lib/ddtrace/contrib/action_view/ext.rb +1 -0
  104. data/lib/ddtrace/contrib/action_view/instrumentation/partial_renderer.rb +1 -0
  105. data/lib/ddtrace/contrib/action_view/instrumentation/template_renderer.rb +1 -0
  106. data/lib/ddtrace/contrib/action_view/integration.rb +8 -0
  107. data/lib/ddtrace/contrib/action_view/patcher.rb +5 -4
  108. data/lib/ddtrace/contrib/action_view/utils.rb +2 -1
  109. data/lib/ddtrace/contrib/active_job/configuration/settings.rb +33 -0
  110. data/lib/ddtrace/contrib/active_job/event.rb +54 -0
  111. data/lib/ddtrace/contrib/active_job/events/discard.rb +46 -0
  112. data/lib/ddtrace/contrib/active_job/events/enqueue.rb +45 -0
  113. data/lib/ddtrace/contrib/active_job/events/enqueue_at.rb +45 -0
  114. data/lib/ddtrace/contrib/active_job/events/enqueue_retry.rb +47 -0
  115. data/lib/ddtrace/contrib/active_job/events/perform.rb +45 -0
  116. data/lib/ddtrace/contrib/active_job/events/retry_stopped.rb +46 -0
  117. data/lib/ddtrace/contrib/active_job/events.rb +39 -0
  118. data/lib/ddtrace/contrib/active_job/ext.rb +32 -0
  119. data/lib/ddtrace/contrib/active_job/integration.rb +46 -0
  120. data/lib/ddtrace/contrib/active_job/log_injection.rb +21 -0
  121. data/lib/ddtrace/contrib/active_job/patcher.rb +33 -0
  122. data/lib/ddtrace/contrib/active_model_serializers/configuration/settings.rb +1 -0
  123. data/lib/ddtrace/contrib/active_model_serializers/event.rb +3 -2
  124. data/lib/ddtrace/contrib/active_model_serializers/events/render.rb +1 -0
  125. data/lib/ddtrace/contrib/active_model_serializers/events/serialize.rb +1 -0
  126. data/lib/ddtrace/contrib/active_model_serializers/events.rb +1 -0
  127. data/lib/ddtrace/contrib/active_model_serializers/ext.rb +1 -0
  128. data/lib/ddtrace/contrib/active_model_serializers/integration.rb +1 -0
  129. data/lib/ddtrace/contrib/active_model_serializers/patcher.rb +1 -0
  130. data/lib/ddtrace/contrib/active_record/configuration/makara_resolver.rb +31 -0
  131. data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +108 -18
  132. data/lib/ddtrace/contrib/active_record/configuration/settings.rb +1 -0
  133. data/lib/ddtrace/contrib/active_record/event.rb +3 -2
  134. data/lib/ddtrace/contrib/active_record/events/instantiation.rb +1 -0
  135. data/lib/ddtrace/contrib/active_record/events/sql.rb +5 -0
  136. data/lib/ddtrace/contrib/active_record/events.rb +1 -0
  137. data/lib/ddtrace/contrib/active_record/ext.rb +1 -0
  138. data/lib/ddtrace/contrib/active_record/integration.rb +8 -0
  139. data/lib/ddtrace/contrib/active_record/patcher.rb +1 -0
  140. data/lib/ddtrace/contrib/active_record/utils.rb +69 -21
  141. data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +105 -3
  142. data/lib/ddtrace/contrib/active_support/cache/patcher.rb +26 -4
  143. data/lib/ddtrace/contrib/active_support/cache/redis.rb +2 -5
  144. data/lib/ddtrace/contrib/active_support/configuration/settings.rb +1 -0
  145. data/lib/ddtrace/contrib/active_support/ext.rb +4 -0
  146. data/lib/ddtrace/contrib/active_support/integration.rb +8 -1
  147. data/lib/ddtrace/contrib/active_support/notifications/event.rb +15 -3
  148. data/lib/ddtrace/contrib/active_support/notifications/subscriber.rb +3 -1
  149. data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +12 -7
  150. data/lib/ddtrace/contrib/active_support/patcher.rb +1 -0
  151. data/lib/ddtrace/contrib/analytics.rb +1 -0
  152. data/lib/ddtrace/contrib/auto_instrument.rb +48 -0
  153. data/lib/ddtrace/contrib/aws/configuration/settings.rb +1 -0
  154. data/lib/ddtrace/contrib/aws/ext.rb +1 -0
  155. data/lib/ddtrace/contrib/aws/instrumentation.rb +36 -1
  156. data/lib/ddtrace/contrib/aws/integration.rb +1 -0
  157. data/lib/ddtrace/contrib/aws/parsed_context.rb +1 -0
  158. data/lib/ddtrace/contrib/aws/patcher.rb +6 -1
  159. data/lib/ddtrace/contrib/aws/services.rb +4 -0
  160. data/lib/ddtrace/contrib/concurrent_ruby/configuration/settings.rb +1 -0
  161. data/lib/ddtrace/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -0
  162. data/lib/ddtrace/contrib/concurrent_ruby/ext.rb +1 -0
  163. data/lib/ddtrace/contrib/concurrent_ruby/future_patch.rb +1 -0
  164. data/lib/ddtrace/contrib/concurrent_ruby/integration.rb +1 -0
  165. data/lib/ddtrace/contrib/concurrent_ruby/patcher.rb +3 -1
  166. data/lib/ddtrace/contrib/configurable.rb +65 -38
  167. data/lib/ddtrace/contrib/configuration/resolver.rb +71 -5
  168. data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +21 -20
  169. data/lib/ddtrace/contrib/configuration/settings.rb +8 -6
  170. data/lib/ddtrace/contrib/dalli/configuration/settings.rb +1 -0
  171. data/lib/ddtrace/contrib/dalli/ext.rb +1 -0
  172. data/lib/ddtrace/contrib/dalli/instrumentation.rb +6 -1
  173. data/lib/ddtrace/contrib/dalli/integration.rb +1 -0
  174. data/lib/ddtrace/contrib/dalli/patcher.rb +2 -39
  175. data/lib/ddtrace/contrib/dalli/quantize.rb +1 -0
  176. data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +3 -0
  177. data/lib/ddtrace/contrib/delayed_job/ext.rb +3 -0
  178. data/lib/ddtrace/contrib/delayed_job/integration.rb +1 -0
  179. data/lib/ddtrace/contrib/delayed_job/patcher.rb +1 -0
  180. data/lib/ddtrace/contrib/delayed_job/plugin.rb +40 -16
  181. data/lib/ddtrace/contrib/elasticsearch/configuration/settings.rb +1 -0
  182. data/lib/ddtrace/contrib/elasticsearch/ext.rb +1 -0
  183. data/lib/ddtrace/contrib/elasticsearch/integration.rb +1 -0
  184. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +6 -0
  185. data/lib/ddtrace/contrib/elasticsearch/quantize.rb +6 -2
  186. data/lib/ddtrace/contrib/ethon/configuration/settings.rb +1 -0
  187. data/lib/ddtrace/contrib/ethon/easy_patch.rb +15 -11
  188. data/lib/ddtrace/contrib/ethon/ext.rb +2 -0
  189. data/lib/ddtrace/contrib/ethon/integration.rb +1 -0
  190. data/lib/ddtrace/contrib/ethon/multi_patch.rb +6 -1
  191. data/lib/ddtrace/contrib/ethon/patcher.rb +4 -2
  192. data/lib/ddtrace/contrib/excon/configuration/settings.rb +1 -0
  193. data/lib/ddtrace/contrib/excon/ext.rb +1 -0
  194. data/lib/ddtrace/contrib/excon/integration.rb +1 -0
  195. data/lib/ddtrace/contrib/excon/middleware.rb +14 -7
  196. data/lib/ddtrace/contrib/excon/patcher.rb +1 -0
  197. data/lib/ddtrace/contrib/extensions.rb +90 -14
  198. data/lib/ddtrace/contrib/faraday/configuration/settings.rb +1 -0
  199. data/lib/ddtrace/contrib/faraday/connection.rb +1 -0
  200. data/lib/ddtrace/contrib/faraday/ext.rb +1 -0
  201. data/lib/ddtrace/contrib/faraday/integration.rb +1 -0
  202. data/lib/ddtrace/contrib/faraday/middleware.rb +6 -3
  203. data/lib/ddtrace/contrib/faraday/patcher.rb +3 -38
  204. data/lib/ddtrace/contrib/faraday/rack_builder.rb +1 -0
  205. data/lib/ddtrace/contrib/grape/configuration/settings.rb +8 -0
  206. data/lib/ddtrace/contrib/grape/endpoint.rb +73 -35
  207. data/lib/ddtrace/contrib/grape/ext.rb +2 -0
  208. data/lib/ddtrace/contrib/grape/instrumentation.rb +4 -3
  209. data/lib/ddtrace/contrib/grape/integration.rb +1 -0
  210. data/lib/ddtrace/contrib/grape/patcher.rb +2 -43
  211. data/lib/ddtrace/contrib/graphql/configuration/settings.rb +1 -0
  212. data/lib/ddtrace/contrib/graphql/ext.rb +1 -0
  213. data/lib/ddtrace/contrib/graphql/integration.rb +1 -0
  214. data/lib/ddtrace/contrib/graphql/patcher.rb +1 -0
  215. data/lib/ddtrace/contrib/grpc/configuration/settings.rb +2 -0
  216. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +6 -1
  217. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +5 -1
  218. data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +13 -8
  219. data/lib/ddtrace/contrib/grpc/ext.rb +1 -0
  220. data/lib/ddtrace/contrib/grpc/integration.rb +1 -0
  221. data/lib/ddtrace/contrib/grpc/intercept_with_datadog.rb +1 -0
  222. data/lib/ddtrace/contrib/grpc/patcher.rb +3 -37
  223. data/lib/ddtrace/contrib/http/circuit_breaker.rb +2 -3
  224. data/lib/ddtrace/contrib/http/configuration/settings.rb +1 -0
  225. data/lib/ddtrace/contrib/http/ext.rb +1 -0
  226. data/lib/ddtrace/contrib/http/instrumentation.rb +13 -8
  227. data/lib/ddtrace/contrib/http/integration.rb +1 -0
  228. data/lib/ddtrace/contrib/http/patcher.rb +2 -1
  229. data/lib/ddtrace/contrib/http_annotation_helper.rb +1 -0
  230. data/lib/ddtrace/contrib/httpclient/configuration/settings.rb +33 -0
  231. data/lib/ddtrace/contrib/httpclient/ext.rb +18 -0
  232. data/lib/ddtrace/contrib/httpclient/instrumentation.rb +148 -0
  233. data/lib/ddtrace/contrib/httpclient/integration.rb +44 -0
  234. data/lib/ddtrace/contrib/httpclient/patcher.rb +39 -0
  235. data/lib/ddtrace/contrib/httprb/configuration/settings.rb +1 -0
  236. data/lib/ddtrace/contrib/httprb/ext.rb +1 -0
  237. data/lib/ddtrace/contrib/httprb/instrumentation.rb +20 -22
  238. data/lib/ddtrace/contrib/httprb/integration.rb +1 -0
  239. data/lib/ddtrace/contrib/httprb/patcher.rb +8 -4
  240. data/lib/ddtrace/contrib/integration.rb +4 -3
  241. data/lib/ddtrace/contrib/kafka/configuration/settings.rb +1 -0
  242. data/lib/ddtrace/contrib/kafka/consumer_event.rb +1 -0
  243. data/lib/ddtrace/contrib/kafka/consumer_group_event.rb +1 -0
  244. data/lib/ddtrace/contrib/kafka/event.rb +4 -3
  245. data/lib/ddtrace/contrib/kafka/events/connection/request.rb +1 -0
  246. data/lib/ddtrace/contrib/kafka/events/consumer/process_batch.rb +1 -0
  247. data/lib/ddtrace/contrib/kafka/events/consumer/process_message.rb +1 -0
  248. data/lib/ddtrace/contrib/kafka/events/consumer_group/heartbeat.rb +1 -0
  249. data/lib/ddtrace/contrib/kafka/events/consumer_group/join_group.rb +1 -0
  250. data/lib/ddtrace/contrib/kafka/events/consumer_group/leave_group.rb +1 -0
  251. data/lib/ddtrace/contrib/kafka/events/consumer_group/sync_group.rb +1 -0
  252. data/lib/ddtrace/contrib/kafka/events/produce_operation/send_messages.rb +1 -0
  253. data/lib/ddtrace/contrib/kafka/events/producer/deliver_messages.rb +1 -0
  254. data/lib/ddtrace/contrib/kafka/events.rb +1 -0
  255. data/lib/ddtrace/contrib/kafka/ext.rb +1 -0
  256. data/lib/ddtrace/contrib/kafka/integration.rb +1 -0
  257. data/lib/ddtrace/contrib/kafka/patcher.rb +1 -0
  258. data/lib/ddtrace/contrib/lograge/configuration/settings.rb +19 -0
  259. data/lib/ddtrace/contrib/lograge/ext.rb +11 -0
  260. data/lib/ddtrace/contrib/lograge/instrumentation.rb +39 -0
  261. data/lib/ddtrace/contrib/lograge/integration.rb +46 -0
  262. data/lib/ddtrace/contrib/lograge/patcher.rb +26 -0
  263. data/lib/ddtrace/contrib/mongodb/configuration/settings.rb +1 -0
  264. data/lib/ddtrace/contrib/mongodb/ext.rb +1 -0
  265. data/lib/ddtrace/contrib/mongodb/instrumentation.rb +6 -3
  266. data/lib/ddtrace/contrib/mongodb/integration.rb +6 -0
  267. data/lib/ddtrace/contrib/mongodb/parsers.rb +1 -0
  268. data/lib/ddtrace/contrib/mongodb/patcher.rb +3 -2
  269. data/lib/ddtrace/contrib/mongodb/subscribers.rb +7 -3
  270. data/lib/ddtrace/contrib/mysql2/configuration/settings.rb +1 -0
  271. data/lib/ddtrace/contrib/mysql2/ext.rb +1 -0
  272. data/lib/ddtrace/contrib/mysql2/instrumentation.rb +6 -1
  273. data/lib/ddtrace/contrib/mysql2/integration.rb +1 -0
  274. data/lib/ddtrace/contrib/mysql2/patcher.rb +2 -1
  275. data/lib/ddtrace/contrib/patchable.rb +21 -9
  276. data/lib/ddtrace/contrib/patcher.rb +12 -8
  277. data/lib/ddtrace/contrib/presto/configuration/settings.rb +1 -0
  278. data/lib/ddtrace/contrib/presto/ext.rb +1 -0
  279. data/lib/ddtrace/contrib/presto/instrumentation.rb +5 -1
  280. data/lib/ddtrace/contrib/presto/integration.rb +1 -0
  281. data/lib/ddtrace/contrib/presto/patcher.rb +7 -3
  282. data/lib/ddtrace/contrib/qless/configuration/settings.rb +36 -0
  283. data/lib/ddtrace/contrib/qless/ext.rb +21 -0
  284. data/lib/ddtrace/contrib/qless/integration.rb +39 -0
  285. data/lib/ddtrace/contrib/qless/patcher.rb +35 -0
  286. data/lib/ddtrace/contrib/qless/qless_job.rb +74 -0
  287. data/lib/ddtrace/contrib/qless/tracer_cleaner.rb +34 -0
  288. data/lib/ddtrace/contrib/que/configuration/settings.rb +2 -0
  289. data/lib/ddtrace/contrib/que/ext.rb +20 -19
  290. data/lib/ddtrace/contrib/que/integration.rb +1 -0
  291. data/lib/ddtrace/contrib/que/patcher.rb +1 -0
  292. data/lib/ddtrace/contrib/que/tracer.rb +4 -2
  293. data/lib/ddtrace/contrib/racecar/configuration/settings.rb +1 -0
  294. data/lib/ddtrace/contrib/racecar/event.rb +8 -2
  295. data/lib/ddtrace/contrib/racecar/events/batch.rb +1 -0
  296. data/lib/ddtrace/contrib/racecar/events/consume.rb +1 -0
  297. data/lib/ddtrace/contrib/racecar/events/message.rb +1 -0
  298. data/lib/ddtrace/contrib/racecar/events.rb +1 -0
  299. data/lib/ddtrace/contrib/racecar/ext.rb +1 -0
  300. data/lib/ddtrace/contrib/racecar/integration.rb +1 -0
  301. data/lib/ddtrace/contrib/racecar/patcher.rb +1 -0
  302. data/lib/ddtrace/contrib/rack/configuration/settings.rb +4 -3
  303. data/lib/ddtrace/contrib/rack/ext.rb +1 -0
  304. data/lib/ddtrace/contrib/rack/integration.rb +8 -0
  305. data/lib/ddtrace/contrib/rack/middlewares.rb +8 -12
  306. data/lib/ddtrace/contrib/rack/patcher.rb +2 -3
  307. data/lib/ddtrace/contrib/rack/request_queue.rb +7 -1
  308. data/lib/ddtrace/contrib/rails/auto_instrument_railtie.rb +10 -0
  309. data/lib/ddtrace/contrib/rails/configuration/settings.rb +8 -0
  310. data/lib/ddtrace/contrib/rails/ext.rb +1 -0
  311. data/lib/ddtrace/contrib/rails/framework.rb +50 -2
  312. data/lib/ddtrace/contrib/rails/integration.rb +1 -0
  313. data/lib/ddtrace/contrib/rails/log_injection.rb +1 -40
  314. data/lib/ddtrace/contrib/rails/middlewares.rb +1 -0
  315. data/lib/ddtrace/contrib/rails/patcher.rb +47 -17
  316. data/lib/ddtrace/contrib/rails/railtie.rb +1 -0
  317. data/lib/ddtrace/contrib/rails/utils.rb +5 -0
  318. data/lib/ddtrace/contrib/rake/configuration/settings.rb +1 -0
  319. data/lib/ddtrace/contrib/rake/ext.rb +1 -0
  320. data/lib/ddtrace/contrib/rake/instrumentation.rb +6 -3
  321. data/lib/ddtrace/contrib/rake/integration.rb +2 -1
  322. data/lib/ddtrace/contrib/rake/patcher.rb +2 -1
  323. data/lib/ddtrace/contrib/redis/configuration/resolver.rb +15 -5
  324. data/lib/ddtrace/contrib/redis/configuration/settings.rb +6 -0
  325. data/lib/ddtrace/contrib/redis/ext.rb +2 -0
  326. data/lib/ddtrace/contrib/redis/instrumentation.rb +90 -0
  327. data/lib/ddtrace/contrib/redis/integration.rb +1 -0
  328. data/lib/ddtrace/contrib/redis/patcher.rb +3 -67
  329. data/lib/ddtrace/contrib/redis/quantize.rb +29 -0
  330. data/lib/ddtrace/contrib/redis/tags.rb +10 -1
  331. data/lib/ddtrace/contrib/redis/vendor/LICENSE +20 -0
  332. data/lib/ddtrace/contrib/redis/vendor/resolver.rb +7 -7
  333. data/lib/ddtrace/contrib/registerable.rb +4 -4
  334. data/lib/ddtrace/contrib/registry.rb +3 -2
  335. data/lib/ddtrace/contrib/resque/configuration/settings.rb +19 -1
  336. data/lib/ddtrace/contrib/resque/ext.rb +1 -0
  337. data/lib/ddtrace/contrib/resque/integration.rb +2 -5
  338. data/lib/ddtrace/contrib/resque/patcher.rb +5 -4
  339. data/lib/ddtrace/contrib/resque/resque_job.rb +26 -2
  340. data/lib/ddtrace/contrib/rest_client/configuration/settings.rb +1 -0
  341. data/lib/ddtrace/contrib/rest_client/ext.rb +1 -0
  342. data/lib/ddtrace/contrib/rest_client/integration.rb +1 -0
  343. data/lib/ddtrace/contrib/rest_client/patcher.rb +3 -1
  344. data/lib/ddtrace/contrib/rest_client/request_patch.rb +7 -4
  345. data/lib/ddtrace/contrib/semantic_logger/configuration/settings.rb +19 -0
  346. data/lib/ddtrace/contrib/semantic_logger/ext.rb +11 -0
  347. data/lib/ddtrace/contrib/semantic_logger/instrumentation.rb +43 -0
  348. data/lib/ddtrace/contrib/semantic_logger/integration.rb +48 -0
  349. data/lib/ddtrace/contrib/semantic_logger/patcher.rb +26 -0
  350. data/lib/ddtrace/contrib/sequel/configuration/settings.rb +1 -0
  351. data/lib/ddtrace/contrib/sequel/database.rb +5 -2
  352. data/lib/ddtrace/contrib/sequel/dataset.rb +5 -3
  353. data/lib/ddtrace/contrib/sequel/ext.rb +2 -0
  354. data/lib/ddtrace/contrib/sequel/integration.rb +1 -0
  355. data/lib/ddtrace/contrib/sequel/patcher.rb +3 -2
  356. data/lib/ddtrace/contrib/sequel/utils.rb +16 -5
  357. data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +3 -0
  358. data/lib/ddtrace/contrib/shoryuken/ext.rb +1 -0
  359. data/lib/ddtrace/contrib/shoryuken/integration.rb +1 -0
  360. data/lib/ddtrace/contrib/shoryuken/patcher.rb +1 -0
  361. data/lib/ddtrace/contrib/shoryuken/tracer.rb +9 -2
  362. data/lib/ddtrace/contrib/sidekiq/client_tracer.rb +1 -0
  363. data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +2 -0
  364. data/lib/ddtrace/contrib/sidekiq/ext.rb +4 -0
  365. data/lib/ddtrace/contrib/sidekiq/integration.rb +11 -0
  366. data/lib/ddtrace/contrib/sidekiq/patcher.rb +27 -0
  367. data/lib/ddtrace/contrib/sidekiq/server_internal_tracer/heartbeat.rb +30 -0
  368. data/lib/ddtrace/contrib/sidekiq/server_internal_tracer/job_fetch.rb +30 -0
  369. data/lib/ddtrace/contrib/sidekiq/server_internal_tracer/scheduled_push.rb +29 -0
  370. data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +6 -7
  371. data/lib/ddtrace/contrib/sidekiq/tracing.rb +1 -1
  372. data/lib/ddtrace/contrib/sinatra/configuration/settings.rb +1 -0
  373. data/lib/ddtrace/contrib/sinatra/env.rb +4 -4
  374. data/lib/ddtrace/contrib/sinatra/ext.rb +1 -0
  375. data/lib/ddtrace/contrib/sinatra/headers.rb +2 -3
  376. data/lib/ddtrace/contrib/sinatra/integration.rb +1 -0
  377. data/lib/ddtrace/contrib/sinatra/patcher.rb +3 -1
  378. data/lib/ddtrace/contrib/sinatra/tracer.rb +28 -7
  379. data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +13 -6
  380. data/lib/ddtrace/contrib/sneakers/configuration/settings.rb +2 -0
  381. data/lib/ddtrace/contrib/sneakers/ext.rb +12 -11
  382. data/lib/ddtrace/contrib/sneakers/integration.rb +1 -0
  383. data/lib/ddtrace/contrib/sneakers/patcher.rb +1 -0
  384. data/lib/ddtrace/contrib/sneakers/tracer.rb +17 -21
  385. data/lib/ddtrace/contrib/status_code_matcher.rb +70 -0
  386. data/lib/ddtrace/contrib/sucker_punch/configuration/settings.rb +1 -0
  387. data/lib/ddtrace/contrib/sucker_punch/exception_handler.rb +5 -6
  388. data/lib/ddtrace/contrib/sucker_punch/ext.rb +1 -0
  389. data/lib/ddtrace/contrib/sucker_punch/instrumentation.rb +5 -0
  390. data/lib/ddtrace/contrib/sucker_punch/integration.rb +1 -0
  391. data/lib/ddtrace/contrib/sucker_punch/patcher.rb +2 -0
  392. data/lib/ddtrace/correlation.rb +3 -1
  393. data/lib/ddtrace/diagnostics/environment_logger.rb +9 -7
  394. data/lib/ddtrace/diagnostics/health.rb +1 -0
  395. data/lib/ddtrace/distributed_tracing/headers/b3.rb +1 -0
  396. data/lib/ddtrace/distributed_tracing/headers/b3_single.rb +1 -0
  397. data/lib/ddtrace/distributed_tracing/headers/datadog.rb +1 -0
  398. data/lib/ddtrace/distributed_tracing/headers/headers.rb +2 -0
  399. data/lib/ddtrace/distributed_tracing/headers/helpers.rb +2 -3
  400. data/lib/ddtrace/encoding.rb +3 -0
  401. data/lib/ddtrace/error.rb +78 -8
  402. data/lib/ddtrace/event.rb +1 -0
  403. data/lib/ddtrace/ext/analytics.rb +1 -0
  404. data/lib/ddtrace/ext/app_types.rb +1 -0
  405. data/lib/ddtrace/ext/correlation.rb +1 -0
  406. data/lib/ddtrace/ext/diagnostics.rb +1 -0
  407. data/lib/ddtrace/ext/distributed.rb +9 -2
  408. data/lib/ddtrace/ext/environment.rb +8 -0
  409. data/lib/ddtrace/ext/errors.rb +1 -0
  410. data/lib/ddtrace/ext/forced_tracing.rb +1 -0
  411. data/lib/ddtrace/ext/git.rb +32 -0
  412. data/lib/ddtrace/ext/http.rb +2 -1
  413. data/lib/ddtrace/ext/integration.rb +9 -0
  414. data/lib/ddtrace/ext/manual_tracing.rb +1 -0
  415. data/lib/ddtrace/ext/metrics.rb +1 -0
  416. data/lib/ddtrace/ext/net.rb +1 -0
  417. data/lib/ddtrace/ext/priority.rb +7 -4
  418. data/lib/ddtrace/ext/profiling.rb +57 -0
  419. data/lib/ddtrace/ext/runtime.rb +5 -6
  420. data/lib/ddtrace/ext/sampling.rb +1 -0
  421. data/lib/ddtrace/ext/sql.rb +1 -0
  422. data/lib/ddtrace/ext/test.rb +9 -0
  423. data/lib/ddtrace/ext/transport.rb +14 -0
  424. data/lib/ddtrace/forced_tracing.rb +3 -0
  425. data/lib/ddtrace/logger.rb +2 -1
  426. data/lib/ddtrace/metrics.rb +84 -24
  427. data/lib/ddtrace/opentelemetry/extensions.rb +2 -1
  428. data/lib/ddtrace/opentelemetry/span.rb +1 -0
  429. data/lib/ddtrace/opentracer/binary_propagator.rb +1 -0
  430. data/lib/ddtrace/opentracer/carrier.rb +1 -0
  431. data/lib/ddtrace/opentracer/distributed_headers.rb +5 -1
  432. data/lib/ddtrace/opentracer/global_tracer.rb +1 -0
  433. data/lib/ddtrace/opentracer/propagator.rb +1 -0
  434. data/lib/ddtrace/opentracer/rack_propagator.rb +1 -0
  435. data/lib/ddtrace/opentracer/scope.rb +1 -0
  436. data/lib/ddtrace/opentracer/scope_manager.rb +1 -0
  437. data/lib/ddtrace/opentracer/span.rb +3 -6
  438. data/lib/ddtrace/opentracer/span_context.rb +1 -0
  439. data/lib/ddtrace/opentracer/span_context_factory.rb +1 -0
  440. data/lib/ddtrace/opentracer/text_map_propagator.rb +1 -0
  441. data/lib/ddtrace/opentracer/thread_local_scope.rb +2 -0
  442. data/lib/ddtrace/opentracer/thread_local_scope_manager.rb +1 -0
  443. data/lib/ddtrace/opentracer/tracer.rb +1 -0
  444. data/lib/ddtrace/opentracer.rb +21 -39
  445. data/lib/ddtrace/patcher.rb +28 -6
  446. data/lib/ddtrace/pin.rb +9 -61
  447. data/lib/ddtrace/pipeline/span_filter.rb +2 -1
  448. data/lib/ddtrace/pipeline/span_processor.rb +1 -0
  449. data/lib/ddtrace/pipeline.rb +1 -0
  450. data/lib/ddtrace/profiling/backtrace_location.rb +33 -0
  451. data/lib/ddtrace/profiling/buffer.rb +42 -0
  452. data/lib/ddtrace/profiling/collectors/stack.rb +301 -0
  453. data/lib/ddtrace/profiling/encoding/profile.rb +46 -0
  454. data/lib/ddtrace/profiling/event.rb +14 -0
  455. data/lib/ddtrace/profiling/events/stack.rb +81 -0
  456. data/lib/ddtrace/profiling/exporter.rb +24 -0
  457. data/lib/ddtrace/profiling/ext/forking.rb +98 -0
  458. data/lib/ddtrace/profiling/flush.rb +44 -0
  459. data/lib/ddtrace/profiling/native_extension.rb +40 -0
  460. data/lib/ddtrace/profiling/pprof/builder.rb +126 -0
  461. data/lib/ddtrace/profiling/pprof/converter.rb +103 -0
  462. data/lib/ddtrace/profiling/pprof/message_set.rb +15 -0
  463. data/lib/ddtrace/profiling/pprof/payload.rb +19 -0
  464. data/lib/ddtrace/profiling/pprof/pprof.proto +212 -0
  465. data/lib/ddtrace/profiling/pprof/pprof_pb.rb +82 -0
  466. data/lib/ddtrace/profiling/pprof/stack_sample.rb +140 -0
  467. data/lib/ddtrace/profiling/pprof/string_table.rb +11 -0
  468. data/lib/ddtrace/profiling/pprof/template.rb +119 -0
  469. data/lib/ddtrace/profiling/preload.rb +4 -0
  470. data/lib/ddtrace/profiling/profiler.rb +31 -0
  471. data/lib/ddtrace/profiling/recorder.rb +96 -0
  472. data/lib/ddtrace/profiling/scheduler.rb +134 -0
  473. data/lib/ddtrace/profiling/tasks/setup.rb +90 -0
  474. data/lib/ddtrace/profiling/trace_identifiers/ddtrace.rb +42 -0
  475. data/lib/ddtrace/profiling/trace_identifiers/helper.rb +46 -0
  476. data/lib/ddtrace/profiling/transport/client.rb +15 -0
  477. data/lib/ddtrace/profiling/transport/http/api/endpoint.rb +101 -0
  478. data/lib/ddtrace/profiling/transport/http/api/instance.rb +37 -0
  479. data/lib/ddtrace/profiling/transport/http/api/spec.rb +41 -0
  480. data/lib/ddtrace/profiling/transport/http/api.rb +44 -0
  481. data/lib/ddtrace/profiling/transport/http/builder.rb +29 -0
  482. data/lib/ddtrace/profiling/transport/http/client.rb +34 -0
  483. data/lib/ddtrace/profiling/transport/http/response.rb +22 -0
  484. data/lib/ddtrace/profiling/transport/http.rb +111 -0
  485. data/lib/ddtrace/profiling/transport/io/client.rb +28 -0
  486. data/lib/ddtrace/profiling/transport/io/response.rb +17 -0
  487. data/lib/ddtrace/profiling/transport/io.rb +31 -0
  488. data/lib/ddtrace/profiling/transport/parcel.rb +18 -0
  489. data/lib/ddtrace/profiling/transport/request.rb +16 -0
  490. data/lib/ddtrace/profiling/transport/response.rb +9 -0
  491. data/lib/ddtrace/profiling.rb +149 -0
  492. data/lib/ddtrace/propagation/grpc_propagator.rb +20 -6
  493. data/lib/ddtrace/propagation/http_propagator.rb +18 -2
  494. data/lib/ddtrace/quantization/hash.rb +1 -0
  495. data/lib/ddtrace/quantization/http.rb +4 -0
  496. data/lib/ddtrace/runtime/metrics.rb +40 -15
  497. data/lib/ddtrace/sampler.rb +22 -11
  498. data/lib/ddtrace/sampling/matcher.rb +1 -0
  499. data/lib/ddtrace/sampling/rate_limiter.rb +66 -16
  500. data/lib/ddtrace/sampling/rule.rb +2 -1
  501. data/lib/ddtrace/sampling/rule_sampler.rb +19 -11
  502. data/lib/ddtrace/sampling.rb +1 -0
  503. data/lib/ddtrace/span.rb +174 -36
  504. data/lib/ddtrace/sync_writer.rb +17 -15
  505. data/lib/ddtrace/tasks/exec.rb +47 -0
  506. data/lib/ddtrace/tasks/help.rb +15 -0
  507. data/lib/ddtrace/tracer.rb +72 -62
  508. data/lib/ddtrace/transport/http/adapters/net.rb +48 -12
  509. data/lib/ddtrace/transport/http/adapters/registry.rb +2 -0
  510. data/lib/ddtrace/transport/http/adapters/test.rb +5 -2
  511. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +26 -16
  512. data/lib/ddtrace/transport/http/api/endpoint.rb +1 -0
  513. data/lib/ddtrace/transport/http/api/fallbacks.rb +1 -0
  514. data/lib/ddtrace/transport/http/api/instance.rb +1 -0
  515. data/lib/ddtrace/transport/http/api/map.rb +1 -0
  516. data/lib/ddtrace/transport/http/api/spec.rb +1 -0
  517. data/lib/ddtrace/transport/http/api.rb +1 -0
  518. data/lib/ddtrace/transport/http/builder.rb +21 -7
  519. data/lib/ddtrace/transport/http/client.rb +3 -1
  520. data/lib/ddtrace/transport/http/env.rb +9 -0
  521. data/lib/ddtrace/transport/http/response.rb +1 -0
  522. data/lib/ddtrace/transport/http/statistics.rb +17 -3
  523. data/lib/ddtrace/transport/http/traces.rb +6 -6
  524. data/lib/ddtrace/transport/http.rb +48 -41
  525. data/lib/ddtrace/transport/io/client.rb +17 -9
  526. data/lib/ddtrace/transport/io/response.rb +2 -3
  527. data/lib/ddtrace/transport/io/traces.rb +10 -1
  528. data/lib/ddtrace/transport/io.rb +2 -1
  529. data/lib/ddtrace/transport/parcel.rb +7 -0
  530. data/lib/ddtrace/transport/request.rb +1 -0
  531. data/lib/ddtrace/transport/response.rb +1 -0
  532. data/lib/ddtrace/transport/statistics.rb +1 -0
  533. data/lib/ddtrace/transport/traces.rb +28 -5
  534. data/lib/ddtrace/utils/compression.rb +28 -0
  535. data/lib/ddtrace/utils/database.rb +1 -0
  536. data/lib/ddtrace/utils/forking.rb +53 -0
  537. data/lib/ddtrace/utils/object_set.rb +40 -0
  538. data/lib/ddtrace/utils/only_once.rb +41 -0
  539. data/lib/ddtrace/utils/sequence.rb +18 -0
  540. data/lib/ddtrace/utils/string_table.rb +46 -0
  541. data/lib/ddtrace/utils/time.rb +40 -3
  542. data/lib/ddtrace/utils.rb +29 -14
  543. data/lib/ddtrace/vendor/active_record/MIT-LICENSE +20 -0
  544. data/lib/ddtrace/vendor/active_record/connection_specification.rb +1 -0
  545. data/lib/ddtrace/vendor/multipart-post/LICENSE +11 -0
  546. data/lib/ddtrace/vendor/multipart-post/multipart/post/composite_read_io.rb +117 -0
  547. data/lib/ddtrace/vendor/multipart-post/multipart/post/multipartable.rb +58 -0
  548. data/lib/ddtrace/vendor/multipart-post/multipart/post/parts.rb +136 -0
  549. data/lib/ddtrace/vendor/multipart-post/multipart/post/version.rb +10 -0
  550. data/lib/ddtrace/vendor/multipart-post/multipart/post.rb +9 -0
  551. data/lib/ddtrace/vendor/multipart-post/multipart.rb +13 -0
  552. data/lib/ddtrace/vendor/multipart-post/net/http/post/multipart.rb +33 -0
  553. data/lib/ddtrace/version.rb +16 -3
  554. data/lib/ddtrace/worker.rb +1 -0
  555. data/lib/ddtrace/workers/async.rb +15 -5
  556. data/lib/ddtrace/workers/loop.rb +32 -5
  557. data/lib/ddtrace/workers/polling.rb +13 -5
  558. data/lib/ddtrace/workers/queue.rb +3 -1
  559. data/lib/ddtrace/workers/runtime_metrics.rb +22 -4
  560. data/lib/ddtrace/workers/trace_writer.rb +14 -16
  561. data/lib/ddtrace/workers.rb +8 -2
  562. data/lib/ddtrace/writer.rb +33 -8
  563. data/lib/ddtrace.rb +22 -48
  564. metadata +180 -374
  565. data/.circleci/config.yml +0 -548
  566. data/.circleci/images/primary/Dockerfile-2.0.0 +0 -73
  567. data/.circleci/images/primary/Dockerfile-2.1.10 +0 -73
  568. data/.circleci/images/primary/Dockerfile-2.2.10 +0 -73
  569. data/.circleci/images/primary/Dockerfile-2.3.8 +0 -75
  570. data/.circleci/images/primary/Dockerfile-2.4.6 +0 -73
  571. data/.circleci/images/primary/Dockerfile-2.5.6 +0 -73
  572. data/.circleci/images/primary/Dockerfile-2.6.4 +0 -73
  573. data/.circleci/images/primary/Dockerfile-2.7.0 +0 -73
  574. data/.circleci/images/primary/Dockerfile-jruby-9.2 +0 -77
  575. data/.dockerignore +0 -1
  576. data/.env +0 -26
  577. data/.github/CODEOWNERS +0 -1
  578. data/.gitlab-ci.yml +0 -27
  579. data/.rspec +0 -1
  580. data/.rubocop.yml +0 -85
  581. data/.simplecov +0 -38
  582. data/Appraisals +0 -1071
  583. data/Gemfile +0 -7
  584. data/Rakefile +0 -791
  585. data/benchmarks/postgres_database.yml +0 -9
  586. data/benchmarks/sidekiq_test.rb +0 -154
  587. data/docker-compose.yml +0 -370
  588. data/lib/ddtrace/augmentation/method_wrapper.rb +0 -20
  589. data/lib/ddtrace/augmentation/method_wrapping.rb +0 -38
  590. data/lib/ddtrace/augmentation/shim.rb +0 -102
  591. data/lib/ddtrace/augmentation.rb +0 -13
  592. data/lib/ddtrace/environment.rb +0 -41
  593. data/lib/ddtrace/monkey.rb +0 -58
  594. data/lib/ddtrace/runtime/cgroup.rb +0 -44
  595. data/lib/ddtrace/runtime/class_count.rb +0 -17
  596. data/lib/ddtrace/runtime/container.rb +0 -73
  597. data/lib/ddtrace/runtime/gc.rb +0 -16
  598. data/lib/ddtrace/runtime/identity.rb +0 -41
  599. data/lib/ddtrace/runtime/object_space.rb +0 -19
  600. data/lib/ddtrace/runtime/socket.rb +0 -14
  601. data/lib/ddtrace/runtime/thread_count.rb +0 -16
  602. data/tasks/release_gem.rake +0 -28
@@ -0,0 +1,301 @@
1
+ # typed: true
2
+
3
+ require 'ddtrace/profiling/native_extension'
4
+ require 'ddtrace/profiling/backtrace_location'
5
+ require 'ddtrace/profiling/events/stack'
6
+ require 'ddtrace/utils/only_once'
7
+ require 'ddtrace/utils/time'
8
+ require 'ddtrace/worker'
9
+ require 'ddtrace/workers/polling'
10
+
11
+ module Datadog
12
+ module Profiling
13
+ module Collectors
14
+ # Collects stack trace samples from Ruby threads for both CPU-time (if available) and wall-clock.
15
+ # Runs on its own background thread.
16
+ #
17
+ class Stack < Worker # rubocop:disable Metrics/ClassLength
18
+ include Workers::Polling
19
+
20
+ DEFAULT_MAX_TIME_USAGE_PCT = 2.0
21
+ MIN_INTERVAL = 0.01
22
+ THREAD_LAST_CPU_TIME_KEY = :datadog_profiler_last_cpu_time
23
+ THREAD_LAST_WALL_CLOCK_KEY = :datadog_profiler_last_wall_clock
24
+ SYNTHETIC_STACK_IN_NATIVE_CODE = [BacktraceLocation.new('', 0, 'In native code').freeze].freeze
25
+
26
+ # This default was picked based on the current sampling performance and on expected concurrency on an average
27
+ # Ruby MRI application. Lowering this optimizes for latency (less impact each time we sample), and raising
28
+ # optimizes for coverage (less chance to miss what a given thread is doing).
29
+ DEFAULT_MAX_THREADS_SAMPLED = 16
30
+
31
+ attr_reader \
32
+ :recorder,
33
+ :max_frames,
34
+ :trace_identifiers_helper,
35
+ :ignore_thread,
36
+ :max_time_usage_pct,
37
+ :thread_api,
38
+ :cpu_time_provider
39
+
40
+ def initialize(
41
+ recorder,
42
+ max_frames:,
43
+ trace_identifiers_helper:, # Usually an instance of Datadog::Profiling::TraceIdentifiers::Helper
44
+ ignore_thread: nil,
45
+ max_time_usage_pct: DEFAULT_MAX_TIME_USAGE_PCT,
46
+ max_threads_sampled: DEFAULT_MAX_THREADS_SAMPLED,
47
+ thread_api: Thread,
48
+ cpu_time_provider: Datadog::Profiling::NativeExtension,
49
+ fork_policy: Workers::Async::Thread::FORK_POLICY_RESTART, # Restart in forks by default
50
+ interval: MIN_INTERVAL,
51
+ enabled: true
52
+ )
53
+ @recorder = recorder
54
+ @max_frames = max_frames
55
+ @trace_identifiers_helper = trace_identifiers_helper
56
+ @ignore_thread = ignore_thread
57
+ @max_time_usage_pct = max_time_usage_pct
58
+ @max_threads_sampled = max_threads_sampled
59
+ @thread_api = thread_api
60
+ # Only set the provider if it's able to work in the current Ruby/OS combo
61
+ @cpu_time_provider = cpu_time_provider unless cpu_time_provider.cpu_time_ns_for(thread_api.current).nil?
62
+
63
+ # Workers::Async::Thread settings
64
+ self.fork_policy = fork_policy
65
+
66
+ # Workers::IntervalLoop settings
67
+ self.loop_base_interval = interval
68
+
69
+ # Workers::Polling settings
70
+ self.enabled = enabled
71
+
72
+ # Cache this proc, since it's pretty expensive to keep recreating it
73
+ @build_backtrace_location = method(:build_backtrace_location).to_proc
74
+ # Cache this buffer, since it's pretty expensive to keep accessing it
75
+ @stack_sample_event_recorder = recorder[Events::StackSample]
76
+ # See below for details on why this is needed
77
+ @needs_process_waiter_workaround =
78
+ Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3') &&
79
+ Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7')
80
+ end
81
+
82
+ def start
83
+ reset_cpu_time_tracking
84
+ perform
85
+ end
86
+
87
+ def perform
88
+ collect_and_wait
89
+ end
90
+
91
+ def loop_back_off?
92
+ false
93
+ end
94
+
95
+ def collect_and_wait
96
+ run_time = Datadog::Utils::Time.measure do
97
+ collect_events
98
+ end
99
+
100
+ # Update wait time to throttle profiling
101
+ self.loop_wait_time = compute_wait_time(run_time)
102
+ end
103
+
104
+ def collect_events
105
+ events = []
106
+ current_wall_time_ns = get_current_wall_time_timestamp_ns
107
+
108
+ # Collect backtraces from each thread
109
+ threads_to_sample.each do |thread|
110
+ next unless thread.alive?
111
+ next if ignore_thread.is_a?(Proc) && ignore_thread.call(thread)
112
+
113
+ event = collect_thread_event(thread, current_wall_time_ns)
114
+ events << event unless event.nil?
115
+ end
116
+
117
+ # Send events to recorder
118
+ recorder.push(events) unless events.empty?
119
+
120
+ events
121
+ end
122
+
123
+ def collect_thread_event(thread, current_wall_time_ns)
124
+ locations = thread.backtrace_locations
125
+ return if locations.nil?
126
+
127
+ # Having empty locations means that the thread is alive, but we don't know what it's doing:
128
+ #
129
+ # 1. It can be starting up
130
+ # ```
131
+ # > Thread.new { sleep }.backtrace
132
+ # => [] # <-- note the thread hasn't actually started running sleep yet, we got there first
133
+ # ```
134
+ # 2. It can be running native code
135
+ # ```
136
+ # > t = Process.detach(fork { sleep })
137
+ # => #<Process::Waiter:0x00007ffe7285f7a0 run>
138
+ # > t.backtrace
139
+ # => [] # <-- this can happen even minutes later, e.g. it's not a race as in 1.
140
+ # ```
141
+ # This effect has been observed in threads created by the Iodine web server and the ffi gem
142
+ #
143
+ # To give customers visibility into these threads, we replace the empty stack with one containing a
144
+ # synthetic placeholder frame, so that these threads are properly represented in the UX.
145
+ locations = SYNTHETIC_STACK_IN_NATIVE_CODE if locations.empty?
146
+
147
+ # Get actual stack size then trim the stack
148
+ stack_size = locations.length
149
+ locations = locations[0..(max_frames - 1)]
150
+
151
+ # Convert backtrace locations into structs
152
+ locations = convert_backtrace_locations(locations)
153
+
154
+ thread_id = thread.object_id
155
+ root_span_id, span_id, trace_resource = trace_identifiers_helper.trace_identifiers_for(thread)
156
+ cpu_time = get_cpu_time_interval!(thread)
157
+ wall_time_interval_ns =
158
+ get_elapsed_since_last_sample_and_set_value(thread, THREAD_LAST_WALL_CLOCK_KEY, current_wall_time_ns)
159
+
160
+ Events::StackSample.new(
161
+ nil,
162
+ locations,
163
+ stack_size,
164
+ thread_id,
165
+ root_span_id,
166
+ span_id,
167
+ trace_resource,
168
+ cpu_time,
169
+ wall_time_interval_ns
170
+ )
171
+ end
172
+
173
+ def get_cpu_time_interval!(thread)
174
+ return unless cpu_time_provider
175
+
176
+ current_cpu_time_ns = cpu_time_provider.cpu_time_ns_for(thread)
177
+
178
+ return unless current_cpu_time_ns
179
+
180
+ get_elapsed_since_last_sample_and_set_value(thread, THREAD_LAST_CPU_TIME_KEY, current_cpu_time_ns)
181
+ end
182
+
183
+ def compute_wait_time(used_time)
184
+ # We took used_time to get the last sample.
185
+ #
186
+ # What we're computing here is -- if used_time corresponds to max_time_usage_pct of the time we should
187
+ # spend working, how much is (100% - max_time_usage_pct) of the time?
188
+ #
189
+ # For instance, if we took 10ms to sample, and max_time_usage_pct is 1%, then the other 99% is 990ms, which
190
+ # means we need to sleep for 990ms to guarantee that we don't spend more than 1% of the time working.
191
+ used_time_ns = used_time * 1e9
192
+ interval = (used_time_ns / (max_time_usage_pct / 100.0)) - used_time_ns
193
+ [interval / 1e9, MIN_INTERVAL].max
194
+ end
195
+
196
+ # Convert backtrace locations into structs
197
+ # Re-use old backtrace location objects if they already exist in the buffer
198
+ def convert_backtrace_locations(locations)
199
+ locations.collect do |location|
200
+ # Re-use existing BacktraceLocation if identical copy, otherwise build a new one.
201
+ @stack_sample_event_recorder.cache(:backtrace_locations).fetch(
202
+ # Function name
203
+ location.base_label,
204
+ # Line number
205
+ location.lineno,
206
+ # Filename
207
+ location.path,
208
+ # Build function
209
+ &@build_backtrace_location
210
+ )
211
+ end
212
+ end
213
+
214
+ def build_backtrace_location(_id, base_label, lineno, path)
215
+ string_table = @stack_sample_event_recorder.string_table
216
+
217
+ Profiling::BacktraceLocation.new(
218
+ string_table.fetch_string(base_label),
219
+ lineno,
220
+ string_table.fetch_string(path)
221
+ )
222
+ end
223
+
224
+ private
225
+
226
+ # If the profiler is started for a while, stopped and then restarted OR whenever the process forks, we need to
227
+ # clean up any leftover per-thread counters, so that the first sample after starting doesn't end up with:
228
+ #
229
+ # a) negative time: At least on my test docker container, and on the reliability environment, after the process
230
+ # forks, the cpu time reference changes and (old cpu time - new cpu time) can be < 0
231
+ #
232
+ # b) large amount of time: if the profiler was started, then stopped for some amount of time, and then
233
+ # restarted, we don't want the first sample to be "blamed" for multiple minutes of CPU time
234
+ #
235
+ # By resetting the last cpu time seen, we start with a clean slate every time we start the stack collector.
236
+ def reset_cpu_time_tracking
237
+ thread_api.list.each do |thread|
238
+ # See below for details on why this is needed
239
+ next if @needs_process_waiter_workaround && thread.is_a?(::Process::Waiter)
240
+
241
+ thread.thread_variable_set(THREAD_LAST_CPU_TIME_KEY, nil)
242
+ thread.thread_variable_set(THREAD_LAST_WALL_CLOCK_KEY, nil)
243
+ end
244
+ end
245
+
246
+ def get_elapsed_since_last_sample_and_set_value(thread, key, current_value)
247
+ # Process::Waiter crash workaround:
248
+ #
249
+ # This is a workaround for a Ruby VM segfault (usually something like
250
+ # "[BUG] Segmentation fault at 0x0000000000000008") in the affected Ruby versions.
251
+ # See https://bugs.ruby-lang.org/issues/17807 for details.
252
+ #
253
+ # In those Ruby versions, there's a very special subclass of `Thread` called `Process::Waiter` that causes VM
254
+ # crashes whenever something tries to read its instance or thread variables. This subclass of thread only
255
+ # shows up when the `Process.detach` API gets used.
256
+ # In the specs you'll find crash regression tests that include a way of reproducing it.
257
+ #
258
+ # As workaround for now we just skip it for the affected Rubies
259
+ return 0 if @needs_process_waiter_workaround && thread.is_a?(::Process::Waiter)
260
+
261
+ last_value = thread.thread_variable_get(key) || current_value
262
+ thread.thread_variable_set(key, current_value)
263
+
264
+ current_value - last_value
265
+ end
266
+
267
+ # Whenever there are more than max_threads_sampled active, we only sample a subset of them.
268
+ # We do this to avoid impacting the latency of the service being profiled. We want to avoid doing
269
+ # a big burst of work all at once (sample everything), and instead do a little work each time
270
+ # (sample a bit by bit).
271
+ #
272
+ # Because we pick the threads to sample randomly, we'll eventually sample all threads -- just not at once.
273
+ # Notice also that this will interact with our dynamic sampling mechanism -- if samples are faster, we take
274
+ # them more often, if they are slower, we take them less often -- which again means that over a longer period
275
+ # we should take sample roughly the same samples.
276
+ #
277
+ # One downside of this approach is that if there really are many threads, the resulting wall clock times
278
+ # in a one minute profile may "drift" around the 60 second mark, e.g. maybe we only sampled a thread once per
279
+ # second and only 59 times, so we'll report 59s, but on the next report we'll include the missing one, so
280
+ # then the result will be 61s. I've observed 60 +- 1.68 secs for an app with ~65 threads, given the
281
+ # default maximum of 16 threads. This seems a reasonable enough margin of error given the improvement to
282
+ # latency (especially on such a large application! -> even bigger latency impact if we tried to sample all
283
+ # threads).
284
+ #
285
+ def threads_to_sample
286
+ all_threads = thread_api.list
287
+
288
+ if all_threads.size > @max_threads_sampled
289
+ all_threads.sample(@max_threads_sampled)
290
+ else
291
+ all_threads
292
+ end
293
+ end
294
+
295
+ def get_current_wall_time_timestamp_ns
296
+ Datadog::Utils::Time.get_time(:nanosecond)
297
+ end
298
+ end
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,46 @@
1
+ # typed: true
2
+ require 'set'
3
+ require 'time'
4
+
5
+ require 'ddtrace/profiling/flush'
6
+ require 'ddtrace/profiling/pprof/template'
7
+
8
+ module Datadog
9
+ module Profiling
10
+ module Encoding
11
+ module Profile
12
+ # Encodes gathered data into the pprof format
13
+ module Protobuf
14
+ module_function
15
+
16
+ def encode(flush)
17
+ return unless flush
18
+
19
+ # Create a pprof template from the list of event types
20
+ event_classes = flush.event_groups.collect(&:event_class).uniq
21
+ template = Pprof::Template.for_event_classes(event_classes)
22
+
23
+ # Add all events to the pprof
24
+ flush.event_groups.each { |event_group| template.add_events!(event_group.event_class, event_group.events) }
25
+
26
+ Datadog.logger.debug do
27
+ max_events = Datadog.configuration.profiling.advanced.max_events
28
+ events_sampled =
29
+ if flush.event_count == max_events
30
+ 'max events limit hit, events were sampled [profile will be biased], '
31
+ else
32
+ ''
33
+ end
34
+
35
+ "Encoding profile covering #{flush.start.iso8601} to #{flush.finish.iso8601}, " \
36
+ "events: #{flush.event_count} (#{events_sampled}#{template.debug_statistics})"
37
+ end
38
+
39
+ # Build the profile and encode it
40
+ template.to_pprof(start: flush.start, finish: flush.finish)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,14 @@
1
+ # typed: true
2
+ module Datadog
3
+ module Profiling
4
+ # Describes a sample of some data obtained from the runtime.
5
+ class Event
6
+ attr_reader \
7
+ :timestamp
8
+
9
+ def initialize(timestamp = nil)
10
+ @timestamp = timestamp || Time.now.utc.to_f
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,81 @@
1
+ # typed: true
2
+ require 'ddtrace/profiling/event'
3
+
4
+ module Datadog
5
+ module Profiling
6
+ module Events
7
+ # Describes a stack profiling event
8
+ class Stack < Event
9
+ attr_reader \
10
+ :hash,
11
+ :frames,
12
+ :total_frame_count,
13
+ :thread_id,
14
+ :root_span_id,
15
+ :span_id,
16
+ :trace_resource
17
+
18
+ def initialize(
19
+ timestamp,
20
+ frames,
21
+ total_frame_count,
22
+ thread_id,
23
+ root_span_id,
24
+ span_id,
25
+ trace_resource
26
+ )
27
+ super(timestamp)
28
+
29
+ @frames = frames
30
+ @total_frame_count = total_frame_count
31
+ @thread_id = thread_id
32
+ @root_span_id = root_span_id
33
+ @span_id = span_id
34
+ @trace_resource = trace_resource
35
+
36
+ @hash = [
37
+ thread_id,
38
+ root_span_id,
39
+ span_id,
40
+ # trace_resource is deliberately not included -- events that share the same (root_span_id, span_id) refer
41
+ # to the same trace
42
+ frames.collect(&:hash),
43
+ total_frame_count
44
+ ].hash
45
+ end
46
+ end
47
+
48
+ # Describes a stack sample
49
+ class StackSample < Stack
50
+ attr_reader \
51
+ :cpu_time_interval_ns,
52
+ :wall_time_interval_ns
53
+
54
+ def initialize(
55
+ timestamp,
56
+ frames,
57
+ total_frame_count,
58
+ thread_id,
59
+ root_span_id,
60
+ span_id,
61
+ trace_resource,
62
+ cpu_time_interval_ns,
63
+ wall_time_interval_ns
64
+ )
65
+ super(
66
+ timestamp,
67
+ frames,
68
+ total_frame_count,
69
+ thread_id,
70
+ root_span_id,
71
+ span_id,
72
+ trace_resource
73
+ )
74
+
75
+ @cpu_time_interval_ns = cpu_time_interval_ns
76
+ @wall_time_interval_ns = wall_time_interval_ns
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,24 @@
1
+ # typed: true
2
+ require 'ddtrace/profiling/transport/io/client'
3
+
4
+ module Datadog
5
+ module Profiling
6
+ # Writes profiling data to a given transport
7
+ class Exporter
8
+ attr_reader \
9
+ :transport
10
+
11
+ def initialize(transport)
12
+ unless transport.is_a?(Profiling::Transport::Client)
13
+ raise ArgumentError, 'Unsupported transport for profiling exporter.'
14
+ end
15
+
16
+ @transport = transport
17
+ end
18
+
19
+ def export(flush)
20
+ transport.send_profiling_flush(flush)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,98 @@
1
+ # typed: false
2
+ module Datadog
3
+ module Profiling
4
+ module Ext
5
+ # Monkey patches `Kernel#fork`, adding a `Kernel#at_fork` callback mechanism which is used to restore
6
+ # profiling abilities after the VM forks.
7
+ module Forking
8
+ def self.supported?
9
+ Process.respond_to?(:fork)
10
+ end
11
+
12
+ def self.apply!
13
+ return false unless supported?
14
+
15
+ modules = [::Process, ::Kernel]
16
+ # TODO: Ruby < 2.3 doesn't support Binding#receiver.
17
+ # Remove "else #eval" clause when Ruby < 2.3 support is dropped.
18
+ # NOTE: Modifying the "main" object as we do here is (as far as I know) irreversible. During tests, this change
19
+ # will stick around even if we otherwise stub `Process` and `Kernel`.
20
+ modules << (TOPLEVEL_BINDING.respond_to?(:receiver) ? TOPLEVEL_BINDING.receiver : TOPLEVEL_BINDING.eval('self'))
21
+
22
+ # Patch top-level binding, Kernel, Process.
23
+ # NOTE: We could instead do Kernel.module_eval { def fork; ... end }
24
+ # however, this method rewrite is more invasive and irreversible.
25
+ # It could also have collisions with other libraries that patch.
26
+ # Opt to modify the inheritance of each relevant target instead.
27
+ modules.each do |mod|
28
+ clazz = if mod.class <= Module
29
+ mod.singleton_class
30
+ else
31
+ mod.class
32
+ end
33
+
34
+ clazz.prepend(Kernel)
35
+ end
36
+ end
37
+
38
+ # Extensions for kernel
39
+ module Kernel
40
+ FORK_STAGES = [:prepare, :parent, :child].freeze
41
+
42
+ def fork
43
+ # If a block is provided, it must be wrapped to trigger callbacks.
44
+ child_block = if block_given?
45
+ proc do
46
+ # Trigger :child callback
47
+ at_fork_blocks[:child].each(&:call) if at_fork_blocks.key?(:child)
48
+
49
+ # Invoke original block
50
+ yield
51
+ end
52
+ end
53
+
54
+ # Trigger :prepare callback
55
+ at_fork_blocks[:prepare].each(&:call) if at_fork_blocks.key?(:prepare)
56
+
57
+ # Start fork
58
+ # If a block is provided, use the wrapped version.
59
+ result = child_block.nil? ? super : super(&child_block)
60
+
61
+ # Trigger correct callbacks depending on whether we're in the parent or child.
62
+ # If we're in the fork, result = nil: trigger child callbacks.
63
+ # If we're in the parent, result = fork PID: trigger parent callbacks.
64
+ # rubocop:disable Style/IfInsideElse
65
+ if result.nil?
66
+ # Trigger :child callback
67
+ at_fork_blocks[:child].each(&:call) if at_fork_blocks.key?(:child)
68
+ else
69
+ # Trigger :parent callback
70
+ at_fork_blocks[:parent].each(&:call) if at_fork_blocks.key?(:parent)
71
+ end
72
+ # rubocop:enable Style/IfInsideElse
73
+
74
+ # Return PID from #fork
75
+ result
76
+ end
77
+
78
+ def at_fork(stage = :prepare, &block)
79
+ raise ArgumentError, 'Bad \'stage\' for ::at_fork' unless FORK_STAGES.include?(stage)
80
+
81
+ at_fork_blocks[stage] = [] unless at_fork_blocks.key?(stage)
82
+ at_fork_blocks[stage] << block
83
+ end
84
+
85
+ module_function
86
+
87
+ def at_fork_blocks
88
+ # Blocks should be shared across all users of this module,
89
+ # e.g. Process#fork, Kernel#fork, etc. should all invoke the same callbacks.
90
+ # rubocop:disable Style/ClassVars
91
+ @@at_fork_blocks ||= {}
92
+ # rubocop:enable Style/ClassVars
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,44 @@
1
+ # typed: false
2
+ require 'datadog/core/environment/identity'
3
+ require 'datadog/core/environment/socket'
4
+
5
+ module Datadog
6
+ module Profiling
7
+ # Entity class used to represent metadata for a given profile
8
+ Flush = Struct.new(
9
+ :start,
10
+ :finish,
11
+ :event_groups,
12
+ :event_count,
13
+ :runtime_id,
14
+ :service,
15
+ :env,
16
+ :version,
17
+ :host,
18
+ :language,
19
+ :runtime_engine,
20
+ :runtime_platform,
21
+ :runtime_version,
22
+ :profiler_version,
23
+ :tags
24
+ ) do
25
+ def initialize(*args)
26
+ super
27
+ self.runtime_id = runtime_id || Datadog::Core::Environment::Identity.id
28
+ self.service = service || Datadog.configuration.service
29
+ self.env = env || Datadog.configuration.env
30
+ self.version = version || Datadog.configuration.version
31
+ self.host = host || Datadog::Core::Environment::Socket.hostname
32
+ self.language = language || Datadog::Core::Environment::Identity.lang
33
+ self.runtime_engine = runtime_engine || Datadog::Core::Environment::Identity.lang_engine
34
+ self.runtime_platform = runtime_platform || Datadog::Core::Environment::Identity.lang_platform
35
+ self.runtime_version = runtime_version || Datadog::Core::Environment::Identity.lang_version
36
+ self.profiler_version = profiler_version || Datadog::Core::Environment::Identity.tracer_version
37
+ self.tags = tags || Datadog.configuration.tags
38
+ end
39
+ end
40
+
41
+ # Represents a collection of events of a specific type being flushed.
42
+ EventGroup = Struct.new(:event_class, :events).freeze
43
+ end
44
+ end
@@ -0,0 +1,40 @@
1
+ # typed: true
2
+ module Datadog
3
+ module Profiling
4
+ # This module contains classes and methods which are implemented using native code in the
5
+ # ext/ddtrace_profiling_native_extension folder, as well as some Ruby-level utilities that don't make sense to
6
+ # write using C
7
+ module NativeExtension
8
+ private_class_method def self.working?
9
+ native_working?
10
+ end
11
+
12
+ unless singleton_class.private_method_defined?(:native_working?)
13
+ private_class_method def self.native_working?
14
+ false
15
+ end
16
+ end
17
+
18
+ unless singleton_class.method_defined?(:clock_id_for)
19
+ def self.clock_id_for(_)
20
+ nil
21
+ end
22
+ end
23
+
24
+ def self.cpu_time_ns_for(thread)
25
+ clock_id =
26
+ begin
27
+ clock_id_for(thread)
28
+ rescue Errno::ESRCH
29
+ nil
30
+ end
31
+
32
+ begin
33
+ ::Process.clock_gettime(clock_id, :nanosecond) if clock_id
34
+ rescue Errno::EINVAL
35
+ nil
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end