datadog 2.7.1 → 2.18.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 (441) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +353 -1
  3. data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +78 -102
  5. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
  7. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
  8. data/ext/datadog_profiling_native_extension/collectors_stack.c +235 -57
  9. data/ext/datadog_profiling_native_extension/collectors_stack.h +21 -5
  10. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +376 -156
  11. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
  12. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  13. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  14. data/ext/datadog_profiling_native_extension/encoded_profile.c +79 -0
  15. data/ext/datadog_profiling_native_extension/encoded_profile.h +8 -0
  16. data/ext/datadog_profiling_native_extension/extconf.rb +14 -8
  17. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
  18. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
  19. data/ext/datadog_profiling_native_extension/heap_recorder.c +295 -532
  20. data/ext/datadog_profiling_native_extension/heap_recorder.h +6 -8
  21. data/ext/datadog_profiling_native_extension/http_transport.c +64 -98
  22. data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +22 -0
  23. data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +8 -5
  24. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +69 -1
  25. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +16 -4
  26. data/ext/datadog_profiling_native_extension/profiling.c +19 -8
  27. data/ext/datadog_profiling_native_extension/ruby_helpers.c +9 -21
  28. data/ext/datadog_profiling_native_extension/ruby_helpers.h +2 -10
  29. data/ext/datadog_profiling_native_extension/stack_recorder.c +231 -181
  30. data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -2
  31. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
  32. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
  33. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
  34. data/ext/libdatadog_api/crashtracker.c +17 -15
  35. data/ext/libdatadog_api/crashtracker.h +5 -0
  36. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  37. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  38. data/ext/libdatadog_api/extconf.rb +2 -2
  39. data/ext/libdatadog_api/init.c +15 -0
  40. data/ext/libdatadog_api/library_config.c +164 -0
  41. data/ext/libdatadog_api/library_config.h +25 -0
  42. data/ext/libdatadog_api/macos_development.md +3 -3
  43. data/ext/libdatadog_api/process_discovery.c +112 -0
  44. data/ext/libdatadog_api/process_discovery.h +5 -0
  45. data/ext/libdatadog_extconf_helpers.rb +2 -2
  46. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
  47. data/lib/datadog/appsec/actions_handler.rb +49 -0
  48. data/lib/datadog/appsec/anonymizer.rb +16 -0
  49. data/lib/datadog/appsec/api_security/lru_cache.rb +56 -0
  50. data/lib/datadog/appsec/api_security/route_extractor.rb +65 -0
  51. data/lib/datadog/appsec/api_security/sampler.rb +59 -0
  52. data/lib/datadog/appsec/api_security.rb +23 -0
  53. data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
  54. data/lib/datadog/appsec/assets/waf_rules/recommended.json +623 -253
  55. data/lib/datadog/appsec/assets/waf_rules/strict.json +69 -107
  56. data/lib/datadog/appsec/autoload.rb +1 -1
  57. data/lib/datadog/appsec/component.rb +49 -65
  58. data/lib/datadog/appsec/compressed_json.rb +40 -0
  59. data/lib/datadog/appsec/configuration/settings.rb +212 -27
  60. data/lib/datadog/appsec/context.rb +74 -0
  61. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +92 -0
  62. data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
  63. data/lib/datadog/appsec/contrib/active_record/patcher.rb +101 -0
  64. data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
  65. data/lib/datadog/appsec/contrib/devise/configuration.rb +52 -0
  66. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +78 -0
  67. data/lib/datadog/appsec/contrib/devise/ext.rb +22 -0
  68. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -2
  69. data/lib/datadog/appsec/contrib/devise/patcher.rb +33 -25
  70. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
  71. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -0
  72. data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +3 -3
  73. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +106 -0
  74. data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
  75. data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
  76. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +42 -0
  77. data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
  78. data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
  79. data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
  80. data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
  81. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +41 -0
  82. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
  83. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +17 -30
  84. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  85. data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
  86. data/lib/datadog/appsec/contrib/rack/ext.rb +34 -0
  87. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
  88. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +78 -98
  89. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  90. data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
  91. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
  92. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +73 -78
  93. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +16 -33
  94. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  95. data/lib/datadog/appsec/contrib/rails/patcher.rb +25 -38
  96. data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
  97. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
  98. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +38 -0
  99. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +31 -68
  100. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  101. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -31
  102. data/lib/datadog/appsec/event.rb +96 -135
  103. data/lib/datadog/appsec/ext.rb +12 -3
  104. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +7 -2
  105. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
  106. data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
  107. data/lib/datadog/appsec/metrics/collector.rb +38 -0
  108. data/lib/datadog/appsec/metrics/exporter.rb +35 -0
  109. data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
  110. data/lib/datadog/appsec/metrics.rb +13 -0
  111. data/lib/datadog/appsec/monitor/gateway/watcher.rb +52 -32
  112. data/lib/datadog/appsec/processor/rule_loader.rb +30 -36
  113. data/lib/datadog/appsec/remote.rb +31 -57
  114. data/lib/datadog/appsec/response.rb +19 -85
  115. data/lib/datadog/appsec/security_engine/engine.rb +194 -0
  116. data/lib/datadog/appsec/security_engine/result.rb +67 -0
  117. data/lib/datadog/appsec/security_engine/runner.rb +87 -0
  118. data/lib/datadog/appsec/security_engine.rb +9 -0
  119. data/lib/datadog/appsec/security_event.rb +39 -0
  120. data/lib/datadog/appsec/utils.rb +0 -2
  121. data/lib/datadog/appsec.rb +22 -12
  122. data/lib/datadog/auto_instrument.rb +3 -0
  123. data/lib/datadog/core/buffer/random.rb +18 -2
  124. data/lib/datadog/core/configuration/agent_settings.rb +52 -0
  125. data/lib/datadog/core/configuration/agent_settings_resolver.rb +4 -18
  126. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  127. data/lib/datadog/core/configuration/components.rb +74 -32
  128. data/lib/datadog/core/configuration/components_state.rb +23 -0
  129. data/lib/datadog/core/configuration/ext.rb +5 -1
  130. data/lib/datadog/core/configuration/option.rb +81 -45
  131. data/lib/datadog/core/configuration/option_definition.rb +6 -4
  132. data/lib/datadog/core/configuration/options.rb +3 -3
  133. data/lib/datadog/core/configuration/settings.rb +121 -50
  134. data/lib/datadog/core/configuration/stable_config.rb +22 -0
  135. data/lib/datadog/core/configuration.rb +43 -11
  136. data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
  137. data/lib/datadog/core/crashtracking/component.rb +4 -13
  138. data/lib/datadog/core/crashtracking/tag_builder.rb +4 -22
  139. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  140. data/lib/datadog/core/encoding.rb +17 -1
  141. data/lib/datadog/core/environment/agent_info.rb +78 -0
  142. data/lib/datadog/core/environment/cgroup.rb +10 -12
  143. data/lib/datadog/core/environment/container.rb +38 -40
  144. data/lib/datadog/core/environment/ext.rb +6 -6
  145. data/lib/datadog/core/environment/git.rb +1 -0
  146. data/lib/datadog/core/environment/identity.rb +3 -3
  147. data/lib/datadog/core/environment/platform.rb +3 -3
  148. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  149. data/lib/datadog/core/error.rb +11 -9
  150. data/lib/datadog/core/logger.rb +2 -2
  151. data/lib/datadog/core/metrics/client.rb +27 -27
  152. data/lib/datadog/core/metrics/logging.rb +5 -5
  153. data/lib/datadog/core/process_discovery/tracer_memfd.rb +15 -0
  154. data/lib/datadog/core/process_discovery.rb +36 -0
  155. data/lib/datadog/core/rate_limiter.rb +4 -2
  156. data/lib/datadog/core/remote/client/capabilities.rb +6 -0
  157. data/lib/datadog/core/remote/client.rb +107 -92
  158. data/lib/datadog/core/remote/component.rb +18 -19
  159. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  160. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  161. data/lib/datadog/core/remote/configuration/repository.rb +14 -1
  162. data/lib/datadog/core/remote/negotiation.rb +9 -9
  163. data/lib/datadog/core/remote/transport/config.rb +4 -3
  164. data/lib/datadog/core/remote/transport/http/api.rb +13 -18
  165. data/lib/datadog/core/remote/transport/http/client.rb +5 -4
  166. data/lib/datadog/core/remote/transport/http/config.rb +27 -55
  167. data/lib/datadog/core/remote/transport/http/negotiation.rb +8 -51
  168. data/lib/datadog/core/remote/transport/http.rb +25 -94
  169. data/lib/datadog/core/remote/transport/negotiation.rb +17 -4
  170. data/lib/datadog/core/remote/worker.rb +10 -7
  171. data/lib/datadog/core/runtime/metrics.rb +12 -5
  172. data/lib/datadog/core/tag_builder.rb +56 -0
  173. data/lib/datadog/core/telemetry/component.rb +84 -49
  174. data/lib/datadog/core/telemetry/emitter.rb +23 -11
  175. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +66 -0
  176. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  177. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  178. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  179. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  180. data/lib/datadog/core/telemetry/event/app_started.rb +269 -0
  181. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  182. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  183. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  184. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  185. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  186. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  187. data/lib/datadog/core/telemetry/event.rb +17 -383
  188. data/lib/datadog/core/telemetry/ext.rb +1 -0
  189. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  190. data/lib/datadog/core/telemetry/logger.rb +5 -4
  191. data/lib/datadog/core/telemetry/logging.rb +12 -6
  192. data/lib/datadog/core/telemetry/metric.rb +28 -6
  193. data/lib/datadog/core/telemetry/request.rb +4 -4
  194. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  195. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  196. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  197. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  198. data/lib/datadog/core/telemetry/transport/telemetry.rb +51 -0
  199. data/lib/datadog/core/telemetry/worker.rb +128 -25
  200. data/lib/datadog/core/transport/http/adapters/net.rb +17 -2
  201. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  202. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
  203. data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +18 -1
  204. data/lib/datadog/core/transport/http/api/spec.rb +36 -0
  205. data/lib/datadog/{tracing → core}/transport/http/builder.rb +53 -31
  206. data/lib/datadog/core/transport/http/env.rb +8 -0
  207. data/lib/datadog/core/transport/http.rb +75 -0
  208. data/lib/datadog/core/transport/response.rb +4 -0
  209. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  210. data/lib/datadog/core/utils/duration.rb +32 -32
  211. data/lib/datadog/core/utils/forking.rb +2 -2
  212. data/lib/datadog/core/utils/network.rb +6 -6
  213. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  214. data/lib/datadog/core/utils/time.rb +20 -0
  215. data/lib/datadog/core/utils/truncation.rb +21 -0
  216. data/lib/datadog/core/utils.rb +7 -0
  217. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  218. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  219. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  220. data/lib/datadog/core/worker.rb +1 -1
  221. data/lib/datadog/core/workers/async.rb +29 -12
  222. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  223. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  224. data/lib/datadog/core.rb +8 -0
  225. data/lib/datadog/di/base.rb +115 -0
  226. data/lib/datadog/di/boot.rb +34 -0
  227. data/lib/datadog/di/code_tracker.rb +26 -15
  228. data/lib/datadog/di/component.rb +23 -14
  229. data/lib/datadog/di/configuration/settings.rb +25 -1
  230. data/lib/datadog/di/contrib/active_record.rb +1 -0
  231. data/lib/datadog/di/contrib/railtie.rb +15 -0
  232. data/lib/datadog/di/contrib.rb +28 -0
  233. data/lib/datadog/di/error.rb +5 -0
  234. data/lib/datadog/di/instrumenter.rb +162 -21
  235. data/lib/datadog/di/logger.rb +30 -0
  236. data/lib/datadog/di/preload.rb +18 -0
  237. data/lib/datadog/di/probe.rb +14 -7
  238. data/lib/datadog/di/probe_builder.rb +1 -0
  239. data/lib/datadog/di/probe_manager.rb +11 -5
  240. data/lib/datadog/di/probe_notification_builder.rb +54 -38
  241. data/lib/datadog/di/probe_notifier_worker.rb +60 -26
  242. data/lib/datadog/di/redactor.rb +0 -1
  243. data/lib/datadog/di/remote.rb +147 -0
  244. data/lib/datadog/di/serializer.rb +19 -8
  245. data/lib/datadog/di/transport/diagnostics.rb +62 -0
  246. data/lib/datadog/di/transport/http/api.rb +42 -0
  247. data/lib/datadog/di/transport/http/client.rb +47 -0
  248. data/lib/datadog/di/transport/http/diagnostics.rb +65 -0
  249. data/lib/datadog/di/transport/http/input.rb +77 -0
  250. data/lib/datadog/di/transport/http.rb +57 -0
  251. data/lib/datadog/di/transport/input.rb +70 -0
  252. data/lib/datadog/di/utils.rb +103 -0
  253. data/lib/datadog/di.rb +14 -76
  254. data/lib/datadog/error_tracking/collector.rb +87 -0
  255. data/lib/datadog/error_tracking/component.rb +167 -0
  256. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  257. data/lib/datadog/error_tracking/configuration.rb +11 -0
  258. data/lib/datadog/error_tracking/ext.rb +18 -0
  259. data/lib/datadog/error_tracking/extensions.rb +16 -0
  260. data/lib/datadog/error_tracking/filters.rb +77 -0
  261. data/lib/datadog/error_tracking.rb +18 -0
  262. data/lib/datadog/kit/appsec/events.rb +15 -3
  263. data/lib/datadog/kit/identity.rb +9 -5
  264. data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
  265. data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
  266. data/lib/datadog/opentelemetry/api/context.rb +16 -2
  267. data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
  268. data/lib/datadog/opentelemetry.rb +2 -1
  269. data/lib/datadog/profiling/collectors/code_provenance.rb +18 -9
  270. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -0
  271. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
  272. data/lib/datadog/profiling/collectors/info.rb +3 -0
  273. data/lib/datadog/profiling/collectors/thread_context.rb +17 -2
  274. data/lib/datadog/profiling/component.rb +64 -82
  275. data/lib/datadog/profiling/encoded_profile.rb +11 -0
  276. data/lib/datadog/profiling/exporter.rb +3 -4
  277. data/lib/datadog/profiling/ext.rb +0 -14
  278. data/lib/datadog/profiling/flush.rb +5 -8
  279. data/lib/datadog/profiling/http_transport.rb +8 -87
  280. data/lib/datadog/profiling/load_native_extension.rb +1 -33
  281. data/lib/datadog/profiling/profiler.rb +2 -0
  282. data/lib/datadog/profiling/scheduler.rb +10 -2
  283. data/lib/datadog/profiling/stack_recorder.rb +9 -9
  284. data/lib/datadog/profiling/tag_builder.rb +5 -41
  285. data/lib/datadog/profiling/tasks/setup.rb +2 -0
  286. data/lib/datadog/profiling.rb +6 -2
  287. data/lib/datadog/tracing/analytics.rb +1 -1
  288. data/lib/datadog/tracing/component.rb +16 -12
  289. data/lib/datadog/tracing/configuration/ext.rb +8 -1
  290. data/lib/datadog/tracing/configuration/settings.rb +22 -10
  291. data/lib/datadog/tracing/context_provider.rb +1 -1
  292. data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
  293. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
  294. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +15 -0
  295. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +19 -12
  296. data/lib/datadog/tracing/contrib/action_pack/ext.rb +2 -0
  297. data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
  298. data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
  299. data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
  300. data/lib/datadog/tracing/contrib/active_record/integration.rb +7 -3
  301. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +7 -2
  302. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +36 -1
  303. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  304. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +14 -4
  305. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
  306. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
  307. data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
  308. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  309. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
  310. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  311. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
  312. data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
  313. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
  314. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  315. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
  316. data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
  317. data/lib/datadog/tracing/contrib/ext.rb +1 -0
  318. data/lib/datadog/tracing/contrib/extensions.rb +29 -3
  319. data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
  320. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
  321. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
  322. data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
  323. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
  324. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
  325. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
  326. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
  327. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
  328. data/lib/datadog/tracing/contrib/http/instrumentation.rb +6 -10
  329. data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
  330. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -16
  331. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +7 -15
  332. data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
  333. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
  334. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +27 -0
  335. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +48 -0
  336. data/lib/datadog/tracing/contrib/karafka/ext.rb +27 -0
  337. data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
  338. data/lib/datadog/tracing/contrib/karafka/monitor.rb +66 -0
  339. data/lib/datadog/tracing/contrib/karafka/patcher.rb +71 -0
  340. data/lib/datadog/tracing/contrib/karafka.rb +37 -0
  341. data/lib/datadog/tracing/contrib/lograge/patcher.rb +4 -2
  342. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  343. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  344. data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
  345. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  346. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
  347. data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
  348. data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
  349. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
  350. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  351. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
  352. data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
  353. data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
  354. data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
  355. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  356. data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
  357. data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
  358. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
  359. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
  360. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
  361. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
  362. data/lib/datadog/tracing/contrib/sidekiq/ext.rb +1 -0
  363. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +5 -2
  364. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
  365. data/lib/datadog/tracing/contrib/support.rb +28 -0
  366. data/lib/datadog/tracing/contrib.rb +1 -0
  367. data/lib/datadog/tracing/correlation.rb +9 -2
  368. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  369. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  370. data/lib/datadog/tracing/distributed/baggage.rb +131 -0
  371. data/lib/datadog/tracing/distributed/datadog.rb +4 -2
  372. data/lib/datadog/tracing/distributed/propagation.rb +25 -4
  373. data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
  374. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  375. data/lib/datadog/tracing/metadata/ext.rb +5 -0
  376. data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
  377. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
  378. data/lib/datadog/tracing/metadata.rb +2 -0
  379. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  380. data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
  381. data/lib/datadog/tracing/span.rb +22 -5
  382. data/lib/datadog/tracing/span_event.rb +124 -4
  383. data/lib/datadog/tracing/span_operation.rb +52 -16
  384. data/lib/datadog/tracing/sync_writer.rb +10 -6
  385. data/lib/datadog/tracing/trace_digest.rb +9 -2
  386. data/lib/datadog/tracing/trace_operation.rb +55 -27
  387. data/lib/datadog/tracing/trace_segment.rb +6 -4
  388. data/lib/datadog/tracing/tracer.rb +66 -14
  389. data/lib/datadog/tracing/transport/http/api.rb +5 -4
  390. data/lib/datadog/tracing/transport/http/client.rb +5 -4
  391. data/lib/datadog/tracing/transport/http/traces.rb +13 -44
  392. data/lib/datadog/tracing/transport/http.rb +13 -70
  393. data/lib/datadog/tracing/transport/serializable_trace.rb +31 -7
  394. data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
  395. data/lib/datadog/tracing/transport/traces.rb +47 -13
  396. data/lib/datadog/tracing/utils.rb +1 -1
  397. data/lib/datadog/tracing/workers/trace_writer.rb +8 -5
  398. data/lib/datadog/tracing/workers.rb +5 -4
  399. data/lib/datadog/tracing/writer.rb +10 -6
  400. data/lib/datadog/tracing.rb +16 -3
  401. data/lib/datadog/version.rb +2 -2
  402. data/lib/datadog.rb +2 -0
  403. metadata +149 -54
  404. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
  405. data/ext/datadog_profiling_loader/extconf.rb +0 -60
  406. data/lib/datadog/appsec/assets/waf_rules/processors.json +0 -92
  407. data/lib/datadog/appsec/assets/waf_rules/scanners.json +0 -114
  408. data/lib/datadog/appsec/contrib/devise/event.rb +0 -57
  409. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -77
  410. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -54
  411. data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
  412. data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
  413. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
  414. data/lib/datadog/appsec/contrib/patcher.rb +0 -12
  415. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
  416. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
  417. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
  418. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
  419. data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
  420. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
  421. data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
  422. data/lib/datadog/appsec/processor/actions.rb +0 -49
  423. data/lib/datadog/appsec/processor/context.rb +0 -107
  424. data/lib/datadog/appsec/processor/rule_merger.rb +0 -170
  425. data/lib/datadog/appsec/processor.rb +0 -106
  426. data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
  427. data/lib/datadog/appsec/reactive/engine.rb +0 -47
  428. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  429. data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
  430. data/lib/datadog/appsec/scope.rb +0 -58
  431. data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
  432. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
  433. data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
  434. data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
  435. data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
  436. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  437. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  438. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  439. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
  440. data/lib/datadog/di/transport.rb +0 -81
  441. data/lib/datadog/tracing/transport/http/api/spec.rb +0 -19
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable Lint/AssignmentInCondition
3
+ require_relative '../core/utils/time'
4
4
 
