dd-trace 5.52.0 → 5.54.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 (332) hide show
  1. package/LICENSE-3rdparty.csv +2 -1
  2. package/README.md +5 -0
  3. package/index.d.ts +87 -22
  4. package/initialize.mjs +3 -4
  5. package/package.json +36 -34
  6. package/packages/datadog-core/src/utils/src/get.js +1 -1
  7. package/packages/datadog-core/src/utils/src/has.js +1 -1
  8. package/packages/datadog-core/src/utils/src/kebabcase.js +4 -6
  9. package/packages/datadog-core/src/utils/src/parse-tags.js +1 -1
  10. package/packages/datadog-core/src/utils/src/pick.js +2 -2
  11. package/packages/datadog-core/src/utils/src/set.js +1 -1
  12. package/packages/datadog-core/src/utils/src/uniq.js +1 -1
  13. package/packages/datadog-instrumentations/src/amqp10.js +19 -17
  14. package/packages/datadog-instrumentations/src/amqplib.js +57 -37
  15. package/packages/datadog-instrumentations/src/apollo.js +2 -2
  16. package/packages/datadog-instrumentations/src/aws-sdk.js +1 -1
  17. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -4
  18. package/packages/datadog-instrumentations/src/child_process.js +3 -3
  19. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +92 -62
  20. package/packages/datadog-instrumentations/src/couchbase.js +5 -4
  21. package/packages/datadog-instrumentations/src/cucumber.js +126 -84
  22. package/packages/datadog-instrumentations/src/cypress.js +2 -1
  23. package/packages/datadog-instrumentations/src/dns.js +1 -1
  24. package/packages/datadog-instrumentations/src/express.js +2 -6
  25. package/packages/datadog-instrumentations/src/fs.js +7 -6
  26. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +28 -34
  27. package/packages/datadog-instrumentations/src/graphql.js +7 -10
  28. package/packages/datadog-instrumentations/src/grpc/client.js +11 -23
  29. package/packages/datadog-instrumentations/src/grpc/server.js +7 -20
  30. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +16 -10
  31. package/packages/datadog-instrumentations/src/helpers/hook.js +1 -1
  32. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -1
  33. package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -41
  34. package/packages/datadog-instrumentations/src/helpers/register.js +21 -18
  35. package/packages/datadog-instrumentations/src/http/client.js +16 -21
  36. package/packages/datadog-instrumentations/src/iovalkey.js +51 -0
  37. package/packages/datadog-instrumentations/src/jest.js +184 -87
  38. package/packages/datadog-instrumentations/src/kafkajs.js +65 -44
  39. package/packages/datadog-instrumentations/src/knex.js +4 -4
  40. package/packages/datadog-instrumentations/src/ldapjs.js +3 -4
  41. package/packages/datadog-instrumentations/src/mariadb.js +38 -61
  42. package/packages/datadog-instrumentations/src/mocha/main.js +85 -59
  43. package/packages/datadog-instrumentations/src/mocha/utils.js +103 -82
  44. package/packages/datadog-instrumentations/src/mocha/worker.js +6 -0
  45. package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
  46. package/packages/datadog-instrumentations/src/mysql.js +20 -36
  47. package/packages/datadog-instrumentations/src/mysql2.js +55 -47
  48. package/packages/datadog-instrumentations/src/net.js +4 -2
  49. package/packages/datadog-instrumentations/src/next.js +7 -14
  50. package/packages/datadog-instrumentations/src/nyc.js +1 -1
  51. package/packages/datadog-instrumentations/src/openai.js +21 -23
  52. package/packages/datadog-instrumentations/src/oracledb.js +1 -1
  53. package/packages/datadog-instrumentations/src/pg.js +6 -13
  54. package/packages/datadog-instrumentations/src/playwright.js +170 -136
  55. package/packages/datadog-instrumentations/src/redis.js +3 -3
  56. package/packages/datadog-instrumentations/src/restify.js +2 -2
  57. package/packages/datadog-instrumentations/src/rhea.js +42 -54
  58. package/packages/datadog-instrumentations/src/router.js +22 -25
  59. package/packages/datadog-instrumentations/src/tedious.js +1 -1
  60. package/packages/datadog-instrumentations/src/url.js +9 -17
  61. package/packages/datadog-instrumentations/src/vitest.js +126 -97
  62. package/packages/datadog-plugin-amqp10/src/consumer.js +7 -3
  63. package/packages/datadog-plugin-amqp10/src/producer.js +7 -3
  64. package/packages/datadog-plugin-amqplib/src/client.js +6 -2
  65. package/packages/datadog-plugin-amqplib/src/consumer.js +7 -3
  66. package/packages/datadog-plugin-amqplib/src/producer.js +7 -3
  67. package/packages/datadog-plugin-amqplib/src/util.js +1 -1
  68. package/packages/datadog-plugin-apollo/src/gateway/request.js +5 -6
  69. package/packages/datadog-plugin-apollo/src/gateway/validate.js +2 -3
  70. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -2
  71. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +2 -2
  72. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +13 -13
  73. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +24 -31
  74. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  75. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +6 -6
  76. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
  77. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -1
  78. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +4 -5
  79. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
  80. package/packages/datadog-plugin-aws-sdk/src/util.js +5 -6
  81. package/packages/datadog-plugin-cassandra-driver/src/index.js +1 -1
  82. package/packages/datadog-plugin-child_process/src/index.js +4 -4
  83. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +23 -23
  84. package/packages/datadog-plugin-cucumber/src/index.js +86 -20
  85. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +97 -27
  86. package/packages/datadog-plugin-cypress/src/plugin.js +11 -1
  87. package/packages/datadog-plugin-cypress/src/support.js +24 -5
  88. package/packages/datadog-plugin-express/src/code_origin.js +30 -0
  89. package/packages/datadog-plugin-express/src/index.js +10 -12
  90. package/packages/datadog-plugin-express/src/tracing.js +19 -0
  91. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +7 -3
  92. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +12 -7
  93. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +6 -2
  94. package/packages/datadog-plugin-google-cloud-vertexai/src/tracing.js +26 -9
  95. package/packages/datadog-plugin-graphql/src/execute.js +2 -2
  96. package/packages/datadog-plugin-graphql/src/index.js +7 -6
  97. package/packages/datadog-plugin-graphql/src/resolve.js +2 -2
  98. package/packages/datadog-plugin-graphql/src/tools/index.js +1 -0
  99. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -0
  100. package/packages/datadog-plugin-graphql/src/tools/transforms.js +1 -0
  101. package/packages/datadog-plugin-grpc/src/client.js +2 -2
  102. package/packages/datadog-plugin-grpc/src/util.js +2 -2
  103. package/packages/datadog-plugin-http/src/client.js +18 -7
  104. package/packages/datadog-plugin-http2/src/client.js +20 -20
  105. package/packages/datadog-plugin-iovalkey/src/index.js +18 -0
  106. package/packages/datadog-plugin-jest/src/index.js +36 -28
  107. package/packages/datadog-plugin-jest/src/util.js +8 -8
  108. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +3 -1
  109. package/packages/datadog-plugin-kafkajs/src/consumer.js +9 -5
  110. package/packages/datadog-plugin-kafkajs/src/producer.js +15 -7
  111. package/packages/datadog-plugin-kafkajs/src/utils.js +1 -1
  112. package/packages/datadog-plugin-langchain/src/handlers/chain.js +7 -7
  113. package/packages/datadog-plugin-langchain/src/handlers/embedding.js +2 -2
  114. package/packages/datadog-plugin-langchain/src/handlers/language_models/chat_model.js +6 -4
  115. package/packages/datadog-plugin-langchain/src/handlers/language_models/llm.js +5 -4
  116. package/packages/datadog-plugin-langchain/src/tracing.js +11 -10
  117. package/packages/datadog-plugin-mariadb/src/index.js +3 -9
  118. package/packages/datadog-plugin-mocha/src/index.js +88 -48
  119. package/packages/datadog-plugin-mongodb-core/src/index.js +1 -1
  120. package/packages/datadog-plugin-mysql/src/index.js +11 -9
  121. package/packages/datadog-plugin-mysql2/src/index.js +16 -0
  122. package/packages/datadog-plugin-net/src/tcp.js +1 -1
  123. package/packages/datadog-plugin-next/src/index.js +6 -5
  124. package/packages/datadog-plugin-openai/src/services.js +6 -10
  125. package/packages/datadog-plugin-openai/src/tracing.js +10 -14
  126. package/packages/datadog-plugin-oracledb/src/index.js +1 -1
  127. package/packages/datadog-plugin-playwright/src/index.js +48 -22
  128. package/packages/datadog-plugin-redis/src/index.js +9 -4
  129. package/packages/datadog-plugin-rhea/src/consumer.js +8 -6
  130. package/packages/datadog-plugin-rhea/src/producer.js +5 -2
  131. package/packages/datadog-plugin-router/src/index.js +1 -1
  132. package/packages/datadog-plugin-selenium/src/index.js +1 -6
  133. package/packages/datadog-plugin-vitest/src/index.js +99 -72
  134. package/packages/datadog-shimmer/src/shimmer.js +163 -36
  135. package/packages/dd-trace/src/appsec/api_security_sampler.js +2 -2
  136. package/packages/dd-trace/src/appsec/blocked_templates.js +1 -1
  137. package/packages/dd-trace/src/appsec/blocking.js +6 -20
  138. package/packages/dd-trace/src/appsec/graphql.js +2 -2
  139. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
  140. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +1 -1
  141. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +1 -1
  142. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +4 -6
  143. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +7 -12
  144. package/packages/dd-trace/src/appsec/iast/analyzers/missing-header-analyzer.js +4 -6
  145. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +4 -0
  146. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +9 -12
  147. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +5 -4
  148. package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +2 -3
  149. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +3 -3
  150. package/packages/dd-trace/src/appsec/iast/index.js +1 -0
  151. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +102 -7
  152. package/packages/dd-trace/src/appsec/iast/path-line.js +7 -8
  153. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +6 -13
  154. package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +6 -6
  155. package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +2 -2
  156. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +3 -3
  157. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +4 -28
  158. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -7
  159. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +3 -4
  160. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +1 -1
  161. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -7
  162. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -2
  163. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +6 -6
  164. package/packages/dd-trace/src/appsec/iast/telemetry/verbosity.js +1 -1
  165. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +1 -1
  166. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +1 -1
  167. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +7 -7
  168. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +23 -24
  169. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +3 -3
  170. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +4 -4
  171. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +6 -11
  172. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +9 -11
  173. package/packages/dd-trace/src/appsec/index.js +15 -12
  174. package/packages/dd-trace/src/appsec/rasp/index.js +19 -17
  175. package/packages/dd-trace/src/appsec/rasp/lfi.js +2 -1
  176. package/packages/dd-trace/src/appsec/rasp/utils.js +11 -6
  177. package/packages/dd-trace/src/appsec/reporter.js +233 -40
  178. package/packages/dd-trace/src/appsec/rule_manager.js +2 -2
  179. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +2 -2
  180. package/packages/dd-trace/src/appsec/stack_trace.js +2 -4
  181. package/packages/dd-trace/src/appsec/telemetry/index.js +1 -2
  182. package/packages/dd-trace/src/appsec/telemetry/rasp.js +3 -14
  183. package/packages/dd-trace/src/appsec/telemetry/waf.js +3 -5
  184. package/packages/dd-trace/src/appsec/user_tracking.js +3 -5
  185. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +8 -8
  186. package/packages/dd-trace/src/azure_metadata.js +2 -7
  187. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +1 -1
  188. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +2 -2
  189. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
  190. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +3 -3
  191. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  192. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  193. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
  194. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +6 -4
  195. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -2
  196. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +0 -2
  197. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
  198. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +1 -1
  199. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +8 -5
  200. package/packages/dd-trace/src/ci-visibility/telemetry.js +4 -0
  201. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
  202. package/packages/dd-trace/src/config.js +82 -51
  203. package/packages/dd-trace/src/config_stable.js +3 -3
  204. package/packages/dd-trace/src/datastreams/encoding.js +9 -9
  205. package/packages/dd-trace/src/datastreams/fnv.js +1 -1
  206. package/packages/dd-trace/src/datastreams/pathway.js +4 -4
  207. package/packages/dd-trace/src/datastreams/processor.js +5 -7
  208. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +1 -1
  209. package/packages/dd-trace/src/datastreams/schemas/schema_sampler.js +4 -6
  210. package/packages/dd-trace/src/datastreams/size.js +1 -1
  211. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +131 -72
  212. package/packages/dd-trace/src/debugger/devtools_client/condition.js +6 -8
  213. package/packages/dd-trace/src/debugger/devtools_client/defaults.js +1 -1
  214. package/packages/dd-trace/src/debugger/devtools_client/index.js +17 -27
  215. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +18 -38
  216. package/packages/dd-trace/src/debugger/devtools_client/send.js +8 -7
  217. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +16 -8
  218. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +8 -10
  219. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +3 -3
  220. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +2 -10
  221. package/packages/dd-trace/src/debugger/devtools_client/state.js +31 -4
  222. package/packages/dd-trace/src/dogstatsd.js +7 -4
  223. package/packages/dd-trace/src/encode/0.4.js +9 -9
  224. package/packages/dd-trace/src/encode/0.5.js +1 -1
  225. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +3 -3
  226. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +1 -1
  227. package/packages/dd-trace/src/encode/tags-processors.js +1 -1
  228. package/packages/dd-trace/src/exporter.js +6 -6
  229. package/packages/dd-trace/src/exporters/agent/writer.js +1 -5
  230. package/packages/dd-trace/src/exporters/common/docker.js +1 -1
  231. package/packages/dd-trace/src/exporters/common/form-data.js +6 -4
  232. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  233. package/packages/dd-trace/src/exporters/common/util.js +1 -1
  234. package/packages/dd-trace/src/external-logger/src/index.js +5 -5
  235. package/packages/dd-trace/src/flare/file.js +1 -5
  236. package/packages/dd-trace/src/format.js +1 -1
  237. package/packages/dd-trace/src/git_properties.js +1 -1
  238. package/packages/dd-trace/src/id.js +12 -6
  239. package/packages/dd-trace/src/iitm.js +10 -22
  240. package/packages/dd-trace/src/lambda/handler.js +6 -6
  241. package/packages/dd-trace/src/lambda/runtime/patch.js +4 -4
  242. package/packages/dd-trace/src/lambda/runtime/ritm.js +1 -1
  243. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +6 -6
  244. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +2 -6
  245. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +3 -3
  246. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +6 -6
  247. package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -1
  248. package/packages/dd-trace/src/llmobs/sdk.js +2 -2
  249. package/packages/dd-trace/src/llmobs/tagger.js +113 -99
  250. package/packages/dd-trace/src/llmobs/util.js +9 -9
  251. package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
  252. package/packages/dd-trace/src/llmobs/writers/util.js +1 -1
  253. package/packages/dd-trace/src/log/index.js +4 -4
  254. package/packages/dd-trace/src/log/log.js +1 -1
  255. package/packages/dd-trace/src/log/writer.js +2 -2
  256. package/packages/dd-trace/src/msgpack/chunk.js +3 -3
  257. package/packages/dd-trace/src/msgpack/encoder.js +28 -28
  258. package/packages/dd-trace/src/noop/dogstatsd.js +6 -6
  259. package/packages/dd-trace/src/noop/span.js +3 -5
  260. package/packages/dd-trace/src/noop/tracer.js +1 -2
  261. package/packages/dd-trace/src/opentelemetry/span_processor.js +2 -2
  262. package/packages/dd-trace/src/opentelemetry/tracer.js +6 -5
  263. package/packages/dd-trace/src/opentracing/propagation/log.js +6 -8
  264. package/packages/dd-trace/src/opentracing/propagation/text_map.js +27 -23
  265. package/packages/dd-trace/src/opentracing/propagation/tracestate.js +8 -4
  266. package/packages/dd-trace/src/opentracing/span.js +9 -14
  267. package/packages/dd-trace/src/opentracing/tracer.js +9 -6
  268. package/packages/dd-trace/src/payload-tagging/index.js +1 -1
  269. package/packages/dd-trace/src/payload-tagging/tagging.js +6 -6
  270. package/packages/dd-trace/src/pkg.js +1 -1
  271. package/packages/dd-trace/src/plugins/ci_plugin.js +62 -10
  272. package/packages/dd-trace/src/plugins/consumer.js +2 -2
  273. package/packages/dd-trace/src/plugins/inbound.js +5 -1
  274. package/packages/dd-trace/src/plugins/index.js +1 -1
  275. package/packages/dd-trace/src/plugins/outbound.js +4 -5
  276. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  277. package/packages/dd-trace/src/plugins/producer.js +2 -2
  278. package/packages/dd-trace/src/plugins/storage.js +2 -2
  279. package/packages/dd-trace/src/plugins/util/ci.js +23 -15
  280. package/packages/dd-trace/src/plugins/util/git.js +165 -11
  281. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +1 -1
  282. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
  283. package/packages/dd-trace/src/plugins/util/llm.js +27 -10
  284. package/packages/dd-trace/src/plugins/util/stacktrace.js +1 -1
  285. package/packages/dd-trace/src/plugins/util/test.js +311 -48
  286. package/packages/dd-trace/src/plugins/util/url.js +1 -1
  287. package/packages/dd-trace/src/plugins/util/urlfilter.js +13 -17
  288. package/packages/dd-trace/src/plugins/util/user-provided-git.js +12 -3
  289. package/packages/dd-trace/src/plugins/util/web.js +5 -4
  290. package/packages/dd-trace/src/priority_sampler.js +22 -22
  291. package/packages/dd-trace/src/profiling/config.js +44 -8
  292. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +5 -5
  293. package/packages/dd-trace/src/profiling/exporters/file.js +2 -1
  294. package/packages/dd-trace/src/profiling/profiler.js +37 -2
  295. package/packages/dd-trace/src/profiling/profilers/events.js +14 -17
  296. package/packages/dd-trace/src/profiling/profilers/shared.js +6 -1
  297. package/packages/dd-trace/src/profiling/profilers/space.js +3 -3
  298. package/packages/dd-trace/src/profiling/profilers/wall.js +6 -7
  299. package/packages/dd-trace/src/profiling/ssi-heuristics.js +3 -5
  300. package/packages/dd-trace/src/profiling/tagger.js +3 -5
  301. package/packages/dd-trace/src/profiling/webspan-utils.js +1 -1
  302. package/packages/dd-trace/src/proxy.js +7 -13
  303. package/packages/dd-trace/src/random_sampler.js +40 -0
  304. package/packages/dd-trace/src/rate_limiter.js +4 -4
  305. package/packages/dd-trace/src/remote_config/index.js +3 -7
  306. package/packages/dd-trace/src/remote_config/manager.js +25 -13
  307. package/packages/dd-trace/src/require-package-json.js +1 -1
  308. package/packages/dd-trace/src/ritm.js +4 -4
  309. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +2 -2
  310. package/packages/dd-trace/src/sampler.js +33 -4
  311. package/packages/dd-trace/src/sampling_rule.js +12 -3
  312. package/packages/dd-trace/src/scope.js +1 -1
  313. package/packages/dd-trace/src/serverless.js +0 -48
  314. package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
  315. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +8 -0
  316. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +2 -3
  317. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  318. package/packages/dd-trace/src/span_processor.js +3 -3
  319. package/packages/dd-trace/src/span_sampler.js +4 -1
  320. package/packages/dd-trace/src/standalone/tracesource.js +1 -1
  321. package/packages/dd-trace/src/startup-log.js +2 -2
  322. package/packages/dd-trace/src/telemetry/dependencies.js +4 -4
  323. package/packages/dd-trace/src/telemetry/logs/log-collector.js +9 -10
  324. package/packages/dd-trace/src/telemetry/metrics.js +10 -5
  325. package/packages/dd-trace/src/telemetry/send-data.js +1 -1
  326. package/packages/dd-trace/src/telemetry/telemetry.js +23 -24
  327. package/packages/dd-trace/src/util.js +1 -1
  328. package/version.js +1 -0
  329. package/packages/datadog-instrumentations/src/paperplane.js +0 -77
  330. package/packages/datadog-plugin-paperplane/src/index.js +0 -25
  331. package/packages/datadog-plugin-paperplane/src/logger.js +0 -11
  332. package/packages/datadog-plugin-paperplane/src/server.js +0 -24
