dd-trace 5.80.0 → 5.82.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 (460) hide show
  1. package/LICENSE-3rdparty.csv +79 -88
  2. package/ext/tags.d.ts +1 -0
  3. package/ext/tags.js +1 -0
  4. package/index.d.ts +42 -35
  5. package/loader-hook.mjs +16 -4
  6. package/package.json +33 -56
  7. package/packages/datadog-core/src/utils/src/parse-tags.js +1 -1
  8. package/packages/datadog-esbuild/index.js +44 -26
  9. package/packages/datadog-esbuild/src/utils.js +14 -2
  10. package/packages/datadog-instrumentations/index.js +1 -0
  11. package/packages/datadog-instrumentations/src/aerospike.js +3 -2
  12. package/packages/datadog-instrumentations/src/ai.js +2 -2
  13. package/packages/datadog-instrumentations/src/amqp10.js +1 -1
  14. package/packages/datadog-instrumentations/src/amqplib.js +4 -4
  15. package/packages/datadog-instrumentations/src/anthropic.js +14 -2
  16. package/packages/datadog-instrumentations/src/apollo-server-core.js +2 -2
  17. package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
  18. package/packages/datadog-instrumentations/src/apollo.js +3 -2
  19. package/packages/datadog-instrumentations/src/avsc.js +1 -1
  20. package/packages/datadog-instrumentations/src/aws-sdk.js +6 -2
  21. package/packages/datadog-instrumentations/src/azure-event-hubs.js +4 -3
  22. package/packages/datadog-instrumentations/src/azure-functions.js +2 -2
  23. package/packages/datadog-instrumentations/src/azure-service-bus.js +3 -4
  24. package/packages/datadog-instrumentations/src/bluebird.js +1 -1
  25. package/packages/datadog-instrumentations/src/bullmq.js +11 -0
  26. package/packages/datadog-instrumentations/src/bunyan.js +1 -1
  27. package/packages/datadog-instrumentations/src/cassandra-driver.js +1 -1
  28. package/packages/datadog-instrumentations/src/child_process.js +2 -2
  29. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +3 -3
  30. package/packages/datadog-instrumentations/src/couchbase.js +1 -1
  31. package/packages/datadog-instrumentations/src/crypto.js +1 -1
  32. package/packages/datadog-instrumentations/src/cucumber.js +12 -13
  33. package/packages/datadog-instrumentations/src/cypress.js +1 -1
  34. package/packages/datadog-instrumentations/src/dns.js +1 -1
  35. package/packages/datadog-instrumentations/src/elasticsearch.js +1 -1
  36. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +1 -1
  37. package/packages/datadog-instrumentations/src/express.js +1 -1
  38. package/packages/datadog-instrumentations/src/find-my-way.js +6 -5
  39. package/packages/datadog-instrumentations/src/fs.js +1 -1
  40. package/packages/datadog-instrumentations/src/generic-pool.js +1 -1
  41. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +137 -15
  42. package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -3
  43. package/packages/datadog-instrumentations/src/google-genai.js +120 -0
  44. package/packages/datadog-instrumentations/src/graphql.js +21 -1
  45. package/packages/datadog-instrumentations/src/grpc/client.js +1 -1
  46. package/packages/datadog-instrumentations/src/grpc/server.js +1 -1
  47. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -1
  48. package/packages/datadog-instrumentations/src/helpers/hook.js +1 -1
  49. package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -1
  50. package/packages/datadog-instrumentations/src/helpers/instrument.js +11 -1
  51. package/packages/datadog-instrumentations/src/helpers/register.js +12 -5
  52. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +27 -0
  53. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +152 -0
  54. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.json +106 -0
  55. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +6 -0
  56. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langchain.js +237 -0
  57. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.js +9 -0
  58. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +11 -0
  59. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +139 -0
  60. package/packages/datadog-instrumentations/src/helpers/router-helper.js +1 -1
  61. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +9 -0
  62. package/packages/datadog-instrumentations/src/hono.js +55 -10
  63. package/packages/datadog-instrumentations/src/ioredis.js +1 -1
  64. package/packages/datadog-instrumentations/src/iovalkey.js +1 -1
  65. package/packages/datadog-instrumentations/src/jest.js +2 -2
  66. package/packages/datadog-instrumentations/src/kafkajs.js +3 -3
  67. package/packages/datadog-instrumentations/src/knex.js +1 -1
  68. package/packages/datadog-instrumentations/src/langchain.js +3 -109
  69. package/packages/datadog-instrumentations/src/ldapjs.js +1 -1
  70. package/packages/datadog-instrumentations/src/light-my-request.js +93 -0
  71. package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
  72. package/packages/datadog-instrumentations/src/lodash.js +1 -2
  73. package/packages/datadog-instrumentations/src/mariadb.js +1 -2
  74. package/packages/datadog-instrumentations/src/memcached.js +1 -1
  75. package/packages/datadog-instrumentations/src/mocha/main.js +1 -1
  76. package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
  77. package/packages/datadog-instrumentations/src/mongodb.js +1 -1
  78. package/packages/datadog-instrumentations/src/mongoose.js +1 -1
  79. package/packages/datadog-instrumentations/src/mquery.js +1 -1
  80. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  81. package/packages/datadog-instrumentations/src/mysql2.js +2 -2
  82. package/packages/datadog-instrumentations/src/net.js +1 -1
  83. package/packages/datadog-instrumentations/src/next.js +1 -1
  84. package/packages/datadog-instrumentations/src/nyc.js +1 -1
  85. package/packages/datadog-instrumentations/src/openai.js +2 -2
  86. package/packages/datadog-instrumentations/src/opensearch.js +1 -1
  87. package/packages/datadog-instrumentations/src/oracledb.js +1 -1
  88. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +1 -1
  89. package/packages/datadog-instrumentations/src/pg.js +3 -3
  90. package/packages/datadog-instrumentations/src/pino.js +1 -1
  91. package/packages/datadog-instrumentations/src/playwright.js +46 -17
  92. package/packages/datadog-instrumentations/src/prisma.js +52 -37
  93. package/packages/datadog-instrumentations/src/process.js +1 -1
  94. package/packages/datadog-instrumentations/src/promise-js.js +1 -1
  95. package/packages/datadog-instrumentations/src/promise.js +1 -1
  96. package/packages/datadog-instrumentations/src/protobufjs.js +1 -1
  97. package/packages/datadog-instrumentations/src/q.js +1 -1
  98. package/packages/datadog-instrumentations/src/redis.js +1 -1
  99. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  100. package/packages/datadog-instrumentations/src/router.js +1 -1
  101. package/packages/datadog-instrumentations/src/selenium.js +4 -2
  102. package/packages/datadog-instrumentations/src/sequelize.js +1 -2
  103. package/packages/datadog-instrumentations/src/sharedb.js +1 -1
  104. package/packages/datadog-instrumentations/src/tedious.js +1 -1
  105. package/packages/datadog-instrumentations/src/undici.js +4 -4
  106. package/packages/datadog-instrumentations/src/url.js +1 -1
  107. package/packages/datadog-instrumentations/src/vitest.js +1 -1
  108. package/packages/datadog-instrumentations/src/vm.js +1 -1
  109. package/packages/datadog-instrumentations/src/when.js +1 -1
  110. package/packages/datadog-instrumentations/src/winston.js +1 -1
  111. package/packages/datadog-instrumentations/src/ws.js +38 -19
  112. package/packages/datadog-plugin-amqp10/src/index.js +1 -1
  113. package/packages/datadog-plugin-amqplib/src/index.js +1 -1
  114. package/packages/datadog-plugin-anthropic/src/index.js +1 -1
  115. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +1 -1
  116. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +4 -4
  117. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  118. package/packages/datadog-plugin-aws-sdk/src/util.js +3 -3
  119. package/packages/datadog-plugin-azure-event-hubs/src/index.js +1 -1
  120. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +19 -5
  121. package/packages/datadog-plugin-azure-service-bus/src/index.js +1 -1
  122. package/packages/datadog-plugin-azure-service-bus/src/producer.js +4 -0
  123. package/packages/datadog-plugin-bullmq/src/consumer.js +60 -0
  124. package/packages/datadog-plugin-bullmq/src/index.js +18 -0
  125. package/packages/datadog-plugin-bullmq/src/producer.js +178 -0
  126. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -1
  127. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +1 -1
  128. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +23 -2
  129. package/packages/datadog-plugin-cypress/src/plugin.js +2 -2
  130. package/packages/datadog-plugin-cypress/src/support.js +73 -31
  131. package/packages/datadog-plugin-express/src/index.js +1 -1
  132. package/packages/datadog-plugin-fastify/src/index.js +1 -1
  133. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +13 -3
  134. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +171 -12
  135. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +1 -2
  136. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +160 -13
  137. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +217 -0
  138. package/packages/datadog-plugin-google-cloud-vertexai/src/index.js +1 -1
  139. package/packages/datadog-plugin-google-genai/src/index.js +17 -0
  140. package/packages/datadog-plugin-google-genai/src/tracing.js +41 -0
  141. package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
  142. package/packages/datadog-plugin-graphql/src/tools/transforms.js +5 -4
  143. package/packages/datadog-plugin-grpc/src/index.js +1 -1
  144. package/packages/datadog-plugin-http/src/client.js +2 -1
  145. package/packages/datadog-plugin-http/src/index.js +25 -5
  146. package/packages/datadog-plugin-http2/src/client.js +2 -2
  147. package/packages/datadog-plugin-http2/src/index.js +1 -1
  148. package/packages/datadog-plugin-jest/src/util.js +1 -1
  149. package/packages/datadog-plugin-kafkajs/src/index.js +1 -1
  150. package/packages/datadog-plugin-langchain/src/index.js +1 -1
  151. package/packages/datadog-plugin-langchain/src/tracing.js +7 -3
  152. package/packages/datadog-plugin-moleculer/src/index.js +1 -1
  153. package/packages/datadog-plugin-mongodb-core/src/index.js +6 -2
  154. package/packages/datadog-plugin-next/src/index.js +11 -3
  155. package/packages/datadog-plugin-openai/src/index.js +1 -1
  156. package/packages/datadog-plugin-openai/src/stream-helpers.js +30 -10
  157. package/packages/datadog-plugin-openai/src/tracing.js +2 -2
  158. package/packages/datadog-plugin-rhea/src/index.js +1 -1
  159. package/packages/datadog-plugin-ws/src/close.js +56 -3
  160. package/packages/datadog-plugin-ws/src/index.js +4 -0
  161. package/packages/datadog-plugin-ws/src/producer.js +39 -4
  162. package/packages/datadog-plugin-ws/src/receiver.js +39 -3
  163. package/packages/datadog-plugin-ws/src/server.js +13 -1
  164. package/packages/datadog-plugin-ws/src/util.js +107 -0
  165. package/packages/datadog-shimmer/src/shimmer.js +2 -2
  166. package/packages/dd-trace/src/aiguard/sdk.js +21 -13
  167. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  168. package/packages/dd-trace/src/appsec/graphql.js +2 -2
  169. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +1 -1
  170. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +1 -1
  171. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +1 -1
  172. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  173. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +1 -1
  174. package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +1 -1
  175. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +3 -3
  176. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +1 -1
  177. package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +1 -1
  178. package/packages/dd-trace/src/appsec/iast/analyzers/untrusted-deserialization-analyzer.js +1 -1
  179. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +1 -1
  180. package/packages/dd-trace/src/appsec/iast/analyzers/weak-cipher-analyzer.js +1 -1
  181. package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +3 -2
  182. package/packages/dd-trace/src/appsec/iast/analyzers/weak-randomness-analyzer.js +1 -1
  183. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +3 -3
  184. package/packages/dd-trace/src/appsec/iast/index.js +5 -5
  185. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +1 -1
  186. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +1 -1
  187. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -2
  188. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +1 -1
  189. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
  190. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +1 -1
  191. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +11 -16
  192. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
  193. package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +1 -1
  194. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -4
  195. package/packages/dd-trace/src/appsec/index.js +8 -8
  196. package/packages/dd-trace/src/appsec/rasp/command_injection.js +1 -1
  197. package/packages/dd-trace/src/appsec/rasp/index.js +1 -1
  198. package/packages/dd-trace/src/appsec/rasp/lfi.js +1 -1
  199. package/packages/dd-trace/src/appsec/rc-products.js +10 -0
  200. package/packages/dd-trace/src/appsec/recommended.json +230 -3
  201. package/packages/dd-trace/src/appsec/remote_config.js +177 -0
  202. package/packages/dd-trace/src/appsec/reporter.js +3 -7
  203. package/packages/dd-trace/src/appsec/rule_manager.js +37 -20
  204. package/packages/dd-trace/src/appsec/sdk/index.js +1 -1
  205. package/packages/dd-trace/src/appsec/sdk/set_user.js +1 -1
  206. package/packages/dd-trace/src/appsec/sdk/track_event.js +2 -2
  207. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +2 -2
  208. package/packages/dd-trace/src/appsec/user_tracking.js +2 -2
  209. package/packages/dd-trace/src/appsec/waf/index.js +17 -3
  210. package/packages/dd-trace/src/appsec/waf/waf_manager.js +11 -0
  211. package/packages/dd-trace/src/azure_metadata.js +8 -2
  212. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +8 -6
  213. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +2 -2
  214. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
  215. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +1 -1
  216. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +4 -2
  217. package/packages/dd-trace/src/config/remote_config.js +34 -0
  218. package/packages/dd-trace/src/config.js +109 -34
  219. package/packages/dd-trace/src/config_defaults.js +16 -3
  220. package/packages/dd-trace/src/constants.js +5 -0
  221. package/packages/dd-trace/src/crashtracking/crashtracker.js +10 -1
  222. package/packages/dd-trace/src/datastreams/checkpointer.js +2 -2
  223. package/packages/dd-trace/src/datastreams/encoding.js +23 -6
  224. package/packages/dd-trace/src/datastreams/index.js +1 -1
  225. package/packages/dd-trace/src/datastreams/pathway.js +41 -2
  226. package/packages/dd-trace/src/datastreams/processor.js +3 -3
  227. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +1 -1
  228. package/packages/dd-trace/src/datastreams/writer.js +2 -2
  229. package/packages/dd-trace/src/debugger/config.js +1 -0
  230. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +15 -5
  231. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
  232. package/packages/dd-trace/src/debugger/devtools_client/config.js +3 -1
  233. package/packages/dd-trace/src/debugger/devtools_client/index.js +37 -17
  234. package/packages/dd-trace/src/debugger/devtools_client/inspector_promises_polyfill.js +2 -0
  235. package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +24 -18
  236. package/packages/dd-trace/src/debugger/devtools_client/send.js +21 -11
  237. package/packages/dd-trace/src/debugger/devtools_client/session.js +1 -1
  238. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +103 -15
  239. package/packages/dd-trace/src/debugger/devtools_client/snapshot/constants.js +25 -0
  240. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +56 -25
  241. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +64 -23
  242. package/packages/dd-trace/src/debugger/devtools_client/snapshot/symbols.js +3 -1
  243. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +404 -0
  244. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +1 -1
  245. package/packages/dd-trace/src/debugger/devtools_client/state.js +8 -3
  246. package/packages/dd-trace/src/debugger/devtools_client/status.js +3 -3
  247. package/packages/dd-trace/src/debugger/index.js +2 -2
  248. package/packages/dd-trace/src/dogstatsd.js +3 -2
  249. package/packages/dd-trace/src/encode/0.4.js +1 -1
  250. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +2 -2
  251. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +1 -1
  252. package/packages/dd-trace/src/encode/span-stats.js +13 -2
  253. package/packages/dd-trace/src/exporter.js +2 -2
  254. package/packages/dd-trace/src/exporters/agent/index.js +1 -1
  255. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +1 -1
  256. package/packages/dd-trace/src/exporters/common/request.js +2 -2
  257. package/packages/dd-trace/src/exporters/common/writer.js +1 -1
  258. package/packages/dd-trace/src/exporters/span-stats/index.js +1 -1
  259. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  260. package/packages/dd-trace/src/flare/index.js +1 -1
  261. package/packages/dd-trace/src/guardrails/index.js +6 -3
  262. package/packages/dd-trace/src/histogram.js +1 -1
  263. package/packages/dd-trace/src/id.js +60 -0
  264. package/packages/dd-trace/src/index.js +1 -1
  265. package/packages/dd-trace/src/lambda/handler.js +4 -4
  266. package/packages/dd-trace/src/lambda/index.js +1 -1
  267. package/packages/dd-trace/src/lambda/runtime/patch.js +4 -4
  268. package/packages/dd-trace/src/lambda/runtime/ritm.js +2 -2
  269. package/packages/dd-trace/src/llmobs/constants/tags.js +8 -1
  270. package/packages/dd-trace/src/llmobs/index.js +8 -9
  271. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +38 -7
  272. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +30 -9
  273. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +3 -3
  274. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +104 -0
  275. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +486 -0
  276. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +1 -1
  277. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +1 -1
  278. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +1 -1
  279. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/llm.js +1 -1
  280. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/vectorstore.js +1 -1
  281. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +2 -2
  282. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +16 -0
  283. package/packages/dd-trace/src/llmobs/plugins/{openai.js → openai/index.js} +63 -6
  284. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +126 -0
  285. package/packages/dd-trace/src/llmobs/plugins/vertexai.js +1 -1
  286. package/packages/dd-trace/src/llmobs/sdk.js +20 -22
  287. package/packages/dd-trace/src/llmobs/span_processor.js +15 -14
  288. package/packages/dd-trace/src/llmobs/tagger.js +4 -0
  289. package/packages/dd-trace/src/llmobs/telemetry.js +3 -4
  290. package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
  291. package/packages/dd-trace/src/llmobs/writers/spans.js +1 -2
  292. package/packages/dd-trace/src/log/index.js +1 -1
  293. package/packages/dd-trace/src/noop/proxy.js +2 -2
  294. package/packages/dd-trace/src/noop/span.js +1 -1
  295. package/packages/dd-trace/src/openfeature/index.js +2 -2
  296. package/packages/dd-trace/src/openfeature/noop.js +14 -14
  297. package/packages/dd-trace/src/openfeature/remote_config.js +31 -0
  298. package/packages/dd-trace/src/openfeature/writers/base.js +5 -5
  299. package/packages/dd-trace/src/openfeature/writers/exposures.js +9 -9
  300. package/packages/dd-trace/src/opentelemetry/context_manager.js +2 -2
  301. package/packages/dd-trace/src/opentelemetry/logs/index.js +2 -2
  302. package/packages/dd-trace/src/opentelemetry/logs/logger.js +3 -2
  303. package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +4 -4
  304. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +5 -3
  305. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +17 -16
  306. package/packages/dd-trace/src/opentelemetry/metrics/constants.js +34 -0
  307. package/packages/dd-trace/src/opentelemetry/metrics/index.js +81 -0
  308. package/packages/dd-trace/src/opentelemetry/metrics/instruments.js +225 -0
  309. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +171 -0
  310. package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +54 -0
  311. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +62 -0
  312. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +251 -0
  313. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +557 -0
  314. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +10 -18
  315. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +47 -32
  316. package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +1 -1
  317. package/packages/dd-trace/src/opentelemetry/span.js +3 -3
  318. package/packages/dd-trace/src/opentelemetry/tracer.js +4 -4
  319. package/packages/dd-trace/src/opentelemetry/tracer_provider.js +1 -1
  320. package/packages/dd-trace/src/opentracing/propagation/text_map.js +24 -8
  321. package/packages/dd-trace/src/opentracing/span.js +3 -3
  322. package/packages/dd-trace/src/opentracing/tracer.js +5 -5
  323. package/packages/dd-trace/src/payload-tagging/index.js +8 -4
  324. package/packages/dd-trace/src/plugin_manager.js +5 -3
  325. package/packages/dd-trace/src/plugins/apollo.js +1 -1
  326. package/packages/dd-trace/src/plugins/ci_plugin.js +27 -27
  327. package/packages/dd-trace/src/plugins/database.js +1 -1
  328. package/packages/dd-trace/src/plugins/index.js +6 -1
  329. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  330. package/packages/dd-trace/src/plugins/outbound.js +1 -1
  331. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  332. package/packages/dd-trace/src/plugins/util/ci.js +1 -1
  333. package/packages/dd-trace/src/plugins/util/git.js +8 -8
  334. package/packages/dd-trace/src/plugins/util/stacktrace.js +1 -1
  335. package/packages/dd-trace/src/plugins/util/test.js +27 -27
  336. package/packages/dd-trace/src/plugins/util/url.js +119 -1
  337. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  338. package/packages/dd-trace/src/plugins/util/web.js +18 -46
  339. package/packages/dd-trace/src/priority_sampler.js +15 -16
  340. package/packages/dd-trace/src/process-tags/index.js +83 -0
  341. package/packages/dd-trace/src/profiling/config.js +33 -22
  342. package/packages/dd-trace/src/profiling/exporter_cli.js +4 -4
  343. package/packages/dd-trace/src/profiling/exporters/agent.js +5 -5
  344. package/packages/dd-trace/src/profiling/index.js +1 -1
  345. package/packages/dd-trace/src/profiling/libuv-size.js +1 -1
  346. package/packages/dd-trace/src/profiling/profiler.js +4 -5
  347. package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +1 -1
  348. package/packages/dd-trace/src/profiling/profilers/events.js +11 -2
  349. package/packages/dd-trace/src/profiling/profilers/wall.js +4 -4
  350. package/packages/dd-trace/src/proxy.js +17 -18
  351. package/packages/dd-trace/src/rate_limiter.js +1 -1
  352. package/packages/dd-trace/src/remote_config/index.js +541 -137
  353. package/packages/dd-trace/src/require-package-json.js +1 -1
  354. package/packages/dd-trace/src/ritm.js +50 -27
  355. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +1 -1
  356. package/packages/dd-trace/src/serverless.js +16 -0
  357. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +8 -0
  358. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  359. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
  360. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  361. package/packages/dd-trace/src/span_format.js +10 -5
  362. package/packages/dd-trace/src/span_processor.js +8 -3
  363. package/packages/dd-trace/src/span_stats.js +21 -8
  364. package/packages/dd-trace/src/spanleak.js +1 -1
  365. package/packages/dd-trace/src/standalone/index.js +1 -1
  366. package/packages/dd-trace/src/startup-log.js +3 -3
  367. package/packages/dd-trace/src/supported-configurations.json +16 -0
  368. package/packages/dd-trace/src/telemetry/dependencies.js +4 -4
  369. package/packages/dd-trace/src/telemetry/endpoints.js +8 -8
  370. package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
  371. package/packages/dd-trace/src/telemetry/telemetry.js +22 -8
  372. package/packages/dd-trace/src/tracer.js +3 -3
  373. package/packages/dd-trace/src/tracer_metadata.js +19 -15
  374. package/vendor/dist/@datadog/sketches-js/LICENSE +39 -0
  375. package/vendor/dist/@datadog/sketches-js/index.js +1 -0
  376. package/vendor/dist/@datadog/source-map/LICENSE +28 -0
  377. package/vendor/dist/@datadog/source-map/index.js +1 -0
  378. package/vendor/dist/@isaacs/ttlcache/LICENSE +55 -0
  379. package/vendor/dist/@isaacs/ttlcache/index.js +1 -0
  380. package/vendor/dist/@opentelemetry/core/LICENSE +201 -0
  381. package/vendor/dist/@opentelemetry/core/index.js +1 -0
  382. package/vendor/dist/@opentelemetry/resources/LICENSE +201 -0
  383. package/vendor/dist/@opentelemetry/resources/index.js +1 -0
  384. package/vendor/dist/astring/LICENSE +19 -0
  385. package/vendor/dist/astring/index.js +1 -0
  386. package/vendor/dist/crypto-randomuuid/index.js +1 -0
  387. package/vendor/dist/escape-string-regexp/LICENSE +9 -0
  388. package/vendor/dist/escape-string-regexp/index.js +1 -0
  389. package/vendor/dist/esquery/LICENSE +24 -0
  390. package/vendor/dist/esquery/index.js +1 -0
  391. package/vendor/dist/ignore/LICENSE +21 -0
  392. package/vendor/dist/ignore/index.js +1 -0
  393. package/vendor/dist/istanbul-lib-coverage/LICENSE +24 -0
  394. package/vendor/dist/istanbul-lib-coverage/index.js +1 -0
  395. package/vendor/dist/jest-docblock/LICENSE +21 -0
  396. package/vendor/dist/jest-docblock/index.js +1 -0
  397. package/vendor/dist/jsonpath-plus/LICENSE +22 -0
  398. package/vendor/dist/jsonpath-plus/index.js +1 -0
  399. package/vendor/dist/limiter/LICENSE +19 -0
  400. package/vendor/dist/limiter/index.js +1 -0
  401. package/vendor/dist/lodash.sortby/LICENSE +47 -0
  402. package/vendor/dist/lodash.sortby/index.js +1 -0
  403. package/vendor/dist/lru-cache/LICENSE +15 -0
  404. package/vendor/dist/lru-cache/index.js +1 -0
  405. package/vendor/dist/meriyah/LICENSE +7 -0
  406. package/vendor/dist/meriyah/index.js +1 -0
  407. package/vendor/dist/module-details-from-path/LICENSE +21 -0
  408. package/vendor/dist/module-details-from-path/index.js +1 -0
  409. package/vendor/dist/mutexify/promise/LICENSE +21 -0
  410. package/vendor/dist/mutexify/promise/index.js +1 -0
  411. package/vendor/dist/opentracing/LICENSE +201 -0
  412. package/vendor/dist/opentracing/binary_carrier.d.ts +11 -0
  413. package/vendor/dist/opentracing/constants.d.ts +61 -0
  414. package/vendor/dist/opentracing/examples/demo/demo.d.ts +2 -0
  415. package/vendor/dist/opentracing/ext/tags.d.ts +90 -0
  416. package/vendor/dist/opentracing/functions.d.ts +20 -0
  417. package/vendor/dist/opentracing/global_tracer.d.ts +14 -0
  418. package/vendor/dist/opentracing/index.d.ts +12 -0
  419. package/vendor/dist/opentracing/index.js +1 -0
  420. package/vendor/dist/opentracing/mock_tracer/index.d.ts +5 -0
  421. package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +13 -0
  422. package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +16 -0
  423. package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +50 -0
  424. package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +26 -0
  425. package/vendor/dist/opentracing/noop.d.ts +8 -0
  426. package/vendor/dist/opentracing/reference.d.ts +33 -0
  427. package/vendor/dist/opentracing/span.d.ts +147 -0
  428. package/vendor/dist/opentracing/span_context.d.ts +26 -0
  429. package/vendor/dist/opentracing/test/api_compatibility.d.ts +16 -0
  430. package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +3 -0
  431. package/vendor/dist/opentracing/test/noop_implementation.d.ts +4 -0
  432. package/vendor/dist/opentracing/test/opentracing_api.d.ts +3 -0
  433. package/vendor/dist/opentracing/test/unittest.d.ts +2 -0
  434. package/vendor/dist/opentracing/tracer.d.ts +127 -0
  435. package/vendor/dist/path-to-regexp/LICENSE +21 -0
  436. package/vendor/dist/path-to-regexp/index.js +1 -0
  437. package/vendor/dist/pprof-format/LICENSE +8 -0
  438. package/vendor/dist/pprof-format/index.js +1 -0
  439. package/vendor/dist/protobufjs/LICENSE +39 -0
  440. package/vendor/dist/protobufjs/index.js +1 -0
  441. package/vendor/dist/protobufjs/minimal/LICENSE +39 -0
  442. package/vendor/dist/protobufjs/minimal/index.js +1 -0
  443. package/vendor/dist/retry/LICENSE +21 -0
  444. package/vendor/dist/retry/index.js +1 -0
  445. package/vendor/dist/rfdc/LICENSE +15 -0
  446. package/vendor/dist/rfdc/index.js +1 -0
  447. package/vendor/dist/semifies/LICENSE +201 -0
  448. package/vendor/dist/semifies/index.js +1 -0
  449. package/vendor/dist/shell-quote/LICENSE +24 -0
  450. package/vendor/dist/shell-quote/index.js +1 -0
  451. package/vendor/dist/source-map/LICENSE +28 -0
  452. package/vendor/dist/source-map/index.js +1 -0
  453. package/vendor/dist/source-map/lib/util/LICENSE +28 -0
  454. package/vendor/dist/source-map/lib/util/index.js +1 -0
  455. package/vendor/dist/source-map/mappings.wasm +0 -0
  456. package/vendor/dist/tlhunter-sorted-set/LICENSE +21 -0
  457. package/vendor/dist/tlhunter-sorted-set/index.js +1 -0
  458. package/vendor/dist/ttl-set/LICENSE +21 -0
  459. package/vendor/dist/ttl-set/index.js +1 -0
  460. package/packages/dd-trace/src/remote_config/manager.js +0 -368