5
- require 'benchmark'
5
+ # rubocop:disable Lint/AssignmentInCondition
6
6
 
7
7
  module Datadog
8
8
  module DI
@@ -52,6 +52,17 @@ module Datadog
52
52
  # (however, Probe instances can be replaced by OpenStruct instances
53
53
  # providing the same interface with not much effort).
54
54
  #
55
+ # Instrumenter (this class) is responsible for building snapshots.
56
+ # This is because to capture values on method entry, those values need to
57
+ # be duplicated or serialized into immutable values to prevent their
58
+ # modification by the instrumented method. Therefore this class must
59
+ # do at least some serialization/snapshot building and to keep the code
60
+ # well-encapsulated, all serialization/snapshot building should thus be
61
+ # initiated from this class rather than downstream code.
62
+ #
63
+ # As a consequence of Instrumenter building snapshots, it should not
64
+ # expose TracePoint objects to any downstream code.
65
+ #
55
66
  # @api private
56
67
  class Instrumenter
57
68
  def initialize(settings, serializer, logger, code_tracker: nil, telemetry: nil)
@@ -92,34 +103,90 @@ module Datadog
92
103
  cls = symbolize_class_name(probe.type_name)
93
104
  serializer = self.serializer
94
105
  method_name = probe.method_name
95
- target_method = cls.instance_method(method_name)
96
- loc = target_method.source_location
106
+ loc = begin
107
+ cls.instance_method(method_name).source_location
108
+ rescue NameError
109
+ # The target method is not defined.
110
+ # This could be because it will be explicitly defined later
111
+ # (since classes can be reopened in Ruby)
112
+ # or the method is virtual (provided by a method_missing handler).
113
+ # In these cases we do not have a source location for the
114
+ # target method here.
115
+ end
97
116
  rate_limiter = probe.rate_limiter