@@ -103,10 +103,8 @@ class StatsBucket {
103
103
  forBacklog (backlogData) {
104
104
  const backlog = new Backlog(backlogData)
105
105
  const existingBacklog = this._backlogs.get(backlog.hash)
106
- if (existingBacklog !== undefined) {
107
- if (existingBacklog.offset > backlog.offset) {
108
- return existingBacklog
109
- }
106
+ if (existingBacklog !== undefined && existingBacklog.offset > backlog.offset) {
107
+ return existingBacklog
110
108
  }
111
109
  this._backlogs.set(backlog.hash, backlog)
112
110
  return backlog
@@ -205,7 +203,9 @@ class DataStreamsProcessor {
205
203
  let parentHash = ENTRY_PARENT_HASH
206
204
  let closestOppositeDirectionHash = ENTRY_PARENT_HASH
207
205
  let closestOppositeDirectionEdgeStart = nowNs
208
- if (ctx != null) {
206
+ if (ctx == null) {
207
+ log.debug(() => 'Setting DSM Checkpoint with empty parent context.')
208
+ } else {
209
209
  pathwayStartNs = ctx.pathwayStartNs
210
210
  edgeStartNs = ctx.edgeStartNs
211
211
  parentHash = ctx.hash
@@ -229,8 +229,6 @@ class DataStreamsProcessor {
229
229
  log.debug(
230
230
  () => `Setting DSM Checkpoint from extracted parent context with hash: ${parentHash} and edge tags: ${edgeTags}`
231
231
  )
232
- } else {
233
- log.debug(() => 'Setting DSM Checkpoint with empty parent context.')
234
232
  }
235
233
  const hash = computePathwayHash(this.service, this.env, edgeTags, parentHash)
236
234
  const edgeLatencyNs = nowNs - edgeStartNs
@@ -20,7 +20,7 @@ class SchemaBuilder {
20
20
  static getSchemaDefinition (schema) {
21
21
  const noNones = convertToJsonCompatible(schema)
22
22
  const definition = jsonStringify(noNones)
23
- const id = fnv64(Buffer.from(definition, 'utf-8')).toString()
23
+ const id = fnv64(Buffer.from(definition, 'utf8')).toString()
24
24
  return new Schema(definition, id)
25
25
  }
26
26
 
@@ -8,12 +8,10 @@ class SchemaSampler {
8
8
 
9
9
  trySample (currentTimeMs) {
10
10
  if (currentTimeMs >= this.lastSampleMs + SAMPLE_INTERVAL_MILLIS) {
11
- if (currentTimeMs >= this.lastSampleMs + SAMPLE_INTERVAL_MILLIS) {
12
- this.lastSampleMs = currentTimeMs
13
- const weight = this.weight
14
- this.weight = 0
15
- return weight
16
- }
11
+ this.lastSampleMs = currentTimeMs
12
+ const weight = this.weight
13
+ this.weight = 0
14
+ return weight
17
15
  }
18
16
  return 0
19
17
  }
@@ -4,7 +4,7 @@ const { types } = require('util')
4
4
 
5
5
  function getSizeOrZero (obj) {
6
6
  if (typeof obj === 'string') {
7
- return Buffer.from(obj, 'utf-8').length
7
+ return Buffer.from(obj, 'utf8').length
8
8
  }
9
9
  if (types.isArrayBuffer(obj)) {
10
10
  return obj.byteLength
@@ -1,30 +1,57 @@
1
1
  'use strict'
2
2
 
3
- const lock = require('mutexify/promise')()
3
+ const mutex = require('mutexify/promise')()
4
4
  const { getGeneratedPosition } = require('./source-maps')
5
5
  const session = require('./session')
6
6
  const { compile: compileCondition, compileSegments, templateRequiresEvaluation } = require('./condition')
7
7
  const { MAX_SNAPSHOTS_PER_SECOND_PER_PROBE, MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE } = require('./defaults')
8
- const { findScriptFromPartialPath, locationToBreakpoint, breakpointToProbes, probeToLocation } = require('./state')
8
+ const {
9
+ findScriptFromPartialPath,
10
+ clearState,
11
+ locationToBreakpoint,
12
+ breakpointToProbes,
13
+ probeToLocation
14
+ } = require('./state')
9
15
  const log = require('../../log')
10
16
 
11
17
  let sessionStarted = false
18
+ const probes = new Map()
19
+ let scriptLoadingStabilizedResolve
20
+ const scriptLoadingStabilized = new Promise((resolve) => { scriptLoadingStabilizedResolve = resolve })
21
+
22
+ // There's a race condition when a probe is first added, where the actual script that the probe is supposed to match
23
+ // hasn't been loaded yet. This will result in either the probe not being added at all, or an incorrect script being
24
+ // matched as the probe target.
25
+ //
26
+ // Therefore, once new scripts has been loaded, all probes are re-evaluated. If the matched `scriptId` has changed, we
27
+ // simply remove the old probe (if it was added to the wrong script) and apply it again.
28
+ session.on('scriptLoadingStabilized', () => {
29
+ log.debug('[debugger:devtools_client] Re-evaluating probes')
30
+ scriptLoadingStabilizedResolve()
31
+ for (const probe of probes.values()) {
32
+ reEvaluateProbe(probe).catch(err => {
33
+ log.error('[debugger:devtools_client] Error re-evaluating probe %s', probe.id, err)
34
+ })
35
+ }
36
+ })
12
37
 
13
38
  module.exports = {
14
- addBreakpoint,
15
- removeBreakpoint
39
+ addBreakpoint: lock(addBreakpoint),
40
+ removeBreakpoint: lock(removeBreakpoint),
41
+ modifyBreakpoint: lock(modifyBreakpoint)
16
42
  }
17
43
 
18
44
  async function addBreakpoint (probe) {
19
45
  if (!sessionStarted) await start()
20
46
 
47
+ probes.set(probe.id, probe)
48
+
21
49
  const file = probe.where.sourceFile
22
50
  let lineNumber = Number(probe.where.lines[0]) // Tracer doesn't support multiple-line breakpoints
23
51
  let columnNumber = 0 // Probes do not contain/support column information
24
52
 
25
53
  // Optimize for sending data to /debugger/v1/input endpoint
26
54
  probe.location = { file, lines: [String(lineNumber)] }
27
- delete probe.where
28
55
 
29
56
  // Optimize for fast calculations when probe is hit
30
57
  probe.templateRequiresEvaluation = templateRequiresEvaluation(probe.segments)
@@ -47,6 +74,8 @@ async function addBreakpoint (probe) {
47
74
  if (!script) throw new Error(`No loaded script found for ${file} (probe: ${probe.id}, version: ${probe.version})`)
48
75
  const { url, scriptId, sourceMapURL, source } = script
49
76
 
77
+ probe.scriptId = scriptId // Needed for detecting script changes during re-evaluation
78
+
50
79
  if (sourceMapURL) {
51
80
  log.debug(
52
81
  '[debugger:devtools_client] Translating location using source map for %s:%d:%d (probe: %s, version: %d)',
@@ -61,87 +90,84 @@ async function addBreakpoint (probe) {
61
90
  throw new Error(`Cannot compile expression: ${probe.when.dsl}`, { cause: err })
62
91
  }
63
92
 
64
- const release = await lock()
93
+ const locationKey = generateLocationKey(scriptId, lineNumber, columnNumber)
94
+ const breakpoint = locationToBreakpoint.get(locationKey)
65
95
 
66
- try {
67
- const locationKey = generateLocationKey(scriptId, lineNumber, columnNumber)
68
- const breakpoint = locationToBreakpoint.get(locationKey)
96
+ log.debug(
97
+ '[debugger:devtools_client] %s breakpoint at %s:%d:%d (probe: %s, version: %d)',
98
+ breakpoint ? 'Updating' : 'Adding', url, lineNumber, columnNumber, probe.id, probe.version
99
+ )
69
100
 
70
- log.debug(
71
- '[debugger:devtools_client] %s breakpoint at %s:%d:%d (probe: %s, version: %d)',
72
- breakpoint ? 'Updating' : 'Adding', url, lineNumber, columnNumber, probe.id, probe.version
73
- )
74
-
75
- if (breakpoint) {
76
- // A breakpoint already exists at this location, so we need to add the probe to the existing breakpoint
77
- await updateBreakpoint(breakpoint, probe)
78
- } else {
79
- // No breakpoint exists at this location, so we need to create a new one
80
- const location = {
81
- scriptId,
82
- lineNumber: lineNumber - 1, // Beware! lineNumber is zero-indexed
83
- columnNumber
84
- }
85
- let result
86
- try {
87
- result = await session.post('Debugger.setBreakpoint', {
88
- location,
89
- condition: probe.condition
90
- })
91
- } catch (err) {
92
- throw new Error(`Error setting breakpoint for probe ${probe.id}`, { cause: err })
93
- }
94
- probeToLocation.set(probe.id, locationKey)
95
- locationToBreakpoint.set(locationKey, { id: result.breakpointId, location, locationKey })
96
- breakpointToProbes.set(result.breakpointId, new Map([[probe.id, probe]]))
101
+ if (breakpoint) {
102
+ // A breakpoint already exists at this location, so we need to add the probe to the existing breakpoint
103
+ await updateBreakpointInternal(breakpoint, probe)
104
+ } else {
105
+ // No breakpoint exists at this location, so we need to create a new one
106
+ const location = {
107
+ scriptId,
108
+ lineNumber: lineNumber - 1, // Beware! lineNumber is zero-indexed
109
+ columnNumber
110
+ }
111
+ let result
112
+ try {
113
+ result = await session.post('Debugger.setBreakpoint', {
114
+ location,
115
+ condition: probe.condition
116
+ })
117
+ } catch (err) {
118
+ throw new Error(`Error setting breakpoint for probe ${probe.id}`, { cause: err })
97
119
  }
98
- } finally {
99
- release()
120
+ probeToLocation.set(probe.id, locationKey)
121
+ locationToBreakpoint.set(locationKey, { id: result.breakpointId, location, locationKey })
122
+ breakpointToProbes.set(result.breakpointId, new Map([[probe.id, probe]]))
100
123
  }
101
124
  }
102
125
 
103
126
  async function removeBreakpoint ({ id }) {
104
127
  if (!sessionStarted) {
105
128
  // We should not get in this state, but abort if we do, so the code doesn't fail unexpected
106
- throw Error(`Cannot remove probe ${id}: Debugger not started`)
129
+ throw new Error(`Cannot remove probe ${id}: Debugger not started`)
107
130
  }
108
131
  if (!probeToLocation.has(id)) {
109
- throw Error(`Unknown probe id: ${id}`)
132
+ throw new Error(`Unknown probe id: ${id}`)
110
133
  }
111
134
 
112
- const release = await lock()
135
+ probes.delete(id)
113
136
 
114
- try {
115
- const locationKey = probeToLocation.get(id)
116
- const breakpoint = locationToBreakpoint.get(locationKey)
117
- const probesAtLocation = breakpointToProbes.get(breakpoint.id)
118
-
119
- probesAtLocation.delete(id)
120
- probeToLocation.delete(id)
121
-
122
- if (probesAtLocation.size === 0) {
123
- locationToBreakpoint.delete(locationKey)
124
- breakpointToProbes.delete(breakpoint.id)
125
- if (breakpointToProbes.size === 0) {
126
- await stop() // TODO: Will this actually delete the breakpoint?
127
- } else {
128
- try {
129
- await session.post('Debugger.removeBreakpoint', { breakpointId: breakpoint.id })
130
- } catch (err) {
131
- throw new Error(`Error removing breakpoint for probe ${id}`, { cause: err })
132
- }
133
- }
137
+ const locationKey = probeToLocation.get(id)
138
+ const breakpoint = locationToBreakpoint.get(locationKey)
139
+ const probesAtLocation = breakpointToProbes.get(breakpoint.id)
140
+
141
+ probesAtLocation.delete(id)
142
+ probeToLocation.delete(id)
143
+
144
+ if (probesAtLocation.size === 0) {
145
+ locationToBreakpoint.delete(locationKey)
146
+ breakpointToProbes.delete(breakpoint.id)
147
+ // TODO: If anything below in this if-block throws, the state is out of sync.
148
+ if (breakpointToProbes.size === 0) {
149
+ await stop() // This will also remove the breakpoint
134
150
  } else {
135
- await updateBreakpoint(breakpoint)
151
+ try {
152
+ await session.post('Debugger.removeBreakpoint', { breakpointId: breakpoint.id })
153
+ } catch (err) {
154
+ throw new Error(`Error removing breakpoint for probe ${id}`, { cause: err })
155
+ }
136
156
  }
137
- } finally {
138
- release()
157
+ } else {
158
+ await updateBreakpointInternal(breakpoint)
139
159
  }
140
160
  }
141
161
 
142
- async function updateBreakpoint (breakpoint, probe) {
162
+ // TODO: Modify existing probe instead of removing it (DEBUG-2817)
163
+ async function modifyBreakpoint (probe) {
164
+ await removeBreakpoint(probe)
165
+ await addBreakpoint(probe)
166
+ }
167
+
168
+ async function updateBreakpointInternal (breakpoint, probe) {
143
169
  const probesAtLocation = breakpointToProbes.get(breakpoint.id)
144
- const conditionBeforeNewProbe = compileCompoundCondition(Array.from(probesAtLocation.values()))
170
+ const conditionBeforeNewProbe = compileCompoundCondition([...probesAtLocation.values()])
145
171
 
146
172
  // If a probe is provided, add it to the breakpoint. If not, it's because we're removing a probe, but potentially
147
173
  // need to update the condtion of the breakpoint.
@@ -150,7 +176,7 @@ async function updateBreakpoint (breakpoint, probe) {
150
176
  probeToLocation.set(probe.id, breakpoint.locationKey)
151
177
  }
152
178
 
153
- const condition = compileCompoundCondition(Array.from(probesAtLocation.values()))
179
+ const condition = compileCompoundCondition([...probesAtLocation.values()])
154
180
 
155
181
  if (condition || conditionBeforeNewProbe !== condition) {
156
182
  try {
@@ -173,25 +199,58 @@ async function updateBreakpoint (breakpoint, probe) {
173
199
  }
174
200
  }
175
201
 
176
- function start () {
202
+ async function reEvaluateProbe (probe) {
203
+ const script = findScriptFromPartialPath(probe.where.sourceFile)
204
+ log.debug('[debugger:devtools_client] re-evaluating probe %s: %s => %s', probe.id, probe.scriptId, script?.scriptId)
205
+
206
+ if (probe.scriptId !== script?.scriptId) {
207
+ log.debug('[debugger:devtools_client] Better match found for probe %s, re-evaluating', probe.id)
208
+ if (probeToLocation.has(probe.id)) {
209
+ await removeBreakpoint(probe)
210
+ }
211
+ await addBreakpoint(probe)
212
+ }
213
+ }
214
+
215
+ async function start () {
177
216
  sessionStarted = true
178
217
  log.debug('[debugger:devtools_client] Starting debugger')
179
- return session.post('Debugger.enable')
218
+ await session.post('Debugger.enable')
219
+
220
+ // Wait until there's a pause in script-loading to avoid accidentally adding probes to incorrect scripts. This is not
221
+ // a guarantee, but best effort.
222
+ log.debug('[debugger:devtools_client] Waiting for script-loading to stabilize')
223
+ await scriptLoadingStabilized
224
+ log.debug('[debugger:devtools_client] Script loading stabilized')
180
225
  }
181
226
 
182
227
  function stop () {
183
228
  sessionStarted = false
229
+ clearState()
184
230
  log.debug('[debugger:devtools_client] Stopping debugger')
185
231
  return session.post('Debugger.disable')
186
232
  }
187
233
 
234
+ function lock (fn) {
235
+ return async function (...args) {
236
+ const release = await mutex()
237
+ try {
238
+ return await fn(...args)
239
+ } finally {
240
+ release()
241
+ }
242
+ }
243
+ }
244
+
188
245
  // Only if all probes have a condition can we use a compound condition.
189
246
  // Otherwise, we need to evaluate each probe individually once the breakpoint is hit.
190
- // TODO: Handle errors - if there's 2 conditons, and one fails but the other returns true, we should still pause the
191
- // breakpoint
192
247
  function compileCompoundCondition (probes) {
248
+ if (probes.length === 1) return probes[0].condition
249
+
193
250
  return probes.every(p => p.condition)
194
- ? probes.map(p => p.condition).filter(Boolean).join(' || ')
251
+ ? probes
252
+ .map((p) => `(() => { try { return ${p.condition} } catch { return false } })()`)
253
+ .join(' || ')
195
254
  : undefined
196
255
  }
197
256
 
@@ -51,9 +51,8 @@ function compileSegments (segments) {
51
51
  let result = '['
52
52
  for (let i = 0; i < segments.length; i++) {
53
53
  const { str, dsl, json } = segments[i]
54
- result += str !== undefined
55
- ? JSON.stringify(str)
56
- : `(() => {
54
+ result += str === undefined
55
+ ? `(() => {
57
56
  try {
58
57
  const result = ${compile(json)}
59
58
  return typeof result === 'string' ? result : $dd_inspect(result, $dd_segmentInspectOptions)
@@ -61,6 +60,7 @@ function compileSegments (segments) {
61
60
  return { expr: ${JSON.stringify(dsl)}, message: \`\${e.name}: \${e.message}\` }
62
61
  }
63
62
  })()`
63
+ : JSON.stringify(str)
64
64
  if (i !== segments.length - 1) {
65
65
  result += ','
66
66
  }
@@ -95,11 +95,9 @@ function compile (node) {
95
95
  }
96
96
  })()`
97
97
  } else if (type === 'instanceof') {
98
- if (isPrimitiveType(value[1])) {
99
- return `(typeof ${compile(value[0])} === '${value[1]}')` // TODO: Is parenthesizing necessary?
100
- } else {
101
- return `Function.prototype[Symbol.hasInstance].call(${assertIdentifier(value[1])}, ${compile(value[0])})`
102
- }
98
+ return isPrimitiveType(value[1])
99
+ ? `(typeof ${compile(value[0])} === '${value[1]}')` // TODO: Is parenthesizing necessary?
100
+ : `Function.prototype[Symbol.hasInstance].call(${assertIdentifier(value[1])}, ${compile(value[0])})`
103
101
  } else if (type === 'ref') {
104
102
  if (value === '@it') {
105
103
  return '$dd_it'
@@ -3,5 +3,5 @@
3
3
  module.exports = {
4
4
  MAX_SNAPSHOTS_PER_SECOND_GLOBALLY: 25,
5
5
  MAX_SNAPSHOTS_PER_SECOND_PER_PROBE: 1,
6
- MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE: 5_000
6
+ MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE: 5000
7
7
  }
@@ -6,7 +6,7 @@ const session = require('./session')
6
6
  const { getLocalStateForCallFrame } = require('./snapshot')
7
7
  const send = require('./send')
8
8
  const { getStackFromCallFrames } = require('./state')
9
- const { ackEmitting, ackError } = require('./status')
9
+ const { ackEmitting } = require('./status')
10
10
  const { parentThreadId } = require('./config')
11
11
  const { MAX_SNAPSHOTS_PER_SECOND_GLOBALLY } = require('./defaults')
12
12
  const log = require('../../log')
@@ -36,7 +36,6 @@ const getDDTagsExpression = `(() => {
36
36
  const threadId = parentThreadId === 0 ? `pid:${process.pid}` : `pid:${process.pid};tid:${parentThreadId}`
37
37
  const threadName = parentThreadId === 0 ? 'MainThread' : `WorkerThread:${parentThreadId}`
38
38
 
39
- const SUPPORT_ITERATOR_METHODS = NODE_MAJOR >= 22
40
39
  const SUPPORT_ARRAY_BUFFER_RESIZE = NODE_MAJOR >= 20
41
40
  const oneSecondNs = 1_000_000_000n
42
41
  let globalSnapshotSamplingRateWindowStart = 0n
@@ -66,6 +65,12 @@ session.on('Debugger.paused', async ({ params }) => {
66
65
  for (let i = 0; i < params.hitBreakpoints.length; i++) {
67
66
  const probesAtLocation = breakpointToProbes.get(params.hitBreakpoints[i])
68
67
 
68
+ if (probesAtLocation === undefined) {
69
+ // This might happen due to a race condition where the breakpoint is in the process of being removed
70
+ log.error('[debugger:devtools_client] No probes found for breakpoint %s', params.hitBreakpoints[i])
71
+ continue
72
+ }
73
+
69
74
  if (probesAtLocation.size !== 1) {
70
75
  numberOfProbesOnBreakpoint = numberOfProbesOnBreakpoint + probesAtLocation.size - 1
71
76
  if (numberOfProbesOnBreakpoint > snapshotProbeIndex.length) {
@@ -77,14 +82,6 @@ session.on('Debugger.paused', async ({ params }) => {
77
82
  }
78
83
  }
79
84
 
80
- // If all the probes have a condition, we know that it triggered. If at least one probe doesn't have a condition, we
81
- // need to verify which conditions are met.
82
- const shouldVerifyConditions = (
83
- SUPPORT_ITERATOR_METHODS
84
- ? probesAtLocation.values()
85
- : Array.from(probesAtLocation.values())
86
- ).some((probe) => probe.condition === undefined)
87
-
88
85
  for (const probe of probesAtLocation.values()) {
89
86
  if (start - probe.lastCaptureNs < probe.nsBetweenSampling) {
90
87
  continue
@@ -109,7 +106,7 @@ session.on('Debugger.paused', async ({ params }) => {
109
106
  maxLength = highestOrUndefined(probe.capture.maxLength, maxLength)
110
107
  }
111
108
 
112
- if (shouldVerifyConditions && probe.condition !== undefined) {
109
+ if (probe.condition !== undefined) {
113
110
  // TODO: Bundle all conditions and evaluate them in a single call
114
111
  // TODO: Handle errors
115
112
  const { result } = await session.post('Debugger.evaluateOnCallFrame', {
@@ -153,27 +150,18 @@ session.on('Debugger.paused', async ({ params }) => {
153
150
  evalResults = result?.value ?? []
154
151
  }
155
152
 
156
- let processLocalState
157
- if (numberOfProbesWithSnapshots !== 0) {
158
- try {
159
- // TODO: Create unique states for each affected probe based on that probes unique `capture` settings (DEBUG-2863)
160
- processLocalState = await getLocalStateForCallFrame(
161
- params.callFrames[0],
162
- { maxReferenceDepth, maxCollectionSize, maxFieldCount, maxLength }
163
- )
164
- } catch (err) {
165
- for (let i = 0; i < numberOfProbesWithSnapshots; i++) {
166
- ackError(err, probes[snapshotProbeIndex[i]]) // TODO: Ok to continue after sending ackError?
167
- }
168
- }
169
- }
153
+ // TODO: Create unique states for each affected probe based on that probes unique `capture` settings (DEBUG-2863)
154
+ const processLocalState = numberOfProbesWithSnapshots !== 0 && await getLocalStateForCallFrame(
155
+ params.callFrames[0],
156
+ { maxReferenceDepth, maxCollectionSize, maxFieldCount, maxLength }
157
+ )
170
158
 
171
159
  await session.post('Debugger.resume')
172
160
  const diff = process.hrtime.bigint() - start // TODO: Recored as telemetry (DEBUG-2858)
173
161
 
174
162
  log.debug(
175
163
  '[debugger:devtools_client] Finished processing breakpoints - main thread paused for: %d ms',
176
- Number(diff) / 1000000
164
+ Number(diff) / 1_000_000
177
165
  )
178
166
 
179
167
  const logger = {
@@ -206,7 +194,9 @@ session.on('Debugger.paused', async ({ params }) => {
206
194
 
207
195
  if (probe.captureSnapshot) {
208
196
  const state = processLocalState()
209
- if (state) {
197
+ if (state instanceof Error) {
198
+ snapshot.captureError = state.message
199
+ } else if (state) {
210
200
  snapshot.captures = {
211
201
  lines: { [probe.location.lines[0]]: { locals: state } }
212
202
  }
@@ -1,8 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { workerData: { rcPort } } = require('node:worker_threads')
4
- const lock = require('mutexify/promise')()
5
- const { addBreakpoint, removeBreakpoint } = require('./breakpoints')
4
+ const { addBreakpoint, removeBreakpoint, modifyBreakpoint } = require('./breakpoints')
6
5
  const { ackReceived, ackInstalled, ackError } = require('./status')
7
6
  const log = require('../../log')
8
7
 
@@ -57,45 +56,26 @@ async function processMsg (action, probe) {
57
56
  }
58
57
  if (!probe.where.sourceFile && !probe.where.lines) {
59
58
  throw new Error(
60
- // eslint-disable-next-line @stylistic/js/max-len
59
+ // eslint-disable-next-line @stylistic/max-len
61
60
  `Unsupported probe insertion point! Only line-based probes are supported (id: ${probe.id}, version: ${probe.version})`
62
61
  )
63
62
  }
64
63
 
65
- // This lock is to ensure that we don't get the following race condition:
66
- //
67
- // When a breakpoint is being removed and there are no other breakpoints, we disable the debugger by calling
68
- // `Debugger.disable` to free resources. However, if a new breakpoint is being added around the same time, we might
69
- // have a race condition where the new breakpoint thinks that the debugger is already enabled because the removal of
70
- // the other breakpoint hasn't had a chance to call `Debugger.disable` yet. Then once the code that's adding the new
71
- // breakpoints tries to call `Debugger.setBreakpoint` it fails because in the meantime `Debugger.disable` was called.
72
- //
73
- // If the code is ever refactored to not tear down the debugger if there's no active breakpoints, we can safely remove
74
- // this lock.
75
- const release = await lock()
76
-
77
- try {
78
- switch (action) {
79
- case 'unapply':
80
- await removeBreakpoint(probe)
81
- break
82
- case 'apply':
83
- await addBreakpoint(probe)
84
- ackInstalled(probe)
85
- break
86
- case 'modify':
87
- // TODO: Modify existing probe instead of removing it (DEBUG-2817)
88
- await removeBreakpoint(probe)
89
- await addBreakpoint(probe)
90
- ackInstalled(probe) // TODO: Should we also send ackInstalled when modifying a probe?
91
- break
92
- default:
93
- throw new Error(
94
- // eslint-disable-next-line @stylistic/js/max-len
95
- `Cannot process probe ${probe.id} (version: ${probe.version}) - unknown remote configuration action: ${action}`
96
- )
97
- }
98
- } finally {
99
- release()
64
+ switch (action) {
65
+ case 'unapply':
66
+ await removeBreakpoint(probe)
67
+ break
68
+ case 'apply':
69
+ await addBreakpoint(probe)
70
+ ackInstalled(probe)
71
+ break
72
+ case 'modify':
73
+ await modifyBreakpoint(probe)
74
+ ackInstalled(probe)
75
+ break
76
+ default:
77
+ throw new Error(
78
+ `Cannot process probe ${probe.id} (version: ${probe.version}) - unknown remote configuration action: ${action}`
79
+ )
100
80
  }
101
81
  }
@@ -13,7 +13,8 @@ const { version } = require('../../../../../package.json')
13
13
  module.exports = send
14
14
 
15
15
  const MAX_MESSAGE_LENGTH = 8 * 1024 // 8KB
16
- const MAX_LOG_PAYLOAD_SIZE = 1024 * 1024 // 1MB
16
+ const MAX_LOG_PAYLOAD_SIZE_MB = 1
17
+ const MAX_LOG_PAYLOAD_SIZE_BYTES = MAX_LOG_PAYLOAD_SIZE_MB * 1024 * 1024
17
18
 
18
19
  const ddsource = 'dd_debugger'
19
20
  const hostname = getHostname()
@@ -48,13 +49,13 @@ function send (message, logger, dd, snapshot) {
48
49
  let json = JSON.stringify(payload)
49
50
  let size = Buffer.byteLength(json)
50
51
 
51
- if (size > MAX_LOG_PAYLOAD_SIZE) {
52
+ if (size > MAX_LOG_PAYLOAD_SIZE_BYTES) {
52
53
  // TODO: This is a very crude way to handle large payloads. Proper pruning will be implemented later (DEBUG-2624)
53
- const line = Object.values(payload.debugger.snapshot.captures.lines)[0]
54
- line.locals = {
55
- notCapturedReason: 'Snapshot was too large',
56
- size: Object.keys(line.locals).length
57
- }
54
+ delete payload.debugger.snapshot.captures
55
+ payload.debugger.snapshot.captureError =
56
+ `Snapshot was too large (max allowed size is ${MAX_LOG_PAYLOAD_SIZE_MB} MiB). ` +
57
+ 'Consider reducing the capture depth or turn off "Capture Variables" completely, ' +
58
+ 'and instead include the variables of interest directly in the message template.'
58
59
  json = JSON.stringify(payload)
59
60
  size = Buffer.byteLength(json)
60
61
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { getRuntimeObject } = require('./collector')
4
4
  const { processRawState } = require('./processor')
5
+ const log = require('../../../log')
5
6
 
6
7
  const DEFAULT_MAX_REFERENCE_DEPTH = 3
7
8
  const DEFAULT_MAX_COLLECTION_SIZE = 100
@@ -24,15 +25,22 @@ async function getLocalStateForCallFrame (
24
25
  const rawState = []
25
26
  let processedState = null
26
27
 
27
- await Promise.all(callFrame.scopeChain.map(async (scope) => {
28
- if (scope.type === 'global') return // The global scope is too noisy
29
- rawState.push(...await getRuntimeObject(
30
- scope.object.objectId,
31
- { maxReferenceDepth, maxCollectionSize, maxFieldCount }
32
- ))
33
- }))
28
+ try {
29
+ await Promise.all(callFrame.scopeChain.map(async (scope) => {
30
+ if (scope.type === 'global') return // The global scope is too noisy
31
+ rawState.push(...await getRuntimeObject(
32
+ scope.object.objectId,
33
+ { maxReferenceDepth, maxCollectionSize, maxFieldCount }
34
+ ))
35
+ }))
36
+ } catch (err) {
37
+ // TODO: We might be able to get part of the scope chain.
38
+ // Consider if we could set errors just for the part of the scope chain that throws during collection.
39
+ log.error('[debugger:devtools_client] Error getting local state for call frame', err)
40
+ return () => new Error('Error getting local state')
41
+ }
34
42
 
35
- // Deplay calling `processRawState` so the caller gets a chance to resume the main thread before processing `rawState`
43
+ // Delay calling `processRawState` so the caller gets a chance to resume the main thread before processing `rawState`
36
44
  return () => {
37
45
  processedState = processedState ?? processRawState(rawState, maxLength)
38
46
  return processedState