ddtrace 1.1.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (524) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +129 -1
  3. data/LICENSE-3rdparty.csv +2 -0
  4. data/README.md +8 -3
  5. data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +2 -2
  6. data/ext/ddtrace_profiling_loader/extconf.rb +1 -0
  7. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +15 -7
  8. data/ext/ddtrace_profiling_native_extension/clock_id.h +21 -1
  9. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +31 -2
  10. data/ext/ddtrace_profiling_native_extension/clock_id_noop.c +11 -2
  11. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +390 -0
  12. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +6 -0
  13. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +391 -0
  14. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +23 -19
  15. data/ext/ddtrace_profiling_native_extension/collectors_stack.h +9 -0
  16. data/ext/ddtrace_profiling_native_extension/extconf.rb +64 -16
  17. data/ext/ddtrace_profiling_native_extension/helpers.h +12 -0
  18. data/ext/ddtrace_profiling_native_extension/http_transport.c +334 -0
  19. data/ext/ddtrace_profiling_native_extension/{libddprof_helpers.h → libdatadog_helpers.h} +2 -1
  20. data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +116 -12
  21. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +89 -4
  22. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +5 -5
  23. data/ext/ddtrace_profiling_native_extension/profiling.c +8 -3
  24. data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +25 -0
  25. data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +65 -0
  26. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +311 -28
  27. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +18 -8
  28. data/lib/datadog/appsec/autoload.rb +4 -2
  29. data/lib/datadog/appsec/configuration.rb +1 -1
  30. data/lib/datadog/appsec/contrib/auto_instrument.rb +0 -2
  31. data/lib/datadog/appsec/contrib/configuration/settings.rb +1 -1
  32. data/lib/datadog/appsec/contrib/rack/configuration/settings.rb +2 -2
  33. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +6 -6
  34. data/lib/datadog/appsec/contrib/rack/integration.rb +5 -5
  35. data/lib/datadog/appsec/contrib/rack/patcher.rb +2 -2
  36. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +1 -1
  37. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +1 -1
  38. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +1 -1
  39. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +2 -2
  40. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +3 -3
  41. data/lib/datadog/appsec/contrib/rails/configuration/settings.rb +2 -2
  42. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +4 -4
  43. data/lib/datadog/appsec/contrib/rails/integration.rb +4 -4
  44. data/lib/datadog/appsec/contrib/rails/patcher.rb +16 -12
  45. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +1 -1
  46. data/lib/datadog/appsec/contrib/sinatra/configuration/settings.rb +2 -2
  47. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +5 -5
  48. data/lib/datadog/appsec/contrib/sinatra/integration.rb +4 -4
  49. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +16 -12
  50. data/lib/datadog/appsec/event.rb +3 -3
  51. data/lib/datadog/appsec/extensions.rb +1 -1
  52. data/lib/datadog/appsec/processor.rb +1 -1
  53. data/lib/datadog/appsec/reactive/engine.rb +2 -2
  54. data/lib/datadog/appsec/reactive/operation.rb +3 -3
  55. data/lib/datadog/appsec.rb +5 -5
  56. data/lib/datadog/ci/configuration/components.rb +1 -1
  57. data/lib/datadog/ci/configuration/settings.rb +1 -1
  58. data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +2 -2
  59. data/lib/datadog/ci/contrib/cucumber/formatter.rb +5 -5
  60. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +1 -1
  61. data/lib/datadog/ci/contrib/cucumber/integration.rb +4 -4
  62. data/lib/datadog/ci/contrib/cucumber/patcher.rb +2 -2
  63. data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +2 -2
  64. data/lib/datadog/ci/contrib/rspec/example.rb +5 -5
  65. data/lib/datadog/ci/contrib/rspec/integration.rb +4 -4
  66. data/lib/datadog/ci/contrib/rspec/patcher.rb +2 -2
  67. data/lib/datadog/ci/ext/environment.rb +8 -6
  68. data/lib/datadog/ci/extensions.rb +4 -4
  69. data/lib/datadog/ci/flush.rb +2 -2
  70. data/lib/datadog/ci/test.rb +3 -3
  71. data/lib/datadog/ci.rb +6 -6
  72. data/lib/datadog/core/buffer/cruby.rb +1 -1
  73. data/lib/datadog/core/buffer/thread_safe.rb +1 -1
  74. data/lib/datadog/core/configuration/agent_settings_resolver.rb +6 -6
  75. data/lib/datadog/core/configuration/base.rb +11 -2
  76. data/lib/datadog/core/configuration/components.rb +70 -52
  77. data/lib/datadog/core/configuration/option_definition.rb +1 -1
  78. data/lib/datadog/core/configuration/option_definition_set.rb +1 -1
  79. data/lib/datadog/core/configuration/options.rb +3 -3
  80. data/lib/datadog/core/configuration/settings.rb +42 -8
  81. data/lib/datadog/core/configuration.rb +8 -5
  82. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  83. data/lib/datadog/core/diagnostics/health.rb +2 -2
  84. data/lib/datadog/core/environment/cgroup.rb +1 -1
  85. data/lib/datadog/core/environment/container.rb +1 -1
  86. data/lib/datadog/core/environment/ext.rb +1 -1
  87. data/lib/datadog/core/environment/identity.rb +2 -2
  88. data/lib/datadog/core/environment/platform.rb +40 -0
  89. data/lib/datadog/core/environment/socket.rb +1 -1
  90. data/lib/datadog/core/error.rb +1 -1
  91. data/lib/datadog/core/extensions.rb +1 -1
  92. data/lib/datadog/core/metrics/client.rb +8 -8
  93. data/lib/datadog/core/metrics/options.rb +3 -3
  94. data/lib/datadog/core/runtime/metrics.rb +6 -6
  95. data/lib/datadog/core/telemetry/client.rb +79 -0
  96. data/lib/datadog/core/telemetry/collector.rb +234 -0
  97. data/lib/datadog/core/telemetry/emitter.rb +48 -0
  98. data/lib/datadog/core/telemetry/event.rb +71 -0
  99. data/lib/datadog/core/telemetry/ext.rb +11 -0
  100. data/lib/datadog/core/telemetry/heartbeat.rb +37 -0
  101. data/lib/datadog/core/telemetry/http/adapters/net.rb +113 -0
  102. data/lib/datadog/core/telemetry/http/env.rb +20 -0
  103. data/lib/datadog/core/telemetry/http/ext.rb +20 -0
  104. data/lib/datadog/core/telemetry/http/response.rb +68 -0
  105. data/lib/datadog/core/telemetry/http/transport.rb +53 -0
  106. data/lib/datadog/core/telemetry/v1/app_event.rb +52 -0
  107. data/lib/datadog/core/telemetry/v1/application.rb +86 -0
  108. data/lib/datadog/core/telemetry/v1/configuration.rb +25 -0
  109. data/lib/datadog/core/telemetry/v1/dependency.rb +36 -0
  110. data/lib/datadog/core/telemetry/v1/host.rb +51 -0
  111. data/lib/datadog/core/telemetry/v1/integration.rb +58 -0
  112. data/lib/datadog/core/telemetry/v1/product.rb +28 -0
  113. data/lib/datadog/core/telemetry/v1/telemetry_request.rb +100 -0
  114. data/lib/datadog/core/utils/object_set.rb +1 -1
  115. data/lib/datadog/core/utils/sequence.rb +5 -0
  116. data/lib/datadog/core/utils/string_table.rb +1 -1
  117. data/lib/datadog/core/utils/time.rb +3 -3
  118. data/lib/datadog/core/utils.rb +3 -3
  119. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +2 -2
  120. data/lib/datadog/core/vendor/multipart-post/net/http/post/multipart.rb +3 -3
  121. data/lib/datadog/core/workers/async.rb +1 -1
  122. data/lib/datadog/core/workers/polling.rb +2 -2
  123. data/lib/datadog/core/workers/runtime_metrics.rb +4 -4
  124. data/lib/datadog/core.rb +50 -50
  125. data/lib/datadog/kit.rb +1 -1
  126. data/lib/datadog/opentracer/distributed_headers.rb +2 -2
  127. data/lib/datadog/opentracer/rack_propagator.rb +11 -7
  128. data/lib/datadog/opentracer/span.rb +1 -1
  129. data/lib/datadog/opentracer/text_map_propagator.rb +9 -6
  130. data/lib/datadog/opentracer/thread_local_scope_manager.rb +26 -3
  131. data/lib/datadog/opentracer/tracer.rb +19 -15
  132. data/lib/datadog/opentracer.rb +16 -16
  133. data/lib/datadog/profiling/buffer.rb +3 -3
  134. data/lib/datadog/profiling/collectors/code_provenance.rb +1 -0
  135. data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +27 -0
  136. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +74 -0
  137. data/lib/datadog/profiling/collectors/old_stack.rb +7 -7
  138. data/lib/datadog/profiling/collectors/stack.rb +3 -6
  139. data/lib/datadog/profiling/encoding/profile.rb +8 -12
  140. data/lib/datadog/profiling/events/stack.rb +1 -1
  141. data/lib/datadog/profiling/exporter.rb +66 -9
  142. data/lib/datadog/profiling/ext/forking.rb +41 -42
  143. data/lib/datadog/profiling/ext.rb +3 -15
  144. data/lib/datadog/profiling/flush.rb +25 -56
  145. data/lib/datadog/profiling/http_transport.rb +132 -0
  146. data/lib/datadog/profiling/old_ext.rb +42 -0
  147. data/lib/datadog/profiling/old_recorder.rb +101 -0
  148. data/lib/datadog/profiling/pprof/builder.rb +4 -4
  149. data/lib/datadog/profiling/pprof/converter.rb +1 -1
  150. data/lib/datadog/profiling/pprof/message_set.rb +1 -1
  151. data/lib/datadog/profiling/pprof/stack_sample.rb +4 -4
  152. data/lib/datadog/profiling/pprof/string_table.rb +1 -1
  153. data/lib/datadog/profiling/pprof/template.rb +5 -5
  154. data/lib/datadog/profiling/preload.rb +1 -1
  155. data/lib/datadog/profiling/scheduler.rb +28 -46
  156. data/lib/datadog/profiling/stack_recorder.rb +14 -4
  157. data/lib/datadog/profiling/tag_builder.rb +6 -1
  158. data/lib/datadog/profiling/tasks/setup.rb +2 -2
  159. data/lib/datadog/profiling/trace_identifiers/ddtrace.rb +2 -2
  160. data/lib/datadog/profiling/trace_identifiers/helper.rb +1 -1
  161. data/lib/datadog/profiling/transport/http/api/endpoint.rb +13 -35
  162. data/lib/datadog/profiling/transport/http/api/instance.rb +2 -2
  163. data/lib/datadog/profiling/transport/http/api/spec.rb +1 -1
  164. data/lib/datadog/profiling/transport/http/api.rb +5 -5
  165. data/lib/datadog/profiling/transport/http/builder.rb +3 -3
  166. data/lib/datadog/profiling/transport/http/client.rb +6 -4
  167. data/lib/datadog/profiling/transport/http/response.rb +1 -3
  168. data/lib/datadog/profiling/transport/http.rb +22 -16
  169. data/lib/datadog/profiling.rb +21 -20
  170. data/lib/datadog/tracing/analytics.rb +1 -1
  171. data/lib/datadog/tracing/buffer.rb +5 -5
  172. data/lib/datadog/tracing/context.rb +1 -1
  173. data/lib/datadog/tracing/context_provider.rb +18 -2
  174. data/lib/datadog/tracing/contrib/action_cable/configuration/settings.rb +2 -2
  175. data/lib/datadog/tracing/contrib/action_cable/event.rb +4 -5
  176. data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +4 -4
  177. data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +3 -3
  178. data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +4 -4
  179. data/lib/datadog/tracing/contrib/action_cable/events.rb +4 -4
  180. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +3 -4
  181. data/lib/datadog/tracing/contrib/action_cable/integration.rb +4 -4
  182. data/lib/datadog/tracing/contrib/action_cable/patcher.rb +4 -4
  183. data/lib/datadog/tracing/contrib/action_mailer/configuration/settings.rb +2 -2
  184. data/lib/datadog/tracing/contrib/action_mailer/event.rb +3 -3
  185. data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +3 -3
  186. data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +3 -3
  187. data/lib/datadog/tracing/contrib/action_mailer/events.rb +2 -2
  188. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +4 -4
  189. data/lib/datadog/tracing/contrib/action_mailer/patcher.rb +3 -3
  190. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +10 -6
  191. data/lib/datadog/tracing/contrib/action_pack/action_controller/patcher.rb +2 -2
  192. data/lib/datadog/tracing/contrib/action_pack/configuration/settings.rb +2 -2
  193. data/lib/datadog/tracing/contrib/action_pack/integration.rb +4 -4
  194. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +2 -2
  195. data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -1
  196. data/lib/datadog/tracing/contrib/action_view/configuration/settings.rb +2 -2
  197. data/lib/datadog/tracing/contrib/action_view/event.rb +1 -1
  198. data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +5 -5
  199. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +5 -5
  200. data/lib/datadog/tracing/contrib/action_view/events.rb +2 -2
  201. data/lib/datadog/tracing/contrib/action_view/instrumentation/partial_renderer.rb +2 -2
  202. data/lib/datadog/tracing/contrib/action_view/instrumentation/template_renderer.rb +2 -2
  203. data/lib/datadog/tracing/contrib/action_view/integration.rb +4 -4
  204. data/lib/datadog/tracing/contrib/action_view/patcher.rb +7 -7
  205. data/lib/datadog/tracing/contrib/action_view/utils.rb +1 -1
  206. data/lib/datadog/tracing/contrib/active_job/configuration/settings.rb +3 -3
  207. data/lib/datadog/tracing/contrib/active_job/event.rb +3 -3
  208. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +4 -4
  209. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +4 -4
  210. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +4 -4
  211. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +4 -4
  212. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +4 -4
  213. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +4 -4
  214. data/lib/datadog/tracing/contrib/active_job/events.rb +6 -6
  215. data/lib/datadog/tracing/contrib/active_job/integration.rb +4 -4
  216. data/lib/datadog/tracing/contrib/active_job/log_injection.rb +0 -2
  217. data/lib/datadog/tracing/contrib/active_job/patcher.rb +4 -4
  218. data/lib/datadog/tracing/contrib/active_model_serializers/configuration/settings.rb +2 -2
  219. data/lib/datadog/tracing/contrib/active_model_serializers/event.rb +4 -5
  220. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +3 -3
  221. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +2 -2
  222. data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +2 -2
  223. data/lib/datadog/tracing/contrib/active_model_serializers/integration.rb +3 -3
  224. data/lib/datadog/tracing/contrib/active_model_serializers/patcher.rb +3 -4
  225. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
  226. data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +3 -3
  227. data/lib/datadog/tracing/contrib/active_record/event.rb +1 -1
  228. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +4 -4
  229. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +6 -6
  230. data/lib/datadog/tracing/contrib/active_record/events.rb +2 -2
  231. data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -6
  232. data/lib/datadog/tracing/contrib/active_record/patcher.rb +2 -2
  233. data/lib/datadog/tracing/contrib/active_record/utils.rb +2 -2
  234. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +19 -9
  235. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +2 -2
  236. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +1 -1
  237. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +2 -2
  238. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -5
  239. data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +1 -1
  240. data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +1 -1
  241. data/lib/datadog/tracing/contrib/active_support/patcher.rb +2 -2
  242. data/lib/datadog/tracing/contrib/analytics.rb +1 -1
  243. data/lib/datadog/tracing/contrib/auto_instrument.rb +4 -4
  244. data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +2 -2
  245. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +3 -4
  246. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -3
  247. data/lib/datadog/tracing/contrib/aws/patcher.rb +5 -5
  248. data/lib/datadog/tracing/contrib/concurrent_ruby/configuration/settings.rb +2 -2
  249. data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +1 -1
  250. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -3
  251. data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +2 -2
  252. data/lib/datadog/tracing/contrib/configurable.rb +2 -2
  253. data/lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb +1 -1
  254. data/lib/datadog/tracing/contrib/configuration/settings.rb +2 -2
  255. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +2 -2
  256. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +4 -5
  257. data/lib/datadog/tracing/contrib/dalli/integration.rb +3 -3
  258. data/lib/datadog/tracing/contrib/dalli/patcher.rb +3 -3
  259. data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -1
  260. data/lib/datadog/tracing/contrib/delayed_job/configuration/settings.rb +3 -3
  261. data/lib/datadog/tracing/contrib/delayed_job/ext.rb +2 -0
  262. data/lib/datadog/tracing/contrib/delayed_job/integration.rb +3 -3
  263. data/lib/datadog/tracing/contrib/delayed_job/patcher.rb +8 -2
  264. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +3 -4
  265. data/lib/datadog/tracing/contrib/delayed_job/server_internal_tracer/worker.rb +32 -0
  266. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +2 -2
  267. data/lib/datadog/tracing/contrib/elasticsearch/integration.rb +3 -3
  268. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -7
  269. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +1 -1
  270. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +2 -2
  271. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
  272. data/lib/datadog/tracing/contrib/ethon/integration.rb +4 -4
  273. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +3 -4
  274. data/lib/datadog/tracing/contrib/ethon/patcher.rb +3 -3
  275. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +2 -2
  276. data/lib/datadog/tracing/contrib/excon/integration.rb +4 -4
  277. data/lib/datadog/tracing/contrib/excon/middleware.rb +6 -7
  278. data/lib/datadog/tracing/contrib/excon/patcher.rb +2 -2
  279. data/lib/datadog/tracing/contrib/extensions.rb +5 -3
  280. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +2 -2
  281. data/lib/datadog/tracing/contrib/faraday/integration.rb +4 -4
  282. data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -6
  283. data/lib/datadog/tracing/contrib/faraday/patcher.rb +5 -5
  284. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +3 -3
  285. data/lib/datadog/tracing/contrib/grape/endpoint.rb +4 -5
  286. data/lib/datadog/tracing/contrib/grape/integration.rb +3 -3
  287. data/lib/datadog/tracing/contrib/grape/patcher.rb +4 -4
  288. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +2 -2
  289. data/lib/datadog/tracing/contrib/graphql/integration.rb +3 -3
  290. data/lib/datadog/tracing/contrib/graphql/patcher.rb +2 -3
  291. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +4 -3
  292. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +14 -5
  293. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +6 -6
  294. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +7 -4
  295. data/lib/datadog/tracing/contrib/grpc/ext.rb +1 -0
  296. data/lib/datadog/tracing/contrib/grpc/integration.rb +3 -3
  297. data/lib/datadog/tracing/contrib/grpc/patcher.rb +5 -5
  298. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +1 -2
  299. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +2 -2
  300. data/lib/datadog/tracing/contrib/http/instrumentation.rb +3 -4
  301. data/lib/datadog/tracing/contrib/http/integration.rb +6 -6
  302. data/lib/datadog/tracing/contrib/http/patcher.rb +3 -3
  303. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +2 -2
  304. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +4 -5
  305. data/lib/datadog/tracing/contrib/httpclient/integration.rb +4 -4
  306. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +3 -3
  307. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +2 -2
  308. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +4 -5
  309. data/lib/datadog/tracing/contrib/httprb/integration.rb +4 -4
  310. data/lib/datadog/tracing/contrib/httprb/patcher.rb +3 -3
  311. data/lib/datadog/tracing/contrib/integration.rb +3 -3
  312. data/lib/datadog/tracing/contrib/kafka/configuration/settings.rb +2 -2
  313. data/lib/datadog/tracing/contrib/kafka/event.rb +3 -3
  314. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +2 -2
  315. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +3 -3
  316. data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +3 -3
  317. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +4 -4
  318. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/join_group.rb +4 -4
  319. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/leave_group.rb +4 -4
  320. data/lib/datadog/tracing/contrib/kafka/events/consumer_group/sync_group.rb +4 -4
  321. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +2 -2
  322. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +2 -2
  323. data/lib/datadog/tracing/contrib/kafka/events.rb +9 -9
  324. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -3
  325. data/lib/datadog/tracing/contrib/kafka/patcher.rb +3 -3
  326. data/lib/datadog/tracing/contrib/lograge/configuration/settings.rb +2 -2
  327. data/lib/datadog/tracing/contrib/lograge/instrumentation.rb +1 -2
  328. data/lib/datadog/tracing/contrib/lograge/integration.rb +3 -3
  329. data/lib/datadog/tracing/contrib/lograge/patcher.rb +2 -2
  330. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +2 -2
  331. data/lib/datadog/tracing/contrib/mongodb/instrumentation.rb +3 -3
  332. data/lib/datadog/tracing/contrib/mongodb/integration.rb +4 -4
  333. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -1
  334. data/lib/datadog/tracing/contrib/mongodb/patcher.rb +3 -3
  335. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +4 -4
  336. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +2 -2
  337. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +3 -4
  338. data/lib/datadog/tracing/contrib/mysql2/integration.rb +3 -3
  339. data/lib/datadog/tracing/contrib/mysql2/patcher.rb +2 -2
  340. data/lib/datadog/tracing/contrib/patcher.rb +13 -2
  341. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +35 -0
  342. data/lib/datadog/tracing/contrib/pg/ext.rb +31 -0
  343. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +128 -0
  344. data/lib/datadog/tracing/contrib/pg/integration.rb +43 -0
  345. data/lib/datadog/tracing/contrib/pg/patcher.rb +31 -0
  346. data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +2 -2
  347. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +2 -3
  348. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -3
  349. data/lib/datadog/tracing/contrib/presto/patcher.rb +4 -4
  350. data/lib/datadog/tracing/contrib/qless/configuration/settings.rb +2 -2
  351. data/lib/datadog/tracing/contrib/qless/integration.rb +3 -3
  352. data/lib/datadog/tracing/contrib/qless/patcher.rb +1 -2
  353. data/lib/datadog/tracing/contrib/qless/qless_job.rb +2 -3
  354. data/lib/datadog/tracing/contrib/qless/tracer_cleaner.rb +0 -2
  355. data/lib/datadog/tracing/contrib/que/configuration/settings.rb +3 -3
  356. data/lib/datadog/tracing/contrib/que/integration.rb +4 -4
  357. data/lib/datadog/tracing/contrib/que/patcher.rb +1 -1
  358. data/lib/datadog/tracing/contrib/que/tracer.rb +1 -1
  359. data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +2 -2
  360. data/lib/datadog/tracing/contrib/racecar/event.rb +4 -5
  361. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +2 -2
  362. data/lib/datadog/tracing/contrib/racecar/events/consume.rb +2 -2
  363. data/lib/datadog/tracing/contrib/racecar/events/message.rb +2 -2
  364. data/lib/datadog/tracing/contrib/racecar/events.rb +3 -3
  365. data/lib/datadog/tracing/contrib/racecar/integration.rb +3 -3
  366. data/lib/datadog/tracing/contrib/racecar/patcher.rb +3 -3
  367. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +2 -2
  368. data/lib/datadog/tracing/contrib/rack/integration.rb +4 -4
  369. data/lib/datadog/tracing/contrib/rack/middlewares.rb +24 -20
  370. data/lib/datadog/tracing/contrib/rack/patcher.rb +12 -2
  371. data/lib/datadog/tracing/contrib/rails/auto_instrument_railtie.rb +1 -1
  372. data/lib/datadog/tracing/contrib/rails/configuration/settings.rb +4 -1
  373. data/lib/datadog/tracing/contrib/rails/framework.rb +18 -22
  374. data/lib/datadog/tracing/contrib/rails/integration.rb +4 -4
  375. data/lib/datadog/tracing/contrib/rails/log_injection.rb +0 -2
  376. data/lib/datadog/tracing/contrib/rails/middlewares.rb +1 -2
  377. data/lib/datadog/tracing/contrib/rails/patcher.rb +7 -8
  378. data/lib/datadog/tracing/contrib/rails/railtie.rb +3 -3
  379. data/lib/datadog/tracing/contrib/rails/utils.rb +1 -1
  380. data/lib/datadog/tracing/contrib/rake/configuration/settings.rb +17 -2
  381. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +12 -7
  382. data/lib/datadog/tracing/contrib/rake/integration.rb +3 -3
  383. data/lib/datadog/tracing/contrib/rake/patcher.rb +3 -4
  384. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +1 -1
  385. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +2 -2
  386. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +6 -7
  387. data/lib/datadog/tracing/contrib/redis/integration.rb +3 -3
  388. data/lib/datadog/tracing/contrib/redis/patcher.rb +6 -6
  389. data/lib/datadog/tracing/contrib/redis/tags.rb +3 -4
  390. data/lib/datadog/tracing/contrib/resque/configuration/settings.rb +3 -3
  391. data/lib/datadog/tracing/contrib/resque/integration.rb +3 -3
  392. data/lib/datadog/tracing/contrib/resque/patcher.rb +2 -2
  393. data/lib/datadog/tracing/contrib/resque/resque_job.rb +3 -4
  394. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +3 -2
  395. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -3
  396. data/lib/datadog/tracing/contrib/rest_client/patcher.rb +2 -2
  397. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -6
  398. data/lib/datadog/tracing/contrib/semantic_logger/configuration/settings.rb +2 -2
  399. data/lib/datadog/tracing/contrib/semantic_logger/instrumentation.rb +1 -2
  400. data/lib/datadog/tracing/contrib/semantic_logger/integration.rb +3 -3
  401. data/lib/datadog/tracing/contrib/semantic_logger/patcher.rb +2 -2
  402. data/lib/datadog/tracing/contrib/sequel/configuration/settings.rb +2 -2
  403. data/lib/datadog/tracing/contrib/sequel/database.rb +4 -5
  404. data/lib/datadog/tracing/contrib/sequel/dataset.rb +4 -5
  405. data/lib/datadog/tracing/contrib/sequel/integration.rb +3 -3
  406. data/lib/datadog/tracing/contrib/sequel/patcher.rb +3 -3
  407. data/lib/datadog/tracing/contrib/sequel/utils.rb +2 -2
  408. data/lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb +3 -3
  409. data/lib/datadog/tracing/contrib/shoryuken/integration.rb +4 -4
  410. data/lib/datadog/tracing/contrib/shoryuken/patcher.rb +1 -1
  411. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +1 -1
  412. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +4 -5
  413. data/lib/datadog/tracing/contrib/sidekiq/configuration/settings.rb +3 -3
  414. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +6 -0
  415. data/lib/datadog/tracing/contrib/sidekiq/integration.rb +3 -3
  416. data/lib/datadog/tracing/contrib/sidekiq/patcher.rb +14 -7
  417. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/heartbeat.rb +19 -1
  418. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/{scheduled_push.rb → redis_info.rb} +5 -6
  419. data/lib/datadog/tracing/contrib/sidekiq/server_internal_tracer/scheduled_poller.rb +53 -0
  420. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -6
  421. data/lib/datadog/tracing/contrib/sidekiq/tracing.rb +2 -2
  422. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +2 -2
  423. data/lib/datadog/tracing/contrib/sinatra/env.rb +2 -2
  424. data/lib/datadog/tracing/contrib/sinatra/framework.rb +0 -2
  425. data/lib/datadog/tracing/contrib/sinatra/headers.rb +1 -1
  426. data/lib/datadog/tracing/contrib/sinatra/integration.rb +3 -3
  427. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +5 -5
  428. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +7 -8
  429. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +6 -7
  430. data/lib/datadog/tracing/contrib/sneakers/configuration/settings.rb +2 -2
  431. data/lib/datadog/tracing/contrib/sneakers/integration.rb +4 -4
  432. data/lib/datadog/tracing/contrib/sneakers/patcher.rb +2 -2
  433. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +2 -3
  434. data/lib/datadog/tracing/contrib/status_code_matcher.rb +2 -2
  435. data/lib/datadog/tracing/contrib/sucker_punch/configuration/settings.rb +2 -2
  436. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +3 -4
  437. data/lib/datadog/tracing/contrib/sucker_punch/integration.rb +3 -3
  438. data/lib/datadog/tracing/contrib/sucker_punch/patcher.rb +4 -5
  439. data/lib/datadog/tracing/contrib.rb +48 -47
  440. data/lib/datadog/tracing/correlation.rb +1 -1
  441. data/lib/datadog/tracing/distributed/headers/b3.rb +4 -4
  442. data/lib/datadog/tracing/distributed/headers/b3_single.rb +7 -7
  443. data/lib/datadog/tracing/distributed/headers/datadog.rb +3 -3
  444. data/lib/datadog/tracing/distributed/headers/parser.rb +37 -0
  445. data/lib/datadog/tracing/distributed/helpers.rb +36 -2
  446. data/lib/datadog/tracing/distributed/metadata/b3.rb +55 -0
  447. data/lib/datadog/tracing/distributed/metadata/b3_single.rb +66 -0
  448. data/lib/datadog/tracing/distributed/metadata/datadog.rb +73 -0
  449. data/lib/datadog/tracing/distributed/metadata/parser.rb +34 -0
  450. data/lib/datadog/tracing/event.rb +1 -1
  451. data/lib/datadog/tracing/metadata/analytics.rb +2 -2
  452. data/lib/datadog/tracing/metadata/errors.rb +2 -2
  453. data/lib/datadog/tracing/metadata/ext.rb +25 -0
  454. data/lib/datadog/tracing/metadata/tagging.rb +8 -2
  455. data/lib/datadog/tracing/metadata.rb +3 -3
  456. data/lib/datadog/tracing/pipeline/span_filter.rb +10 -6
  457. data/lib/datadog/tracing/pipeline.rb +3 -3
  458. data/lib/datadog/tracing/propagation/grpc.rb +68 -58
  459. data/lib/datadog/tracing/propagation/http.rb +8 -8
  460. data/lib/datadog/tracing/runtime/metrics.rb +1 -1
  461. data/lib/datadog/tracing/sampling/all_sampler.rb +1 -1
  462. data/lib/datadog/tracing/sampling/priority_sampler.rb +5 -5
  463. data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +2 -2
  464. data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +3 -3
  465. data/lib/datadog/tracing/sampling/rate_limiter.rb +1 -1
  466. data/lib/datadog/tracing/sampling/rate_sampler.rb +7 -7
  467. data/lib/datadog/tracing/sampling/rule.rb +3 -3
  468. data/lib/datadog/tracing/sampling/rule_sampler.rb +4 -4
  469. data/lib/datadog/tracing/sampling/span/matcher.rb +80 -0
  470. data/lib/datadog/tracing/span.rb +25 -5
  471. data/lib/datadog/tracing/span_operation.rb +10 -9
  472. data/lib/datadog/tracing/sync_writer.rb +5 -5
  473. data/lib/datadog/tracing/trace_operation.rb +16 -9
  474. data/lib/datadog/tracing/trace_segment.rb +5 -5
  475. data/lib/datadog/tracing/tracer.rb +15 -15
  476. data/lib/datadog/tracing/workers/trace_writer.rb +9 -9
  477. data/lib/datadog/tracing/workers.rb +3 -3
  478. data/lib/datadog/tracing/writer.rb +5 -5
  479. data/lib/datadog/tracing.rb +8 -8
  480. data/lib/ddtrace/auto_instrument.rb +9 -2
  481. data/lib/ddtrace/transport/ext.rb +7 -1
  482. data/lib/ddtrace/transport/http/adapters/net.rb +3 -2
  483. data/lib/ddtrace/transport/http/adapters/test.rb +1 -1
  484. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +2 -2
  485. data/lib/ddtrace/transport/http/api/map.rb +1 -1
  486. data/lib/ddtrace/transport/http/api.rb +4 -4
  487. data/lib/ddtrace/transport/http/builder.rb +5 -5
  488. data/lib/ddtrace/transport/http/client.rb +2 -2
  489. data/lib/ddtrace/transport/http/response.rb +1 -1
  490. data/lib/ddtrace/transport/http/statistics.rb +1 -1
  491. data/lib/ddtrace/transport/http/traces.rb +5 -5
  492. data/lib/ddtrace/transport/http.rb +12 -9
  493. data/lib/ddtrace/transport/io/client.rb +2 -2
  494. data/lib/ddtrace/transport/io/response.rb +1 -1
  495. data/lib/ddtrace/transport/io/traces.rb +3 -3
  496. data/lib/ddtrace/transport/io.rb +3 -3
  497. data/lib/ddtrace/transport/statistics.rb +2 -2
  498. data/lib/ddtrace/transport/trace_formatter.rb +5 -5
  499. data/lib/ddtrace/transport/traces.rb +5 -5
  500. data/lib/ddtrace/version.rb +1 -1
  501. data/lib/ddtrace.rb +6 -6
  502. metadata +57 -33
  503. data/.editorconfig +0 -22
  504. data/.gitignore +0 -58
  505. data/CONTRIBUTING.md +0 -81
  506. data/ddtrace.gemspec +0 -68
  507. data/docs/0.x-trace.png +0 -0
  508. data/docs/1.0-trace.png +0 -0
  509. data/docs/AutoInstrumentation.md +0 -36
  510. data/docs/Deprecation.md +0 -8
  511. data/docs/DevelopmentGuide.md +0 -259
  512. data/docs/GettingStarted.md +0 -2688
  513. data/docs/ProfilingDevelopment.md +0 -110
  514. data/docs/PublicApi.md +0 -14
  515. data/docs/UpgradeGuide.md +0 -736
  516. data/lib/datadog/profiling/recorder.rb +0 -117
  517. data/lib/datadog/profiling/transport/client.rb +0 -16
  518. data/lib/datadog/profiling/transport/io/client.rb +0 -29
  519. data/lib/datadog/profiling/transport/io/response.rb +0 -18
  520. data/lib/datadog/profiling/transport/io.rb +0 -32
  521. data/lib/datadog/profiling/transport/parcel.rb +0 -19
  522. data/lib/datadog/profiling/transport/request.rb +0 -17
  523. data/lib/datadog/profiling/transport/response.rb +0 -10
  524. data/lib/datadog/tracing/distributed/parser.rb +0 -70
