ddtrace 0.45.0 → 0.52.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 (586) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +22 -0
  3. data/.gitignore +7 -1
  4. data/CHANGELOG.md +406 -1
  5. data/CONTRIBUTING.md +1 -5
  6. data/LICENSE-3rdparty.csv +2 -0
  7. data/bin/ddtracerb +15 -0
  8. data/ddtrace.gemspec +19 -38
  9. data/docs/DevelopmentGuide.md +43 -0
  10. data/docs/GettingStarted.md +164 -76
  11. data/docs/ProfilingDevelopment.md +107 -0
  12. data/ext/ddtrace_profiling_native_extension/extconf.rb +28 -0
  13. data/ext/ddtrace_profiling_native_extension/profiling.c +17 -0
  14. data/lib/datadog/ci/configuration/components.rb +31 -0
  15. data/lib/datadog/ci/configuration/settings.rb +37 -0
  16. data/lib/datadog/ci/context_flush.rb +29 -0
  17. data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +31 -0
  18. data/lib/datadog/ci/contrib/cucumber/ext.rb +20 -0
  19. data/lib/datadog/ci/contrib/cucumber/formatter.rb +98 -0
  20. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +27 -0
  21. data/lib/datadog/ci/contrib/cucumber/integration.rb +48 -0
  22. data/lib/datadog/ci/contrib/cucumber/patcher.rb +26 -0
  23. data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +31 -0
  24. data/lib/datadog/ci/contrib/rspec/example.rb +74 -0
  25. data/lib/datadog/ci/contrib/rspec/ext.rb +19 -0
  26. data/lib/datadog/ci/contrib/rspec/integration.rb +49 -0
  27. data/lib/datadog/ci/contrib/rspec/patcher.rb +26 -0
  28. data/lib/datadog/ci/ext/app_types.rb +10 -0
  29. data/lib/datadog/ci/ext/environment.rb +443 -0
  30. data/lib/datadog/ci/ext/settings.rb +11 -0
  31. data/lib/datadog/ci/ext/test.rb +35 -0
  32. data/lib/datadog/ci/extensions.rb +18 -0
  33. data/lib/datadog/ci/test.rb +77 -0
  34. data/lib/datadog/ci.rb +17 -0
  35. data/lib/datadog/contrib.rb +69 -0
  36. data/lib/datadog/core/environment/cgroup.rb +52 -0
  37. data/lib/datadog/core/environment/class_count.rb +20 -0
  38. data/lib/datadog/core/environment/container.rb +91 -0
  39. data/lib/datadog/core/environment/ext.rb +27 -0
  40. data/lib/datadog/core/environment/gc.rb +19 -0
  41. data/lib/datadog/core/environment/identity.rb +51 -0
  42. data/lib/datadog/core/environment/socket.rb +17 -0
  43. data/lib/datadog/core/environment/thread_count.rb +19 -0
  44. data/lib/datadog/core/environment/variable_helpers.rb +42 -0
  45. data/lib/ddtrace/analytics.rb +3 -0
  46. data/lib/ddtrace/auto_instrument.rb +2 -0
  47. data/lib/ddtrace/auto_instrument_base.rb +1 -0
  48. data/lib/ddtrace/buffer.rb +10 -8
  49. data/lib/ddtrace/chunker.rb +1 -0
  50. data/lib/ddtrace/configuration/agent_settings_resolver.rb +231 -0
  51. data/lib/ddtrace/configuration/base.rb +9 -11
  52. data/lib/ddtrace/configuration/components.rb +167 -26
  53. data/lib/ddtrace/configuration/dependency_resolver.rb +1 -0
  54. data/lib/ddtrace/configuration/option.rb +1 -0
  55. data/lib/ddtrace/configuration/option_definition.rb +2 -3
  56. data/lib/ddtrace/configuration/option_definition_set.rb +1 -0
  57. data/lib/ddtrace/configuration/option_set.rb +1 -0
  58. data/lib/ddtrace/configuration/options.rb +7 -9
  59. data/lib/ddtrace/configuration/pin_setup.rb +1 -0
  60. data/lib/ddtrace/configuration/settings.rb +128 -10
  61. data/lib/ddtrace/configuration.rb +118 -26
  62. data/lib/ddtrace/context.rb +23 -20
  63. data/lib/ddtrace/context_flush.rb +15 -2
  64. data/lib/ddtrace/context_provider.rb +1 -1
  65. data/lib/ddtrace/contrib/action_cable/configuration/settings.rb +1 -0
  66. data/lib/ddtrace/contrib/action_cable/event.rb +6 -4
  67. data/lib/ddtrace/contrib/action_cable/events/broadcast.rb +1 -0
  68. data/lib/ddtrace/contrib/action_cable/events/perform_action.rb +1 -0
  69. data/lib/ddtrace/contrib/action_cable/events/transmit.rb +1 -0
  70. data/lib/ddtrace/contrib/action_cable/events.rb +1 -0
  71. data/lib/ddtrace/contrib/action_cable/ext.rb +1 -0
  72. data/lib/ddtrace/contrib/action_cable/instrumentation.rb +1 -0
  73. data/lib/ddtrace/contrib/action_cable/integration.rb +1 -0
  74. data/lib/ddtrace/contrib/action_cable/patcher.rb +1 -0
  75. data/lib/ddtrace/contrib/action_pack/action_controller/instrumentation.rb +22 -13
  76. data/lib/ddtrace/contrib/action_pack/action_controller/patcher.rb +2 -1
  77. data/lib/ddtrace/contrib/action_pack/configuration/settings.rb +1 -0
  78. data/lib/ddtrace/contrib/action_pack/ext.rb +1 -0
  79. data/lib/ddtrace/contrib/action_pack/integration.rb +1 -0
  80. data/lib/ddtrace/contrib/action_pack/patcher.rb +1 -0
  81. data/lib/ddtrace/contrib/action_pack/utils.rb +2 -1
  82. data/lib/ddtrace/contrib/action_view/configuration/settings.rb +1 -0
  83. data/lib/ddtrace/contrib/action_view/event.rb +4 -3
  84. data/lib/ddtrace/contrib/action_view/events/render_partial.rb +1 -0
  85. data/lib/ddtrace/contrib/action_view/events/render_template.rb +1 -0
  86. data/lib/ddtrace/contrib/action_view/events.rb +1 -0
  87. data/lib/ddtrace/contrib/action_view/ext.rb +1 -0
  88. data/lib/ddtrace/contrib/action_view/instrumentation/partial_renderer.rb +1 -0
  89. data/lib/ddtrace/contrib/action_view/instrumentation/template_renderer.rb +1 -0
  90. data/lib/ddtrace/contrib/action_view/integration.rb +1 -0
  91. data/lib/ddtrace/contrib/action_view/patcher.rb +5 -4
  92. data/lib/ddtrace/contrib/action_view/utils.rb +2 -1
  93. data/lib/ddtrace/contrib/active_model_serializers/configuration/settings.rb +1 -0
  94. data/lib/ddtrace/contrib/active_model_serializers/event.rb +3 -2
  95. data/lib/ddtrace/contrib/active_model_serializers/events/render.rb +1 -0
  96. data/lib/ddtrace/contrib/active_model_serializers/events/serialize.rb +1 -0
  97. data/lib/ddtrace/contrib/active_model_serializers/events.rb +1 -0
  98. data/lib/ddtrace/contrib/active_model_serializers/ext.rb +1 -0
  99. data/lib/ddtrace/contrib/active_model_serializers/integration.rb +1 -0
  100. data/lib/ddtrace/contrib/active_model_serializers/patcher.rb +1 -0
  101. data/lib/ddtrace/contrib/active_record/configuration/makara_resolver.rb +31 -0
  102. data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +108 -18
  103. data/lib/ddtrace/contrib/active_record/configuration/settings.rb +1 -0
  104. data/lib/ddtrace/contrib/active_record/event.rb +3 -2
  105. data/lib/ddtrace/contrib/active_record/events/instantiation.rb +1 -0
  106. data/lib/ddtrace/contrib/active_record/events/sql.rb +1 -0
  107. data/lib/ddtrace/contrib/active_record/events.rb +1 -0
  108. data/lib/ddtrace/contrib/active_record/ext.rb +1 -0
  109. data/lib/ddtrace/contrib/active_record/integration.rb +1 -0
  110. data/lib/ddtrace/contrib/active_record/patcher.rb +1 -0
  111. data/lib/ddtrace/contrib/active_record/utils.rb +5 -3
  112. data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +1 -0
  113. data/lib/ddtrace/contrib/active_support/cache/patcher.rb +8 -7
  114. data/lib/ddtrace/contrib/active_support/cache/redis.rb +2 -5
  115. data/lib/ddtrace/contrib/active_support/configuration/settings.rb +1 -0
  116. data/lib/ddtrace/contrib/active_support/ext.rb +1 -0
  117. data/lib/ddtrace/contrib/active_support/integration.rb +1 -0
  118. data/lib/ddtrace/contrib/active_support/notifications/event.rb +5 -3
  119. data/lib/ddtrace/contrib/active_support/notifications/subscriber.rb +3 -1
  120. data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +10 -5
  121. data/lib/ddtrace/contrib/active_support/patcher.rb +1 -0
  122. data/lib/ddtrace/contrib/analytics.rb +1 -0
  123. data/lib/ddtrace/contrib/auto_instrument.rb +4 -3
  124. data/lib/ddtrace/contrib/aws/configuration/settings.rb +1 -0
  125. data/lib/ddtrace/contrib/aws/ext.rb +1 -0
  126. data/lib/ddtrace/contrib/aws/instrumentation.rb +30 -0
  127. data/lib/ddtrace/contrib/aws/integration.rb +1 -0
  128. data/lib/ddtrace/contrib/aws/parsed_context.rb +1 -0
  129. data/lib/ddtrace/contrib/aws/patcher.rb +6 -0
  130. data/lib/ddtrace/contrib/aws/services.rb +3 -0
  131. data/lib/ddtrace/contrib/concurrent_ruby/configuration/settings.rb +1 -0
  132. data/lib/ddtrace/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -0
  133. data/lib/ddtrace/contrib/concurrent_ruby/ext.rb +1 -0
  134. data/lib/ddtrace/contrib/concurrent_ruby/future_patch.rb +1 -0
  135. data/lib/ddtrace/contrib/concurrent_ruby/integration.rb +1 -0
  136. data/lib/ddtrace/contrib/concurrent_ruby/patcher.rb +3 -1
  137. data/lib/ddtrace/contrib/configurable.rb +65 -40
  138. data/lib/ddtrace/contrib/configuration/resolver.rb +71 -5
  139. data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +20 -20
  140. data/lib/ddtrace/contrib/configuration/settings.rb +8 -6
  141. data/lib/ddtrace/contrib/dalli/configuration/settings.rb +1 -0
  142. data/lib/ddtrace/contrib/dalli/ext.rb +1 -0
  143. data/lib/ddtrace/contrib/dalli/instrumentation.rb +2 -1
  144. data/lib/ddtrace/contrib/dalli/integration.rb +1 -0
  145. data/lib/ddtrace/contrib/dalli/patcher.rb +2 -39
  146. data/lib/ddtrace/contrib/dalli/quantize.rb +1 -0
  147. data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +1 -0
  148. data/lib/ddtrace/contrib/delayed_job/ext.rb +1 -0
  149. data/lib/ddtrace/contrib/delayed_job/integration.rb +1 -0
  150. data/lib/ddtrace/contrib/delayed_job/patcher.rb +1 -0
  151. data/lib/ddtrace/contrib/delayed_job/plugin.rb +1 -1
  152. data/lib/ddtrace/contrib/elasticsearch/configuration/settings.rb +1 -0
  153. data/lib/ddtrace/contrib/elasticsearch/ext.rb +1 -0
  154. data/lib/ddtrace/contrib/elasticsearch/integration.rb +1 -0
  155. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +2 -0
  156. data/lib/ddtrace/contrib/elasticsearch/quantize.rb +6 -2
  157. data/lib/ddtrace/contrib/ethon/configuration/settings.rb +1 -0
  158. data/lib/ddtrace/contrib/ethon/easy_patch.rb +7 -6
  159. data/lib/ddtrace/contrib/ethon/ext.rb +1 -0
  160. data/lib/ddtrace/contrib/ethon/integration.rb +1 -0
  161. data/lib/ddtrace/contrib/ethon/multi_patch.rb +2 -1
  162. data/lib/ddtrace/contrib/ethon/patcher.rb +4 -2
  163. data/lib/ddtrace/contrib/excon/configuration/settings.rb +1 -0
  164. data/lib/ddtrace/contrib/excon/ext.rb +1 -0
  165. data/lib/ddtrace/contrib/excon/integration.rb +1 -0
  166. data/lib/ddtrace/contrib/excon/middleware.rb +3 -6
  167. data/lib/ddtrace/contrib/excon/patcher.rb +1 -0
  168. data/lib/ddtrace/contrib/extensions.rb +64 -14
  169. data/lib/ddtrace/contrib/faraday/configuration/settings.rb +1 -0
  170. data/lib/ddtrace/contrib/faraday/connection.rb +1 -0
  171. data/lib/ddtrace/contrib/faraday/ext.rb +1 -0
  172. data/lib/ddtrace/contrib/faraday/integration.rb +1 -0
  173. data/lib/ddtrace/contrib/faraday/middleware.rb +2 -3
  174. data/lib/ddtrace/contrib/faraday/patcher.rb +3 -38
  175. data/lib/ddtrace/contrib/faraday/rack_builder.rb +1 -0
  176. data/lib/ddtrace/contrib/grape/configuration/settings.rb +1 -0
  177. data/lib/ddtrace/contrib/grape/endpoint.rb +34 -31
  178. data/lib/ddtrace/contrib/grape/ext.rb +1 -0
  179. data/lib/ddtrace/contrib/grape/instrumentation.rb +4 -3
  180. data/lib/ddtrace/contrib/grape/integration.rb +1 -0
  181. data/lib/ddtrace/contrib/grape/patcher.rb +2 -43
  182. data/lib/ddtrace/contrib/graphql/configuration/settings.rb +1 -0
  183. data/lib/ddtrace/contrib/graphql/ext.rb +1 -0
  184. data/lib/ddtrace/contrib/graphql/integration.rb +1 -0
  185. data/lib/ddtrace/contrib/graphql/patcher.rb +1 -0
  186. data/lib/ddtrace/contrib/grpc/configuration/settings.rb +2 -0
  187. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +1 -0
  188. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +4 -4
  189. data/lib/ddtrace/contrib/grpc/datadog_interceptor.rb +13 -8
  190. data/lib/ddtrace/contrib/grpc/ext.rb +1 -0
  191. data/lib/ddtrace/contrib/grpc/integration.rb +1 -0
  192. data/lib/ddtrace/contrib/grpc/intercept_with_datadog.rb +1 -0
  193. data/lib/ddtrace/contrib/grpc/patcher.rb +3 -37
  194. data/lib/ddtrace/contrib/http/circuit_breaker.rb +2 -3
  195. data/lib/ddtrace/contrib/http/configuration/settings.rb +1 -0
  196. data/lib/ddtrace/contrib/http/ext.rb +1 -0
  197. data/lib/ddtrace/contrib/http/instrumentation.rb +7 -6
  198. data/lib/ddtrace/contrib/http/integration.rb +1 -0
  199. data/lib/ddtrace/contrib/http/patcher.rb +2 -1
  200. data/lib/ddtrace/contrib/http_annotation_helper.rb +1 -0
  201. data/lib/ddtrace/contrib/httpclient/configuration/settings.rb +1 -0
  202. data/lib/ddtrace/contrib/httpclient/ext.rb +1 -0
  203. data/lib/ddtrace/contrib/httpclient/instrumentation.rb +16 -20
  204. data/lib/ddtrace/contrib/httpclient/integration.rb +1 -0
  205. data/lib/ddtrace/contrib/httpclient/patcher.rb +8 -4
  206. data/lib/ddtrace/contrib/httprb/configuration/settings.rb +1 -0
  207. data/lib/ddtrace/contrib/httprb/ext.rb +1 -0
  208. data/lib/ddtrace/contrib/httprb/instrumentation.rb +16 -21
  209. data/lib/ddtrace/contrib/httprb/integration.rb +1 -0
  210. data/lib/ddtrace/contrib/httprb/patcher.rb +8 -4
  211. data/lib/ddtrace/contrib/integration.rb +4 -3
  212. data/lib/ddtrace/contrib/kafka/configuration/settings.rb +1 -0
  213. data/lib/ddtrace/contrib/kafka/consumer_event.rb +1 -0
  214. data/lib/ddtrace/contrib/kafka/consumer_group_event.rb +1 -0
  215. data/lib/ddtrace/contrib/kafka/event.rb +3 -2
  216. data/lib/ddtrace/contrib/kafka/events/connection/request.rb +1 -0
  217. data/lib/ddtrace/contrib/kafka/events/consumer/process_batch.rb +1 -0
  218. data/lib/ddtrace/contrib/kafka/events/consumer/process_message.rb +1 -0
  219. data/lib/ddtrace/contrib/kafka/events/consumer_group/heartbeat.rb +1 -0
  220. data/lib/ddtrace/contrib/kafka/events/consumer_group/join_group.rb +1 -0
  221. data/lib/ddtrace/contrib/kafka/events/consumer_group/leave_group.rb +1 -0
  222. data/lib/ddtrace/contrib/kafka/events/consumer_group/sync_group.rb +1 -0
  223. data/lib/ddtrace/contrib/kafka/events/produce_operation/send_messages.rb +1 -0
  224. data/lib/ddtrace/contrib/kafka/events/producer/deliver_messages.rb +1 -0
  225. data/lib/ddtrace/contrib/kafka/events.rb +1 -0
  226. data/lib/ddtrace/contrib/kafka/ext.rb +1 -0
  227. data/lib/ddtrace/contrib/kafka/integration.rb +1 -0
  228. data/lib/ddtrace/contrib/kafka/patcher.rb +1 -0
  229. data/lib/ddtrace/contrib/lograge/configuration/settings.rb +19 -0
  230. data/lib/ddtrace/contrib/lograge/ext.rb +11 -0
  231. data/lib/ddtrace/contrib/lograge/instrumentation.rb +39 -0
  232. data/lib/ddtrace/contrib/lograge/integration.rb +46 -0
  233. data/lib/ddtrace/contrib/{cucumber → lograge}/patcher.rb +7 -4
  234. data/lib/ddtrace/contrib/mongodb/configuration/settings.rb +1 -0
  235. data/lib/ddtrace/contrib/mongodb/ext.rb +1 -0
  236. data/lib/ddtrace/contrib/mongodb/instrumentation.rb +5 -2
  237. data/lib/ddtrace/contrib/mongodb/integration.rb +1 -0
  238. data/lib/ddtrace/contrib/mongodb/parsers.rb +1 -0
  239. data/lib/ddtrace/contrib/mongodb/patcher.rb +3 -2
  240. data/lib/ddtrace/contrib/mongodb/subscribers.rb +3 -3
  241. data/lib/ddtrace/contrib/mysql2/configuration/settings.rb +1 -0
  242. data/lib/ddtrace/contrib/mysql2/ext.rb +1 -0
  243. data/lib/ddtrace/contrib/mysql2/instrumentation.rb +2 -1
  244. data/lib/ddtrace/contrib/mysql2/integration.rb +1 -0
  245. data/lib/ddtrace/contrib/mysql2/patcher.rb +2 -1
  246. data/lib/ddtrace/contrib/patchable.rb +3 -2
  247. data/lib/ddtrace/contrib/patcher.rb +12 -8
  248. data/lib/ddtrace/contrib/presto/configuration/settings.rb +1 -0
  249. data/lib/ddtrace/contrib/presto/ext.rb +1 -0
  250. data/lib/ddtrace/contrib/presto/instrumentation.rb +2 -1
  251. data/lib/ddtrace/contrib/presto/integration.rb +1 -0
  252. data/lib/ddtrace/contrib/presto/patcher.rb +7 -3
  253. data/lib/ddtrace/contrib/qless/configuration/settings.rb +1 -0
  254. data/lib/ddtrace/contrib/qless/ext.rb +1 -0
  255. data/lib/ddtrace/contrib/qless/integration.rb +1 -0
  256. data/lib/ddtrace/contrib/qless/patcher.rb +5 -5
  257. data/lib/ddtrace/contrib/qless/qless_job.rb +2 -0
  258. data/lib/ddtrace/contrib/qless/tracer_cleaner.rb +2 -0
  259. data/lib/ddtrace/contrib/que/configuration/settings.rb +1 -0
  260. data/lib/ddtrace/contrib/que/ext.rb +20 -19
  261. data/lib/ddtrace/contrib/que/integration.rb +1 -0
  262. data/lib/ddtrace/contrib/que/patcher.rb +1 -0
  263. data/lib/ddtrace/contrib/que/tracer.rb +2 -1
  264. data/lib/ddtrace/contrib/racecar/configuration/settings.rb +1 -0
  265. data/lib/ddtrace/contrib/racecar/event.rb +4 -2
  266. data/lib/ddtrace/contrib/racecar/events/batch.rb +1 -0
  267. data/lib/ddtrace/contrib/racecar/events/consume.rb +1 -0
  268. data/lib/ddtrace/contrib/racecar/events/message.rb +1 -0
  269. data/lib/ddtrace/contrib/racecar/events.rb +1 -0
  270. data/lib/ddtrace/contrib/racecar/ext.rb +1 -0
  271. data/lib/ddtrace/contrib/racecar/integration.rb +1 -0
  272. data/lib/ddtrace/contrib/racecar/patcher.rb +1 -0
  273. data/lib/ddtrace/contrib/rack/configuration/settings.rb +4 -3
  274. data/lib/ddtrace/contrib/rack/ext.rb +1 -0
  275. data/lib/ddtrace/contrib/rack/integration.rb +1 -0
  276. data/lib/ddtrace/contrib/rack/middlewares.rb +7 -11
  277. data/lib/ddtrace/contrib/rack/patcher.rb +2 -3
  278. data/lib/ddtrace/contrib/rack/request_queue.rb +1 -0
  279. data/lib/ddtrace/contrib/rails/auto_instrument_railtie.rb +1 -0
  280. data/lib/ddtrace/contrib/rails/configuration/settings.rb +1 -0
  281. data/lib/ddtrace/contrib/rails/ext.rb +1 -0
  282. data/lib/ddtrace/contrib/rails/framework.rb +26 -1
  283. data/lib/ddtrace/contrib/rails/integration.rb +1 -0
  284. data/lib/ddtrace/contrib/rails/log_injection.rb +1 -40
  285. data/lib/ddtrace/contrib/rails/middlewares.rb +1 -0
  286. data/lib/ddtrace/contrib/rails/patcher.rb +18 -11
  287. data/lib/ddtrace/contrib/rails/railtie.rb +1 -0
  288. data/lib/ddtrace/contrib/rails/utils.rb +1 -0
  289. data/lib/ddtrace/contrib/rake/configuration/settings.rb +1 -0
  290. data/lib/ddtrace/contrib/rake/ext.rb +1 -0
  291. data/lib/ddtrace/contrib/rake/instrumentation.rb +6 -3
  292. data/lib/ddtrace/contrib/rake/integration.rb +1 -0
  293. data/lib/ddtrace/contrib/rake/patcher.rb +2 -1
  294. data/lib/ddtrace/contrib/redis/configuration/resolver.rb +12 -4
  295. data/lib/ddtrace/contrib/redis/configuration/settings.rb +1 -0
  296. data/lib/ddtrace/contrib/redis/ext.rb +1 -0
  297. data/lib/ddtrace/contrib/redis/integration.rb +1 -0
  298. data/lib/ddtrace/contrib/redis/patcher.rb +1 -0
  299. data/lib/ddtrace/contrib/redis/quantize.rb +2 -0
  300. data/lib/ddtrace/contrib/redis/tags.rb +1 -0
  301. data/lib/ddtrace/contrib/redis/vendor/LICENSE +20 -0
  302. data/lib/ddtrace/contrib/redis/vendor/resolver.rb +7 -7
  303. data/lib/ddtrace/contrib/registerable.rb +5 -4
  304. data/lib/ddtrace/contrib/registry.rb +3 -2
  305. data/lib/ddtrace/contrib/resque/configuration/settings.rb +18 -1
  306. data/lib/ddtrace/contrib/resque/ext.rb +1 -0
  307. data/lib/ddtrace/contrib/resque/integration.rb +2 -1
  308. data/lib/ddtrace/contrib/resque/patcher.rb +5 -4
  309. data/lib/ddtrace/contrib/resque/resque_job.rb +25 -1
  310. data/lib/ddtrace/contrib/rest_client/configuration/settings.rb +1 -0
  311. data/lib/ddtrace/contrib/rest_client/ext.rb +1 -0
  312. data/lib/ddtrace/contrib/rest_client/integration.rb +1 -0
  313. data/lib/ddtrace/contrib/rest_client/patcher.rb +3 -1
  314. data/lib/ddtrace/contrib/rest_client/request_patch.rb +3 -4
  315. data/lib/ddtrace/contrib/semantic_logger/configuration/settings.rb +19 -0
  316. data/lib/ddtrace/contrib/semantic_logger/ext.rb +11 -0
  317. data/lib/ddtrace/contrib/semantic_logger/instrumentation.rb +43 -0
  318. data/lib/ddtrace/contrib/semantic_logger/integration.rb +48 -0
  319. data/lib/ddtrace/contrib/semantic_logger/patcher.rb +26 -0
  320. data/lib/ddtrace/contrib/sequel/configuration/settings.rb +1 -0
  321. data/lib/ddtrace/contrib/sequel/database.rb +2 -1
  322. data/lib/ddtrace/contrib/sequel/dataset.rb +2 -1
  323. data/lib/ddtrace/contrib/sequel/ext.rb +1 -0
  324. data/lib/ddtrace/contrib/sequel/integration.rb +1 -0
  325. data/lib/ddtrace/contrib/sequel/patcher.rb +3 -2
  326. data/lib/ddtrace/contrib/sequel/utils.rb +6 -6
  327. data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +2 -0
  328. data/lib/ddtrace/contrib/shoryuken/ext.rb +1 -0
  329. data/lib/ddtrace/contrib/shoryuken/integration.rb +1 -0
  330. data/lib/ddtrace/contrib/shoryuken/patcher.rb +1 -0
  331. data/lib/ddtrace/contrib/shoryuken/tracer.rb +8 -4
  332. data/lib/ddtrace/contrib/sidekiq/client_tracer.rb +1 -0
  333. data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +1 -0
  334. data/lib/ddtrace/contrib/sidekiq/ext.rb +1 -0
  335. data/lib/ddtrace/contrib/sidekiq/integration.rb +1 -0
  336. data/lib/ddtrace/contrib/sidekiq/patcher.rb +1 -0
  337. data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +3 -7
  338. data/lib/ddtrace/contrib/sidekiq/tracing.rb +1 -1
  339. data/lib/ddtrace/contrib/sinatra/configuration/settings.rb +1 -0
  340. data/lib/ddtrace/contrib/sinatra/env.rb +2 -3
  341. data/lib/ddtrace/contrib/sinatra/ext.rb +1 -0
  342. data/lib/ddtrace/contrib/sinatra/headers.rb +2 -3
  343. data/lib/ddtrace/contrib/sinatra/integration.rb +1 -0
  344. data/lib/ddtrace/contrib/sinatra/patcher.rb +3 -1
  345. data/lib/ddtrace/contrib/sinatra/tracer.rb +14 -6
  346. data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +11 -4
  347. data/lib/ddtrace/contrib/sneakers/configuration/settings.rb +1 -0
  348. data/lib/ddtrace/contrib/sneakers/ext.rb +12 -11
  349. data/lib/ddtrace/contrib/sneakers/integration.rb +1 -0
  350. data/lib/ddtrace/contrib/sneakers/patcher.rb +1 -0
  351. data/lib/ddtrace/contrib/sneakers/tracer.rb +3 -4
  352. data/lib/ddtrace/contrib/status_code_matcher.rb +6 -3
  353. data/lib/ddtrace/contrib/sucker_punch/configuration/settings.rb +1 -0
  354. data/lib/ddtrace/contrib/sucker_punch/exception_handler.rb +5 -6
  355. data/lib/ddtrace/contrib/sucker_punch/ext.rb +1 -0
  356. data/lib/ddtrace/contrib/sucker_punch/instrumentation.rb +5 -0
  357. data/lib/ddtrace/contrib/sucker_punch/integration.rb +1 -0
  358. data/lib/ddtrace/contrib/sucker_punch/patcher.rb +2 -0
  359. data/lib/ddtrace/correlation.rb +3 -1
  360. data/lib/ddtrace/diagnostics/environment_logger.rb +9 -7
  361. data/lib/ddtrace/diagnostics/health.rb +1 -0
  362. data/lib/ddtrace/distributed_tracing/headers/b3.rb +1 -0
  363. data/lib/ddtrace/distributed_tracing/headers/b3_single.rb +1 -0
  364. data/lib/ddtrace/distributed_tracing/headers/datadog.rb +1 -0
  365. data/lib/ddtrace/distributed_tracing/headers/headers.rb +2 -0
  366. data/lib/ddtrace/distributed_tracing/headers/helpers.rb +2 -3
  367. data/lib/ddtrace/encoding.rb +3 -0
  368. data/lib/ddtrace/error.rb +78 -8
  369. data/lib/ddtrace/event.rb +1 -0
  370. data/lib/ddtrace/ext/analytics.rb +1 -0
  371. data/lib/ddtrace/ext/app_types.rb +1 -1
  372. data/lib/ddtrace/ext/correlation.rb +1 -0
  373. data/lib/ddtrace/ext/diagnostics.rb +1 -0
  374. data/lib/ddtrace/ext/distributed.rb +2 -1
  375. data/lib/ddtrace/ext/environment.rb +8 -0
  376. data/lib/ddtrace/ext/errors.rb +1 -0
  377. data/lib/ddtrace/ext/forced_tracing.rb +1 -0
  378. data/lib/ddtrace/ext/git.rb +10 -1
  379. data/lib/ddtrace/ext/http.rb +2 -1
  380. data/lib/ddtrace/ext/integration.rb +1 -0
  381. data/lib/ddtrace/ext/manual_tracing.rb +1 -0
  382. data/lib/ddtrace/ext/metrics.rb +1 -0
  383. data/lib/ddtrace/ext/net.rb +1 -0
  384. data/lib/ddtrace/ext/priority.rb +1 -0
  385. data/lib/ddtrace/ext/profiling.rb +56 -0
  386. data/lib/ddtrace/ext/runtime.rb +1 -7
  387. data/lib/ddtrace/ext/sampling.rb +1 -0
  388. data/lib/ddtrace/ext/sql.rb +1 -0
  389. data/lib/ddtrace/ext/test.rb +3 -18
  390. data/lib/ddtrace/ext/transport.rb +3 -0
  391. data/lib/ddtrace/forced_tracing.rb +3 -0
  392. data/lib/ddtrace/logger.rb +2 -1
  393. data/lib/ddtrace/metrics.rb +84 -24
  394. data/lib/ddtrace/opentelemetry/extensions.rb +2 -1
  395. data/lib/ddtrace/opentelemetry/span.rb +1 -0
  396. data/lib/ddtrace/opentracer/binary_propagator.rb +1 -0
  397. data/lib/ddtrace/opentracer/carrier.rb +1 -0
  398. data/lib/ddtrace/opentracer/distributed_headers.rb +4 -0
  399. data/lib/ddtrace/opentracer/global_tracer.rb +1 -0
  400. data/lib/ddtrace/opentracer/propagator.rb +1 -0
  401. data/lib/ddtrace/opentracer/rack_propagator.rb +1 -0
  402. data/lib/ddtrace/opentracer/scope.rb +1 -0
  403. data/lib/ddtrace/opentracer/scope_manager.rb +1 -0
  404. data/lib/ddtrace/opentracer/span.rb +3 -6
  405. data/lib/ddtrace/opentracer/span_context.rb +1 -0
  406. data/lib/ddtrace/opentracer/span_context_factory.rb +1 -0
  407. data/lib/ddtrace/opentracer/text_map_propagator.rb +1 -0
  408. data/lib/ddtrace/opentracer/thread_local_scope.rb +2 -0
  409. data/lib/ddtrace/opentracer/thread_local_scope_manager.rb +1 -0
  410. data/lib/ddtrace/opentracer/tracer.rb +1 -0
  411. data/lib/ddtrace/opentracer.rb +21 -39
  412. data/lib/ddtrace/patcher.rb +28 -6
  413. data/lib/ddtrace/pin.rb +9 -61
  414. data/lib/ddtrace/pipeline/span_filter.rb +2 -1
  415. data/lib/ddtrace/pipeline/span_processor.rb +1 -0
  416. data/lib/ddtrace/pipeline.rb +1 -0
  417. data/lib/ddtrace/profiling/backtrace_location.rb +33 -0
  418. data/lib/ddtrace/profiling/buffer.rb +42 -0
  419. data/lib/ddtrace/profiling/collectors/stack.rb +257 -0
  420. data/lib/ddtrace/profiling/encoding/profile.rb +38 -0
  421. data/lib/ddtrace/profiling/event.rb +14 -0
  422. data/lib/ddtrace/profiling/events/stack.rb +81 -0
  423. data/lib/ddtrace/profiling/exporter.rb +24 -0
  424. data/lib/ddtrace/profiling/ext/cpu.rb +67 -0
  425. data/lib/ddtrace/profiling/ext/cthread.rb +156 -0
  426. data/lib/ddtrace/profiling/ext/forking.rb +98 -0
  427. data/lib/ddtrace/profiling/flush.rb +44 -0
  428. data/lib/ddtrace/profiling/native_extension.rb +18 -0
  429. data/lib/ddtrace/profiling/pprof/builder.rb +120 -0
  430. data/lib/ddtrace/profiling/pprof/converter.rb +90 -0
  431. data/lib/ddtrace/profiling/pprof/message_set.rb +15 -0
  432. data/lib/ddtrace/profiling/pprof/payload.rb +19 -0
  433. data/lib/ddtrace/profiling/pprof/pprof.proto +212 -0
  434. data/lib/ddtrace/profiling/pprof/pprof_pb.rb +82 -0
  435. data/lib/ddtrace/profiling/pprof/stack_sample.rb +117 -0
  436. data/lib/ddtrace/profiling/pprof/string_table.rb +11 -0
  437. data/lib/ddtrace/profiling/pprof/template.rb +119 -0
  438. data/lib/ddtrace/profiling/preload.rb +4 -0
  439. data/lib/ddtrace/profiling/profiler.rb +31 -0
  440. data/lib/ddtrace/profiling/recorder.rb +96 -0
  441. data/lib/ddtrace/profiling/scheduler.rb +134 -0
  442. data/lib/ddtrace/profiling/tasks/setup.rb +82 -0
  443. data/lib/ddtrace/profiling/trace_identifiers/ddtrace.rb +41 -0
  444. data/lib/ddtrace/profiling/trace_identifiers/helper.rb +46 -0
  445. data/lib/ddtrace/profiling/transport/client.rb +15 -0
  446. data/lib/ddtrace/profiling/transport/http/api/endpoint.rb +101 -0
  447. data/lib/ddtrace/profiling/transport/http/api/instance.rb +37 -0
  448. data/lib/ddtrace/profiling/transport/http/api/spec.rb +41 -0
  449. data/lib/ddtrace/profiling/transport/http/api.rb +44 -0
  450. data/lib/ddtrace/profiling/transport/http/builder.rb +29 -0
  451. data/lib/ddtrace/profiling/transport/http/client.rb +34 -0
  452. data/lib/ddtrace/profiling/transport/http/response.rb +22 -0
  453. data/lib/ddtrace/profiling/transport/http.rb +120 -0
  454. data/lib/ddtrace/profiling/transport/io/client.rb +28 -0
  455. data/lib/ddtrace/profiling/transport/io/response.rb +17 -0
  456. data/lib/ddtrace/profiling/transport/io.rb +31 -0
  457. data/lib/ddtrace/profiling/transport/parcel.rb +18 -0
  458. data/lib/ddtrace/profiling/transport/request.rb +16 -0
  459. data/lib/ddtrace/profiling/transport/response.rb +9 -0
  460. data/lib/ddtrace/profiling.rb +151 -0
  461. data/lib/ddtrace/propagation/grpc_propagator.rb +2 -0
  462. data/lib/ddtrace/propagation/http_propagator.rb +3 -2
  463. data/lib/ddtrace/quantization/hash.rb +1 -0
  464. data/lib/ddtrace/quantization/http.rb +4 -0
  465. data/lib/ddtrace/runtime/metrics.rb +21 -14
  466. data/lib/ddtrace/sampler.rb +2 -1
  467. data/lib/ddtrace/sampling/matcher.rb +1 -0
  468. data/lib/ddtrace/sampling/rate_limiter.rb +1 -0
  469. data/lib/ddtrace/sampling/rule.rb +2 -1
  470. data/lib/ddtrace/sampling/rule_sampler.rb +6 -10
  471. data/lib/ddtrace/sampling.rb +1 -0
  472. data/lib/ddtrace/span.rb +44 -19
  473. data/lib/ddtrace/sync_writer.rb +17 -15
  474. data/lib/ddtrace/tasks/exec.rb +47 -0
  475. data/lib/ddtrace/tasks/help.rb +15 -0
  476. data/lib/ddtrace/tracer.rb +48 -50
  477. data/lib/ddtrace/transport/http/adapters/net.rb +28 -8
  478. data/lib/ddtrace/transport/http/adapters/registry.rb +2 -0
  479. data/lib/ddtrace/transport/http/adapters/test.rb +1 -0
  480. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +3 -4
  481. data/lib/ddtrace/transport/http/api/endpoint.rb +1 -0
  482. data/lib/ddtrace/transport/http/api/fallbacks.rb +1 -0
  483. data/lib/ddtrace/transport/http/api/instance.rb +1 -0
  484. data/lib/ddtrace/transport/http/api/map.rb +1 -0
  485. data/lib/ddtrace/transport/http/api/spec.rb +1 -0
  486. data/lib/ddtrace/transport/http/api.rb +1 -0
  487. data/lib/ddtrace/transport/http/builder.rb +8 -1
  488. data/lib/ddtrace/transport/http/client.rb +3 -1
  489. data/lib/ddtrace/transport/http/env.rb +9 -0
  490. data/lib/ddtrace/transport/http/response.rb +1 -0
  491. data/lib/ddtrace/transport/http/statistics.rb +3 -2
  492. data/lib/ddtrace/transport/http/traces.rb +6 -6
  493. data/lib/ddtrace/transport/http.rb +51 -38
  494. data/lib/ddtrace/transport/io/client.rb +17 -9
  495. data/lib/ddtrace/transport/io/response.rb +2 -3
  496. data/lib/ddtrace/transport/io/traces.rb +10 -1
  497. data/lib/ddtrace/transport/io.rb +2 -1
  498. data/lib/ddtrace/transport/parcel.rb +7 -0
  499. data/lib/ddtrace/transport/request.rb +1 -0
  500. data/lib/ddtrace/transport/response.rb +1 -0
  501. data/lib/ddtrace/transport/statistics.rb +1 -0
  502. data/lib/ddtrace/transport/traces.rb +21 -3
  503. data/lib/ddtrace/utils/compression.rb +28 -0
  504. data/lib/ddtrace/utils/database.rb +1 -0
  505. data/lib/ddtrace/utils/forking.rb +2 -1
  506. data/lib/ddtrace/utils/object_set.rb +40 -0
  507. data/lib/ddtrace/utils/only_once.rb +41 -0
  508. data/lib/ddtrace/utils/sequence.rb +18 -0
  509. data/lib/ddtrace/utils/string_table.rb +46 -0
  510. data/lib/ddtrace/utils/time.rb +34 -2
  511. data/lib/ddtrace/utils.rb +14 -2
  512. data/lib/ddtrace/vendor/active_record/MIT-LICENSE +20 -0
  513. data/lib/ddtrace/vendor/active_record/connection_specification.rb +1 -0
  514. data/lib/ddtrace/vendor/multipart-post/LICENSE +11 -0
  515. data/lib/ddtrace/vendor/multipart-post/multipart/post/composite_read_io.rb +117 -0
  516. data/lib/ddtrace/vendor/multipart-post/multipart/post/multipartable.rb +58 -0
  517. data/lib/ddtrace/vendor/multipart-post/multipart/post/parts.rb +136 -0
  518. data/lib/ddtrace/vendor/multipart-post/multipart/post/version.rb +10 -0
  519. data/lib/ddtrace/vendor/multipart-post/multipart/post.rb +9 -0
  520. data/lib/ddtrace/vendor/multipart-post/multipart.rb +13 -0
  521. data/lib/ddtrace/vendor/multipart-post/net/http/post/multipart.rb +33 -0
  522. data/lib/ddtrace/version.rb +15 -2
  523. data/lib/ddtrace/worker.rb +1 -0
  524. data/lib/ddtrace/workers/async.rb +15 -5
  525. data/lib/ddtrace/workers/loop.rb +32 -5
  526. data/lib/ddtrace/workers/polling.rb +13 -5
  527. data/lib/ddtrace/workers/queue.rb +3 -1
  528. data/lib/ddtrace/workers/runtime_metrics.rb +15 -1
  529. data/lib/ddtrace/workers/trace_writer.rb +14 -16
  530. data/lib/ddtrace/workers.rb +8 -2
  531. data/lib/ddtrace/writer.rb +14 -7
  532. data/lib/ddtrace.rb +20 -56
  533. metadata +130 -446
  534. data/.circleci/config.yml +0 -566
  535. data/.circleci/images/primary/Dockerfile-2.0.0 +0 -73
  536. data/.circleci/images/primary/Dockerfile-2.1.10 +0 -73
  537. data/.circleci/images/primary/Dockerfile-2.2.10 +0 -73
  538. data/.circleci/images/primary/Dockerfile-2.3.8 +0 -75
  539. data/.circleci/images/primary/Dockerfile-2.4.6 +0 -73
  540. data/.circleci/images/primary/Dockerfile-2.5.6 +0 -73
  541. data/.circleci/images/primary/Dockerfile-2.6.4 +0 -73
  542. data/.circleci/images/primary/Dockerfile-2.7.0 +0 -73
  543. data/.circleci/images/primary/Dockerfile-3.0.0 +0 -73
  544. data/.circleci/images/primary/Dockerfile-jruby-9.2 +0 -77
  545. data/.dockerignore +0 -1
  546. data/.env +0 -26
  547. data/.github/CODEOWNERS +0 -1
  548. data/.github/workflows/add-milestone-to-pull-requests.yml +0 -42
  549. data/.github/workflows/create-next-milestone.yml +0 -20
  550. data/.gitlab-ci.yml +0 -27
  551. data/.rspec +0 -1
  552. data/.rubocop.yml +0 -85
  553. data/.simplecov +0 -41
  554. data/Appraisals +0 -1350
  555. data/Gemfile +0 -9
  556. data/Rakefile +0 -993
  557. data/benchmarks/postgres_database.yml +0 -9
  558. data/benchmarks/sidekiq_test.rb +0 -154
  559. data/docker-compose.yml +0 -400
  560. data/lib/ddtrace/augmentation/method_wrapper.rb +0 -20
  561. data/lib/ddtrace/augmentation/method_wrapping.rb +0 -38
  562. data/lib/ddtrace/augmentation/shim.rb +0 -102
  563. data/lib/ddtrace/augmentation.rb +0 -13
  564. data/lib/ddtrace/contrib/cucumber/configuration/settings.rb +0 -38
  565. data/lib/ddtrace/contrib/cucumber/ext.rb +0 -19
  566. data/lib/ddtrace/contrib/cucumber/formatter.rb +0 -104
  567. data/lib/ddtrace/contrib/cucumber/instrumentation.rb +0 -24
  568. data/lib/ddtrace/contrib/cucumber/integration.rb +0 -45
  569. data/lib/ddtrace/contrib/rspec/configuration/settings.rb +0 -38
  570. data/lib/ddtrace/contrib/rspec/example.rb +0 -61
  571. data/lib/ddtrace/contrib/rspec/example_group.rb +0 -61
  572. data/lib/ddtrace/contrib/rspec/ext.rb +0 -19
  573. data/lib/ddtrace/contrib/rspec/integration.rb +0 -46
  574. data/lib/ddtrace/contrib/rspec/patcher.rb +0 -25
  575. data/lib/ddtrace/environment.rb +0 -41
  576. data/lib/ddtrace/ext/ci.rb +0 -297
  577. data/lib/ddtrace/monkey.rb +0 -58
  578. data/lib/ddtrace/runtime/cgroup.rb +0 -44
  579. data/lib/ddtrace/runtime/class_count.rb +0 -17
  580. data/lib/ddtrace/runtime/container.rb +0 -73
  581. data/lib/ddtrace/runtime/gc.rb +0 -16
  582. data/lib/ddtrace/runtime/identity.rb +0 -40
  583. data/lib/ddtrace/runtime/object_space.rb +0 -19
  584. data/lib/ddtrace/runtime/socket.rb +0 -14
  585. data/lib/ddtrace/runtime/thread_count.rb +0 -16
  586. data/tasks/release_gem.rake +0 -28
