dd-trace 6.13.0 → 6.15.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 (208) 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/index.d.ts +8 -0
  14. package/package.json +13 -10
  15. package/packages/datadog-esbuild/index.js +3 -1
  16. package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
  17. package/packages/datadog-instrumentations/src/fs.js +24 -20
  18. package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
  19. package/packages/datadog-instrumentations/src/graphql.js +16 -16
  20. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
  21. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  22. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +265 -0
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
  27. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
  28. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  29. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
  30. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +14 -5
  31. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +251 -0
  32. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +11 -1
  33. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
  34. package/packages/datadog-instrumentations/src/jest.js +166 -45
  35. package/packages/datadog-instrumentations/src/knex.js +76 -0
  36. package/packages/datadog-instrumentations/src/mariadb.js +6 -0
  37. package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
  38. package/packages/datadog-instrumentations/src/mocha/main.js +66 -20
  39. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
  40. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
  41. package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
  42. package/packages/datadog-instrumentations/src/net.js +14 -17
  43. package/packages/datadog-instrumentations/src/next.js +212 -62
  44. package/packages/datadog-instrumentations/src/openai.js +42 -40
  45. package/packages/datadog-instrumentations/src/pg.js +15 -0
  46. package/packages/datadog-instrumentations/src/playwright.js +113 -13
  47. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
  48. package/packages/datadog-instrumentations/src/sequelize.js +94 -2
  49. package/packages/datadog-instrumentations/src/undici.js +53 -4
  50. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +37 -3
  51. package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
  52. package/packages/datadog-instrumentations/src/vitest-worker.js +71 -14
  53. package/packages/datadog-instrumentations/src/webdriverio.js +965 -6
  54. package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
  55. package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
  56. package/packages/datadog-plugin-amqp10/src/util.js +2 -1
  57. package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
  58. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
  59. package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
  60. package/packages/datadog-plugin-cucumber/src/index.js +0 -2
  61. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
  62. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
  63. package/packages/datadog-plugin-graphql/src/execute.js +998 -196
  64. package/packages/datadog-plugin-graphql/src/index.js +27 -7
  65. package/packages/datadog-plugin-graphql/src/jit.js +136 -0
  66. package/packages/datadog-plugin-graphql/src/request.js +18 -27
  67. package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
  68. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
  69. package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
  70. package/packages/datadog-plugin-graphql/src/utils.js +208 -120
  71. package/packages/datadog-plugin-graphql/src/validate.js +10 -23
  72. package/packages/datadog-plugin-jest/src/index.js +0 -6
  73. package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
  74. package/packages/datadog-plugin-mocha/src/index.js +403 -75
  75. package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
  76. package/packages/datadog-plugin-mysql/src/index.js +41 -15
  77. package/packages/datadog-plugin-net/src/tcp.js +3 -1
  78. package/packages/datadog-plugin-next/src/index.js +63 -29
  79. package/packages/datadog-plugin-playwright/src/index.js +167 -27
  80. package/packages/datadog-plugin-undici/src/index.js +27 -41
  81. package/packages/datadog-plugin-vitest/src/index.js +6 -12
  82. package/packages/dd-trace/src/aiguard/evaluation.js +2 -1
  83. package/packages/dd-trace/src/aiguard/messages/anthropic.js +8 -1
  84. package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
  85. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
  86. package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
  87. package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
  88. package/packages/dd-trace/src/appsec/graphql.js +6 -2
  89. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
  90. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
  91. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
  92. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +3 -1
  93. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +531 -95
  94. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
  95. package/packages/dd-trace/src/appsec/lambda.js +44 -26
  96. package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
  97. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
  100. package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +5 -173
  101. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
  102. package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
  103. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
  104. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +394 -225
  105. package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
  106. package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
  107. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
  108. package/packages/dd-trace/src/ci-visibility/final-flush.js +2 -1
  109. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
  110. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
  111. package/packages/dd-trace/src/ci-visibility/requests/request.js +11 -0
  112. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
  113. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +180 -0
  114. package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
  115. package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
  116. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -0
  117. package/packages/dd-trace/src/config/index.js +73 -13
  118. package/packages/dd-trace/src/config/parsers.js +11 -1
  119. package/packages/dd-trace/src/config/stable.js +3 -3
  120. package/packages/dd-trace/src/config/supported-configurations.json +22 -2
  121. package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
  122. package/packages/dd-trace/src/debugger/config.js +12 -1
  123. package/packages/dd-trace/src/debugger/constants.js +1 -0
  124. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
  125. package/packages/dd-trace/src/debugger/devtools_client/request-options.js +28 -0
  126. package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -40
  127. package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
  128. package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
  129. package/packages/dd-trace/src/debugger/index.js +23 -3
  130. package/packages/dd-trace/src/dogstatsd.js +510 -76
  131. package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
  132. package/packages/dd-trace/src/encode/0.4.js +5 -5
  133. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
  134. package/packages/dd-trace/src/evp_proxy/direct.js +3 -25
  135. package/packages/dd-trace/src/exporters/agent/index.js +2 -1
  136. package/packages/dd-trace/src/exporters/agent/writer.js +24 -7
  137. package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
  138. package/packages/dd-trace/src/exporters/agentless/writer.js +103 -119
  139. package/packages/dd-trace/src/exporters/common/agents.js +28 -6
  140. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
  141. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
  142. package/packages/dd-trace/src/exporters/common/proxy.js +52 -0
  143. package/packages/dd-trace/src/exporters/common/request.js +42 -14
  144. package/packages/dd-trace/src/exporters/common/url.js +40 -1
  145. package/packages/dd-trace/src/exporters/common/writer.js +9 -7
  146. package/packages/dd-trace/src/flush.js +6 -3
  147. package/packages/dd-trace/src/id.js +14 -0
  148. package/packages/dd-trace/src/index.js +5 -2
  149. package/packages/dd-trace/src/llmobs/experiments/dataset.js +2 -1
  150. package/packages/dd-trace/src/llmobs/index.js +32 -32
  151. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
  152. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
  153. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
  154. package/packages/dd-trace/src/llmobs/util.js +0 -33
  155. package/packages/dd-trace/src/llmobs/writers/base.js +49 -32
  156. package/packages/dd-trace/src/log/index.js +7 -1
  157. package/packages/dd-trace/src/{ci-visibility/log-submission → log-submission}/log-submission-plugin.js +48 -19
  158. package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
  159. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  160. package/packages/dd-trace/src/opentelemetry/logs/index.js +5 -24
  161. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
  162. package/packages/dd-trace/src/opentelemetry/metrics/index.js +15 -22
  163. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +14 -4
  164. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +10 -0
  165. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +5 -0
  166. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
  167. package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
  168. package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
  169. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
  170. package/packages/dd-trace/src/opentracing/propagation/text_map.js +101 -20
  171. package/packages/dd-trace/src/payload-tagging/index.js +2 -1
  172. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
  173. package/packages/dd-trace/src/plugins/tracing.js +12 -10
  174. package/packages/dd-trace/src/plugins/util/ci.js +3 -1
  175. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
  176. package/packages/dd-trace/src/plugins/util/test.js +83 -20
  177. package/packages/dd-trace/src/plugins/util/url.js +2 -2
  178. package/packages/dd-trace/src/plugins/util/web.js +4 -9
  179. package/packages/dd-trace/src/priority_sampler.js +4 -0
  180. package/packages/dd-trace/src/profiling/config.js +1 -0
  181. package/packages/dd-trace/src/profiling/oom.js +7 -2
  182. package/packages/dd-trace/src/profiling/profiler.js +23 -13
  183. package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
  184. package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
  185. package/packages/dd-trace/src/proxy.js +75 -5
  186. package/packages/dd-trace/src/remote_config/index.js +319 -101
  187. package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
  188. package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
  189. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +5 -1
  190. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -1
  191. package/packages/dd-trace/src/sampling_rule.js +39 -10
  192. package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +4 -8
  193. package/packages/dd-trace/src/serverless/vercel.js +53 -20
  194. package/packages/dd-trace/src/serverless.js +10 -3
  195. package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
  196. package/packages/dd-trace/src/span_processor.js +18 -3
  197. package/packages/dd-trace/src/span_stats.js +24 -28
  198. package/packages/dd-trace/src/startup-log.js +3 -2
  199. package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
  200. package/packages/dd-trace/src/telemetry/send-data.js +23 -20
  201. package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
  202. package/packages/dd-trace/src/tracer.js +4 -5
  203. package/packages/dd-trace/src/tracer_metadata.js +11 -3
  204. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  205. package/vendor/dist/protobufjs/index.js +1 -1
  206. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  207. package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +0 -27
  208. 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
  /**
@@ -158,6 +185,7 @@ function resourceLocator (span) {
158
185
  * @property {number} [sampleRate=1] - Deterministic sampling rate in [0, 1].
159
186
  * @property {string} [provenance] - Optional provenance/metadata for this rule.
160
187
  * @property {number} [maxPerSecond] - Maximum samples per second (rate limit).
188
+ * @property {boolean} [discard=false] - Whether to fully drop a trace if not kept.
161
189
  */