@@ -8,6 +8,7 @@ module.exports = function getDebuggerConfig (config) {
8
8
  hostname: config.hostname,
9
9
  logLevel: config.logLevel,
10
10
  port: config.port,
11
+ propagateProcessTags: config.propagateProcessTags,
11
12
  repositoryUrl: config.repositoryUrl,
12
13
  runtimeId: config.tags['runtime-id'],
13
14
  service: config.service,
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const mutex = require('mutexify/promise')()
3
+ const mutex = require('../../../../../vendor/dist/mutexify/promise')()
4
4
  const { getGeneratedPosition } = require('./source-maps')
5
5
  const session = require('./session')
6
6
  const { compile: compileCondition, compileSegments, templateRequiresEvaluation } = require('./condition')
@@ -64,8 +64,9 @@ async function addBreakpoint (probe) {
64
64
  const snapshotsPerSecond = probe.sampling?.snapshotsPerSecond ?? (probe.captureSnapshot
65
65
  ? MAX_SNAPSHOTS_PER_SECOND_PER_PROBE
66
66
  : MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE)
67
- probe.nsBetweenSampling = BigInt(1 / snapshotsPerSecond * 1e9)
68
- probe.lastCaptureNs = 0n
67
+ probe.nsBetweenSampling = BigInt(Math.trunc(1 / snapshotsPerSecond * 1e9))
68
+ // Initialize to a large negative value to ensure first probe hit is always captured
69
+ probe.lastCaptureNs = BigInt(Number.MIN_SAFE_INTEGER)
69
70
 
70
71
  // Warning: The code below relies on undocumented behavior of the inspector!
71
72
  // It expects that `await session.post('Debugger.enable')` will wait for all loaded scripts to be emitted as
@@ -80,8 +81,17 @@ async function addBreakpoint (probe) {
80
81
  log.debug(
81
82
  '[debugger:devtools_client] Translating location using source map for %s:%d:%d (probe: %s, version: %d)',
82
83
  file, lineNumber, columnNumber, probe.id, probe.version
83
- );
84
- ({ line: lineNumber, column: columnNumber } = await getGeneratedPosition(url, source, lineNumber, sourceMapURL))
84
+ )
85
+ const position = await getGeneratedPosition(url, source, lineNumber, sourceMapURL)
86
+ if (position.line !== null && position.column !== null) {
87
+ lineNumber = position.line
88
+ columnNumber = position.column
89
+ } else {
90
+ throw new Error(
91
+ // eslint-disable-next-line @stylistic/max-len
92
+ `Could not find generated position for ${url}:${lineNumber}:${columnNumber} (probe: ${probe.id}, version: ${probe.version})`
93
+ )
94
+ }
85
95
  }
86
96
 
87
97
  try {
@@ -33,7 +33,7 @@ const reservedWords = new Set([
33
33
  // Future reserved words in strict mode
34
34
  'implements', 'interface', 'package', 'private', 'protected', 'public',
35
35
 
36
- // Litterals
36
+ // Literals
37
37
  'NaN'
38
38
  ])
39
39
 
@@ -2,8 +2,8 @@
2
2
 
3
3
  const { workerData: { config: parentConfig, parentThreadId, configPort } } = require('node:worker_threads')
4
4
  const { format } = require('node:url')
5
- const log = require('./log')
6
5
  const defaults = require('../../config_defaults')
6
+ const log = require('./log')
7
7
 
8
8
  const config = module.exports = {
9
9
  ...parentConfig,
@@ -24,4 +24,6 @@ function updateUrl (updates) {
24
24
  hostname: updates.hostname || defaults.hostname,
25
25
  port: updates.port
26
26
  })
27
+
28
+ config.dynamicInstrumentation.captureTimeoutNs = BigInt(updates.dynamicInstrumentation.captureTimeoutMs) * 1_000_000n
27
29
  }
@@ -1,17 +1,18 @@
1
1
  'use strict'
2
2
 
3
3
  const { randomUUID } = require('crypto')
4
+ const { version } = require('../../../../../package.json')
5
+ const { NODE_MAJOR } = require('../../../../../version')
6
+ const processTags = require('../../process-tags')
4
7
  const { breakpointToProbes } = require('./state')
5
8
  const session = require('./session')
6
9
  const { getLocalStateForCallFrame } = require('./snapshot')
7
10
  const send = require('./send')
8
11
  const { getStackFromCallFrames } = require('./state')
9
12
  const { ackEmitting } = require('./status')
10
- const { parentThreadId } = require('./config')
13
+ const config = require('./config')
11
14
  const { MAX_SNAPSHOTS_PER_SECOND_GLOBALLY } = require('./defaults')
12
15
  const log = require('./log')
13
- const { version } = require('../../../../../package.json')
14
- const { NODE_MAJOR } = require('../../../../../version')
15
16
 
16
17
  require('./remote_config')
17
18
 
@@ -33,8 +34,8 @@ const getDDTagsExpression = `(() => {
33
34
 
34
35
  // There doesn't seem to be an official standard for the content of these fields, so we're just populating them with
35
36
  // something that should be useful to a Node.js developer.
36
- const threadId = parentThreadId === 0 ? `pid:${process.pid}` : `pid:${process.pid};tid:${parentThreadId}`
37
- const threadName = parentThreadId === 0 ? 'MainThread' : `WorkerThread:${parentThreadId}`
37
+ const threadId = config.parentThreadId === 0 ? `pid:${process.pid}` : `pid:${process.pid};tid:${config.parentThreadId}`
38
+ const threadName = config.parentThreadId === 0 ? 'MainThread' : `WorkerThread:${config.parentThreadId}`
38
39
 
39
40
  const SUPPORT_ARRAY_BUFFER_RESIZE = NODE_MAJOR >= 20
40
41
  const oneSecondNs = 1_000_000_000n
@@ -46,6 +47,7 @@ let snapshotProbeIndexBuffer, snapshotProbeIndex
46
47
 
47
48
  if (SUPPORT_ARRAY_BUFFER_RESIZE) {
48
49
  // TODO: Is a limit of 256 snapshots ever going to be a problem?
50
+ // @ts-ignore - ArrayBuffer constructor with maxByteLength is available in Node.js 20+ but not in @types/node@18
49
51
  // eslint-disable-next-line n/no-unsupported-features/es-syntax
50
52
  snapshotProbeIndexBuffer = new ArrayBuffer(1, { maxByteLength: 256 })
51
53
  // TODO: Is a limit of 256 probes ever going to be a problem?
@@ -165,13 +167,20 @@ session.on('Debugger.paused', async ({ params }) => {
165
167
  }
166
168
 
167
169
  // TODO: Create unique states for each affected probe based on that probes unique `capture` settings (DEBUG-2863)
168
- const processLocalState = numberOfProbesWithSnapshots !== 0 && await getLocalStateForCallFrame(
169
- params.callFrames[0],
170
- { maxReferenceDepth, maxCollectionSize, maxFieldCount, maxLength }
171
- )
170
+ let processLocalState, captureErrors
171
+ if (numberOfProbesWithSnapshots !== 0) {
172
+ const opts = {
173
+ maxReferenceDepth,
174
+ maxCollectionSize,
175
+ maxFieldCount,
176
+ maxLength,
177
+ deadlineNs: start + config.dynamicInstrumentation.captureTimeoutNs
178
+ }
179
+ ;({ processLocalState, captureErrors } = await getLocalStateForCallFrame(params.callFrames[0], opts))
180
+ }
172
181
 
173
182
  await session.post('Debugger.resume')
174
- const diff = process.hrtime.bigint() - start // TODO: Recored as telemetry (DEBUG-2858)
183
+ const diff = process.hrtime.bigint() - start // TODO: Recorded as telemetry (DEBUG-2858)
175
184
 
176
185
  // This doesn't measure the overhead of the CDP protocol. The actual pause time is slightly larger.
177
186
  // On my machine I'm seeing around 1.7ms of overhead.
@@ -207,15 +216,26 @@ session.on('Debugger.paused', async ({ params }) => {
207
216
  language: 'javascript'
208
217
  }
209
218
 
219
+ if (config.propagateProcessTags.enabled) {
220
+ snapshot[processTags.DYNAMIC_INSTRUMENTATION_FIELD_NAME] = processTags.tagsObject
221
+ }
222
+
210
223
  if (probe.captureSnapshot) {
211
- const state = processLocalState()
212
- if (state instanceof Error) {
213
- snapshot.captureError = state.message
214
- } else if (state) {
215
- snapshot.captures = {
216
- lines: { [probe.location.lines[0]]: { locals: state } }
217
- }
224
+ if (captureErrors?.length > 0) {
225
+ // There was an error collecting the snapshot for this probe, let's not try again
226
+ probe.captureSnapshot = false
227
+ probe.permanentEvaluationErrors = captureErrors.map(error => ({
228
+ expr: '',
229
+ message: error.message
230
+ }))
218
231
  }
232
+ snapshot.captures = {
233
+ lines: { [probe.location.lines[0]]: { locals: processLocalState() } }
234
+ }
235
+ }
236
+
237
+ if (probe.permanentEvaluationErrors !== undefined) {
238
+ snapshot.evaluationErrors = [...probe.permanentEvaluationErrors]
219
239
  }
220
240
 
221
241
  let message = ''
@@ -5,6 +5,7 @@
5
5
  const { builtinModules } = require('node:module')
6
6
 
7
7
  if (builtinModules.includes('inspector/promises')) {
8
+ // @ts-ignore - inspector/promises is available in Node.js 20+ but not in @types/node@18
8
9
  module.exports = require('node:inspector/promises')
9
10
  } else {
10
11
  const inspector = require('node:inspector')
@@ -12,6 +13,7 @@ if (builtinModules.includes('inspector/promises')) {
12
13
 
13
14
  // The rest of the code in this file is lifted from:
14
15
  // https://github.com/nodejs/node/blob/1d4d76ff3fb08f9a0c55a1d5530b46c4d5d550c7/lib/inspector/promises.js
16
+ // @ts-expect-error - We intentionally override 'post' with a promisified version, changing its signature
15
17
  class Session extends inspector.Session {
16
18
  constructor () { super() } // eslint-disable-line no-useless-constructor
17
19
  }
@@ -1,34 +1,40 @@
1
1
  'use strict'
2
2
 
3
3
  class JSONBuffer {
4
+ #maxSize
5
+ #timeout
6
+ #onFlush
7
+ #timer
8
+ #partialJson
9
+
4
10
  constructor ({ size, timeout, onFlush }) {
5
- this._maxSize = size
6
- this._timeout = timeout
7
- this._onFlush = onFlush
8
- this._reset()
11
+ this.#maxSize = size
12
+ this.#timeout = timeout
13
+ this.#onFlush = onFlush
14
+ this.#reset()
9
15
  }
10
16
 
11
- _reset () {
12
- clearTimeout(this._timer)
13
- this._timer = null
14
- this._partialJson = null
17
+ #reset () {
18
+ clearTimeout(this.#timer)
19
+ this.#timer = undefined
20
+ this.#partialJson = undefined
15
21
  }
16
22
 
17
- _flush () {
18
- const json = `${this._partialJson}]`
19
- this._reset()
20
- this._onFlush(json)
23
+ #flush () {
24
+ const json = `${this.#partialJson}]`
25
+ this.#reset()
26
+ this.#onFlush(json)
21
27
  }