117
+ settings = self.settings
98
118
 
99
119
  mod = Module.new do
100
- define_method(method_name) do |*args, **kwargs| # steep:ignore
120
+ define_method(method_name) do |*args, **kwargs, &target_block| # steep:ignore
101
121
  if rate_limiter.nil? || rate_limiter.allow?
102
122
  # Arguments may be mutated by the method, therefore
103
123
  # they need to be serialized prior to method invocation.
104
124
  entry_args = if probe.capture_snapshot?
105
- serializer.serialize_args(args, kwargs)
125
+ instance_vars = Instrumenter.get_instance_variables(self)
126
+ serializer.serialize_args(args, kwargs, instance_vars,
127
+ depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
128
+ attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count)
106
129
  end
107
- rv = nil
108
- duration = Benchmark.realtime do # steep:ignore
109
- rv = super(*args, **kwargs)
130
+ start_time = Core::Utils::Time.get_time
131
+ # Under Ruby 2.6 we cannot just call super(*args, **kwargs)
132
+ # for methods defined via method_missing.
133
+ rv = if args.any?
134
+ if kwargs.any?
135
+ super(*args, **kwargs, &target_block)
136
+ else
137
+ super(*args, &target_block)
138
+ end
139
+ elsif kwargs.any?
140
+ super(**kwargs, &target_block)
141
+ else
142
+ super(&target_block)
110
143
  end
