dd-trace 6.12.0 → 6.14.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 (251) hide show
  1. package/LICENSE-3rdparty.csv +3 -1
  2. package/ci/init.js +8 -3
  3. package/ci/test-optimization-validation/ci-package-scripts.js +2 -2
  4. package/ci/test-optimization-validation/ci-remediation.js +6 -6
  5. package/ci/test-optimization-validation/command-blocker.js +7 -5
  6. package/ci/test-optimization-validation/framework-adapters/cucumber.js +1 -1
  7. package/ci/test-optimization-validation/framework-adapters/cypress.js +9 -11
  8. package/ci/test-optimization-validation/framework-adapters/vitest.js +3 -3
  9. package/ci/test-optimization-validation/package-check.js +1 -1
  10. package/ci/test-optimization-validation/report-writer.js +7 -5
  11. package/ci/test-optimization-validation/scenarios/ci-wiring.js +5 -4
  12. package/ci/vitest-no-worker-init-runner-setup.mjs +8 -0
  13. package/ci/vitest-no-worker-init-setup.mjs +13 -13
  14. package/ci/vitest-no-worker-init-v5-setup.mjs +4 -0
  15. package/index.d.ts +127 -26
  16. package/package.json +22 -19
  17. package/packages/datadog-esbuild/index.js +3 -1
  18. package/packages/datadog-instrumentations/src/bunyan.js +4 -2
  19. package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
  20. package/packages/datadog-instrumentations/src/fs.js +24 -20
  21. package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
  22. package/packages/datadog-instrumentations/src/graphql.js +16 -16
  23. package/packages/datadog-instrumentations/src/helpers/bunyan.js +12 -3
  24. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
  25. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  26. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +266 -0
  27. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
  28. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
  29. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
  30. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
  31. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
  32. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  33. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
  34. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +13 -0
  35. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +279 -0
  36. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +12 -1
  37. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
  38. package/packages/datadog-instrumentations/src/jest.js +165 -38
  39. package/packages/datadog-instrumentations/src/knex.js +76 -0
  40. package/packages/datadog-instrumentations/src/mariadb-bundle.js +1597 -0
  41. package/packages/datadog-instrumentations/src/mariadb.js +13 -0
  42. package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
  43. package/packages/datadog-instrumentations/src/mocha/main.js +25 -15
  44. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
  45. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
  46. package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
  47. package/packages/datadog-instrumentations/src/net.js +14 -17
  48. package/packages/datadog-instrumentations/src/next.js +212 -62
  49. package/packages/datadog-instrumentations/src/openai.js +42 -40
  50. package/packages/datadog-instrumentations/src/pg.js +15 -0
  51. package/packages/datadog-instrumentations/src/pino.js +15 -4
  52. package/packages/datadog-instrumentations/src/playwright.js +137 -27
  53. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
  54. package/packages/datadog-instrumentations/src/sequelize.js +94 -2
  55. package/packages/datadog-instrumentations/src/undici.js +53 -4
  56. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +44 -7
  57. package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
  58. package/packages/datadog-instrumentations/src/vitest-worker.js +82 -14
  59. package/packages/datadog-instrumentations/src/webdriverio.js +986 -1
  60. package/packages/datadog-instrumentations/src/winston.js +6 -3
  61. package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
  62. package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
  63. package/packages/datadog-plugin-amqp10/src/util.js +2 -1
  64. package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
  65. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
  66. package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
  67. package/packages/datadog-plugin-cucumber/src/index.js +0 -2
  68. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
  69. package/packages/datadog-plugin-cypress/src/support.js +1 -0
  70. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
  71. package/packages/datadog-plugin-graphql/src/execute.js +998 -196
  72. package/packages/datadog-plugin-graphql/src/index.js +27 -7
  73. package/packages/datadog-plugin-graphql/src/jit.js +136 -0
  74. package/packages/datadog-plugin-graphql/src/request.js +18 -27
  75. package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
  76. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
  77. package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
  78. package/packages/datadog-plugin-graphql/src/utils.js +208 -120
  79. package/packages/datadog-plugin-graphql/src/validate.js +10 -23
  80. package/packages/datadog-plugin-http/src/client.js +2 -15
  81. package/packages/datadog-plugin-http2/src/client.js +2 -15
  82. package/packages/datadog-plugin-jest/src/index.js +0 -6
  83. package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
  84. package/packages/datadog-plugin-mocha/src/index.js +403 -75
  85. package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
  86. package/packages/datadog-plugin-mysql/src/index.js +41 -15
  87. package/packages/datadog-plugin-net/src/tcp.js +3 -1
  88. package/packages/datadog-plugin-next/src/index.js +63 -29
  89. package/packages/datadog-plugin-openai-agents/src/integration.js +15 -11
  90. package/packages/datadog-plugin-playwright/src/index.js +176 -28
  91. package/packages/datadog-plugin-undici/src/index.js +29 -56
  92. package/packages/datadog-plugin-vitest/src/index.js +6 -12
  93. package/packages/dd-trace/src/aiguard/evaluation.js +96 -21
  94. package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -3
  95. package/packages/dd-trace/src/aiguard/messages/anthropic.js +29 -10
  96. package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
  97. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
  98. package/packages/dd-trace/src/aiguard/noop.js +9 -1
  99. package/packages/dd-trace/src/aiguard/redaction.js +183 -0
  100. package/packages/dd-trace/src/aiguard/sdk.js +7 -2
  101. package/packages/dd-trace/src/aiguard/tags.js +2 -0
  102. package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
  103. package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
  104. package/packages/dd-trace/src/appsec/graphql.js +6 -2
  105. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
  106. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
  107. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
  108. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +11 -36
  109. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
  110. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +10 -9
  111. package/packages/dd-trace/src/appsec/lambda.js +44 -26
  112. package/packages/dd-trace/src/appsec/rule_manager.js +2 -0
  113. package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
  114. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
  115. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
  116. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
  117. package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +7 -150
  118. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
  119. package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
  120. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
  121. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +397 -234
  122. package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
  123. package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
  124. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
  125. package/packages/dd-trace/src/ci-visibility/final-flush.js +21 -0
  126. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
  127. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
  128. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
  129. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +176 -0
  130. package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
  131. package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
  132. package/packages/dd-trace/src/config/generated-config-types.d.ts +10 -0
  133. package/packages/dd-trace/src/config/index.js +75 -14
  134. package/packages/dd-trace/src/config/parsers.js +11 -1
  135. package/packages/dd-trace/src/config/stable.js +3 -3
  136. package/packages/dd-trace/src/config/supported-configurations.json +47 -2
  137. package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
  138. package/packages/dd-trace/src/debugger/config.js +12 -1
  139. package/packages/dd-trace/src/debugger/constants.js +1 -0
  140. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
  141. package/packages/dd-trace/src/debugger/devtools_client/request-options.js +33 -0
  142. package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -39
  143. package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
  144. package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
  145. package/packages/dd-trace/src/debugger/index.js +23 -3
  146. package/packages/dd-trace/src/dogstatsd.js +532 -71
  147. package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
  148. package/packages/dd-trace/src/encode/0.4.js +5 -5
  149. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
  150. package/packages/dd-trace/src/evp_proxy/direct.js +27 -23
  151. package/packages/dd-trace/src/exporters/agent/index.js +24 -3
  152. package/packages/dd-trace/src/exporters/agent/writer.js +28 -11
  153. package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
  154. package/packages/dd-trace/src/exporters/agentless/writer.js +100 -118
  155. package/packages/dd-trace/src/exporters/common/agents.js +28 -6
  156. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
  157. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
  158. package/packages/dd-trace/src/exporters/common/request.js +31 -11
  159. package/packages/dd-trace/src/exporters/common/url.js +40 -1
  160. package/packages/dd-trace/src/exporters/common/writer.js +31 -7
  161. package/packages/dd-trace/src/exporters/span-stats/index.js +23 -4
  162. package/packages/dd-trace/src/external-logger/src/index.js +4 -3
  163. package/packages/dd-trace/src/flush.js +105 -0
  164. package/packages/dd-trace/src/id.js +14 -0
  165. package/packages/dd-trace/src/index.js +5 -2
  166. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -0
  167. package/packages/dd-trace/src/llmobs/experiments/dataset.js +52 -2
  168. package/packages/dd-trace/src/llmobs/experiments/experiment.js +420 -105
  169. package/packages/dd-trace/src/llmobs/experiments/index.js +54 -42
  170. package/packages/dd-trace/src/llmobs/experiments/noop.js +39 -8
  171. package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
  172. package/packages/dd-trace/src/llmobs/experiments/util.js +21 -0
  173. package/packages/dd-trace/src/llmobs/index.js +111 -48
  174. package/packages/dd-trace/src/llmobs/noop.js +2 -1
  175. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
  176. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
  177. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +8 -4
  178. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +6 -3
  179. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
  180. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +13 -6
  181. package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +5 -7
  182. package/packages/dd-trace/src/llmobs/util.js +0 -33
  183. package/packages/dd-trace/src/llmobs/writers/base.js +106 -53
  184. package/packages/dd-trace/src/log/index.js +7 -1
  185. package/packages/dd-trace/src/log-submission/log-submission-plugin.js +249 -0
  186. package/packages/dd-trace/src/noop/span.js +5 -0
  187. package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
  188. package/packages/dd-trace/src/openfeature/writers/exposures.js +8 -1
  189. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  190. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +45 -3
  191. package/packages/dd-trace/src/opentelemetry/logs/index.js +9 -25
  192. package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +7 -4
  193. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
  194. package/packages/dd-trace/src/opentelemetry/metrics/index.js +18 -23
  195. package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +8 -0
  196. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +18 -6
  197. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +14 -2
  198. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +25 -5
  199. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +61 -25
  200. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
  201. package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
  202. package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
  203. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
  204. package/packages/dd-trace/src/opentelemetry/tracer.js +26 -2
  205. package/packages/dd-trace/src/opentracing/propagation/text_map.js +494 -351
  206. package/packages/dd-trace/src/opentracing/span.js +28 -0
  207. package/packages/dd-trace/src/otel-thread-ctx.js +23 -5
  208. package/packages/dd-trace/src/payload-tagging/index.js +2 -1
  209. package/packages/dd-trace/src/plugin_manager.js +2 -0
  210. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
  211. package/packages/dd-trace/src/plugins/tracing.js +12 -10
  212. package/packages/dd-trace/src/plugins/util/ci.js +3 -1
  213. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
  214. package/packages/dd-trace/src/plugins/util/status-validator.js +98 -0
  215. package/packages/dd-trace/src/plugins/util/test.js +157 -41
  216. package/packages/dd-trace/src/plugins/util/url.js +2 -2
  217. package/packages/dd-trace/src/plugins/util/web.js +6 -74
  218. package/packages/dd-trace/src/profiling/config.js +1 -0
  219. package/packages/dd-trace/src/profiling/oom.js +11 -5
  220. package/packages/dd-trace/src/profiling/profiler.js +30 -13
  221. package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
  222. package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
  223. package/packages/dd-trace/src/profiling/profilers/wall.js +14 -14
  224. package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
  225. package/packages/dd-trace/src/proxy.js +108 -10
  226. package/packages/dd-trace/src/remote_config/index.js +319 -101
  227. package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
  228. package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
  229. package/packages/dd-trace/src/runtime_metrics/index.js +5 -0
  230. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +10 -1
  231. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +22 -7
  232. package/packages/dd-trace/src/sampling_rule.js +36 -9
  233. package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +51 -0
  234. package/packages/dd-trace/src/serverless/vercel.js +155 -0
  235. package/packages/dd-trace/src/serverless.js +45 -21
  236. package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
  237. package/packages/dd-trace/src/span_stats.js +64 -31
  238. package/packages/dd-trace/src/startup-log.js +3 -2
  239. package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
  240. package/packages/dd-trace/src/telemetry/send-data.js +18 -16
  241. package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
  242. package/packages/dd-trace/src/tracer.js +26 -5
  243. package/packages/dd-trace/src/tracer_metadata.js +11 -3
  244. package/packages/dd-trace/src/web-tags-cache.js +67 -13
  245. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
  246. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  247. package/vendor/dist/protobufjs/index.js +1 -1
  248. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  249. package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +0 -27
  250. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +0 -53
  251. package/packages/dd-trace/src/encode/agentless-json.js +0 -209