22
28
 
23
29
  write (str, size = Buffer.byteLength(str)) {
24
- if (this._timer === null) {
25
- this._partialJson = `[${str}`
26
- this._timer = setTimeout(() => this._flush(), this._timeout)
27
- } else if (Buffer.byteLength(this._partialJson) + size + 2 > this._maxSize) {
28
- this._flush()
30
+ if (this.#timer === undefined) {
31
+ this.#partialJson = `[${str}`
32
+ this.#timer = setTimeout(() => this.#flush(), this.#timeout)
33
+ } else if (Buffer.byteLength(/** @type {string} */ (this.#partialJson)) + size + 2 > this.#maxSize) {
34
+ this.#flush()
29
35
  this.write(str, size)
30
36
  } else {
31
- this._partialJson += `,${str}`
37
+ this.#partialJson += `,${str}`
32
38
  }
33
39
  }
34
40
  }
@@ -3,13 +3,14 @@
3
3
  const { hostname: getHostname } = require('os')
4
4
  const { stringify } = require('querystring')
5
5
 
6
- const config = require('./config')
7
- const JSONBuffer = require('./json-buffer')
8
6
  const request = require('../../exporters/common/request')
9
7
  const { GIT_COMMIT_SHA, GIT_REPOSITORY_URL } = require('../../plugins/util/tags')
10
- const log = require('./log')
11
8
  const { version } = require('../../../../../package.json')
12
9
  const { getEnvironmentVariable } = require('../../config-helper')
10
+ const log = require('./log')
11
+ const JSONBuffer = require('./json-buffer')
12
+ const config = require('./config')
13
+ const { pruneSnapshot } = require('./snapshot-pruner')
13
14
 
14
15
  module.exports = send
15
16
 
@@ -55,14 +56,23 @@ function send (message, logger, dd, snapshot) {
55
56
  let size = Buffer.byteLength(json)
56
57
 
57
58
  if (size > MAX_LOG_PAYLOAD_SIZE_BYTES) {
58
- // TODO: This is a very crude way to handle large payloads. Proper pruning will be implemented later (DEBUG-2624)
59
- delete payload.debugger.snapshot.captures
60
- payload.debugger.snapshot.captureError =
61
- `Snapshot was too large (max allowed size is ${MAX_LOG_PAYLOAD_SIZE_MB} MiB). ` +
62
- 'Consider reducing the capture depth or turn off "Capture Variables" completely, ' +
63
- 'and instead include the variables of interest directly in the message template.'
64
- json = JSON.stringify(payload)
65
- size = Buffer.byteLength(json)
59
+ let pruned
60
+ try {
61
+ pruned = pruneSnapshot(json, size, MAX_LOG_PAYLOAD_SIZE_BYTES)
62
+ } catch (err) {
63
+ log.error('[debugger:devtools_client] Error pruning snapshot', err)
64
+ }
65
+
66
+ if (pruned) {
67
+ json = pruned
68
+ size = Buffer.byteLength(json)
69
+ } else {
70
+ // Fallback if pruning fails
71
+ const line = Object.keys(snapshot.captures.lines)[0]
72
+ snapshot.captures.lines[line] = { pruned: true }
73
+ json = JSON.stringify(payload)
74
+ size = Buffer.byteLength(json)
75
+ }
66
76
  }
67
77
 
68
78
  jsonBuffer.write(json, size)
@@ -7,7 +7,7 @@ const inspector = require('./inspector_promises_polyfill')
7
7
  * connect: () => void,
8
8
  * connectToMainThread: () => void
9
9
  * disconnect: () => void,
10
- * post: (method: string, params?: object) => Promise<any>,
10
+ * post: (method: string, params?: object) => Promise<unknown>,
11
11
  * }} CDPSession
12
12
  */
13
13
  const session = /** @type {CDPSession} */ (new inspector.Session())
@@ -1,16 +1,42 @@
1
1
  'use strict'
2
2
 
3
- const { collectionSizeSym, fieldCountSym } = require('./symbols')
4
3
  const session = require('../session')
4
+ const { collectionSizeSym, largeCollectionSkipThresholdSym, fieldCountSym, timeBudgetSym } = require('./symbols')
5
+ const { LARGE_OBJECT_SKIP_THRESHOLD } = require('./constants')
5
6
 
6
7
  const LEAF_SUBTYPES = new Set(['date', 'regexp'])
7
8
  const ITERABLE_SUBTYPES = new Set(['map', 'set', 'weakmap', 'weakset'])
9
+ const SIZE_IN_DESCRIPTION_SUBTYPES = new Set(['array', 'typedarray', 'arraybuffer', 'dataview', 'map', 'set'])
8
10
 
9
11
  module.exports = {
10
- getRuntimeObject: getObject
12
+ collectObjectProperties
11
13
  }
12
14
 
13
- async function getObject (objectId, opts, depth = 0, collection = false) {
15
+ /**
16
+ * @typedef {object} GetObjectOptions
17
+ * @property {object} maxReferenceDepth - The maximum depth of the object to traverse
18
+ * @property {number} maxCollectionSize - The maximum size of a collection to include in the snapshot
19
+ * @property {number} maxFieldCount - The maximum number of properties on an object to include in the snapshot
20
+ * @property {bigint} deadlineNs - The deadline in nanoseconds compared to `process.hrtime.bigint()`
21
+ * @property {object} ctx - A context object to track the state/progress of the snapshot collection.
22
+ * @property {boolean} ctx.deadlineReached - Will be set to `true` if the deadline has been reached.
23
+ * @property {Error[]} ctx.captureErrors - An array on which errors can be pushed if an issue is detected while
24
+ * collecting the snapshot.
25
+ */
26
+
27
+ /**
28
+ * Collect the properties of an object using the Chrome DevTools Protocol.
29
+ *
30
+ * @param {string} objectId - The ID of the object to get the properties of
31
+ * @param {GetObjectOptions} opts - The options for the snapshot. Also used to track the deadline and communicate the
32
+ * deadline overrun to the caller using the `deadlineReached` flag.
33
+ * @param {number} [depth=0] - The depth of the object. Only used internally by this module to track the current depth
34
+ * and should not be set by the caller.
35
+ * @param {boolean} [collection=false] - Whether the object is a collection. Only used internally by this module to
36
+ * track the current object type and should not be set by the caller.
37
+ * @returns {Promise<object[]>} The properties of the object
38
+ */
39
+ async function collectObjectProperties (objectId, opts, depth = 0, collection = false) {
14
40
  const { result, privateProperties } = await session.post('Runtime.getProperties', {
15
41
  objectId,
16
42
  ownProperties: true // exclude inherited properties
@@ -28,6 +54,13 @@ async function getObject (objectId, opts, depth = 0, collection = false) {
28
54
  } else if (result.length > opts.maxFieldCount) {
29
55
  // Trim the number of properties on the object if there's too many.
30
56
  const size = result.length
57
+ if (size > LARGE_OBJECT_SKIP_THRESHOLD) {
58
+ opts.ctx.captureErrors.push(new Error(
59
+ `An object with ${size} properties was detected while collecting a snapshot. ` +
60
+ `This exceeds the maximum number of allowed properties of ${LARGE_OBJECT_SKIP_THRESHOLD}. ` +
61
+ 'Future snapshots for existing probes in this location will be skipped until the Node.js process is restarted'
62
+ ))
63
+ }
31
64
  result.length = opts.maxFieldCount
32
65
  result[fieldCountSym] = size
33
66
  } else if (privateProperties) {
@@ -43,32 +76,61 @@ async function traverseGetPropertiesResult (props, opts, depth) {
43
76
 
44
77
  if (depth >= opts.maxReferenceDepth) return props
45
78
 
46
- const promises = []
79
+ const work = []
47
80
 
48
81
  for (const prop of props) {
49
82
  if (prop.value === undefined) continue
50
- const { value: { type, objectId, subtype } } = prop
83
+ const { value: { type, objectId, subtype, description } } = prop
51
84
  if (type === 'object') {
52
85
  if (objectId === undefined) continue // if `subtype` is "null"
53
86
  if (LEAF_SUBTYPES.has(subtype)) continue // don't waste time with these subtypes
54
- promises.push(getObjectProperties(subtype, objectId, opts, depth).then((properties) => {
55
- prop.value.properties = properties
56
- }))
87
+ const size = parseLengthFromDescription(description, subtype)
88
+ if (size !== null && size >= LARGE_OBJECT_SKIP_THRESHOLD) {
89
+ const empty = []
90
+ empty[largeCollectionSkipThresholdSym] = size
91
+ prop.value.properties = empty
92
+ continue
93
+ }
94
+ work.push([
95
+ prop.value,
96
+ () => collectPropertiesBySubtype(subtype, objectId, opts, depth).then((properties) => {
97
+ prop.value.properties = properties
98
+ })
99
+ ])
57
100
  } else if (type === 'function') {
58
- promises.push(getFunctionProperties(objectId, opts, depth + 1).then((properties) => {
59
- prop.value.properties = properties
60
- }))
101
+ work.push([
102
+ prop.value,
103
+ () => getFunctionProperties(objectId, opts, depth + 1).then((properties) => {
104
+ prop.value.properties = properties
105
+ })
106
+ ])
61
107
  }
62
108
  }
63
109
 
64
- if (promises.length) {
65
- await Promise.all(promises)
110
+ if (work.length) {
111
+ // Iterate over the work in chunks of 2. The closer to 1, the less we'll overshoot the deadline, but the longer it
112
+ // takes to complete. `2` seems to be the best compromise.
113
+ // Anecdotally, on my machine, with no deadline, a concurrency of `1` takes twice as long as a concurrency of `2`.
114
+ // From thereon, there's no real measurable savings with a higher concurrency.
115
+ for (let i = 0; i < work.length; i += 2) {
116
+ if (overBudget(opts)) {
117
+ for (let j = i; j < work.length; j++) {
118
+ work[j][0][timeBudgetSym] = true
119
+ }
120
+ break
121
+ }
122
+ // eslint-disable-next-line no-await-in-loop
123
+ await Promise.all([
124
+ work[i][1](),
125
+ work[i + 1]?.[1]()
126
+ ])
127
+ }
66
128
  }
67
129
 
68
130
  return props
69
131
  }
70
132
 
71
- function getObjectProperties (subtype, objectId, opts, depth) {
133
+ function collectPropertiesBySubtype (subtype, objectId, opts, depth) {
72
134
  if (ITERABLE_SUBTYPES.has(subtype)) {
73
135
  return getIterable(objectId, opts, depth)
74
136
  } else if (subtype === 'promise') {
@@ -78,7 +140,7 @@ function getObjectProperties (subtype, objectId, opts, depth) {
78
140
  } else if (subtype === 'arraybuffer') {
79
141
  return getArrayBuffer(objectId, opts, depth)
80
142
  }
81
- return getObject(objectId, opts, depth + 1, subtype === 'array' || subtype === 'typedarray')
143
+ return collectObjectProperties(objectId, opts, depth + 1, subtype === 'array' || subtype === 'typedarray')
82
144
  }
83
145
 
84
146
  // TODO: The following extra information from `internalProperties` might be relevant to include for functions:
@@ -189,3 +251,29 @@ function removeNonEnumerableProperties (props) {
189
251
  }
190
252
  }
191
253
  }
254
+
255
+ function parseLengthFromDescription (description, subtype) {
256
+ if (typeof description !== 'string') return null
257
+ if (!SIZE_IN_DESCRIPTION_SUBTYPES.has(subtype)) return null
258
+
259
+ const open = description.lastIndexOf('(')
260
+ if (open === -1) return null
261
+
262
+ const close = description.indexOf(')', open + 1)
263
+ if (close === -1) return null
264
+
265
+ const s = description.slice(open + 1, close)
266
+ if (s === '') return null
267
+
268
+ const n = Number(s)
269
+ if (!Number.isSafeInteger(n) || n < 0) return null
270
+ if (String(n) !== s) return null
271
+
272
+ return n
273
+ }
274
+
275
+ function overBudget (opts) {
276
+ if (opts.ctx.deadlineReached) return true
277
+ opts.ctx.deadlineReached = process.hrtime.bigint() >= opts.deadlineNs
278
+ return opts.ctx.deadlineReached
279
+ }
@@ -0,0 +1,25 @@
1
+ 'use strict'
2
+
3
+ const { getEnvironmentVariable } = require('../../../config-helper')
4
+
5
+ const largeObjectSkipThreshold = Number(
6
+ getEnvironmentVariable('_DD_DYNAMIC_INSTRUMENTATION_EXPERIMENTAL_LARGE_OBJECT_SKIP_THRESHOLD')
7
+ )
8
+
9
+ module.exports = {
10
+ /**
11
+ * When collecting a snapshot, this constant controls what happens when objects with a large number of properties or
12
+ * collections (arrays, maps, sets, etc.) with a large number of elements are detected:
13
+ *
14
+ * - If a collection is detected with more than this number of elements, none of its elements will be included in the
15
+ * snapshot.
16
+ * - If an object is detected with more than this number of properties, it will be included in the snapshot, but
17
+ * snapshotting will be turned off for that probe in the future, until the probe is either updated or the Node.js
18
+ * process is restarted.
19
+ */
20
+ LARGE_OBJECT_SKIP_THRESHOLD: Number.isNaN(largeObjectSkipThreshold) ? 500 : largeObjectSkipThreshold,
21
+ DEFAULT_MAX_COLLECTION_SIZE: 100,
22
+ DEFAULT_MAX_FIELD_COUNT: 20,
23
+ DEFAULT_MAX_LENGTH: 255,
24
+ DEFAULT_MAX_REFERENCE_DEPTH: 3,
25
+ }
@@ -1,52 +1,83 @@
1
1
  'use strict'
2
2
 
3
- const { getRuntimeObject } = require('./collector')
3
+ const {
4
+ DEFAULT_MAX_REFERENCE_DEPTH,
5
+ DEFAULT_MAX_COLLECTION_SIZE,
6
+ DEFAULT_MAX_FIELD_COUNT,
7
+ DEFAULT_MAX_LENGTH
8
+ } = require('./constants')
9
+ const { collectObjectProperties } = require('./collector')
4
10
  const { processRawState } = require('./processor')
5
- const log = require('../log')
6
11
 
7
- const DEFAULT_MAX_REFERENCE_DEPTH = 3
8
- const DEFAULT_MAX_COLLECTION_SIZE = 100
9
- const DEFAULT_MAX_FIELD_COUNT = 20
10
- const DEFAULT_MAX_LENGTH = 255
12
+ const BIGINT_MAX = (1n << 256n) - 1n
11
13
 
12
14
  module.exports = {
13
15
  getLocalStateForCallFrame
14
16
  }
15
17
 
16
- function returnError () {
17
- return new Error('Error getting local state')
18
- }
18
+ /**
19
+ * @typedef {object} GetLocalStateForCallFrameOptions
20
+ * @property {number} [maxReferenceDepth] - The maximum depth of the object to traverse. Defaults to
21
+ * {@link DEFAULT_MAX_REFERENCE_DEPTH}.
22
+ * @property {number} [maxCollectionSize] - The maximum size of a collection to include in the snapshot. Defaults to
23
+ * {@link DEFAULT_MAX_COLLECTION_SIZE}.
24
+ * @property {number} [maxFieldCount] - The maximum number of properties on an object to include in the snapshot.
25
+ * Defaults to {@link DEFAULT_MAX_FIELD_COUNT}.
26
+ * @property {number} [maxLength] - The maximum length of a string to include in the snapshot. Defaults to
27
+ * {@link DEFAULT_MAX_LENGTH}.
28
+ * @property {bigint} [deadlineNs] - The deadline in nanoseconds compared to `process.hrtime.bigint()`. Defaults to
29
+ * {@link BIGINT_MAX}. If the deadline is reached, the snapshot will be truncated.
30
+ */
19
31
 
32
+ /**
33
+ * Get the local state for a call frame.
34
+ *
35
+ * @param {import('inspector').Debugger.CallFrame} callFrame - The call frame to get the local state for
36
+ * @param {GetLocalStateForCallFrameOptions} [opts] - The options for the snapshot
37
+ * @returns {Promise<object>} The local state for the call frame
38
+ */
20
39
  async function getLocalStateForCallFrame (
21
40
  callFrame,
22
41
  {
23
42
  maxReferenceDepth = DEFAULT_MAX_REFERENCE_DEPTH,
24
43
  maxCollectionSize = DEFAULT_MAX_COLLECTION_SIZE,
25
44
  maxFieldCount = DEFAULT_MAX_FIELD_COUNT,
26
- maxLength = DEFAULT_MAX_LENGTH
45
+ maxLength = DEFAULT_MAX_LENGTH,
46
+ deadlineNs = BIGINT_MAX
27
47
  } = {}
28
48
  ) {
49
+ /** @type {{ deadlineReached: boolean, captureErrors: Error[] }} */
50
+ const ctx = { deadlineReached: false, captureErrors: [] }
51
+ const opts = { maxReferenceDepth, maxCollectionSize, maxFieldCount, deadlineNs, ctx }
29
52
  const rawState = []
30
53
  let processedState = null
31
54
 
32
- try {
33
- await Promise.all(callFrame.scopeChain.map(async (scope) => {
34
- if (scope.type === 'global') return // The global scope is too noisy
35
- rawState.push(...await getRuntimeObject(
36
- scope.object.objectId,
37
- { maxReferenceDepth, maxCollectionSize, maxFieldCount }
55
+ for (const scope of callFrame.scopeChain) {
56
+ if (scope.type === 'global') continue // The global scope is too noisy
57
+ const { objectId } = scope.object
58
+ if (objectId === undefined) continue // I haven't seen this happen, but according to the types it's possible
59
+ try {
60
+ // The objectId for a scope points to a pseudo-object whose properties are the actual variables in the scope.
61
+ // This is why we can just call `collectObjectProperties` directly and expect it to return the in-scope variables
62
+ // as an array.
63
+ // eslint-disable-next-line no-await-in-loop
64
+ rawState.push(...await collectObjectProperties(objectId, opts))
65
+ } catch (err) {
66
+ ctx.captureErrors.push(new Error(
67
+ `Error getting local state for closure scope (type: ${scope.type}). ` +
68
+ 'Future snapshots for existing probes in this location will be skipped until the Node.js process is restarted',
69
+ { cause: err } // TODO: The cause is not used by the backend
38
70
  ))
39
- }))
40
- } catch (err) {
41
- // TODO: We might be able to get part of the scope chain.
42
- // Consider if we could set errors just for the part of the scope chain that throws during collection.
43
- log.error('[debugger:devtools_client] Error getting local state for call frame', err)
44
- return returnError
71
+ }
72
+ if (ctx.deadlineReached === true) break // TODO: Bad UX; Variables in remaining scopes are silently dropped
45
73
  }
46
74
 
47
75
  // Delay calling `processRawState` so the caller gets a chance to resume the main thread before processing `rawState`
48
- return () => {
49
- processedState = processedState ?? processRawState(rawState, maxLength)
50
- return processedState
76
+ return {
77
+ processLocalState () {
78
+ processedState = processedState ?? processRawState(rawState, maxLength)
79
+ return processedState
80
+ },
81
+ captureErrors: ctx.captureErrors
51
82
  }
52
83
  }