144
+ duration = Core::Utils::Time.get_time - start_time
111
145
  # The method itself is not part of the stack trace because
112
146
  # we are getting the stack trace from outside of the method.
113
147
  # Add the method in manually as the top frame.
114
- method_frame = Location.new(loc.first, loc.last, method_name)
115
- caller_locs = [method_frame] + caller_locations # steep:ignore
148
+ method_frame = if loc
149
+ [Location.new(loc.first, loc.last, method_name)]
150
+ else
151
+ # For virtual and lazily-defined methods, we do not have
152
+ # the original source location here, and they won't be
153
+ # included in the stack trace currently.
154
+ # TODO when begin/end trace points are added for local
155
+ # variable capture in method probes, we should be able
156
+ # to obtain actual method execution location and use
157
+ # that location here.
158
+ []
159
+ end
160
+ caller_locs = method_frame + caller_locations # steep:ignore
116
161
  # TODO capture arguments at exit
117
162
  # & is to stop steep complaints, block is always present here.
118
163
  block&.call(probe: probe, rv: rv, duration: duration, caller_locations: caller_locs,
164
+ instance_vars: probe.capture_snapshot? ? Instrumenter.get_instance_variables(self) : nil,
119
165
  serialized_entry_args: entry_args)
120
166
  rv