162
190
 
163
191
  /**
@@ -168,16 +196,16 @@ class SamplingRule {
168
196
  /**
169
197
  * @param {SamplingRuleConfig} [config]
170
198
  */
171
- constructor ({ name, service, resource, tags, sampleRate = 1, provenance, maxPerSecond } = {}) {
199
+ constructor ({ name, service, resource, tags, sampleRate = 1, provenance, maxPerSecond, discard = false } = {}) {
172
200
  this.matchers = []
173
201
 
174
- if (name) {
202
+ if (name !== undefined) {
175
203
  this.matchers.push(matcher(name, nameLocator))
176
204
  }
177
- if (service) {
205
+ if (service !== undefined) {
178
206
  this.matchers.push(matcher(service, serviceLocator))
179
207
  }
180
- if (resource) {
208
+ if (resource !== undefined) {
181
209
  this.matchers.push(matcher(resource, resourceLocator))
182
210
  }
183
211
  if (tags) {
@@ -189,6 +217,7 @@ class SamplingRule {
189
217
  this._sampler = new Sampler(sampleRate)
190
218
  this._limiter = undefined
191
219
  this.provenance = provenance
220
+ this.discard = !!discard
192
221
 
193
222
  if (Number.isFinite(maxPerSecond)) {
194
223
  this._limiter = new RateLimiter(maxPerSecond)
@@ -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 }) {
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const { AUTO_REJECT } = require('../../../ext/priority')
3
4
  const log = require('./log')
4
5
  const spanFormat = require('./span_format')
5
6
  const SpanSampler = require('./span_sampler')
@@ -34,7 +35,20 @@ class SpanProcessor {
34
35
  sample (span) {
35
36
  const spanContext = span.context()
36
37
  this._prioritySampler.sample(spanContext)
37
- this._spanSampler.sample(spanContext)
38
+ if (!this.#isDiscarded(spanContext)) {
39
+ this._spanSampler.sample(spanContext)
40
+ }
41
+ }
42
+
43
+ /**
44
+ * A rule's reject decision can later be overridden (e.g. a product force-keeping the trace via
45
+ * `PrioritySampler.keepTrace()`), so `discard` only applies while the priority is still a reject.
46
+ *
47
+ * @param {import('./opentracing/span_context')} spanContext
48
+ * @returns {boolean}
49
+ */
50
+ #isDiscarded (spanContext) {
51
+ return spanContext._sampling.discard && spanContext._sampling.priority <= AUTO_REJECT
38
52
  }
39
53
 
40
54
  process (span) {
@@ -56,11 +70,12 @@ class SpanProcessor {
56
70
 
57
71
  let isFirstSpanInChunk = true
58
72
  const stampApmDisabled = this._config.apmTracingEnabled === false
73
+ const discard = this.#isDiscarded(spanContext)
59
74
 
60
75
  for (const span of started) {
61
76
  if (span._duration === undefined) {
62
77
  active.push(span)
63
- } else {
78
+ } else if (!discard) {
64
79
  const formattedSpan = spanFormat(span, isFirstSpanInChunk, this._processTags)
65
80
  if (stampApmDisabled) {
66
81
  formattedSpan.metrics[APM_TRACING_ENABLED_KEY] = 0
@@ -76,7 +91,7 @@ class SpanProcessor {
76
91
  }
77
92
  }
78
93
 
79
- if (formatted.length !== 0 && trace.isRecording !== false) {
94
+ if (!discard && formatted.length !== 0 && trace.isRecording !== false) {
80
95
  this._exporter.export(formatted)
81
96
  }
82
97
 
@@ -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