dd-trace 5.124.0 → 5.125.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 (201) 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/vitest.js +3 -3
  8. package/ci/test-optimization-validation/package-check.js +1 -1
  9. package/ci/test-optimization-validation/report-writer.js +7 -5
  10. package/ci/vitest-no-worker-init-runner-setup.mjs +8 -0
  11. package/ci/vitest-no-worker-init-setup.mjs +13 -13
  12. package/ci/vitest-no-worker-init-v5-setup.mjs +4 -0
  13. package/package.json +13 -10
  14. package/packages/datadog-esbuild/index.js +3 -1
  15. package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
  16. package/packages/datadog-instrumentations/src/fs.js +24 -20
  17. package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
  18. package/packages/datadog-instrumentations/src/graphql.js +16 -16
  19. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
  20. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  21. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +265 -0
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
  27. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  28. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
  29. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +13 -0
  30. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +251 -0
  31. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +11 -1
  32. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
  33. package/packages/datadog-instrumentations/src/jest.js +25 -20
  34. package/packages/datadog-instrumentations/src/knex.js +76 -0
  35. package/packages/datadog-instrumentations/src/mariadb.js +6 -0
  36. package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
  37. package/packages/datadog-instrumentations/src/mocha/main.js +25 -15
  38. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
  39. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
  40. package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
  41. package/packages/datadog-instrumentations/src/net.js +14 -17
  42. package/packages/datadog-instrumentations/src/next.js +212 -62
  43. package/packages/datadog-instrumentations/src/openai.js +42 -40
  44. package/packages/datadog-instrumentations/src/pg.js +15 -0
  45. package/packages/datadog-instrumentations/src/playwright.js +109 -13
  46. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
  47. package/packages/datadog-instrumentations/src/sequelize.js +94 -2
  48. package/packages/datadog-instrumentations/src/undici.js +53 -4
  49. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +37 -3
  50. package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
  51. package/packages/datadog-instrumentations/src/vitest-worker.js +71 -14
  52. package/packages/datadog-instrumentations/src/webdriverio.js +965 -6
  53. package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
  54. package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
  55. package/packages/datadog-plugin-amqp10/src/util.js +2 -1
  56. package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
  57. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
  58. package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
  59. package/packages/datadog-plugin-cucumber/src/index.js +0 -2
  60. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
  61. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
  62. package/packages/datadog-plugin-graphql/src/execute.js +998 -196
  63. package/packages/datadog-plugin-graphql/src/index.js +27 -7
  64. package/packages/datadog-plugin-graphql/src/jit.js +136 -0
  65. package/packages/datadog-plugin-graphql/src/request.js +18 -27
  66. package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
  67. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
  68. package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
  69. package/packages/datadog-plugin-graphql/src/utils.js +208 -120
  70. package/packages/datadog-plugin-graphql/src/validate.js +10 -23
  71. package/packages/datadog-plugin-jest/src/index.js +0 -6
  72. package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
  73. package/packages/datadog-plugin-mocha/src/index.js +403 -75
  74. package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
  75. package/packages/datadog-plugin-mysql/src/index.js +41 -15
  76. package/packages/datadog-plugin-net/src/tcp.js +3 -1
  77. package/packages/datadog-plugin-next/src/index.js +63 -29
  78. package/packages/datadog-plugin-playwright/src/index.js +167 -27
  79. package/packages/datadog-plugin-undici/src/index.js +27 -41
  80. package/packages/datadog-plugin-vitest/src/index.js +6 -12
  81. package/packages/dd-trace/src/aiguard/evaluation.js +2 -1
  82. package/packages/dd-trace/src/aiguard/messages/anthropic.js +8 -1
  83. package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
  84. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
  85. package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
  86. package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
  87. package/packages/dd-trace/src/appsec/graphql.js +6 -2
  88. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
  89. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
  90. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
  91. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +11 -36
  92. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
  93. package/packages/dd-trace/src/appsec/lambda.js +44 -26
  94. package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
  95. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
  96. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
  97. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +5 -173
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
  100. package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
  101. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
  102. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +394 -225
  103. package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
  104. package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
  105. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
  106. package/packages/dd-trace/src/ci-visibility/final-flush.js +2 -1
  107. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
  108. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
  109. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
  110. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +176 -0
  111. package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
  112. package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
  113. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -0
  114. package/packages/dd-trace/src/config/index.js +73 -13
  115. package/packages/dd-trace/src/config/parsers.js +11 -1
  116. package/packages/dd-trace/src/config/stable.js +3 -3
  117. package/packages/dd-trace/src/config/supported-configurations.json +20 -2
  118. package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
  119. package/packages/dd-trace/src/debugger/config.js +12 -1
  120. package/packages/dd-trace/src/debugger/constants.js +1 -0
  121. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
  122. package/packages/dd-trace/src/debugger/devtools_client/request-options.js +33 -0
  123. package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -40
  124. package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
  125. package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
  126. package/packages/dd-trace/src/debugger/index.js +23 -3
  127. package/packages/dd-trace/src/dogstatsd.js +510 -76
  128. package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
  129. package/packages/dd-trace/src/encode/0.4.js +5 -5
  130. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
  131. package/packages/dd-trace/src/evp_proxy/direct.js +27 -23
  132. package/packages/dd-trace/src/exporters/agent/index.js +2 -1
  133. package/packages/dd-trace/src/exporters/agent/writer.js +24 -7
  134. package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
  135. package/packages/dd-trace/src/exporters/agentless/writer.js +100 -118
  136. package/packages/dd-trace/src/exporters/common/agents.js +28 -6
  137. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
  138. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
  139. package/packages/dd-trace/src/exporters/common/request.js +31 -11
  140. package/packages/dd-trace/src/exporters/common/url.js +40 -1
  141. package/packages/dd-trace/src/exporters/common/writer.js +9 -7
  142. package/packages/dd-trace/src/flush.js +6 -3
  143. package/packages/dd-trace/src/id.js +14 -0
  144. package/packages/dd-trace/src/index.js +5 -2
  145. package/packages/dd-trace/src/llmobs/experiments/dataset.js +2 -1
  146. package/packages/dd-trace/src/llmobs/index.js +32 -32
  147. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
  148. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
  149. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
  150. package/packages/dd-trace/src/llmobs/util.js +0 -33
  151. package/packages/dd-trace/src/llmobs/writers/base.js +49 -32
  152. package/packages/dd-trace/src/log/index.js +7 -1
  153. package/packages/dd-trace/src/{ci-visibility/log-submission → log-submission}/log-submission-plugin.js +48 -19
  154. package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
  155. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  156. package/packages/dd-trace/src/opentelemetry/logs/index.js +5 -24
  157. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
  158. package/packages/dd-trace/src/opentelemetry/metrics/index.js +15 -22
  159. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +14 -4
  160. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +10 -0
  161. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
  162. package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
  163. package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
  164. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
  165. package/packages/dd-trace/src/opentracing/propagation/text_map.js +93 -18
  166. package/packages/dd-trace/src/payload-tagging/index.js +2 -1
  167. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
  168. package/packages/dd-trace/src/plugins/tracing.js +12 -10
  169. package/packages/dd-trace/src/plugins/util/ci.js +3 -1
  170. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
  171. package/packages/dd-trace/src/plugins/util/test.js +83 -20
  172. package/packages/dd-trace/src/plugins/util/url.js +2 -2
  173. package/packages/dd-trace/src/plugins/util/web.js +4 -9
  174. package/packages/dd-trace/src/profiling/config.js +1 -0
  175. package/packages/dd-trace/src/profiling/oom.js +7 -2
  176. package/packages/dd-trace/src/profiling/profiler.js +23 -13
  177. package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
  178. package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
  179. package/packages/dd-trace/src/proxy.js +75 -5
  180. package/packages/dd-trace/src/remote_config/index.js +319 -101
  181. package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
  182. package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
  183. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +5 -1
  184. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -1
  185. package/packages/dd-trace/src/sampling_rule.js +36 -9
  186. package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +4 -8
  187. package/packages/dd-trace/src/serverless/vercel.js +53 -20
  188. package/packages/dd-trace/src/serverless.js +10 -3
  189. package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
  190. package/packages/dd-trace/src/span_stats.js +24 -28
  191. package/packages/dd-trace/src/startup-log.js +3 -2
  192. package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
  193. package/packages/dd-trace/src/telemetry/send-data.js +18 -16
  194. package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
  195. package/packages/dd-trace/src/tracer.js +4 -5
  196. package/packages/dd-trace/src/tracer_metadata.js +11 -3
  197. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  198. package/vendor/dist/protobufjs/index.js +1 -1
  199. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  200. package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +0 -27
  201. package/packages/dd-trace/src/encode/agentless-json.js +0 -210