121
167
  else
122
- super(*args, **kwargs)
168
+ # stop standard from trying to mess up my code
169
+ _ = 42
170
+
171
+ # The necessity to invoke super in each of these specific
172
+ # ways is very difficult to test.
173
+ # Existing tests, even though I wrote many, still don't
174
+ # cause a failure if I replace all of the below with a
175
+ # simple super(*args, **kwargs, &target_block).
176
+ # But, let's be safe and go through the motions in case
177
+ # there is actually a legitimate need for the breakdown.
178
+ # TODO figure out how to test this properly.
179
+ if args.any?
180
+ if kwargs.any?
181
+ super(*args, **kwargs, &target_block)
182
+ else
183
+ super(*args, &target_block)
184
+ end
185
+ elsif kwargs.any?
186
+ super(**kwargs, &target_block)
187
+ else
188
+ super(&target_block)
189
+ end
123
190
  end
124
191
  end
125
192
  end
@@ -191,11 +258,12 @@ module Datadog
191
258
  #
192
259
  # If the requested file is not in code tracker's registry,
193
260
  # or the code tracker does not exist at all,
194
- # do not attempt to instrumnet now.
261
+ # do not attempt to instrument now.
195
262
  # The caller should add the line to the list of pending lines
196
263
  # to instrument and install the hook when the file in
197
264
  # question is loaded (and hopefully, by then code tracking
198
265
  # is active, otherwise the line will never be instrumented.)
266
+ raise_if_probe_in_loaded_features(probe)
199
267
  raise Error::DITargetNotDefined, "File not in code tracker registry: #{probe.file}"
200
268
  end
201
269
  end
@@ -203,6 +271,7 @@ module Datadog
203
271
  # Same as previous comment, if untargeted trace points are not
204
272
  # explicitly defined, and we do not have code tracking, do not
205
273
  # instrument the method.
274
+ raise_if_probe_in_loaded_features(probe)
206
275
  raise Error::DITargetNotDefined, "File not in code tracker registry: #{probe.file}"
207
276
  end
208
277
 
@@ -222,26 +291,51 @@ module Datadog
222
291
  # overhead of targeted trace points is minimal, don't worry about
223
292
  # this optimization just yet and create a trace point for each probe.
224
293
 
225
- tp = TracePoint.new(:line) do |tp|
294
+ types = if iseq
295
+ # When targeting trace points we can target the 'end' line of a method.
296
+ # However, by adding the :return trace point we lose diagnostics
297
+ # for lines that contain no executable code (e.g. comments only)
298
+ # and thus cannot actually be instrumented.
299
+ [:line, :return, :b_return]
300
+ else
301
+ [:line]
302
+ end
303
+ tp = TracePoint.new(*types) do |tp|
226
304
  begin
227
305
  # If trace point is not targeted, we must verify that the invocation
228
306
  # is the file & line that we want, because untargeted trace points
229
307
  # are invoked for *each* line of Ruby executed.
230
- if iseq || tp.lineno == probe.line_no && probe.file_matches?(tp.path)
308
+ # TODO find out exactly when the path in trace point is relative.
309
+ # Looks like this is the case when line trace point is not targeted?
310
+ if iseq || tp.lineno == probe.line_no && (
311
+ probe.file == tp.path || probe.file_matches?(tp.path)
312
+ )
231
313
  if rate_limiter.nil? || rate_limiter.allow?
314
+ locals = if probe.capture_snapshot?
315
+ serializer.serialize_vars(Instrumenter.get_local_variables(tp),
316
+ depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
317
+ attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count,)
318
+ end
319
+ instance_vars = if probe.capture_snapshot?
320
+ serializer.serialize_vars(Instrumenter.get_instance_variables(tp.self),
321
+ depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
322
+ attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count,)
323
+ end
232
324
  # & is to stop steep complaints, block is always present here.
233
- block&.call(probe: probe, trace_point: tp, caller_locations: caller_locations)
325
+ block&.call(probe: probe,
326
+ locals: locals, instance_vars: instance_vars,
327
+ path: tp.path, caller_locations: caller_locations)
234
328
  end
235
329
  end
236
330
  rescue => exc
237
331
  raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
238
- logger.warn("Unhandled exception in line trace point: #{exc.class}: #{exc}")
332
+ logger.debug { "di: unhandled exception in line trace point: #{exc.class}: #{exc}" }
239
333
  telemetry&.report(exc, description: "Unhandled exception in line trace point")