@@ -0,0 +1,391 @@
1
+ #include <ruby.h>
2
+ #include <ruby/thread.h>
3
+ #include <ruby/thread_native.h>
4
+ #include <ruby/debug.h>
5
+ #include <stdbool.h>
6
+ #include <signal.h>
7
+ #include "helpers.h"
8
+ #include "ruby_helpers.h"
9
+ #include "collectors_cpu_and_wall_time.h"
10
+ #include "private_vm_api_access.h"
11
+
12
+ // Used to trigger the periodic execution of Collectors::CpuAndWallTime, which implements all of the sampling logic
13
+ // itself; this class only implements the "doing it periodically" part.
14
+ //
15
+ // This file implements the native bits of the Datadog::Profiling::Collectors::CpuAndWallTimeWorker class
16
+
17
+ // ---
18
+ // Here be dragons: This component is quite fiddly and probably one of the more complex in the profiler as it deals with
19
+ // multiple threads, signal handlers, global state, etc.
20
+ //
21
+ // ## Design notes for this class:
22
+ //
23
+ // ### Constraints
24
+ //
25
+ // Currently, sampling Ruby threads requires calling Ruby VM APIs that are only safe to call while holding on to the
26
+ // global VM lock (and are not async-signal safe -- cannot be called from a signal handler).
27
+ //
28
+ // @ivoanjo: As a note, I don't think we should think of this constraint as set in stone. Since can reach into the Ruby
29
+ // internals, we may be able to figure out a way of overcoming it. But it's definitely going to be hard so for now
30
+ // we're considering it as a given.
31
+ //
32
+ // ### Flow for triggering samples
33
+ //
34
+ // The flow for triggering samples is as follows:
35
+ //
36
+ // 1. Inside the `run_sampling_trigger_loop` function (running in the `CpuAndWallTimeWorker` background thread),
37
+ // a `SIGPROF` signal gets sent to the current process.
38
+ //
39
+ // 2. The `handle_sampling_signal` signal handler function gets called to handle the `SIGPROF` signal.
40
+ //
41
+ // Which thread the signal handler function gets called on by the operating system is quite important. We need to perform
42
+ // an operation -- calling the `rb_postponed_job_register_one` API -- that can only be called from the thread that
43
+ // is holding on to the global VM lock. So this is the thread we're "hoping" our signal lands on.
44
+ //
45
+ // The signal never lands on the `CpuAndWallTimeWorker` background thread because we explicitly block it off from that
46
+ // thread in `block_sigprof_signal_handler_from_running_in_current_thread`.
47
+ //
48
+ // If the signal lands on a thread that is not holding onto the global VM lock, we can't proceed to the next step,
49
+ // and we need to restart the sampling flow from step 1. (There's still quite a few improvements we can make here,
50
+ // but this is the current state of the implementation).
51
+ //
52
+ // 3. Inside `handle_sampling_signal`, if it's getting executed by the Ruby thread that is holding the global VM lock,
53
+ // we can call `rb_postponed_job_register_one` to ask the Ruby VM to call our `sample_from_postponed_job` function
54
+ // "as soon as it can".
55
+ //
56
+ // 4. The Ruby VM calls our `sample_from_postponed_job` from a thread holding the global VM lock. A sample is recorded by
57
+ // calling `cpu_and_wall_time_collector_sample`.
58
+ //
59
+ // ---
60
+
61
+ // Contains state for a single CpuAndWallTimeWorker instance
62
+ struct cpu_and_wall_time_worker_state {
63
+ // Important: This is not atomic nor is it guaranteed to replace memory barriers and the like. Aka this works for
64
+ // telling the sampling trigger loop to stop, but if we ever need to communicate more, we should move to actual
65
+ // atomic operations. stdatomic.h seems a nice thing to reach out for.
66
+ volatile bool should_run;
67
+
68
+ VALUE cpu_and_wall_time_collector_instance;
69
+ // When something goes wrong during sampling, we record the Ruby exception here, so that it can be "re-raised" on
70
+ // the CpuAndWallTimeWorker thread
71
+ VALUE failure_exception;
72
+ };
73
+
74
+ static VALUE _native_new(VALUE klass);
75
+ static VALUE _native_initialize(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE cpu_and_wall_time_collector_instance);
76
+ static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr);
77
+ static VALUE _native_sampling_loop(VALUE self, VALUE instance);
78
+ static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance);
79
+ static void install_sigprof_signal_handler(void (*signal_handler_function)(int, siginfo_t *, void *));
80
+ static void remove_sigprof_signal_handler(void);
81
+ static void block_sigprof_signal_handler_from_running_in_current_thread(void);
82
+ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext);
83
+ static void *run_sampling_trigger_loop(void *state_ptr);
84
+ static void interrupt_sampling_trigger_loop(void *state_ptr);
85
+ static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused);
86
+ static VALUE handle_sampling_failure(VALUE self_instance, VALUE exception);
87
+ static VALUE _native_current_sigprof_signal_handler(DDTRACE_UNUSED VALUE self);
88
+ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance);
89
+ static VALUE _native_is_running(DDTRACE_UNUSED VALUE self, VALUE instance);
90
+ static void testing_signal_handler(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext);
91
+ static VALUE _native_install_testing_signal_handler(DDTRACE_UNUSED VALUE self);
92
+ static VALUE _native_remove_testing_signal_handler(DDTRACE_UNUSED VALUE self);
93
+
94
+ // Global state -- be very careful when accessing or modifying it
95
+
96
+ // Note: Global state must only be mutated while holding the global VM lock (we piggy back on it to ensure correctness).
97
+ // The active_sampler_instance needs to be global because we access it from the signal handler.
98
+ static VALUE active_sampler_instance = Qnil;
99
+ // ...We also store active_sampler_owner_thread to be able to tell who the active_sampler_instance belongs to (and also
100
+ // to detect when it is outdated)
101
+ static VALUE active_sampler_owner_thread = Qnil;
102
+
103
+ void collectors_cpu_and_wall_time_worker_init(VALUE profiling_module) {
104
+ rb_global_variable(&active_sampler_instance);
105
+ rb_global_variable(&active_sampler_owner_thread);
106
+
107
+ VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
108
+ VALUE collectors_cpu_and_wall_time_worker_class = rb_define_class_under(collectors_module, "CpuAndWallTimeWorker", rb_cObject);
109
+ // Hosts methods used for testing the native code using RSpec
110
+ VALUE testing_module = rb_define_module_under(collectors_cpu_and_wall_time_worker_class, "Testing");
111
+
112
+ // Instances of the CpuAndWallTimeWorker class are "TypedData" objects.
113
+ // "TypedData" objects are special objects in the Ruby VM that can wrap C structs.
114
+ // In this case, it wraps the cpu_and_wall_time_worker_state.
115
+ //
116
+ // Because Ruby doesn't know how to initialize native-level structs, we MUST override the allocation function for objects
117
+ // of this class so that we can manage this part. Not overriding or disabling the allocation function is a common
118
+ // gotcha for "TypedData" objects that can very easily lead to VM crashes, see for instance
119
+ // https://bugs.ruby-lang.org/issues/18007 for a discussion around this.
120
+ rb_define_alloc_func(collectors_cpu_and_wall_time_worker_class, _native_new);
121
+
122
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_initialize", _native_initialize, 2);
123
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_sampling_loop", _native_sampling_loop, 1);
124
+ rb_define_singleton_method(collectors_cpu_and_wall_time_worker_class, "_native_stop", _native_stop, 1);
125
+ rb_define_singleton_method(testing_module, "_native_current_sigprof_signal_handler", _native_current_sigprof_signal_handler, 0);
126
+ rb_define_singleton_method(testing_module, "_native_is_running?", _native_is_running, 1);
127
+ rb_define_singleton_method(testing_module, "_native_install_testing_signal_handler", _native_install_testing_signal_handler, 0);
128
+ rb_define_singleton_method(testing_module, "_native_remove_testing_signal_handler", _native_remove_testing_signal_handler, 0);
129
+ }
130
+
131
+ // This structure is used to define a Ruby object that stores a pointer to a struct cpu_and_wall_time_worker_state
132
+ // See also https://github.com/ruby/ruby/blob/master/doc/extension.rdoc for how this works
133
+ static const rb_data_type_t cpu_and_wall_time_worker_typed_data = {
134
+ .wrap_struct_name = "Datadog::Profiling::Collectors::CpuAndWallTimeWorker",
135
+ .function = {
136
+ .dmark = cpu_and_wall_time_worker_typed_data_mark,
137
+ .dfree = RUBY_DEFAULT_FREE,
138
+ .dsize = NULL, // We don't track profile memory usage (although it'd be cool if we did!)
139
+ //.dcompact = NULL, // FIXME: Add support for compaction
140
+ },
141
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
142
+ };
143
+
144
+ static VALUE _native_new(VALUE klass) {
145
+ struct cpu_and_wall_time_worker_state *state = ruby_xcalloc(1, sizeof(struct cpu_and_wall_time_worker_state));
146
+
147
+ state->should_run = false;
148
+ state->cpu_and_wall_time_collector_instance = Qnil;
149
+ state->failure_exception = Qnil;
150
+
151
+ return TypedData_Wrap_Struct(klass, &cpu_and_wall_time_worker_typed_data, state);
152
+ }
153
+
154
+ static VALUE _native_initialize(DDTRACE_UNUSED VALUE _self, VALUE self_instance, VALUE cpu_and_wall_time_collector_instance) {
155
+ struct cpu_and_wall_time_worker_state *state;
156
+ TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
157
+
158
+ state->cpu_and_wall_time_collector_instance = enforce_cpu_and_wall_time_collector_instance(cpu_and_wall_time_collector_instance);
159
+
160
+ return Qtrue;
161
+ }
162
+
163
+ // Since our state contains references to Ruby objects, we need to tell the Ruby GC about them
164
+ static void cpu_and_wall_time_worker_typed_data_mark(void *state_ptr) {
165
+ struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr;
166
+
167
+ rb_gc_mark(state->cpu_and_wall_time_collector_instance);
168
+ rb_gc_mark(state->failure_exception);
169
+ }
170
+
171
+ // Called in a background thread created in CpuAndWallTimeWorker#start
172
+ static VALUE _native_sampling_loop(DDTRACE_UNUSED VALUE _self, VALUE instance) {
173
+ struct cpu_and_wall_time_worker_state *state;
174
+ TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
175
+
176
+ if (active_sampler_owner_thread != Qnil && is_thread_alive(active_sampler_owner_thread)) {
177
+ rb_raise(
178
+ rb_eRuntimeError,
179
+ "Could not start CpuAndWallTimeWorker: There's already another instance of CpuAndWallTimeWorker active in a different thread"
180
+ );
181
+ }
182
+
183
+ // This write to a global is thread-safe BECAUSE we're still holding on to the global VM lock at this point
184
+ active_sampler_instance = instance;
185
+ active_sampler_owner_thread = rb_thread_current();
186
+
187
+ state->should_run = true;
188
+
189
+ block_sigprof_signal_handler_from_running_in_current_thread(); // We want to interrupt the thread with the global VM lock, never this one
190
+
191
+ install_sigprof_signal_handler(handle_sampling_signal);
192
+
193
+ // Release GVL, get to the actual work!
194
+ int exception_state;
195
+ rb_protect(release_gvl_and_run_sampling_trigger_loop, instance, &exception_state);
196
+
197
+ // The sample trigger loop finished (either cleanly or with an error); let's clean up
198
+
199
+ remove_sigprof_signal_handler();
200
+ active_sampler_instance = Qnil;
201
+ active_sampler_owner_thread = Qnil;
202
+
203
+ // Ensure that instance is not garbage collected while the native sampling loop is running; this is probably not needed, but just in case
204
+ RB_GC_GUARD(instance);
205
+
206
+ if (exception_state) rb_jump_tag(exception_state); // Re-raise any exception that happened
207
+
208
+ return Qnil;
209
+ }
210
+
211
+ static VALUE _native_stop(DDTRACE_UNUSED VALUE _self, VALUE self_instance) {
212
+ struct cpu_and_wall_time_worker_state *state;
213
+ TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
214
+
215
+ state->should_run = false;
216
+
217
+ return Qtrue;
218
+ }
219
+
220
+ static void install_sigprof_signal_handler(void (*signal_handler_function)(int, siginfo_t *, void *)) {
221
+ struct sigaction existing_signal_handler_config = {.sa_sigaction = NULL};
222
+ struct sigaction signal_handler_config = {
223
+ .sa_flags = SA_RESTART | SA_SIGINFO,
224
+ .sa_sigaction = signal_handler_function
225
+ };
226
+ sigemptyset(&signal_handler_config.sa_mask);
227
+
228
+ if (sigaction(SIGPROF, &signal_handler_config, &existing_signal_handler_config) != 0) {
229
+ rb_sys_fail("Could not start CpuAndWallTimeWorker: Could not install signal handler");
230
+ }
231
+
232
+ // In some corner cases (e.g. after a fork), our signal handler may still be around, and that's ok
233
+ if (existing_signal_handler_config.sa_sigaction == handle_sampling_signal) return;
234
+
235
+ if (existing_signal_handler_config.sa_handler != NULL || existing_signal_handler_config.sa_sigaction != NULL) {
236
+ // A previous signal handler already existed. Currently we don't support this situation, so let's just back out
237
+ // of the installation.
238
+
239
+ if (sigaction(SIGPROF, &existing_signal_handler_config, NULL) != 0) {
240
+ rb_sys_fail(
241
+ "Could not start CpuAndWallTimeWorker: Could not re-install pre-existing SIGPROF signal handler. " \
242
+ "This may break the component had installed it."
243
+ );
244
+ }
245
+
246
+ rb_raise(rb_eRuntimeError, "Could not start CpuAndWallTimeWorker: There's a pre-existing SIGPROF signal handler");
247
+ }
248
+ }
249
+
250
+ static void remove_sigprof_signal_handler(void) {
251
+ struct sigaction signal_handler_config = {
252
+ .sa_handler = SIG_DFL, // Reset back to default
253
+ .sa_flags = SA_RESTART // TODO: Unclear if this is actually needed/does anything at all
254
+ };
255
+ sigemptyset(&signal_handler_config.sa_mask);
256
+
257
+ if (sigaction(SIGPROF, &signal_handler_config, NULL) != 0) rb_sys_fail("Failure while removing the signal handler");
258
+ }
259
+
260
+ static void block_sigprof_signal_handler_from_running_in_current_thread(void) {
261
+ sigset_t signals_to_block;
262
+ sigemptyset(&signals_to_block);
263
+ sigaddset(&signals_to_block, SIGPROF);
264
+ pthread_sigmask(SIG_BLOCK, &signals_to_block, NULL);
265
+ }
266
+
267
+ static void handle_sampling_signal(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) {
268
+ if (!ruby_thread_has_gvl_p()) {
269
+ return; // Not safe to enqueue a sample from this thread
270
+ }
271
+
272
+ // We implicitly assume there can be no concurrent nor nested calls to handle_sampling_signal because
273
+ // a) we get triggered using SIGPROF, and the docs state second SIGPROF will not interrupt an existing one
274
+ // b) we validate we are in the thread that has the global VM lock; if a different thread gets a signal, it will return early
275
+ // because it will not have the global VM lock
276
+ // TODO: Validate that this does not impact Ractors
277
+
278
+ // Note: rb_postponed_job_register_one ensures that if there's a previous sample_from_postponed_job queued for execution
279
+ // then we will not queue a second one. It does this by doing a linear scan on the existing jobs; in the future we
280
+ // may want to implement that check ourselves.
281
+
282
+ // TODO: Do something with result (potentially update tracking counters?)
283
+ /*int result =*/ rb_postponed_job_register_one(0, sample_from_postponed_job, NULL);
284
+ }
285
+
286
+ // The actual sampling trigger loop always runs **without** the global vm lock.
287
+ static void *run_sampling_trigger_loop(void *state_ptr) {
288
+ struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr;
289
+
290
+ struct timespec time_between_signals = {.tv_nsec = 10 * 1000 * 1000 /* 10ms */};
291
+
292
+ while (state->should_run) {
293
+ // TODO: This is still a placeholder for a more complex mechanism. In particular:
294
+ // * We want to signal a particular thread or threads, not the process in general
295
+ // * We want to track if a signal landed on the thread holding the global VM lock and do something about it
296
+ // * We want to do more than having a fixed sampling rate
297
+
298
+ kill(getpid(), SIGPROF);
299
+ nanosleep(&time_between_signals, NULL);
300
+ }
301
+
302
+ return NULL; // Unused
303
+ }
304
+
305
+ // This is called by the Ruby VM when it wants to shut down the background thread
306
+ static void interrupt_sampling_trigger_loop(void *state_ptr) {
307
+ struct cpu_and_wall_time_worker_state *state = (struct cpu_and_wall_time_worker_state *) state_ptr;
308
+
309
+ state->should_run = false;
310
+ }
311
+
312
+ static void sample_from_postponed_job(DDTRACE_UNUSED void *_unused) {
313
+ VALUE instance = active_sampler_instance; // Read from global variable
314
+
315
+ // This can potentially happen if the CpuAndWallTimeWorker was stopped while the postponed job was waiting to be executed; nothing to do
316
+ if (instance == Qnil) return;
317
+
318
+ struct cpu_and_wall_time_worker_state *state;
319
+ TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
320
+
321
+ // Trigger sampling using the Collectors::CpuAndWallTime; rescue against any exceptions that happen during sampling
322
+ VALUE (*function_to_call_safely)(VALUE) = cpu_and_wall_time_collector_sample;
323
+ VALUE function_to_call_safely_arg = state->cpu_and_wall_time_collector_instance;
324
+ VALUE (*exception_handler_function)(VALUE, VALUE) = handle_sampling_failure;
325
+ VALUE exception_handler_function_arg = instance;
326
+ rb_rescue2(
327
+ function_to_call_safely,
328
+ function_to_call_safely_arg,
329
+ exception_handler_function,
330
+ exception_handler_function_arg,
331
+ rb_eException, // rb_eException is the base class of all Ruby exceptions
332
+ 0 // Required by API to be the last argument
333
+ );
334
+ }
335
+
336
+ static VALUE handle_sampling_failure(VALUE self_instance, VALUE exception) {
337
+ struct cpu_and_wall_time_worker_state *state;
338
+ TypedData_Get_Struct(self_instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
339
+
340
+ state->should_run = false;
341
+ state->failure_exception = exception;
342
+
343
+ return Qnil;
344
+ }
345
+
346
+ static VALUE _native_current_sigprof_signal_handler(DDTRACE_UNUSED VALUE self) {
347
+ struct sigaction existing_signal_handler_config = {.sa_sigaction = NULL};
348
+ if (sigaction(SIGPROF, NULL, &existing_signal_handler_config) != 0) {
349
+ rb_sys_fail("Failed to probe existing handler");
350
+ }
351
+
352
+ if (existing_signal_handler_config.sa_sigaction == handle_sampling_signal) {
353
+ return ID2SYM(rb_intern("profiling"));
354
+ } else if (existing_signal_handler_config.sa_sigaction != NULL) {
355
+ return ID2SYM(rb_intern("other"));
356
+ } else {
357
+ return Qnil;
358
+ }
359
+ }
360
+
361
+ static VALUE release_gvl_and_run_sampling_trigger_loop(VALUE instance) {
362
+ struct cpu_and_wall_time_worker_state *state;
363
+ TypedData_Get_Struct(instance, struct cpu_and_wall_time_worker_state, &cpu_and_wall_time_worker_typed_data, state);
364
+
365
+ rb_thread_call_without_gvl(run_sampling_trigger_loop, state, interrupt_sampling_trigger_loop, state);
366
+
367
+ // If we stopped sampling due to an exception, re-raise it (now in the worker thread)
368
+ if (state->failure_exception != Qnil) rb_exc_raise(state->failure_exception);
369
+
370
+ return Qnil;
371
+ }
372
+
373
+ static VALUE _native_is_running(DDTRACE_UNUSED VALUE self, VALUE instance) {
374
+ return \
375
+ (active_sampler_owner_thread != Qnil && is_thread_alive(active_sampler_owner_thread) && active_sampler_instance == instance) ?
376
+ Qtrue : Qfalse;
377
+ }
378
+
379
+ static void testing_signal_handler(DDTRACE_UNUSED int _signal, DDTRACE_UNUSED siginfo_t *_info, DDTRACE_UNUSED void *_ucontext) {
380
+ /* Does nothing on purpose */
381
+ }
382
+
383
+ static VALUE _native_install_testing_signal_handler(DDTRACE_UNUSED VALUE self) {
384
+ install_sigprof_signal_handler(testing_signal_handler);
385
+ return Qtrue;
386
+ }
387
+
388
+ static VALUE _native_remove_testing_signal_handler(DDTRACE_UNUSED VALUE self) {
389
+ remove_sigprof_signal_handler();
390
+ return Qtrue;
391
+ }
@@ -1,9 +1,12 @@
1
1
  #include <ruby.h>
2
2
  #include <ruby/debug.h>
3
3
  #include "extconf.h"
4
- #include "libddprof_helpers.h"
4
+ #include "helpers.h"
5
+ #include "libdatadog_helpers.h"
6
+ #include "ruby_helpers.h"
5
7
  #include "private_vm_api_access.h"
6
8
  #include "stack_recorder.h"
9
+ #include "collectors_stack.h"
7
10
 
8
11
  // Gathers stack traces from running threads, storing them in a StackRecorder instance
9
12
  // This file implements the native bits of the Datadog::Profiling::Collectors::Stack class
@@ -14,37 +17,36 @@
14
17
  static VALUE missing_string = Qnil;
15
18
 
16
19
  // Used as scratch space during sampling
17
- typedef struct sampling_buffer {
20
+ struct sampling_buffer {
18
21
  unsigned int max_frames;
19
22
  VALUE *stack_buffer;
20
23
  int *lines_buffer;
21
24
  bool *is_ruby_frame;
22
25
  ddprof_ffi_Location *locations;
23
26
  ddprof_ffi_Line *lines;
24
- } sampling_buffer;
27
+ }; // Note: typedef'd in the header to sampling_buffer
25
28
 
26
29
  static VALUE _native_sample(VALUE self, VALUE thread, VALUE recorder_instance, VALUE metric_values_hash, VALUE labels_array, VALUE max_frames);
27
- void sample(VALUE thread, sampling_buffer* buffer, VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels);
28
- void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer* buffer, char *frames_omitted_message, int frames_omitted_message_size);
29
- void record_placeholder_stack_in_native_code(VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels);
30
- sampling_buffer *sampling_buffer_new(unsigned int max_frames);
31
- void sampling_buffer_free(sampling_buffer *buffer);
30
+ static void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer* buffer, char *frames_omitted_message, int frames_omitted_message_size);
31
+ static void record_placeholder_stack_in_native_code(VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels);
32
32
 