@@ -1,21 +1,24 @@
1
1
  'use strict'
2
2
 
3
- const { DogStatsDClient, MetricsAggregationClient } = require('../dogstatsd')
3
+ const { channel } = require('dc-polyfill')
4
+ const { DogStatsDClient, createMetricsAggregationClient } = require('../dogstatsd')
4
5
  const processTags = require('../process-tags')
5
6
 
7
+ const identityRefreshChannel = channel('datadog:identity:refresh')
8
+
6
9
  /**
7
- * Builds the aggregating DogStatsD client used to emit DD-proprietary tracer
8
- * metrics (runtime.node.*, datadog.tracer.*). Shared by both runtime-metrics
9
- * paths (DogStatsD and OTLP) so their client construction can't drift apart.
10
+ * Builds the DogStatsD tags (with process tags applied) for the runtime-metrics client.
11
+ * Shared by `createMetricsClient()` and `subscribeToIdentityRefresh()` so their tag
12
+ * composition can't drift apart.
10
13
  *
11
14
  * Process tags are applied here, not via config/generateClientConfig, so they only
12
15
  * reach this bounded set of runtime metrics. Putting them on the global tags would
13
16
  * also tag user-facing custom metrics, inflating their cardinality (and billing).
14
17
  *
15
18
  * @param {import('../config/config-base')} config - Tracer configuration
16
- * @returns {MetricsAggregationClient}
19
+ * @returns {{ host: string, port: number, tags: string[], lookup: Function, metricsProxyUrl?: URL }}
17
20
  */