240
334
  # TODO test this path
241
335
  end
242
336
  rescue => exc
243
- raise if settings.dynamic_instrumentation.propagate_all_exceptions
244
- logger.warn("Unhandled exception in line trace point: #{exc.class}: #{exc}")
337
+ raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
338
+ logger.debug { "di: unhandled exception in line trace point: #{exc.class}: #{exc}" }
245
339
  telemetry&.report(exc, description: "Unhandled exception in line trace point")
246
340
  # TODO test this path
247
341
  end
@@ -266,7 +360,9 @@ module Datadog
266
360
  else
267
361
  tp.enable
268
362
  end
363
+ # TracePoint#enable returns false when it succeeds.
269
364
  end
365
+ true
270
366
  end
271
367
 
272
368
  def unhook_line(probe)
@@ -285,7 +381,7 @@ module Datadog
285
381
  hook_line(probe, &block)
286
382
  else
287
383
  # TODO add test coverage for this path
288
- logger.warn("Unknown probe type to hook: #{probe}")
384
+ logger.debug { "di: unknown probe type to hook: #{probe}" }
289
385
  end
290
386
  end
291
387
 
@@ -296,7 +392,32 @@ module Datadog
296
392
  unhook_line(probe)
297
393
  else
298
394
  # TODO add test coverage for this path
299
- logger.warn("Unknown probe type to unhook: #{probe}")
395
+ logger.debug { "di: unknown probe type to unhook: #{probe}" }
396
+ end
397
+ end
398
+
399
+ class << self
400
+ def get_instance_variables(object)
401
+ {}.tap do |hash|
402
+ object.instance_variables.each do |var|
403
+ hash[var] = object.instance_variable_get(var)
404
+ end
405
+ end
406
+ end
407
+
408
+ def get_local_variables(trace_point)
409
+ # binding appears to be constructed on access, therefore
410
+ # 1) we should attempt to cache it and
411
+ # 2) we should not call +binding+ until we actually need variable values.
412
+ binding = trace_point.binding
413
+
414
+ # steep hack - should never happen
415
+ return {} unless binding
416
+
417
+ binding.local_variables.each_with_object({}) do |name, map|
418
+ value = binding.local_variable_get(name)
419
+ map[name] = value
420
+ end
300
421
  end
301
422
  end
302
423
 
@@ -304,6 +425,26 @@ module Datadog
304
425
 
305
426
  attr_reader :lock
306
427
 
428
+ def raise_if_probe_in_loaded_features(probe)
429
+ return unless probe.file
430
+
431
+ # If the probe file is in the list of loaded files
432
+ # (as per $LOADED_FEATURES, using either exact or suffix match),
433
+ # raise an error indicating that
434
+ # code tracker is missing the loaded file because the file
435
+ # won't be loaded again (DI only works in production environments
436
+ # that do not normally reload code).
437
+ if $LOADED_FEATURES.include?(probe.file)
438
+ raise Error::DITargetNotInRegistry, "File loaded but is not in code tracker registry: #{probe.file}"
439
+ end
440
+ # Ths is an expensive check
441
+ $LOADED_FEATURES.each do |path|
442
+ if Utils.path_matches_suffix?(path, probe.file)
443
+ raise Error::DITargetNotInRegistry, "File matching probe path (#{probe.file}) was loaded and is not in code tracker registry: #{path}"
444
+ end
445
+ end
446
+ end
447
+
307
448
  # TODO test that this resolves qualified names e.g. A::B
308
449
  def symbolize_class_name(cls_name)
309
450
  Object.const_get(cls_name)
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Datadog
6
+ module DI
7
+ # Logger facade to add the +trace+ method.
8
+ #
9
+ # @api private
10
+ class Logger
11
+ extend Forwardable # steep:ignore
12
+
13
+ def initialize(settings, target)
14
+ @settings = settings
15
+ @target = target
16
+ end
17
+
18
+ attr_reader :settings
19
+ attr_reader :target
20
+
21
+ def_delegators :target, :debug # steep:ignore
22
+
23
+ def trace(&block)
24
+ if settings.dynamic_instrumentation.internal.trace_logging
25
+ debug(&block)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Require 'datadog/di/preload' early in the application boot process to
4
+ # enable dynamic instrumentation for third-party libraries used by the
5
+ # application.
6
+
7
+ require_relative 'base'
8
+
9
+ # Code tracking is required for line probes to work; see the comments
10
+ # on the activate_tracking methods in di.rb for further details.
11
+ #
12
+ # Unlike di.rb which conditionally activates tracking only if the
13
+ # DD_DYNAMIC_INSTRUMENTATION_ENABLED environment variable is set, this file
14
+ # always activates tracking. This is because this file is explicitly loaded
15
+ # by customer applications for the purpose of enabling code tracking
16
+ # early in application boot process (i.e., before datadog library itself
17
+ # is loaded).
18
+ Datadog::DI.activate_tracking
@@ -36,7 +36,9 @@ module Datadog
36
36
 
37
37
  def initialize(id:, type:,
38
38
  file: nil, line_no: nil, type_name: nil, method_name: nil,
39
- template: nil, capture_snapshot: false, max_capture_depth: nil, rate_limit: nil)
39
+ template: nil, capture_snapshot: false, max_capture_depth: nil,
40
+ max_capture_attribute_count: nil,
41
+ rate_limit: nil)
40
42
  # Perform some sanity checks here to detect unexpected attribute
41
43
  # combinations, in order to not do them in subsequent code.
42
44
  unless KNOWN_TYPES.include?(type)
@@ -64,6 +66,7 @@ module Datadog
64
66
  @template = template
65
67
  @capture_snapshot = !!capture_snapshot
66
68
  @max_capture_depth = max_capture_depth
69
+ @max_capture_attribute_count = max_capture_attribute_count
67
70
 
68
71
  # These checks use instance methods that have more complex logic
69
72
  # than checking a single argument value. To avoid duplicating
@@ -91,6 +94,10 @@ module Datadog
91
94
  # the global default will be used.