@@ -0,0 +1,257 @@
1
+ # typed: true
2
+ require 'ddtrace/profiling/backtrace_location'
3
+ require 'ddtrace/profiling/events/stack'
4
+ require 'ddtrace/utils/only_once'
5
+ require 'ddtrace/utils/time'
6
+ require 'ddtrace/worker'
7
+ require 'ddtrace/workers/polling'
8
+
9
+ module Datadog
10
+ module Profiling
11
+ module Collectors
12
+ # Collects stack trace samples from Ruby threads for both CPU-time (if available) and wall-clock.
13
+ # Runs on its own background thread.
14
+ #
15
+ class Stack < Worker # rubocop:disable Metrics/ClassLength
16
+ include Workers::Polling
17
+
18
+ DEFAULT_MAX_TIME_USAGE_PCT = 2.0
19
+ MIN_INTERVAL = 0.01
20
+ THREAD_LAST_CPU_TIME_KEY = :datadog_profiler_last_cpu_time
21
+
22
+ attr_reader \
23
+ :recorder,
24
+ :max_frames,
25
+ :trace_identifiers_helper,
26
+ :ignore_thread,
27
+ :max_time_usage_pct,
28
+ :thread_api
29
+
30
+ def initialize(
31
+ recorder,
32
+ max_frames:,
33
+ trace_identifiers_helper:, # Usually an instance of Datadog::Profiling::TraceIdentifiers::Helper
34
+ ignore_thread: nil,
35
+ max_time_usage_pct: DEFAULT_MAX_TIME_USAGE_PCT,
36
+ thread_api: Thread,
37
+ fork_policy: Workers::Async::Thread::FORK_POLICY_RESTART, # Restart in forks by default
38
+ interval: MIN_INTERVAL,
39
+ enabled: true
40
+ )
41
+ @recorder = recorder
42
+ @max_frames = max_frames
43
+ @trace_identifiers_helper = trace_identifiers_helper
44
+ @ignore_thread = ignore_thread
45
+ @max_time_usage_pct = max_time_usage_pct
46
+ @thread_api = thread_api
47
+
48
+ # Workers::Async::Thread settings
49
+ self.fork_policy = fork_policy
50
+
51
+ # Workers::IntervalLoop settings
52
+ self.loop_base_interval = interval
53
+
54
+ # Workers::Polling settings
55
+ self.enabled = enabled
56
+
57
+ @warn_about_missing_cpu_time_instrumentation_only_once = Datadog::Utils::OnlyOnce.new
58
+
59
+ # Cache this proc, since it's pretty expensive to keep recreating it
60
+ @build_backtrace_location = method(:build_backtrace_location).to_proc
61
+ # Cache this buffer, since it's pretty expensive to keep accessing it
62
+ @stack_sample_event_recorder = recorder[Events::StackSample]
63
+ end
64
+
65
+ def start
66
+ @last_wall_time = Datadog::Utils::Time.get_time
67
+ reset_cpu_time_tracking
68
+ perform
69
+ end
70
+
71
+ def perform
72
+ collect_and_wait
73
+ end
74
+
75
+ def loop_back_off?
76
+ false
77
+ end
78
+
79
+ def collect_and_wait
80
+ run_time = Datadog::Utils::Time.measure do
81
+ collect_events
82
+ end
83
+
84
+ # Update wait time to throttle profiling
85
+ self.loop_wait_time = compute_wait_time(run_time)
86
+ end
87
+
88
+ def collect_events
89
+ events = []
90
+
91
+ # Compute wall time interval
92
+ current_wall_time = Datadog::Utils::Time.get_time
93
+ last_wall_time = if instance_variable_defined?(:@last_wall_time)
94
+ @last_wall_time
95
+ else
96
+ current_wall_time
97
+ end
98
+
99
+ wall_time_interval_ns = ((current_wall_time - last_wall_time).round(9) * 1e9).to_i
100
+ @last_wall_time = current_wall_time
101
+
102
+ # Collect backtraces from each thread
103
+ thread_api.list.each do |thread|
104
+ next unless thread.alive?
105
+ next if ignore_thread.is_a?(Proc) && ignore_thread.call(thread)
106
+
107
+ event = collect_thread_event(thread, wall_time_interval_ns)
108
+ events << event unless event.nil?
109
+ end
110
+
111
+ # Send events to recorder
112
+ recorder.push(events) unless events.empty?
113
+
114
+ events
115
+ end
116
+
117
+ def collect_thread_event(thread, wall_time_interval_ns)
118
+ locations = thread.backtrace_locations
119
+ return if locations.nil?
120
+
121
+ # Get actual stack size then trim the stack
122
+ stack_size = locations.length
123
+ locations = locations[0..(max_frames - 1)]
124
+
125
+ # Convert backtrace locations into structs
126
+ locations = convert_backtrace_locations(locations)
127
+
128
+ thread_id = thread.respond_to?(:pthread_thread_id) ? thread.pthread_thread_id : thread.object_id
129
+ trace_id, span_id, trace_resource_container = trace_identifiers_helper.trace_identifiers_for(thread)
130
+ cpu_time = get_cpu_time_interval!(thread)
131
+
132
+ Events::StackSample.new(
133
+ nil,
134
+ locations,
135
+ stack_size,
136
+ thread_id,
137
+ trace_id,
138
+ span_id,
139
+ trace_resource_container,
140
+ cpu_time,
141
+ wall_time_interval_ns
142
+ )
143
+ end
144
+
145
+ def get_cpu_time_interval!(thread)
146
+ # Return if we can't get the current CPU time
147
+ unless thread.respond_to?(:cpu_time_instrumentation_installed?) && thread.cpu_time_instrumentation_installed?
148
+ warn_about_missing_cpu_time_instrumentation(thread)
149
+ return
150
+ end
151
+
152
+ current_cpu_time_ns = thread.cpu_time(:nanosecond)
153
+
154
+ # NOTE: This can still be nil even when all of the checks above passed because of a race: there's a bit of
155
+ # initialization that needs to be done by the thread itself, and it's possible for us to try to sample
156
+ # *before* the thread had time to finish the initialization
157
+ return unless current_cpu_time_ns
158
+
159
+ last_cpu_time_ns = (thread.thread_variable_get(THREAD_LAST_CPU_TIME_KEY) || current_cpu_time_ns)
160
+ interval = current_cpu_time_ns - last_cpu_time_ns
161
+
162
+ # Update CPU time for thread
163
+ thread.thread_variable_set(THREAD_LAST_CPU_TIME_KEY, current_cpu_time_ns)
164
+
165
+ # Return interval
166
+ interval
167
+ end
168
+
169
+ def compute_wait_time(used_time)
170
+ # We took used_time to get the last sample.
171
+ #
172
+ # What we're computing here is -- if used_time corresponds to max_time_usage_pct of the time we should
173
+ # spend working, how much is (100% - max_time_usage_pct) of the time?
174
+ #
175
+ # For instance, if we took 10ms to sample, and max_time_usage_pct is 1%, then the other 99% is 990ms, which
176
+ # means we need to sleep for 990ms to guarantee that we don't spend more than 1% of the time working.
177
+ used_time_ns = used_time * 1e9
178
+ interval = (used_time_ns / (max_time_usage_pct / 100.0)) - used_time_ns
179
+ [interval / 1e9, MIN_INTERVAL].max
180
+ end
181
+
182
+ # Convert backtrace locations into structs
183
+ # Re-use old backtrace location objects if they already exist in the buffer
184
+ def convert_backtrace_locations(locations)
185
+ locations.collect do |location|
186
+ # Re-use existing BacktraceLocation if identical copy, otherwise build a new one.
187
+ @stack_sample_event_recorder.cache(:backtrace_locations).fetch(
188
+ # Function name
189
+ location.base_label,
190
+ # Line number
191
+ location.lineno,
192
+ # Filename
193
+ location.path,
194
+ # Build function
195
+ &@build_backtrace_location
196
+ )
197
+ end
198
+ end
199
+
200
+ def build_backtrace_location(_id, base_label, lineno, path)
201
+ string_table = @stack_sample_event_recorder.string_table
202
+
203
+ Profiling::BacktraceLocation.new(
204
+ string_table.fetch_string(base_label),
205
+ lineno,
206
+ string_table.fetch_string(path)
207
+ )
208
+ end
209
+
210
+ private
211
+
212
+ def warn_about_missing_cpu_time_instrumentation(thread)
213
+ @warn_about_missing_cpu_time_instrumentation_only_once.run do
214
+ # Is the profiler thread instrumented? If it is, then we know instrumentation is available, but seems to be
215
+ # missing on this thread we just found.
216
+ #
217
+ # As far as we know, it can be missing due to one the following:
218
+ #
219
+ # a) The thread was started before we installed our instrumentation.
220
+ # In this case, the fix is to make sure ddtrace gets loaded before any other parts of the application.
221
+ #
222
+ # b) The thread was started using the Ruby native APIs (e.g. from a C extension such as ffi).
223
+ # Known cases right now that trigger this are the ethon/typhoeus gems.
224
+ # We currently have no solution for this case; these threads will always be missing our CPU instrumentation.
225
+ #
226
+ # c) The thread was started with `Thread.start`/`Thread.fork` and hasn't yet enabled the instrumentation.
227
+ # When threads are started using these APIs, there's a small time window during which the thread has started
228
+ # but our code to apply the instrumentation hasn't run yet; in these cases it's just a matter of allowing
229
+ # it to run and our instrumentation to be applied.
230
+ #
231
+ if thread_api.current.respond_to?(:cpu_time) && thread_api.current.cpu_time
232
+ Datadog.logger.debug(
233
+ "Thread ('#{thread}') is missing profiling instrumentation; other threads should be unaffected"
234
+ )
235
+ end
236
+ end
237
+ end
238
+
239
+ # If the profiler is started for a while, stopped and then restarted OR whenever the process forks, we need to
240
+ # clean up any leftover per-thread cpu time counters, so that the first sample after starting doesn't end up with:
241
+ #
242
+ # a) negative time: At least on my test docker container, and on the reliability environment, after the process
243
+ # forks, the clock reference changes and (old cpu time - new cpu time) can be < 0
244
+ #
245
+ # b) large amount of time: if the profiler was started, then stopped for some amount of time, and then
246
+ # restarted, we don't want the first sample to be "blamed" for multiple minutes of CPU time
247
+ #
248
+ # By resetting the last cpu time seen, we start with a clean slate every time we start the stack collector.
249
+ def reset_cpu_time_tracking
250
+ thread_api.list.each do |thread|
251
+ thread.thread_variable_set(THREAD_LAST_CPU_TIME_KEY, nil)
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,38 @@
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
+ "Encoding profile covering #{flush.start.iso8601} to #{flush.finish.iso8601}, " \
28
+ "events: #{flush.event_count} (#{template.debug_statistics})"
29
+ end
30
+
31
+ # Build the profile and encode it
32
+ template.to_pprof
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ 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
+ :trace_id,
15
+ :span_id,
16
+ :trace_resource_container
17
+
18
+ def initialize(
19
+ timestamp,
20
+ frames,
21
+ total_frame_count,
22
+ thread_id,
23
+ trace_id,
24
+ span_id,
25
+ trace_resource_container
26
+ )
27
+ super(timestamp)
28
+
29
+ @frames = frames
30
+ @total_frame_count = total_frame_count
31
+ @thread_id = thread_id
32
+ @trace_id = trace_id
33
+ @span_id = span_id
34
+ @trace_resource_container = trace_resource_container
35
+
36
+ @hash = [
37
+ thread_id,
38
+ trace_id,
39
+ span_id,
40
+ # trace_resource_container is deliberately not included -- events that share the same (trace_id, span_id)
41
+ # pair should also have the same trace_resource_container
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
+ trace_id,
60
+ span_id,
61
+ trace_resource_container,
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
+ trace_id,
71
+ span_id,
72
+ trace_resource_container
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,67 @@
1
+ # typed: true
2
+ module Datadog
3
+ module Profiling
4
+ module Ext
5
+ # Monkey patches Ruby's `Thread` with our `Ext::CThread` to enable CPU-time profiling
6
+ module CPU
7
+ # We cannot apply our CPU extension if a broken rollbar is around because that can cause customer apps to fail
8
+ # with a SystemStackError: stack level too deep.
9
+ #
10
+ # This occurs whenever our extensions to Thread are applied BEFORE rollbar applies its own. This happens
11
+ # because a loop forms: our extension tries to call Thread#initialize, but it's intercepted by rollbar, which
12
+ # then tries to call the original Thread#initialize as well, but instead alls our extension, leading to stack
13
+ # exhaustion.
14
+ #
15
+ # See https://github.com/rollbar/rollbar-gem/pull/1018 for more details on the issue
16
+ ROLLBAR_INCOMPATIBLE_VERSIONS = Gem::Requirement.new('<= 3.1.1')
17
+
18
+ def self.supported?
19
+ unsupported_reason.nil?
20
+ end
21
+
22
+ def self.apply!
23
+ return false unless supported?
24
+
25
+ # Applying CThread to Thread will ensure any new threads
26
+ # will provide a thread/clock ID for CPU timing.
27
+ require 'ddtrace/profiling/ext/cthread'
28
+ ::Thread.prepend(Profiling::Ext::CThread)
29
+ ::Thread.singleton_class.prepend(Datadog::Profiling::Ext::WrapThreadStartFork)
30
+ end
31
+
32
+ def self.unsupported_reason
33
+ # NOTE: Only the first matching reason is returned, so try to keep a nice order on reasons -- e.g. tell users
34
+ # first that they can't use this on macOS before telling them that they have the wrong ffi version
35
+
36
+ if RUBY_ENGINE == 'jruby'
37
+ 'JRuby is not supported'
38
+ elsif RUBY_PLATFORM.include?('darwin')
39
+ 'Feature requires Linux; macOS is not supported'
40
+ elsif RUBY_PLATFORM =~ /(mswin|mingw)/
41
+ 'Feature requires Linux; Windows is not supported'
42
+ elsif !RUBY_PLATFORM.include?('linux')
43
+ "Feature requires Linux; #{RUBY_PLATFORM} is not supported"
44
+ elsif Gem::Specification.find_all_by_name('rollbar', ROLLBAR_INCOMPATIBLE_VERSIONS).any?
45
+ 'You have an incompatible rollbar gem version installed; ensure that you have rollbar >= 3.1.2 by ' \
46
+ "adding `gem 'rollbar', '>= 3.1.2'` to your Gemfile or gems.rb file. " \
47
+ 'See https://github.com/rollbar/rollbar-gem/pull/1018 for details'
48
+ elsif Gem::Specification.find_all_by_name('logging').any? && logging_inherit_context_enabled?
49
+ 'The `logging` gem is installed and its thread inherit context feature is enabled. ' \
50
+ "Please add LOGGING_INHERIT_CONTEXT=false to your application's environment variables to disable the " \
51
+ 'conflicting `logging` gem feature. ' \
52
+ 'See https://github.com/TwP/logging/pull/230 for details'
53
+ end
54
+ end
55
+
56
+ private_class_method def self.logging_inherit_context_enabled?
57
+ # The logging gem provides a mechanism to disable the conflicting behavior, see
58
+ # https://github.com/TwP/logging/blob/ae9872d093833b2a5a34cbe1faa4e895a81f6845/lib/logging/diagnostic_context.rb#L418
59
+ # Here we check if the behavior is enabled
60
+ inherit_context_configuration = ENV['LOGGING_INHERIT_CONTEXT']
61
+
62
+ inherit_context_configuration.nil? || !%w[false no 0].include?(inherit_context_configuration.downcase)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,156 @@
1
+ # typed: false
2
+ require 'ffi'
3
+
4
+ module Datadog
5
+ module Profiling
6
+ module Ext
7
+ # C-struct for retrieving clock ID from pthread
8
+ class CClockId < FFI::Struct
9
+ layout :value, :int
10
+ end
11
+
12
+ # Enables interfacing with pthread via FFI
13
+ module NativePthread
14
+ extend FFI::Library
15
+ ffi_lib ['pthread', 'libpthread.so.0']
16
+ attach_function :pthread_self, [], :ulong
17
+ attach_function :pthread_getcpuclockid, [:ulong, CClockId], :int
18
+
19
+ # NOTE: Only returns thread ID for thread that evaluates this call.
20
+ # a.k.a. evaluating `get_pthread_thread_id(thread_a)` from within
21
+ # `thread_b` will return `thread_b`'s thread ID, not `thread_a`'s.
22
+ def self.get_pthread_thread_id(thread)
23
+ return unless ::Thread.current == thread
24
+
25
+ pthread_self
26
+ end
27
+
28
+ def self.get_clock_id(thread, pthread_id)
29
+ return unless ::Thread.current == thread && pthread_id
30
+
31
+ clock = CClockId.new
32
+ clock[:value] = 0
33
+ pthread_getcpuclockid(pthread_id, clock).zero? ? clock[:value] : nil
34
+ end
35
+ end
36
+
37
+ # Extension used to enable CPU-time profiling via use of pthread's `getcpuclockid`.
38
+ module CThread
39
+ def self.prepended(base)
40
+ # Threads that have already been created, will not have resolved
41
+ # a thread/clock ID. This is because these IDs can only be resolved
42
+ # from within the thread's execution context, which we do not control.
43
+ #
44
+ # We can mitigate this for the current thread via #update_native_ids,
45
+ # since we are currently running within its execution context. We cannot
46
+ # do this for any other threads that may have been created already.
47
+ # (This is why it's important that CThread is applied before anything else runs.)
48
+ base.current.send(:update_native_ids) if base.current.is_a?(CThread)
49
+ end
50
+
51
+ # Process::Waiter crash workaround:
52
+ #
53
+ # This is a workaround for a Ruby VM segfault (usually something like
54
+ # "[BUG] Segmentation fault at 0x0000000000000008") in the affected Ruby versions.
55
+ # See https://bugs.ruby-lang.org/issues/17807 and the regression tests added to this module's specs for details.
56
+ #
57
+ # In those Ruby versions, there's a very special subclass of `Thread` called `Process::Waiter` that causes VM
58
+ # crashes whenever something tries to read its instance variables. This subclass of thread only shows up when
59
+ # the `Process.detach` API gets used.
60
+ # In this module's specs you can find crash regression tests that include a way of reproducing it.
61
+ #
62
+ # The workaround is to use `defined?` to check first if the instance variable exists. This seems to be fine
63
+ # with Ruby.
64
+ # Note that this crash doesn't affect `@foo ||=` nor instance variable writes (after the first write ever of any
65
+ # instance variable on a `Process::Waiter`, then further reads and writes to that or any other instance are OK;
66
+ # it looks like there's some lazily-created structure that is missing and did not get created).
67
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3') &&
68
+ Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7')
69
+ attr_reader :pthread_thread_id
70
+ else
71
+ def pthread_thread_id
72
+ defined?(@pthread_thread_id) && @pthread_thread_id
73
+ end
74
+ end
75
+
76
+ def initialize(*args)
77
+ @pid = ::Process.pid
78
+ @pthread_thread_id = nil
79
+ @clock_id = nil
80
+
81
+ # Wrap the work block with our own
82
+ # so we can retrieve the native thread ID within the thread's context.
83
+ wrapped_block = proc do |*t_args|
84
+ # Set native thread ID & clock ID
85
+ update_native_ids
86
+ yield(*t_args)
87
+ end
88
+ wrapped_block.ruby2_keywords if wrapped_block.respond_to?(:ruby2_keywords, true)
89
+
90
+ super(*args, &wrapped_block)
91
+ end
92
+ ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
93
+
94
+ def cpu_time(unit = :float_second)
95
+ ::Process.clock_gettime(clock_id, unit) if clock_id
96
+ end
97
+
98
+ def cpu_time_instrumentation_installed?
99
+ # If this thread was started before this module was added to Thread OR if something caused the initialize
100
+ # method above not to be properly called on new threads, this instance variable is never defined (never set to
101
+ # any value at all, including nil).
102
+ #
103
+ # Thus, we can use @clock_id as a canary to detect a thread that has missing instrumentation, because we
104
+ # know that in initialize above we always set this variable to nil.
105
+ defined?(@clock_id) != nil
106
+ end
107
+
108
+ private
109
+
110
+ def clock_id
111
+ update_native_ids if forked?
112
+ defined?(@clock_id) && @clock_id
113
+ end
114
+
115
+ def forked?
116
+ ::Process.pid != (@pid ||= nil)
117
+ end
118
+
119
+ def update_native_ids
120
+ # Can only resolve if invoked from same thread
121
+ return unless ::Thread.current == self
122
+
123
+ @pid = ::Process.pid
124
+ @pthread_thread_id = NativePthread.get_pthread_thread_id(self)
125
+ @clock_id = NativePthread.get_clock_id(self, @pthread_thread_id)
126
+ end
127
+ end
128
+
129
+ # Threads in Ruby can be started by creating a new instance of `Thread` (or a subclass) OR by calling
130
+ # `start`/`fork` on `Thread` (or a subclass).
131
+ #
132
+ # This module intercepts calls to `start`/`fork`, ensuring that the `update_native_ids` operation is correctly
133
+ # called once the new thread starts.
134
+ #
135
+ # Note that unlike CThread above, this module should be prepended to the `Thread`'s singleton class, not to
136
+ # the class.
137
+ module WrapThreadStartFork
138
+ def start(*args)
139
+ # Wrap the work block with our own
140
+ # so we can retrieve the native thread ID within the thread's context.
141
+ wrapped_block = proc do |*t_args|
142
+ # Set native thread ID & clock ID
143
+ ::Thread.current.send(:update_native_ids)
144
+ yield(*t_args)
145
+ end
146
+ wrapped_block.ruby2_keywords if wrapped_block.respond_to?(:ruby2_keywords, true)
147
+
148
+ super(*args, &wrapped_block)
149
+ end
150
+ ruby2_keywords :start if respond_to?(:ruby2_keywords, true)
151
+
152
+ alias fork start
153
+ end
154
+ end
155
+ end
156
+ end