33
33
  void collectors_stack_init(VALUE profiling_module) {
34
34
  VALUE collectors_module = rb_define_module_under(profiling_module, "Collectors");
35
35
  VALUE collectors_stack_class = rb_define_class_under(collectors_module, "Stack", rb_cObject);
36
+ // Hosts methods used for testing the native code using RSpec
37
+ VALUE testing_module = rb_define_module_under(collectors_stack_class, "Testing");
36
38
 
37
- rb_define_singleton_method(collectors_stack_class, "_native_sample", _native_sample, 5);
39
+ rb_define_singleton_method(testing_module, "_native_sample", _native_sample, 5);
38
40
 
39
41
  missing_string = rb_str_new2("");
40
42
  rb_global_variable(&missing_string);
41
43
  }
42
44
 
43
- // This method exists only to enable testing Collectors::Stack behavior using RSpec.
45
+ // This method exists only to enable testing Datadog::Profiling::Collectors::Stack behavior using RSpec.
44
46
  // It SHOULD NOT be used for other purposes.
45
- static VALUE _native_sample(VALUE self, VALUE thread, VALUE recorder_instance, VALUE metric_values_hash, VALUE labels_array, VALUE max_frames) {
46
- Check_Type(metric_values_hash, T_HASH);
47
- Check_Type(labels_array, T_ARRAY);
47
+ static VALUE _native_sample(DDTRACE_UNUSED VALUE _self, VALUE thread, VALUE recorder_instance, VALUE metric_values_hash, VALUE labels_array, VALUE max_frames) {
48
+ ENFORCE_TYPE(metric_values_hash, T_HASH);
49
+ ENFORCE_TYPE(labels_array, T_ARRAY);
48
50
 
49
51
  if (RHASH_SIZE(metric_values_hash) != ENABLED_VALUE_TYPES_COUNT) {
50
52
  rb_raise(
@@ -78,7 +80,7 @@ static VALUE _native_sample(VALUE self, VALUE thread, VALUE recorder_instance, V
78
80
 
79
81
  sampling_buffer *buffer = sampling_buffer_new(max_frames_requested);
80
82
 
81
- sample(
83
+ sample_thread(
82
84
  thread,
83
85
  buffer,
84
86
  recorder_instance,
@@ -91,7 +93,7 @@ static VALUE _native_sample(VALUE self, VALUE thread, VALUE recorder_instance, V
91
93
  return Qtrue;
92
94
  }
93
95
 
94
- void sample(VALUE thread, sampling_buffer* buffer, VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels) {
96
+ void sample_thread(VALUE thread, sampling_buffer* buffer, VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels) {
95
97
  int captured_frames = ddtrace_rb_profile_frames(
96
98
  thread,
97
99
  0 /* stack starting depth */,
@@ -139,8 +141,8 @@ void sample(VALUE thread, sampling_buffer* buffer, VALUE recorder_instance, ddpr
139
141
  // **IMPORTANT**: Be very careful when calling any `rb_profile_frame_...` API with a non-Ruby frame, as legacy
140
142
  // Rubies may assume that what's in a buffer will lead to a Ruby frame.
141
143
  //
142
- // In particular for Ruby 2.2 and below the buffer contains a Ruby string (see the notes on our custom
143
- // rb_profile_frames for Ruby 2.2 and below) and CALLING **ANY** OF THOSE APIs ON IT WILL CAUSE INSTANT VM CRASHES
144
+ // In particular for Ruby 2.2 the buffer contains a Ruby string (see the notes on our custom
145
+ // rb_profile_frames for Ruby 2.2) and CALLING **ANY** OF THOSE APIs ON IT WILL CAUSE INSTANT VM CRASHES
144
146
 
145
147
  #ifndef USE_LEGACY_RB_PROFILE_FRAMES // Modern Rubies
146
148
  name = ddtrace_rb_profile_frame_method_name(buffer->stack_buffer[i]);
@@ -186,7 +188,7 @@ void sample(VALUE thread, sampling_buffer* buffer, VALUE recorder_instance, ddpr
186
188
  );
187
189
  }
188
190
 
189
- void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer* buffer, char *frames_omitted_message, int frames_omitted_message_size) {
191
+ static void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer* buffer, char *frames_omitted_message, int frames_omitted_message_size) {
190
192
  ptrdiff_t frames_omitted = stack_depth_for(thread) - buffer->max_frames;
191
193
 
192
194
  if (frames_omitted == 0) return; // Perfect fit!
@@ -228,7 +230,7 @@ void maybe_add_placeholder_frames_omitted(VALUE thread, sampling_buffer* buffer,
228
230
  //
229
231
  // To give customers visibility into these threads, rather than reporting an empty stack, we replace the empty stack
230
232
  // with one containing a placeholder frame, so that these threads are properly represented in the UX.
231
- void record_placeholder_stack_in_native_code(VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels) {
233
+ static void record_placeholder_stack_in_native_code(VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels) {
232
234
  ddprof_ffi_Line placeholder_stack_in_native_code_line = {
233
235
  .function = (ddprof_ffi_Function) {
234
236
  .name = DDPROF_FFI_CHARSLICE_C(""),
@@ -268,6 +270,8 @@ sampling_buffer *sampling_buffer_new(unsigned int max_frames) {
268
270
  }
269
271
 
270
272
  void sampling_buffer_free(sampling_buffer *buffer) {
273
+ if (buffer == NULL) rb_raise(rb_eArgError, "sampling_buffer_free called with NULL buffer");
274
+
271
275
  ruby_xfree(buffer->stack_buffer);
272
276
  ruby_xfree(buffer->lines_buffer);
273
277
  ruby_xfree(buffer->is_ruby_frame);
@@ -0,0 +1,9 @@
1
+ #pragma once
2
+
3
+ #include <ddprof/ffi.h>
4
+
5
+ typedef struct sampling_buffer sampling_buffer;
6
+
7
+ void sample_thread(VALUE thread, sampling_buffer* buffer, VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels);
8
+ sampling_buffer *sampling_buffer_new(unsigned int max_frames);
9
+ void sampling_buffer_free(sampling_buffer *buffer);
@@ -10,13 +10,31 @@ SKIPPED_REASON_FILE = "#{__dir__}/skipped_reason.txt".freeze
10
10
  File.delete(SKIPPED_REASON_FILE) rescue nil
11
11
 
12
12
  def skip_building_extension!(reason)
13
- $stderr.puts(Datadog::Profiling::NativeExtensionHelpers::Supported.failure_banner_for(**reason))
13
+ fail_install_if_missing_extension =
14
+ Datadog::Profiling::NativeExtensionHelpers.fail_install_if_missing_extension?
15
+
16
+ $stderr.puts(
17
+ Datadog::Profiling::NativeExtensionHelpers::Supported.failure_banner_for(
18
+ **reason,
19
+ fail_install: fail_install_if_missing_extension,
20
+ )
21
+ )
22
+
14
23
  File.write(
15
24
  SKIPPED_REASON_FILE,
16
25
  Datadog::Profiling::NativeExtensionHelpers::Supported.render_skipped_reason_file(**reason),
17
26
  )
18
27
 
19
- File.write('Makefile', 'all install clean: # dummy makefile that does nothing')
28
+ if fail_install_if_missing_extension
29
+ require 'mkmf'
30
+ Logging.message(
31
+ ' [ddtrace] Failure cause: ' \
32
+ "#{Datadog::Profiling::NativeExtensionHelpers::Supported.render_skipped_reason_file(**reason)}\n"
33
+ )
34
+ else
35
+ File.write('Makefile', 'all install clean: # dummy makefile that does nothing')
36
+ end
37
+
20
38
  exit
21
39
  end
22
40
 
@@ -24,7 +42,8 @@ unless Datadog::Profiling::NativeExtensionHelpers::Supported.supported?
24
42
  skip_building_extension!(Datadog::Profiling::NativeExtensionHelpers::Supported.unsupported_reason)
25
43
  end
26
44
 
27
- $stderr.puts(%(
45
+ $stderr.puts(
46
+ %(
28
47
  +------------------------------------------------------------------------------+
29
48
  | ** Preparing to build the ddtrace profiling native extension... ** |
30
49
  | |
@@ -41,7 +60,8 @@ $stderr.puts(%(
41
60
  | Thanks for using ddtrace! You rock! |
42
61
  +------------------------------------------------------------------------------+
43
62
 
44
- ))
63
+ )
64
+ )
45
65
 
46
66
  # NOTE: we MUST NOT require 'mkmf' before we check the #skip_building_extension? because the require triggers checks
47
67
  # that may fail on an environment not properly setup for building Ruby extensions.
@@ -73,6 +93,9 @@ add_compiler_flag '-Wno-declaration-after-statement'
73
93
  # cause a segfault later. Let's ensure that never happens.
74
94
  add_compiler_flag '-Werror-implicit-function-declaration'
75
95
 
96
+ # Warn on unused parameters to functions. Use `DDTRACE_UNUSED` to mark things as known-to-not-be-used.
97
+ add_compiler_flag '-Wunused-parameter'
98
+
76
99
  # The native extension is not intended to expose any symbols/functions for other native libraries to use;
77
100
  # the sole exception being `Init_ddtrace_profiling_native_extension` which needs to be visible for Ruby to call it when
78
101
  # it `dlopen`s the library.
@@ -81,17 +104,24 @@ add_compiler_flag '-Werror-implicit-function-declaration'
81
104
  # For more details see https://gcc.gnu.org/wiki/Visibility
82
105
  add_compiler_flag '-fvisibility=hidden'
83
106
 
107
+ # Enable all other compiler warnings
108
+ add_compiler_flag '-Wall'
109
+ add_compiler_flag '-Wextra'
110
+
84
111
  if RUBY_PLATFORM.include?('linux')
85
112
  # Supposedly, the correct way to do this is
86
113
  # ```
87
114
  # have_library 'pthread'
88
115
  # have_func 'pthread_getcpuclockid'
89
116
  # ```
90
- # but it broke the build on Windows and on older Ruby versions (2.1 and 2.2)
117
+ # but it broke the build on Windows and on older Ruby versions (2.2)
91
118
  # so instead we just assume that we have the function we need on Linux, and nowhere else
92
119
  $defs << '-DHAVE_PTHREAD_GETCPUCLOCKID'
93
120
  end
94
121
 
122
+ # On older Rubies, there was no struct rb_native_thread. See private_vm_api_acccess.c for details.
123
+ $defs << '-DNO_RB_NATIVE_THREAD' if RUBY_VERSION < '3.2'
124
+
95
125
  # On older Rubies, we need to use a backported version of this function. See private_vm_api_access.h for details.
96
126
  $defs << '-DUSE_BACKPORTED_RB_PROFILE_FRAME_METHOD_NAME' if RUBY_VERSION < '3'
97
127
 
@@ -112,14 +142,39 @@ if RUBY_VERSION < '2.3'
112
142
  $defs << '-DNO_RB_TIME_TIMESPEC_NEW'
113
143
  # ...the VM changed enough that we need an alternative legacy rb_profile_frames
114
144
  $defs << '-DUSE_LEGACY_RB_PROFILE_FRAMES'
145
+ # ... you couldn't name threads
146
+ $defs << '-DNO_THREAD_NAMES'
147
+ # ...the ruby_thread_has_gvl_p function was not exposed to users outside of the VM
148
+ $defs << '-DNO_THREAD_HAS_GVL'
115
149
  end
116
150
 
117
- # If we got here, libddprof is available and loaded
118
- ENV['PKG_CONFIG_PATH'] = "#{ENV['PKG_CONFIG_PATH']}:#{Libddprof.pkgconfig_folder}"
151
+ # If we got here, libdatadog is available and loaded
152
+ ENV['PKG_CONFIG_PATH'] = "#{ENV['PKG_CONFIG_PATH']}:#{Libdatadog.pkgconfig_folder}"
153
+ Logging.message(" [ddtrace] PKG_CONFIG_PATH set to #{ENV['PKG_CONFIG_PATH'].inspect}\n")
154
+
119
155
  unless pkg_config('ddprof_ffi_with_rpath')
120
- skip_building_extension!(Datadog::Profiling::NativeExtensionHelpers::Supported::FAILED_TO_CONFIGURE_LIBDDPROF)
156
+ skip_building_extension!(
157
+ if Datadog::Profiling::NativeExtensionHelpers::Supported.pkg_config_missing?
158
+ Datadog::Profiling::NativeExtensionHelpers::Supported::PKG_CONFIG_IS_MISSING
159
+ else
160
+ # Less specific error message
161
+ Datadog::Profiling::NativeExtensionHelpers::Supported::FAILED_TO_CONFIGURE_LIBDATADOG
162
+ end
163
+ )
121
164
  end
122
165
 
166
+ # See comments on the helper method being used for why we need to additionally set this.
167
+ # The extremely excessive escaping around ORIGIN below seems to be correct and was determined after a lot of
168
+ # experimentation. We need to get these special characters across a lot of tools untouched...
169
+ $LDFLAGS += \
170
+ ' -Wl,-rpath,$$$\\\\{ORIGIN\\}/' \
171
+ "#{Datadog::Profiling::NativeExtensionHelpers.libdatadog_folder_relative_to_native_lib_folder}"
172
+ Logging.message(" [ddtrace] After pkg-config $LDFLAGS were set to: #{$LDFLAGS.inspect}\n")
173
+
174
+ Logging.message(" [ddtrace] Using compiler:\n")
175
+ xsystem("#{CONFIG['CC']} --version")
176
+ Logging.message(" [ddtrace] End of compiler information\n")
177
+
123
178
  # Tag the native extension library with the Ruby version and Ruby platform.
124
179
  # This makes it easier for development (avoids "oops I forgot to rebuild when I switched my Ruby") and ensures that
125
180
  # the wrong library is never loaded.
@@ -153,13 +208,6 @@ else
153
208
  # This gem ships source code copies of these VM headers for the different Ruby VM versions;
154
209
  # see https://github.com/ruby-debug/debase-ruby_core_source for details
155
210
 
156
- thread_native_for_ruby_2_1 = proc { true }
157
- if RUBY_VERSION < '2.2'
158
- # This header became public in Ruby 2.2, but we need to pull it from the private headers folder for 2.1
159
- thread_native_for_ruby_2_1 = proc { have_header('thread_native.h') }
160
- $defs << '-DRUBY_2_1_WORKAROUND'
161
- end
162
-
163
211
  create_header
164
212
 
165
213
  require 'debase/ruby_core_source'
@@ -167,7 +215,7 @@ else
167
215
 
168
216
  Debase::RubyCoreSource
169
217
  .create_makefile_with_core(
170
- proc { have_header('vm_core.h') && have_header('iseq.h') && thread_native_for_ruby_2_1.call },
218
+ proc { have_header('vm_core.h') && have_header('iseq.h') },
171
219
  EXTENSION_NAME,
172
220
  )
173
221
  end