92
95
  attr_reader :max_capture_depth
93
96
 
97
+ # Configured maximum capture attribute count. Can be nil in which case
98
+ # the global default will be used.
99
+ attr_reader :max_capture_attribute_count
100
+
94
101
  # Rate limit in effect, in invocations per second. Always present.
95
102
  attr_reader :rate_limit
96
103
 
@@ -148,16 +155,16 @@ module Datadog
148
155
  # Returns whether the provided +path+ matches the user-designated
149
156
  # file (of a line probe).
150
157
  #
151
- # If file is an absolute path (i.e., it starts with a slash), the file
152
- # must be identical to path to match.
153
- #
154
- # If file is not an absolute path, the path matches if the file is its suffix,
155
- # at a path component boundary.
158
+ # Delegates to Utils.path_can_match_spec? which performs fuzzy
159
+ # matching. See the comments in utils.rb for details.
156
160
  def file_matches?(path)
161
+ if path.nil?
162
+ raise ArgumentError, "Cannot match against a nil path"
163
+ end
157
164
  unless file
158
165
  raise ArgumentError, "Probe does not have a file to match against"
159
166
  end
160
- Utils.path_matches_suffix?(path, file)
167
+ Utils.path_can_match_spec?(path, file)
161
168
  end
162
169
 
163
170
  # Instrumentation module for method probes.
@@ -37,6 +37,7 @@ module Datadog
37
37
  template: config["template"],
38
38
  capture_snapshot: !!config["captureSnapshot"],
39
39
  max_capture_depth: config["capture"]&.[]("maxReferenceDepth"),
40
+ max_capture_attribute_count: config["capture"]&.[]("maxFieldCount"),
40
41
  rate_limit: config["sampling"]&.[]("snapshotsPerSecond"),
41
42
  )
42
43
  rescue KeyError => exc
@@ -32,7 +32,7 @@ module Datadog
32
32
  install_pending_method_probes(tp.self)
33
33
  rescue => exc
34
34
  raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
35
- logger.warn("Unhandled exception in definition trace point: #{exc.class}: #{exc}")
35
+ logger.debug { "di: unhandled exception in definition trace point: #{exc.class}: #{exc}" }
36
36
  telemetry&.report(exc, description: "Unhandled exception in definition trace point")
37
37
  # TODO test this path
38
38
  end
@@ -111,16 +111,18 @@ module Datadog
111
111
  # Always remove from pending list here because it makes the
112
112
  # API smaller and shouldn't cause any actual problems.
113
113
  @pending_probes.delete(probe.id)
114
+ logger.trace { "di: installed #{probe.type} probe at #{probe.location} (#{probe.id})" }
114
115
  true
115
116
  rescue Error::DITargetNotDefined
116
117
  @pending_probes[probe.id] = probe
118
+ logger.trace { "di: could not install #{probe.type} probe at #{probe.location} (#{probe.id}) because its target is not defined, adding it to pending list" }
117
119
  false
118
120
  end
119
121
  rescue => exc
120
122
  # In "propagate all exceptions" mode we will try to instrument again.
121
123
  raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
122
124
 
123
- logger.warn("Error processing probe configuration: #{exc.class}: #{exc}")
125
+ logger.debug { "di: error processing probe configuration: #{exc.class}: #{exc}" }
124
126
  telemetry&.report(exc, description: "Error processing probe configuration")
125
127
  # TODO report probe as failed to agent since we won't attempt to
126
128
  # install it again.
@@ -160,8 +162,8 @@ module Datadog
160
162
  raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
161
163
  # Silence all exceptions?
162
164
  # TODO should we propagate here and rescue upstream?
163
- logger.warn("Error removing probe #{probe.id}: #{exc.class}: #{exc}")
164
- telemetry&.report(exc, description: "Error removing probe #{probe.id}")
165
+ logger.debug { "di: error removing #{probe.type} probe at #{probe.location} (#{probe.id}): #{exc.class}: #{exc}" }
166
+ telemetry&.report(exc, description: "Error removing probe")
165
167
  end
166
168
  end
167
169
  end
@@ -190,7 +192,7 @@ module Datadog
190
192
  rescue => exc
191
193
  raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
192
194
 
193
- logger.warn("Error installing probe after class is defined: #{exc.class}: #{exc}")
195
+ logger.debug { "di: error installing #{probe.type} probe at #{probe.location} (#{probe.id}) after class is defined: #{exc.class}: #{exc}" }
194
196
  telemetry&.report(exc, description: "Error installing probe after class is defined")
195
197
  end
196
198
  end
@@ -206,6 +208,9 @@ module Datadog
206
208
  # point, which is invoked for each required or loaded file
207
209
  # (and also for eval'd code, but those invocations are filtered out).
208
210
  def install_pending_line_probes(path)
211
+ if path.nil?
212
+ raise ArgumentError, "path must not be nil"
213
+ end
209
214
  @lock.synchronize do
210
215
  @pending_probes.values.each do |probe|
211
216
  if probe.line?
@@ -225,6 +230,7 @@ module Datadog
225
230
  # backend (once per the probe's lifetime) and a snapshot corresponding
226
231
  # to the current invocation.
227
232
  def probe_executed_callback(probe:, **opts)
233
+ logger.trace { "di: executed #{probe.type} probe at #{probe.location} (#{probe.id})" }
228
234
  unless probe.emitting_notified?
229
235
  payload = probe_notification_builder.build_emitting(probe)
230
236
  probe_notifier_worker.add_status(payload)
@@ -32,55 +32,72 @@ module Datadog
32
32
  status: 'EMITTING',)
33
33
  end
34
34
 
35
+ def build_errored(probe, exc)
36
+ build_status(probe,
37
+ message: "Instrumentation for probe #{probe.id} failed: #{exc}",
38
+ status: 'ERROR',)
39
+ end
40
+
35
41
  # Duration is in seconds.