18
- function createMetricsClient (config) {
21
+ function buildClientConfig (config) {
19
22
  const clientConfig = DogStatsDClient.generateClientConfig(config)
20
23
 
21
24
  if (config.DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED) {
@@ -24,7 +27,33 @@ function createMetricsClient (config) {
24
27
  }
25
28
  }
26
29
 
27
- return new MetricsAggregationClient(new DogStatsDClient(clientConfig))
30
+ return clientConfig
31
+ }
32
+
33
+ /**
34
+ * Builds the aggregating DogStatsD client used to emit DD-proprietary tracer
35
+ * metrics (runtime.node.*, datadog.tracer.*). Shared by both runtime-metrics
36
+ * paths (DogStatsD and OTLP) so their client construction can't drift apart.
37
+ *
38
+ * @param {import('../config/config-base')} config - Tracer configuration
39
+ * @returns {ReturnType<typeof createMetricsAggregationClient>}
40
+ */
41
+ function createMetricsClient (config) {
42
+ return createMetricsAggregationClient(buildClientConfig(config))
43
+ }
44
+
45
+ /**
46
+ * Subscribes a runtime-metrics client to the identity-refresh channel so its DogStatsD tags
47
+ * (runtime-id, RC client id) reflect `config.tags` after a MicroVM clone resume.
48
+ *
49
+ * @param {ReturnType<typeof createMetricsAggregationClient>} client - The client returned by `createMetricsClient()`
50
+ * @param {import('../config/config-base')} config - Tracer configuration
51
+ * @returns {() => void} Unsubscribe function; call it from the owning module's `stop()`
52
+ */
53
+ function subscribeToIdentityRefresh (client, config) {
54
+ const onIdentityRefresh = () => client.updateTags(buildClientConfig(config).tags)
55
+ identityRefreshChannel.subscribe(onIdentityRefresh)
56
+ return () => identityRefreshChannel.unsubscribe(onIdentityRefresh)
28
57
  }
29
58
 
30
- module.exports = { createMetricsClient }
59
+ module.exports = { createMetricsClient, subscribeToIdentityRefresh }
@@ -13,6 +13,7 @@ const noop = runtimeMetrics = {
13
13
  gauge () {},
14
14
  increment () {},
15
15
  decrement () {},
16
+ flush (done) { done?.() },
16
17
  }
17
18
 
18
19
  module.exports = {
@@ -42,6 +43,10 @@ module.exports = {
42
43
  runtimeMetrics = noop
43
44
  Object.setPrototypeOf(module.exports, noop)
44
45
  },
46
+
47
+ flush (done) {
48
+ runtimeMetrics.flush(done)
49
+ },
45
50
  }
46
51
 
47
52
  Object.setPrototypeOf(module.exports, noop)
@@ -5,7 +5,7 @@ const process = require('node:process')
5
5
  const { performance, monitorEventLoopDelay, PerformanceObserver, constants } = require('node:perf_hooks')
6
6
  const { metrics } = require('@opentelemetry/api')
7
7
  const log = require('../log')
8
- const { createMetricsClient } = require('./client')
8
+ const { createMetricsClient, subscribeToIdentityRefresh } = require('./client')
9
9
 
10
10
  const METER_NAME = 'datadog.runtime_metrics'
11
11
 
@@ -53,6 +53,7 @@ const registeredBatchCallbacks = []
53
53
  // equivalent; keep a DogStatsD client so OTLP-path customers don't lose them.
54
54
  let client = null
55
55
  let flushInterval = null
56
+ let unsubscribeIdentityRefresh = null
56
57
 
57
58
  module.exports = {
58
59
  /**
@@ -62,6 +63,7 @@ module.exports = {
62
63
  this.stop()
63
64
 
64
65
  client = createMetricsClient(config)
66
+ unsubscribeIdentityRefresh = subscribeToIdentityRefresh(client, config)
65
67
  flushInterval = setInterval(() => {
66
68
  client.flush()
67
69
  }, config.DD_RUNTIME_METRICS_FLUSH_INTERVAL ?? 10_000)
@@ -221,6 +223,8 @@ module.exports = {
221
223
  clearInterval(flushInterval)
222
224
  flushInterval = null
223
225
  }
226
+ unsubscribeIdentityRefresh?.()
227
+ unsubscribeIdentityRefresh = null
224
228
  client = null
225
229
  },
226
230
 
@@ -245,6 +249,11 @@ module.exports = {
245
249
  decrement (name, tag) {
246
250
  this.count(name, -1, tag)
247
251
  },
252
+
253
+ flush (done) {
254
+ if (client) return client.flush(done)
255
+ done?.()
256
+ },
248
257
  }
249
258
 
250
259
  /**
@@ -8,7 +8,7 @@ const process = require('process')
8
8
  const { performance, PerformanceObserver, monitorEventLoopDelay } = require('perf_hooks')
9
9
  const log = require('../log')
10
10
  const { NODE_MAJOR, NODE_MINOR } = require('../../../../version')
11
- const { createMetricsClient } = require('./client')
11
+ const { createMetricsClient, subscribeToIdentityRefresh } = require('./client')
12
12
 
13
13
  const eventLoopDelayResolution = 4
14
14
  const EVENT_LOOP_SAMPLE_PER_ITERATION_AVAILABLE = NODE_MAJOR > 26 ||
@@ -27,6 +27,8 @@ let client = null
27
27
  let lastTime = 0
28
28
  let lastCpuUsage = null
29
29
  let eventLoopDelayObserver = null
30
+ let capture = null
31
+ let unsubscribeIdentityRefresh = null
30
32
 
31
33
  // !!!!!!!!!!!
32
34
  // IMPORTANT
@@ -48,6 +50,7 @@ module.exports = {
48
50
  const trackGc = config.runtimeMetrics.gc !== false
49
51
 
50
52
  client = createMetricsClient(config)
53
+ unsubscribeIdentityRefresh = subscribeToIdentityRefresh(client, config)
51
54
 
52
55
  if (trackGc) {
53
56
  startGCObserver()
@@ -76,11 +79,10 @@ module.exports = {
76
79
  lastTime = performance.now()
77
80
 
78
81
  if (nativeMetrics) {
79
- interval = setInterval(() => {
82
+ capture = () => {
80
83
  captureNativeMetrics(trackEventLoop, trackGc)
81
84
  captureCommonMetrics(trackEventLoop)
82
- client.flush()
83
- }, flushIntervalMs)
85
+ }
84
86
  } else {
85
87
  lastCpuUsage = process.cpuUsage()
86
88
 
@@ -92,17 +94,21 @@ module.exports = {
92
94
  eventLoopDelayObserver.enable()
93
95
  }
94
96
 
95
- interval = setInterval(() => {
97
+ capture = () => {
96
98
  captureCpuUsage()
97
99
  captureCommonMetrics(trackEventLoop)
98
100
  captureHeapSpace()
99
101
  if (trackEventLoop) {
100
102
  captureEventLoopDelay()
101
103
  }
102
- client.flush()
103
- }, flushIntervalMs)
104
+ }
104
105
  }
105
106
 
107
+ interval = setInterval(() => {
108
+ capture()
109
+ client.flush()
110
+ }, flushIntervalMs)
111
+
106
112
  interval.unref?.()
107
113
  },
108
114
 
@@ -113,7 +119,10 @@ module.exports = {
113
119
  clearInterval(interval)
114
120
  interval = null
115
121
 
122
+ unsubscribeIdentityRefresh?.()
123
+ unsubscribeIdentityRefresh = null
116
124
  client = null
125
+ capture = null
117
126
  lastCpuUsage = null
118
127
 
119
128
  gcObserver?.disconnect()
@@ -158,6 +167,12 @@ module.exports = {
158
167
  decrement (name, tag) {
159
168
  this.count(name, -1, tag)
160
169
  },
170
+
171
+ flush (done) {
172
+ if (!client) return done?.()
173
+ capture?.()
174
+ client.flush(done)
175
+ },
161
176
  }
162
177
 
163
178
  function captureCpuUsage () {
@@ -34,6 +34,21 @@ class AlwaysMatcher {
34
34
  }
35
35
  }
36
36
 
37
+ /**
38
+ * Matcher that always returns false for unsupported patterns.
39
+ * Implements the minimal `RuleMatcher` interface.
40
+ * @implements {RuleMatcher}
41
+ */
42
+ class NeverMatcher {
43
+ /**
44
+ * @param {DatadogSpan} span
45
+ * @returns {boolean}
46
+ */
47
+ match (span) {
48
+ return false
49
+ }
50
+ }
51
+
37
52
  /**
38
53
  * Matcher that evaluates a glob pattern against a derived subject.
39
54
  */
@@ -62,6 +77,8 @@ class GlobMatcher {
62
77
  * Matcher that evaluates a regular expression against a derived subject.
63
78
  */
64
79
  class RegExpMatcher {
80
+ #resetLastIndex
81
+
65
82
  /**
66
83
  * @param {RegExp} pattern - Regular expression used to test the subject.
67
84
  * @param {Locator} locator - Function extracting the subject to test.
@@ -69,6 +86,7 @@ class RegExpMatcher {
69
86
  constructor (pattern, locator) {
70
87
  this.pattern = pattern
71
88
  this.locator = locator
89
+ this.#resetLastIndex = pattern.global || pattern.sticky
72
90
  }
73
91
 
74
92
  /**
@@ -77,17 +95,23 @@ class RegExpMatcher {
77
95
  */
78
96
  match (span) {
79
97
  const subject = this.locator(span)
80
- if (!subject) return false
81
- return this.pattern.test(subject)
98
+ if (subject === undefined) return false
99
+ if (!this.#resetLastIndex) return this.pattern.test(subject)
100
+
101
+ this.pattern.lastIndex = 0
102
+ const matched = this.pattern.test(subject)
103
+ this.pattern.lastIndex = 0
104
+ return matched
82
105
  }
83
106
  }
84
107
 
85
108
  /**
86
109
  * Creates a matcher for the provided pattern and locator.
87
110
  * Returns a glob matcher for non-trivial strings, a regexp matcher for RegExp,
88
- * or an always-true matcher for wildcard or missing patterns.
111
+ * an always-true matcher for wildcard patterns, or an always-false matcher for
112
+ * unsupported patterns.
89
113
  *
90
- * @param {string|RegExp|undefined} pattern
114
+ * @param {unknown} pattern
91
115
  * @param {Locator} locator
92
116
  * @returns {RuleMatcher}
93
117
  */
@@ -96,10 +120,13 @@ function matcher (pattern, locator) {
96
120
  return new RegExpMatcher(pattern, locator)
97
121
  }
98
122
 
99
- if (typeof pattern === 'string' && pattern !== '*' && pattern !== '**' && pattern !== '***') {
123
+ if (typeof pattern === 'string') {
124
+ if (pattern === '*' || pattern === '**' || pattern === '***') {
125
+ return new AlwaysMatcher()
126
+ }
100
127
  return new GlobMatcher(pattern, locator)
101
128
  }
102
- return new AlwaysMatcher()
129
+ return new NeverMatcher()
103
130
  }
104
131
 
105
132
  /**
@@ -171,13 +198,13 @@ class SamplingRule {
171
198
  constructor ({ name, service, resource, tags, sampleRate = 1, provenance, maxPerSecond } = {}) {
172
199
  this.matchers = []
173
200
 
174
- if (name) {
201
+ if (name !== undefined) {
175
202
  this.matchers.push(matcher(name, nameLocator))
176
203
  }
177
- if (service) {
204
+ if (service !== undefined) {
178
205
  this.matchers.push(matcher(service, serviceLocator))
179
206
  }
180
- if (resource) {
207
+ if (resource !== undefined) {
181
208
  this.matchers.push(matcher(resource, resourceLocator))
182
209
  }
183
210
  if (tags) {
@@ -0,0 +1,51 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Tracks transport deliveries that must outlive a serverless request.
5
+ *
6
+ * The tracker is created only for platforms with an invocation-retention
7
+ * boundary. Exporters keep their normal callback path when it is absent.
8
+ */
9
+ class TelemetryDeliveryTracker {
10
+ #deliveries = new Set()
11
+
12
+ /**
13
+ * Tracks one asynchronous transport delivery until its callback runs.
14
+ * @param {(done: () => void) => void} deliver
15
+ * @param {(() => void)|undefined} done
16
+ */
17
+ track (deliver, done) {
18
+ const delivery = { callbacks: done ? [done] : [] }
19
+ this.#deliveries.add(delivery)
20
+
21
+ const complete = () => {
22
+ if (!this.#deliveries.delete(delivery)) return
23
+ for (const callback of delivery.callbacks) callback()
24
+ }
25
+
26
+ try {
27
+ deliver(complete)
28
+ } catch (error) {
29
+ complete()
30
+ throw error
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Calls back after every delivery active at this boundary has completed.
36
+ * @param {(() => void)|undefined} done
37
+ */
38
+ waitForIdle (done) {
39
+ if (!done) return
40
+
41
+ let pending = this.#deliveries.size
42
+ if (pending === 0) return done()
43
+
44
+ const complete = () => {
45
+ if (--pending === 0) done()
46
+ }
47
+ for (const delivery of this.#deliveries) delivery.callbacks.push(complete)
48
+ }
49
+ }
50
+
51
+ module.exports = TelemetryDeliveryTracker
@@ -0,0 +1,155 @@
1
+ 'use strict'
2
+
3
+ const { channel } = require('dc-polyfill')
4
+
5
+ const { getEnvironmentVariable } = require('../config/helper')
6
+ const log = require('../log')
7
+
8
+ const httpRequestFinishChannel = channel('apm:http:server:request:finish')
9
+ const http2RequestStartChannel = channel('apm:http2:server:request:start')
10
+ const http2ResponseEmitChannel = channel('apm:http2:server:response:emit')
11
+ const VERCEL_REQUEST_CONTEXT = Symbol.for('@vercel/request-context')
12
+ const VERCEL_FLUSH_TIMEOUT = 2000
13
+ const vercelRetentionHandlers = new WeakMap()
14
+
15
+ /**
16
+ * @typedef {{ flushAll?: (done: () => void, options?: { timeout?: number }) => void }} TelemetryFlusher
17
+ */
18
+
19
+ /**
20
+ * @typedef {{ complete: () => void, promise: Promise<void> }} VercelFlush
21
+ */
22
+
23
+ /**
24
+ * @returns {VercelFlush}
25
+ */
26
+ function createVercelFlush () {
27
+ let complete
28
+ const promise = new Promise(resolve => { complete = resolve })
29
+ return { complete, promise }
30
+ }
31
+
32
+ /**
33
+ * @param {TelemetryFlusher} tracer
34
+ * @param {() => void} done
35
+ * @returns {void}
36
+ */
37
+ function flushVercelTelemetry (tracer, done) {
38
+ setImmediate(() => {
39
+ try {
40
+ tracer.flushAll(done, { timeout: VERCEL_FLUSH_TIMEOUT })
41
+ } catch (error) {
42
+ log.warn('Unable to flush Vercel telemetry:', error)
43
+ done()
44
+ }
45
+ })
46
+ }
47
+
48
+ function getVercelRequestContext () {
49
+ return globalThis[VERCEL_REQUEST_CONTEXT]?.get?.()
50
+ }
51
+
52
+ // HTTP/2 binds response lifecycle events while handling its request-start channel.
53
+ function activateHttp2Lifecycle () {}
54
+
55
+ /**
56
+ * Retains a Vercel Node Function until configured telemetry exporters complete.
57
+ *
58
+ * @param {TelemetryFlusher} tracer
59
+ * @returns {(() => void)|undefined}
60
+ */
61
+ function registerVercelTelemetryRetention (tracer) {
62
+ const existing = vercelRetentionHandlers.get(tracer)
63
+ if (existing) return existing
64
+
65
+ if (typeof tracer?.flushAll !== 'function') return
66
+ let flushInProgress = false
67
+ let queuedFlush
68
+
69
+ /**
70
+ * @param {VercelFlush} flush
71
+ */
72
+ const startFlush = flush => {
73
+ flushVercelTelemetry(tracer, () => {
74
+ flush.complete()
75
+ const nextFlush = queuedFlush
76
+ queuedFlush = undefined
77
+ if (nextFlush) {
78
+ startFlush(nextFlush)
79
+ } else {
80
+ flushInProgress = false
81
+ }
82
+ })
83
+ }
84
+ const flushRequest = () => {
85
+ const requestContext = getVercelRequestContext()
86
+ if (!requestContext) return
87
+
88
+ const { waitUntil } = requestContext
89
+ if (typeof waitUntil !== 'function') return
90
+
91
+ const shouldStart = !flushInProgress
92
+ const flush = queuedFlush ?? createVercelFlush()
93
+ if (shouldStart) {
94
+ flushInProgress = true
95
+ } else {
96
+ queuedFlush = flush
97
+ }
98
+
99
+ try {
100
+ waitUntil(flush.promise)
101
+ } catch (error) {
102
+ log.warn('Unable to retain Vercel telemetry:', error)
103
+ }
104
+ if (shouldStart) startFlush(flush)
105
+ }
106
+ // The HTTP finish channel activates its response wrapper directly. HTTP/2 needs
107
+ // a passive request-start subscriber before it can bind response emit events.
108
+ const flushHttp2Response = ({ eventName }) => {
109
+ if (eventName === 'close') flushRequest()
110
+ }
111
+ httpRequestFinishChannel.subscribe(flushRequest)
112
+ http2RequestStartChannel.subscribe(activateHttp2Lifecycle)
113
+ http2ResponseEmitChannel.subscribe(flushHttp2Response)
114
+
115
+ const unregister = () => {
116
+ httpRequestFinishChannel.unsubscribe(flushRequest)
117
+ http2RequestStartChannel.unsubscribe(activateHttp2Lifecycle)
118
+ http2ResponseEmitChannel.unsubscribe(flushHttp2Response)
119
+ vercelRetentionHandlers.delete(tracer)
120
+ }
121
+ vercelRetentionHandlers.set(tracer, unregister)
122
+ return unregister
123
+ }
124
+
125
+ /**
126
+ * Gets Vercel deployment tags to attach to spans.
127
+ *
128
+ * @returns {string[]|undefined}
129
+ */
130
+ function getVercelPlatformTags () {
131
+ let tags
132
+ const projectId = getEnvironmentVariable('VERCEL_PROJECT_ID')
133
+ if (projectId) {
134
+ tags = ['vercel.project_id', projectId]
135
+ }
136
+
137
+ const environment = getEnvironmentVariable('VERCEL_ENV')
138
+ if (environment) {
139
+ tags ??= []
140
+ tags.push('vercel.environment', environment)
141
+ }
142
+
143
+ const region = getEnvironmentVariable('VERCEL_REGION')
144
+ if (region) {
145
+ tags ??= []
146
+ tags.push('vercel.region', region)
147
+ }
148
+
149
+ return tags
150
+ }
151
+
152
+ module.exports = {
153
+ getVercelPlatformTags,
154
+ registerVercelTelemetryRetention,
155
+ }
@@ -2,6 +2,9 @@
2
2
 
3
3
  const { getEnvironmentVariable, getValueFromEnvSources } = require('./config/helper')
4
4
 
5
+ const IS_AWS_LAMBDA_MICROVM = getEnvironmentVariable('AWS_LAMBDA_MICROVM_IMAGE_ARN') !== undefined
6
+ const isVercelAtStartup = getEnvironmentVariable('VERCEL') === '1'
7
+
5
8
  function getIsGCPFunction () {
6
9
  const isDeprecatedGCPFunction =
7
10
  getEnvironmentVariable('FUNCTION_NAME') !== undefined &&
@@ -39,50 +42,71 @@ function isInServerlessEnvironment () {
39
42
  const isGCPFunction = getIsGCPFunction()
40
43
  const isAzureFunction = getIsAzureFunction()
41
44
 
42
- return inAWSLambda || isGCPFunction || isAzureFunction
45
+ return IS_AWS_LAMBDA_MICROVM || inAWSLambda || isGCPFunction || isAzureFunction
43
46
  }
44
47
 
45
48
  /**
46
49
  * Gets tags describing the serverless platform where the tracer is running.
47
50
  *
51
+ * @param {{ isVercel: boolean }} [platform] Detected serverless platform.
48
52
  * @returns {string[]|undefined}
49
53
  */
50
- function getServerlessPlatformTags () {
51
- if (getEnvironmentVariable('VERCEL') === '1') {
52
- return getVercelPlatformTags()
54
+ function getServerlessPlatformTags (platform = getServerlessPlatform()) {
55
+ if (platform.isVercel) {
56
+ return require('./serverless/vercel').getVercelPlatformTags()
53
57
  }
54
58
  }
55
59
 
56
60
  /**
57
- * @returns {string[]|undefined}
61
+ * Detects the serverless platform once while configuration is built.
62
+ * @returns {{ isVercel: boolean }}
58
63
  */
59
- function getVercelPlatformTags () {
60
- let tags
61
- const projectId = getEnvironmentVariable('VERCEL_PROJECT_ID')
62
- if (projectId) {
63
- tags = ['vercel.project_id', projectId]
64
- }
64
+ function getServerlessPlatform () {
65
+ return { isVercel: supportsServerlessTelemetryRetention() }
66
+ }
65
67
 
66
- const environment = getEnvironmentVariable('VERCEL_ENV')
67
- if (environment) {
68
- tags ??= []
69
- tags.push('vercel.environment', environment)
70
- }
68
+ /**
69
+ * Whether the current platform can retain an invocation for telemetry delivery.
70
+ *
71
+ * Add future serverless platforms here as they gain an equivalent retention hook.
72
+ * @returns {boolean}
73
+ */
74
+ function supportsServerlessTelemetryRetention () {
75
+ return isVercelAtStartup
76
+ }
71
77
 
72
- const region = getEnvironmentVariable('VERCEL_REGION')
73
- if (region) {
74
- tags ??= []
75
- tags.push('vercel.region', region)
78
+ /**
79
+ * Creates delivery tracking for platforms with an invocation retention hook.
80
+ */
81
+ function createServerlessDeliveryTracker () {
82
+ if (supportsServerlessTelemetryRetention()) {
83
+ return new (require('./serverless/telemetry-delivery-tracker'))()
76
84
  }
85
+ }
77
86
 
78
- return tags
87
+ /**
88
+ * Registers the lifecycle adapter selected by the detected serverless platform.
89
+ * @param {{ flushAll?: (done: () => void) => void }} tracer
90
+ */
91
+ function initializeServerlessTelemetry (tracer) {
92
+ if (supportsServerlessTelemetryRetention()) {
93
+ return require('./serverless/vercel').registerVercelTelemetryRetention(tracer)
94
+ }
79
95
  }
80
96
 
81
97
  module.exports = {
82
98
  getServerlessPlatformTags,
99
+ getServerlessPlatform,
100
+ supportsServerlessTelemetryRetention,
101
+ createServerlessDeliveryTracker,
83
102
  getIsGCPFunction,
84
103
  getIsAzureFunction,
85
104
  enableGCPPubSubPushSubscription,
86
105
  getIsFlexConsumptionAzureFunction,
106
+ initializeServerlessTelemetry,
107
+ IS_AWS_LAMBDA_MICROVM,
108
+ // true only for a Node that bundles its own OpenSSL, whose CSPRNG keeps the snapshot's DRBG
109
+ // state across a MicroVM clone resume
110
+ NODE_BUNDLES_OPENSSL: process.config.variables.node_shared_openssl === false,
87
111
  IS_SERVERLESS: isInServerlessEnvironment(),
88
112
  }
@@ -5,7 +5,7 @@ function identityService ({ tracerService }) {
5
5
  }
6
6
 
7
7
  function getFormattedHostString ({ host, port }) {
8
- return [host, port].filter(Boolean).join(':')
8
+ return port ? `${host}:${port}` : host
9
9
  }
10
10
 
11
11
  function httpPluginClientService ({ tracerService, pluginConfig, sessionDetails }) {