@@ -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 }
@@ -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
 
@@ -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 ||
@@ -28,6 +28,7 @@ let lastTime = 0
28
28
  let lastCpuUsage = null
29
29
  let eventLoopDelayObserver = null
30
30
  let capture = null
31
+ let unsubscribeIdentityRefresh = null
31
32
 
32
33
  // !!!!!!!!!!!
33
34
  // IMPORTANT
@@ -49,6 +50,7 @@ module.exports = {
49
50
  const trackGc = config.runtimeMetrics.gc !== false
50
51
 
51
52
  client = createMetricsClient(config)
53
+ unsubscribeIdentityRefresh = subscribeToIdentityRefresh(client, config)
52
54
 
53
55
  if (trackGc) {
54
56
  startGCObserver()
@@ -117,6 +119,8 @@ module.exports = {
117
119
  clearInterval(interval)
118
120
  interval = null
119
121
 
122
+ unsubscribeIdentityRefresh?.()
123
+ unsubscribeIdentityRefresh = null
120
124
  client = null
121
125
  capture = null
122
126
  lastCpuUsage = null
@@ -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) {
@@ -18,11 +18,8 @@ class TelemetryDeliveryTracker {
18
18
  const delivery = { callbacks: done ? [done] : [] }
19
19
  this.#deliveries.add(delivery)
20
20
 
21
- let completed = false
22
21
  const complete = () => {
23
- if (completed) return
24
- completed = true
25
- this.#deliveries.delete(delivery)
22
+ if (!this.#deliveries.delete(delivery)) return
26
23
  for (const callback of delivery.callbacks) callback()
27
24
  }
28
25
 
@@ -41,14 +38,13 @@ class TelemetryDeliveryTracker {
41
38
  waitForIdle (done) {
42
39
  if (!done) return
43
40
 
44
- const deliveries = [...this.#deliveries]
45
- if (deliveries.length === 0) return done()
41
+ let pending = this.#deliveries.size
42
+ if (pending === 0) return done()
46
43
 
47
- let pending = deliveries.length
48
44
  const complete = () => {
49
45
  if (--pending === 0) done()
50
46
  }
51
- for (const delivery of deliveries) delivery.callbacks.push(complete)
47
+ for (const delivery of this.#deliveries) delivery.callbacks.push(complete)
52
48
  }
53
49
  }
54
50
 
@@ -16,6 +16,19 @@ const vercelRetentionHandlers = new WeakMap()
16
16
  * @typedef {{ flushAll?: (done: () => void, options?: { timeout?: number }) => void }} TelemetryFlusher
17
17
  */
18
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
+
19
32
  /**
20
33
  * @param {TelemetryFlusher} tracer
21
34
  * @param {() => void} done
@@ -32,25 +45,6 @@ function flushVercelTelemetry (tracer, done) {
32
45
  })
33
46
  }
34
47
 
35
- function registerVercelRequestFlush (tracer) {
36
- const requestContext = getVercelRequestContext()
37
- if (!requestContext) return
38
-
39
- const { waitUntil } = requestContext
40
- if (typeof waitUntil !== 'function') return
41
-
42
- // Retain the invocation synchronously, then flush after the response completes.
43
- let done
44
- const pending = new Promise(resolve => { done = resolve })
45
- try {
46
- waitUntil(pending)
47
- flushVercelTelemetry(tracer, done)
48
- } catch (error) {
49
- log.warn('Unable to retain Vercel telemetry:', error)
50
- done()
51
- }
52
- }
53
-
54
48
  function getVercelRequestContext () {
55
49
  return globalThis[VERCEL_REQUEST_CONTEXT]?.get?.()
56
50
  }
@@ -69,9 +63,48 @@ function registerVercelTelemetryRetention (tracer) {
69
63
  if (existing) return existing
70
64
 
71
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
+ }
72
106
  // The HTTP finish channel activates its response wrapper directly. HTTP/2 needs
73
107
  // a passive request-start subscriber before it can bind response emit events.
74
- const flushRequest = () => registerVercelRequestFlush(tracer)
75
108
  const flushHttp2Response = ({ eventName }) => {
76
109
  if (eventName === 'close') flushRequest()
77
110
  }
@@ -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,7 +42,7 @@ 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
  /**
@@ -59,7 +62,7 @@ function getServerlessPlatformTags (platform = getServerlessPlatform()) {
59
62
  * @returns {{ isVercel: boolean }}
60
63
  */
61
64
  function getServerlessPlatform () {
62
- return { isVercel: getEnvironmentVariable('VERCEL') === '1' }
65
+ return { isVercel: supportsServerlessTelemetryRetention() }
63
66
  }
64
67
 
65
68
  /**
@@ -69,7 +72,7 @@ function getServerlessPlatform () {
69
72
  * @returns {boolean}
70
73
  */
71
74
  function supportsServerlessTelemetryRetention () {
72
- return getServerlessPlatform().isVercel
75
+ return isVercelAtStartup
73
76
  }
74
77
 
75
78
  /**
@@ -101,5 +104,9 @@ module.exports = {
101
104
  enableGCPPubSubPushSubscription,
102
105
  getIsFlexConsumptionAzureFunction,
103
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,
104
111
  IS_SERVERLESS: isInServerlessEnvironment(),
105
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 }) {
@@ -136,19 +136,8 @@ class SpanAggKey {
136
136
  }
137
137
 
138
138
  toString () {
139
- return [
140
- this.name,
141
- this.service,
142
- this.resource,
143
- this.type,
144
- this.statusCode,
145
- this.synthetics,
146
- this.method,
147
- this.endpoint,
148
- this.srvSrc,
149
- this.spanKind,
150
- this.rpcStatusCode,
151
- ].join(',')
139
+ return `${this.name},${this.service},${this.resource},${this.type},${this.statusCode},${this.synthetics},` +
140
+ `${this.method},${this.endpoint},${this.srvSrc},${this.spanKind},${this.rpcStatusCode}`
152
141
  }
153
142
  }
154
143
 
@@ -201,19 +190,26 @@ class TimeBuckets extends Map {
201
190
  }
202
191
 
203
192
  class SpanStatsProcessor {
204
- constructor ({
205
- stats: {
206
- DD_TRACE_STATS_COMPUTATION_ENABLED: enabled = false,
207
- interval = 10,
208
- } = {},
209
- hostname,
210
- port,
211
- url,
212
- env,
213
- tags,
214
- version: appVersion,
215
- _DD_TRACE_METRICS_OTEL_FLUSH_INTERVAL: flushIntervalMs,
216
- } = {}, otlpExporter) {
193
+ #config
194
+
195
+ /**
196
+ * @param {import('./config/config-base')} config
197
+ * @param {import('./opentelemetry/metrics/otlp_span_stats_exporter').OtlpStatsExporter} [otlpExporter]
198
+ */
199
+ constructor (config, otlpExporter) {
200
+ const {
201
+ stats: {
202
+ DD_TRACE_STATS_COMPUTATION_ENABLED: enabled = false,
203
+ interval = 10,
204
+ } = {},
205
+ hostname,
206
+ port,
207
+ url,
208
+ env,
209
+ tags,
210
+ version: appVersion,
211
+ _DD_TRACE_METRICS_OTEL_FLUSH_INTERVAL: flushIntervalMs,
212
+ } = config
217
213
  if (!otlpExporter) {
218
214
  this.exporter = new SpanStatsExporter({ hostname, port, tags, url })
219
215
  }
@@ -225,7 +221,7 @@ class SpanStatsProcessor {
225
221
  this.enabled = enabled
226
222
  this.otlpExporter = otlpExporter || null
227
223
  this.env = env
228
- this.tags = tags || {}
224
+ this.#config = config
229
225
  this.sequence = 0
230
226
  this.version = appVersion
231
227
 
@@ -258,7 +254,7 @@ class SpanStatsProcessor {
258
254
  Stats: this.#toV06Payload(drained),
259
255
  Lang: 'javascript',
260
256
  TracerVersion: pkg.version,
261
- RuntimeID: this.tags['runtime-id'],
257
+ RuntimeID: this.#config.tags['runtime-id'],
262
258
  Sequence: ++this.sequence,
263
259
  ProcessTags: processTags.serialized,
264
260
  }, done)
@@ -78,7 +78,7 @@ function configInfo () {
78
78
  const url = config.url
79
79
  const profilingEnabled = config.profiling.DD_PROFILING_ENABLED
80
80
 
81
- return {
81
+ const startupLog = {
82
82
  [inspect.custom] () {
83
83
  return String(this)
84
84
  },
@@ -102,7 +102,6 @@ function configInfo () {
102
102
  sample_rate: config.sampler.sampleRate,
103
103
  sampling_rules: samplingRules,
104
104
  tags: config.tags,
105
- ...(config.tags && config.tags.version && { dd_version: config.tags.version }),
106
105
  log_injection_enabled: !!config.logInjection,
107
106
  runtime_metrics_enabled: !!config.runtimeMetrics,
108
107
  profiling_enabled: profilingEnabled === 'true' || profilingEnabled === 'auto',
@@ -112,6 +111,8 @@ function configInfo () {
112
111
  otlp_metrics_export_enabled: !!config.DD_METRICS_OTEL_ENABLED,
113
112
  otlp_logs_export_enabled: !!config.DD_LOGS_OTEL_ENABLED,
114
113
  }
114
+ if (config.tags?.version) startupLog.dd_version = config.tags.version
115
+ return startupLog
115
116
  }
116
117
 
117
118
  /**
@@ -0,0 +1,28 @@
1
+ 'use strict'
2
+
3
+ const { createSiteUrl } = require('../exporters/common/url')
4
+
5
+ const STAGING_SITE = 'datad0g.com'
6
+
7
+ let cachedSite
8
+ let cachedUrl
9
+
10
+ /**
11
+ * @param {string} site
12
+ * @returns {URL}
13
+ */
14
+ function getAgentlessTelemetryUrl (site) {
15
+ if (site === cachedSite && cachedUrl !== undefined) return cachedUrl
16
+
17
+ const intake = site === STAGING_SITE
18
+ ? 'all-http-intake.logs'
19
+ : 'instrumentation-telemetry-intake'
20
+ const url = createSiteUrl(site, intake)
21
+ if (url === undefined) throw new Error(`Invalid DD_SITE for agentless telemetry: ${site}`)
22
+
23
+ cachedSite = site
24
+ cachedUrl = url
25
+ return url
26
+ }
27
+
28
+ module.exports = getAgentlessTelemetryUrl
@@ -2,6 +2,7 @@
2
2
 
3
3
  const request = require('../exporters/common/request')
4
4
  const log = require('../log')
5
+ const getAgentlessTelemetryUrl = require('./agentless-url')
5
6
 
6
7
  /**
7
8
  * @typedef {Record<string, unknown>} TelemetryPayloadObject
@@ -69,6 +70,7 @@ const log = require('../log')
69
70
  */
70
71
 
71
72
  let agentTelemetry = true
73
+ let getTestOptimizationAgent
72
74
 
73
75
  /**
74
76
  * @param {import('../config/config-base')} config
@@ -98,16 +100,6 @@ function getHeaders (config, application, reqType) {
98
100
  return headers
99
101
  }
100
102
 
101
- /**
102
- * @param {string | undefined} site
103
- */
104
- function getAgentlessTelemetryEndpoint (site) {
105
- if (site === 'datad0g.com') { // staging
106
- return 'https://all-http-intake.logs.datad0g.com'
107
- }
108
- return `https://instrumentation-telemetry-intake.${site}`
109
- }
110
-
111
103
  let seqId = 0
112
104
 
113
105
  /**
@@ -144,10 +136,18 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
144
136
  let url = config.url
145
137
 
146
138
  const isCiVisibilityAgentlessMode = isCiVisibility && testOptimization.DD_CIVISIBILITY_AGENTLESS_ENABLED
139
+ const isApmTracingAgentlessMode = config.experimental?.exporter === 'agentless'
140
+ const isAgentlessMode = isCiVisibilityAgentlessMode || isApmTracingAgentlessMode
141
+
142
+ if (isCiVisibility && getTestOptimizationAgent === undefined) {
143
+ ({ getAgent: getTestOptimizationAgent } = require('../ci-visibility/exporters/agents'))
144
+ }
147
145
 
148
- if (isCiVisibilityAgentlessMode) {
146
+ if (isAgentlessMode) {
149
147
  try {
150
- url = testOptimization.DD_CIVISIBILITY_AGENTLESS_URL ?? new URL(getAgentlessTelemetryEndpoint(config.site))
148
+ url = isCiVisibilityAgentlessMode
149
+ ? testOptimization.DD_CIVISIBILITY_AGENTLESS_URL ?? getAgentlessTelemetryUrl(config.site)
150
+ : getAgentlessTelemetryUrl(config.site)
151
151
  } catch (err) {
152
152
  log.error('Telemetry endpoint url is invalid', err)
153
153
  // No point to do the request if the URL is invalid
@@ -160,9 +160,10 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
160
160
  hostname,
161
161
  port,
162
162
  method: 'POST',
163
- path: isCiVisibilityAgentlessMode ? '/api/v2/apmtelemetry' : '/telemetry/proxy/api/v2/apmtelemetry',
163
+ path: isAgentlessMode ? '/api/v2/apmtelemetry' : '/telemetry/proxy/api/v2/apmtelemetry',
164
164
  headers: getHeaders(config, application, reqType),
165
165
  }
166
+ if (isCiVisibility) options.agent = getTestOptimizationAgent(url)
166
167
 
167
168
  const data = JSON.stringify({
168
169
  api_version: 'v2',
@@ -177,7 +178,7 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
177
178
  })
178
179
 
179
180
  request(data, options, (error) => {
180
- if (error && config.DD_API_KEY && config.site) {
181
+ if (!isAgentlessMode && error && config.DD_API_KEY && config.site) {
181
182
  if (agentTelemetry) {
182
183
  log.warn('Agent telemetry failed, started agentless telemetry')
183
184
  agentTelemetry = false
@@ -185,7 +186,7 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
185
186
  // figure out which data center to send to
186
187
  let backendUrl
187
188
  try {
188
- backendUrl = new URL(getAgentlessTelemetryEndpoint(config.site))
189
+ backendUrl = getAgentlessTelemetryUrl(config.site)
189
190
  } catch {
190
191
  log.error('Invalid Telemetry URL')
191
192
  return
@@ -197,6 +198,7 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
197
198
  headers: backendHeader,
198
199
  path: '/api/v2/apmtelemetry',
199
200
  }
201
+ if (isCiVisibility) backendOptions.agent = getTestOptimizationAgent(backendUrl)
200
202
  request(data, backendOptions, (error) => {
201
203
  if (error) {
202
204
  log.error('Error sending telemetry data', error)
@@ -204,7 +206,7 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
204
206
  })
205
207
  }
206
208
 
207
- if (!error && !agentTelemetry) {
209
+ if (!isAgentlessMode && !error && !agentTelemetry) {
208
210
  agentTelemetry = true
209
211
  log.info('Started agent telemetry')
210
212
  }
@@ -4,13 +4,14 @@ const dc = /** @type {typeof import('diagnostics_channel')} */ (require('dc-poly
4
4
  const childProcessChannel = dc.tracingChannel('datadog:child_process:execution')
5
5
 
6
6
  let subscribed = false
7
- let runtimeId
7
+ let savedConfig
8
8
 
9
9
  function isOptionsObject (value) {
10
10
  return value != null && typeof value === 'object' && !Array.isArray(value) && value
11
11
  }
12
12
 
13
13
  function getEnvWithRuntimeId (env) {
14
+ const runtimeId = savedConfig.DD_ROOT_JS_SESSION_ID || savedConfig.tags['runtime-id']
14
15
  // eslint-disable-next-line eslint-rules/eslint-process-env
15
16
  return { ...(env ?? process.env), DD_ROOT_JS_SESSION_ID: runtimeId }
16
17
  }
@@ -43,7 +44,7 @@ function start (config) {
43
44
  if (!config.telemetry.DD_INSTRUMENTATION_TELEMETRY_ENABLED || subscribed) return
44
45
  subscribed = true
45
46
 
46
- runtimeId = config.DD_ROOT_JS_SESSION_ID || config.tags['runtime-id']
47
+ savedConfig = config
47
48
 
48
49
  childProcessChannel.subscribe(
49
50
  /** @type {import('diagnostics_channel').TracingChannelSubscribers<object>} */ ({ start: onChildProcessStart })