42
+ # path is the actual path of the instrumented file.
36
43
  def build_executed(probe,
37
- trace_point: nil, rv: nil, duration: nil, caller_locations: nil,
38
- args: nil, kwargs: nil, serialized_entry_args: nil)
39
- snapshot = if probe.line? && probe.capture_snapshot?
40
- if trace_point.nil?
41
- raise "Cannot create snapshot because there is no trace point"
42
- end
43
- get_local_variables(trace_point)
44
- end
45
- # TODO check how many stack frames we should be keeping/sending,
46
- # this should be all frames for enriched probes and no frames for
47
- # non-enriched probes?
48
- build_snapshot(probe, rv: rv, snapshot: snapshot,
44
+ path: nil, rv: nil, duration: nil, caller_locations: nil,
45
+ locals: nil, args: nil, kwargs: nil, instance_vars: nil,
46
+ serialized_entry_args: nil)
47
+ build_snapshot(probe, rv: rv, locals: locals,
49
48
  # Actual path of the instrumented file.
50
- path: trace_point&.path,
51
- duration: duration, caller_locations: caller_locations, args: args, kwargs: kwargs,
49
+ path: path,
50
+ duration: duration,
51
+ # TODO check how many stack frames we should be keeping/sending,
52
+ # this should be all frames for enriched probes and no frames for
53
+ # non-enriched probes?
54
+ caller_locations: caller_locations,
55
+ args: args, kwargs: kwargs, instance_vars: instance_vars,
52
56
  serialized_entry_args: serialized_entry_args)
53
57
  end
54
58
 
55
- def build_snapshot(probe, rv: nil, snapshot: nil, path: nil,
56
- duration: nil, caller_locations: nil, args: nil, kwargs: nil,
59
+ def build_snapshot(probe, rv: nil, locals: nil, path: nil,
60
+ duration: nil, caller_locations: nil,
61
+ args: nil, kwargs: nil, instance_vars: nil,
57
62
  serialized_entry_args: nil)
58
63
  # TODO also verify that non-capturing probe does not pass
59
64
  # snapshot or vars/args into this method
60
65
  captures = if probe.capture_snapshot?
61
66
  if probe.method?
67
+ return_arguments = {
68
+ "@return": serializer.serialize_value(rv,
69
+ depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
70
+ attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count),
71
+ }
72
+ if instance_vars
73
+ return_arguments.update(
74
+ serializer.serialize_vars(instance_vars,
75
+ depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
76
+ attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count,)
77
+ )
78
+ end
62
79
  {
63
80
  entry: {
64
81
  # standard:disable all
65
82
  arguments: if serialized_entry_args
66
83
  serialized_entry_args
67
84
  else
68
- (args || kwargs) && serializer.serialize_args(args, kwargs)
85
+ (args || kwargs) && serializer.serialize_args(args, kwargs, instance_vars,
86
+ depth: probe.max_capture_depth || settings.dynamic_instrumentation.max_capture_depth,
87
+ attribute_count: probe.max_capture_attribute_count || settings.dynamic_instrumentation.max_capture_attribute_count)
69
88
  end,
70
89
  throwable: nil,
71
90
  # standard:enable all
72
91
  },
73
92
  return: {
74
- arguments: {
75
- "@return": serializer.serialize_value(rv),
76
- },
93
+ arguments: return_arguments,
77
94
  throwable: nil,
78
95
  },
79
96
  }
80
97
  elsif probe.line?
81
98
  {
82
- lines: snapshot && {
83
- probe.line_no => {locals: serializer.serialize_vars(snapshot)},
99
+ lines: locals && {
100
+ probe.line_no => {locals: locals.merge(instance_vars || {})},
84
101
  },
85
102
  }
86
103
  end
@@ -121,7 +138,7 @@ module Datadog
121
138
  },
122
139
  # In python tracer duration is under debugger.snapshot,
123
140
  # but UI appears to expect it here at top level.
124
- duration: duration ? (duration * 10**9).to_i : nil,
141
+ duration: duration ? (duration * 10**9).to_i : 0,
125
142
  host: nil,
126
143
  logger: {
127
144
  name: probe.file,
@@ -135,15 +152,17 @@ module Datadog
135
152
  version: 2,
136
153
  },
137
154
  # TODO add tests that the trace/span id is correctly propagated
138
- "dd.trace_id": Datadog::Tracing.active_trace&.id,
139
- "dd.span_id": Datadog::Tracing.active_span&.id,
155
+ "dd.trace_id": active_trace&.id&.to_s,
156
+ "dd.span_id": active_span&.id&.to_s,
140
157
  ddsource: 'dd_debugger',
141
158
  message: probe.template && evaluate_template(probe.template,
142
- duration: duration ? duration * 1000 : nil),
159
+ duration: duration ? duration * 1000 : 0),
143
160
  timestamp: timestamp,
144
161
  }
145
162
  end
146
163
 
164
+ private
165
+
147
166
  def build_status(probe, message:, status:)
148
167
  {
149
168
  service: settings.service,
@@ -177,21 +196,18 @@ module Datadog
177
196
  end
178
197
 
179
198
  def timestamp_now
180
- (Time.now.to_f * 1000).to_i
199
+ (Core::Utils::Time.now.to_f * 1000).to_i
181
200
  end
182
201
 
183
- def get_local_variables(trace_point)
184
- # binding appears to be constructed on access, therefore
185
- # 1) we should attempt to cache it and
186
- # 2) we should not call +binding+ until we actually need variable values.
187
- binding = trace_point.binding
188
-
189
- # steep hack - should never happen
190
- return {} unless binding
202
+ def active_trace
203
+ if defined?(Datadog::Tracing)
204
+ Datadog::Tracing.active_trace
205
+ end
206
+ end
191
207
 
192
- binding.local_variables.each_with_object({}) do |name, map|
193
- value = binding.local_variable_get(name)
194
- map[name] = value
208
+ def active_span
209
+ if defined?(Datadog::Tracing)
210
+ Datadog::Tracing.active_span
195
211
  end
196
212
  end
197
213
  end