dd-trace 6.8.0 → 6.10.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 (209) hide show
  1. package/ci/diagnose.js +27 -25
  2. package/ci/init.js +6 -6
  3. package/ci/runbook.md +114 -20
  4. package/ci/test-optimization-validation/approval-artifacts.js +36 -3
  5. package/ci/test-optimization-validation/approval.js +78 -22
  6. package/ci/test-optimization-validation/blocker-category.js +24 -0
  7. package/ci/test-optimization-validation/ci-discovery.js +23 -17
  8. package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
  9. package/ci/test-optimization-validation/ci-remediation.js +1 -1
  10. package/ci/test-optimization-validation/cli.js +280 -52
  11. package/ci/test-optimization-validation/command-blocker.js +159 -20
  12. package/ci/test-optimization-validation/command-output-policy.js +9 -3
  13. package/ci/test-optimization-validation/command-runner.js +9 -7
  14. package/ci/test-optimization-validation/environment.js +4 -2
  15. package/ci/test-optimization-validation/executable.js +15 -13
  16. package/ci/test-optimization-validation/execution-lock.js +70 -0
  17. package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
  18. package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
  19. package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
  20. package/ci/test-optimization-validation/generated-files.js +38 -28
  21. package/ci/test-optimization-validation/generated-test-contract.js +8 -4
  22. package/ci/test-optimization-validation/generated-verifier.js +24 -17
  23. package/ci/test-optimization-validation/literal-glob.js +52 -0
  24. package/ci/test-optimization-validation/manifest-loader.js +3 -0
  25. package/ci/test-optimization-validation/manifest-scaffold.js +300 -50
  26. package/ci/test-optimization-validation/manifest-schema.js +80 -17
  27. package/ci/test-optimization-validation/offline-fixtures.js +13 -4
  28. package/ci/test-optimization-validation/package-check.js +94 -0
  29. package/ci/test-optimization-validation/plan-writer.js +183 -10
  30. package/ci/test-optimization-validation/preflight-runner.js +110 -31
  31. package/ci/test-optimization-validation/project-build-artifact.js +31 -0
  32. package/ci/test-optimization-validation/redaction.js +18 -27
  33. package/ci/test-optimization-validation/report-writer.js +182 -48
  34. package/ci/test-optimization-validation/result-semantics.js +20 -3
  35. package/ci/test-optimization-validation/runner-command.js +40 -20
  36. package/ci/test-optimization-validation/runner-contract.js +79 -43
  37. package/ci/test-optimization-validation/scenarios/basic-reporting.js +59 -5
  38. package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
  39. package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
  40. package/ci/test-optimization-validation/static-diagnosis.js +10 -3
  41. package/ci/test-optimization-validation/test-output.js +2 -1
  42. package/ci/test-optimization-validation/validation-blocker.js +21 -0
  43. package/ci/vitest-no-worker-init-setup.mjs +140 -42
  44. package/index.d.ts +140 -1
  45. package/init.js +1 -17
  46. package/initialize.mjs +11 -0
  47. package/loader-hook.mjs +6 -4
  48. package/package.json +8 -5
  49. package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
  50. package/packages/datadog-esbuild/src/utils.js +16 -1
  51. package/packages/datadog-instrumentations/src/ai.js +61 -34
  52. package/packages/datadog-instrumentations/src/bluebird.js +6 -6
  53. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +81 -5
  54. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
  55. package/packages/datadog-instrumentations/src/cucumber.js +124 -47
  56. package/packages/datadog-instrumentations/src/dns.js +21 -2
  57. package/packages/datadog-instrumentations/src/electron.js +1 -0
  58. package/packages/datadog-instrumentations/src/fastify.js +3 -1
  59. package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
  60. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
  61. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  62. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +629 -0
  63. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
  64. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +199 -0
  65. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
  66. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
  67. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +62 -0
  68. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
  69. package/packages/datadog-instrumentations/src/helpers/router-helper.js +37 -6
  70. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
  71. package/packages/datadog-instrumentations/src/jest.js +980 -234
  72. package/packages/datadog-instrumentations/src/mocha/main.js +108 -10
  73. package/packages/datadog-instrumentations/src/mocha/utils.js +66 -50
  74. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +25 -0
  75. package/packages/datadog-instrumentations/src/mocha/worker.js +12 -18
  76. package/packages/datadog-instrumentations/src/mysql.js +46 -16
  77. package/packages/datadog-instrumentations/src/mysql2.js +119 -18
  78. package/packages/datadog-instrumentations/src/next.js +155 -23
  79. package/packages/datadog-instrumentations/src/openai.js +14 -0
  80. package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
  81. package/packages/datadog-instrumentations/src/pg.js +209 -11
  82. package/packages/datadog-instrumentations/src/playwright.js +173 -79
  83. package/packages/datadog-instrumentations/src/promise-js.js +4 -4
  84. package/packages/datadog-instrumentations/src/promise.js +3 -3
  85. package/packages/datadog-instrumentations/src/router.js +195 -19
  86. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +85 -13
  87. package/packages/datadog-instrumentations/src/vitest-main.js +528 -72
  88. package/packages/datadog-instrumentations/src/vitest-util.js +106 -12
  89. package/packages/datadog-instrumentations/src/vitest-worker.js +382 -40
  90. package/packages/datadog-instrumentations/src/webdriverio.js +212 -22
  91. package/packages/datadog-instrumentations/src/when.js +3 -3
  92. package/packages/datadog-instrumentations/src/ws.js +5 -1
  93. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
  94. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
  95. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -5
  96. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
  97. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -3
  98. package/packages/datadog-plugin-cucumber/src/index.js +5 -1
  99. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +51 -47
  100. package/packages/datadog-plugin-cypress/src/support.js +7 -4
  101. package/packages/datadog-plugin-electron/src/net.js +10 -4
  102. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
  103. package/packages/datadog-plugin-http/src/client.js +1 -1
  104. package/packages/datadog-plugin-http2/src/client.js +1 -1
  105. package/packages/datadog-plugin-jest/src/index.js +6 -22
  106. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
  107. package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
  108. package/packages/datadog-plugin-kafkajs/src/producer.js +5 -3
  109. package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
  110. package/packages/datadog-plugin-mocha/src/index.js +832 -4
  111. package/packages/datadog-plugin-mysql/src/index.js +37 -0
  112. package/packages/datadog-plugin-next/src/index.js +51 -21
  113. package/packages/datadog-plugin-openai/src/tracing.js +4 -0
  114. package/packages/datadog-plugin-openai-agents/src/integration.js +278 -69
  115. package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
  116. package/packages/datadog-plugin-pg/src/index.js +66 -1
  117. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  118. package/packages/datadog-plugin-vitest/src/index.js +103 -27
  119. package/packages/datadog-plugin-ws/src/util.js +2 -1
  120. package/packages/datadog-shimmer/src/shimmer.js +6 -2
  121. package/packages/dd-trace/src/aiguard/sdk.js +3 -0
  122. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
  123. package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
  124. package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
  125. package/packages/dd-trace/src/appsec/handlers/http-request.js +228 -0
  126. package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
  127. package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
  128. package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
  129. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
  130. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  131. package/packages/dd-trace/src/appsec/index.js +48 -476
  132. package/packages/dd-trace/src/appsec/sdk/track_event.js +9 -0
  133. package/packages/dd-trace/src/carrier.js +356 -0
  134. package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
  135. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
  136. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +27 -13
  137. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +17 -0
  138. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +21 -1
  139. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
  140. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
  141. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
  142. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +1 -1
  143. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
  144. package/packages/dd-trace/src/config/generated-config-types.d.ts +5 -0
  145. package/packages/dd-trace/src/config/helper.js +2 -0
  146. package/packages/dd-trace/src/config/index.js +16 -5
  147. package/packages/dd-trace/src/config/remote_config.js +1 -1
  148. package/packages/dd-trace/src/config/supported-configurations.json +18 -0
  149. package/packages/dd-trace/src/datastreams/context.js +6 -1
  150. package/packages/dd-trace/src/datastreams/manager.js +5 -1
  151. package/packages/dd-trace/src/datastreams/pathway.js +23 -22
  152. package/packages/dd-trace/src/datastreams/processor.js +3 -2
  153. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
  154. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  155. package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
  156. package/packages/dd-trace/src/guardrails/log.js +1 -10
  157. package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
  158. package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
  159. package/packages/dd-trace/src/llmobs/experiments/index.js +33 -25
  160. package/packages/dd-trace/src/llmobs/experiments/util.js +4 -2
  161. package/packages/dd-trace/src/llmobs/index.js +34 -2
  162. package/packages/dd-trace/src/llmobs/noop.js +2 -0
  163. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
  164. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  165. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
  166. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  167. package/packages/dd-trace/src/llmobs/sdk.js +149 -68
  168. package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
  169. package/packages/dd-trace/src/llmobs/tagger.js +96 -0
  170. package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
  171. package/packages/dd-trace/src/llmobs/util.js +78 -0
  172. package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
  173. package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
  174. package/packages/dd-trace/src/log/channels.js +1 -9
  175. package/packages/dd-trace/src/log/levels.js +12 -0
  176. package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
  177. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  178. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
  179. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
  180. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
  181. package/packages/dd-trace/src/opentelemetry/span.js +4 -0
  182. package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
  183. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
  184. package/packages/dd-trace/src/plugin_manager.js +2 -0
  185. package/packages/dd-trace/src/plugins/ci_plugin.js +21 -5
  186. package/packages/dd-trace/src/plugins/index.js +1 -0
  187. package/packages/dd-trace/src/plugins/util/ci.js +6 -0
  188. package/packages/dd-trace/src/plugins/util/git.js +6 -4
  189. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +2 -2
  190. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
  191. package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +3 -62
  192. package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
  193. package/packages/dd-trace/src/plugins/util/test.js +397 -74
  194. package/packages/dd-trace/src/plugins/util/url.js +1 -1
  195. package/packages/dd-trace/src/plugins/util/web.js +76 -3
  196. package/packages/dd-trace/src/profiler.js +1 -1
  197. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
  198. package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
  199. package/packages/dd-trace/src/proxy.js +1 -0
  200. package/packages/dd-trace/src/ritm.js +5 -0
  201. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
  202. package/packages/dd-trace/src/sampling_rule.js +4 -2
  203. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
  204. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
  205. package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
  206. package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
  207. package/vendor/dist/pprof-format/index.js +1 -1
  208. package/version.js +10 -8
  209. /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
@@ -9,6 +9,8 @@ const { METRIC_TYPES } = require('./constants')
9
9
  /**
10
10
  * @typedef {import('@opentelemetry/api').MetricOptions} MetricOptions
11
11
  * @typedef {import('@opentelemetry/core').InstrumentationScope} InstrumentationScope
12
+ * @typedef {Counter | UpDownCounter | Histogram | Gauge |
13
+ * ObservableGauge | ObservableCounter | ObservableUpDownCounter} Instrument
12
14
  */
13
15
 
14
16
  /**
@@ -25,7 +27,7 @@ class Meter {
25
27
  /**
26
28
  * Creates a new Meter instance.
27
29
  *
28
- * @param {MeterProvider} meterProvider - Parent meter provider
30
+ * @param {import('./meter_provider')} meterProvider - Parent meter provider
29
31
  * @param {InstrumentationScope} instrumentationScope - Instrumentation scope information
30
32
  * @param {string} [instrumentationScope.name] - Meter name (defaults to 'dd-trace-js')
31
33
  * @param {string} [instrumentationScope.version] - Meter version (defaults to tracer version)
@@ -50,11 +52,13 @@ class Meter {
50
52
  * Instruments are cached by type and normalized (lowercase) name.
51
53
  *
52
54
  *
55
+ * @template {Instrument} T
53
56
  * @param {string} name - Instrument name (will be normalized to lowercase)
54
57
  * @param {string} type - Instrument type (e.g., 'counter', 'histogram', 'gauge')
55
- * @param {Function} InstrumentClass - Constructor for the instrument type
56
- * @param {MetricOptions} [options] - Instrument options (description, unit, etc.)
57
- * @returns {Instrument} The instrument instance (new or cached)
58
+ * @param {new (name: string, options: object, instrumentationScope: InstrumentationScope,
59
+ * reader: object) => T} InstrumentClass - Constructor for the instrument type
60
+ * @param {MetricOptions} options - Instrument options (description, unit, etc.)
61
+ * @returns {T} The instrument instance (new or cached)
58
62
  */
59
63
  #getOrCreateInstrument (name, type, InstrumentClass, options) {
60
64
  const normalizedName = name.toLowerCase()
@@ -109,7 +109,7 @@ class PeriodicMetricReader {
109
109
  /**
110
110
  * Creates a new PeriodicMetricReader instance.
111
111
  *
112
- * @param {OtlpHttpMetricExporter} exporter - Metric exporter for sending to Datadog Agent
112
+ * @param {import('./otlp_http_metric_exporter')} exporter - Metric exporter for sending to Datadog Agent
113
113
  * @param {number} exportInterval - Export interval in milliseconds
114
114
  * @param {string} temporalityPreference - Temporality preference: DELTA, CUMULATIVE, or LOWMEMORY
115
115
  * @param {number} maxBatchedQueueSize - Maximum number of measurements to queue before dropping
@@ -38,6 +38,10 @@ function hrTimeToMilliseconds (hrTime) {
38
38
  /**
39
39
  * Several of these attributes are not yet supported by the Node.js OTel API.
40
40
  * We check for old equivalents where we can, but not all had equivalents.
41
+ *
42
+ * @param {string | undefined} spanName
43
+ * @param {import('@opentelemetry/api').SpanKind} kind
44
+ * @param {import('@opentelemetry/api').Attributes} attributes
41
45
  */
42
46
  function spanNameMapper (spanName, kind, attributes) {
43
47
  if (spanName) return spanName
@@ -1,7 +1,39 @@
1
1
  'use strict'
2
2
 
3
3
  const { channel } = require('dc-polyfill')
4
- const pick = require('../../../../datadog-core/src/utils/src/pick')
4
+ const {
5
+ pickTextMap,
6
+ readBaggage,
7
+ readB3,
8
+ readB3Flags,
9
+ readB3Sampled,
10
+ readB3SpanId,
11
+ readB3TraceId,
12
+ readDatadogOrigin,
13
+ readDatadogParentId,
14
+ readDatadogSamplingPriority,
15
+ readDatadogTags,
16
+ readDatadogTraceId,
17
+ readLegacyBaggage,
18
+ readSqsd,
19
+ readTraceparent,
20
+ readTracestate,
21
+ writeBaggage,
22
+ writeB3,
23
+ writeB3Flags,
24
+ writeB3ParentId,
25
+ writeB3Sampled,
26
+ writeB3SpanId,
27
+ writeB3TraceId,
28
+ writeDatadogOrigin,
29
+ writeDatadogParentId,
30
+ writeDatadogSamplingPriority,
31
+ writeDatadogTags,
32
+ writeDatadogTraceId,
33
+ writeLegacyBaggage,
34
+ writeTraceparent,
35
+ writeTracestate,
36
+ } = require('../../carrier')
5
37
  const id = require('../../id')
6
38
  const DatadogSpanContext = require('../span_context')
7
39
  const log = require('../../log')
@@ -20,21 +52,8 @@ const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
20
52
  const injectCh = channel('dd-trace:span:inject')
21
53
  const extractCh = channel('dd-trace:span:extract')
22
54
 
23
- const traceKey = 'x-datadog-trace-id'
24
- const spanKey = 'x-datadog-parent-id'
25
- const originKey = 'x-datadog-origin'
26
- const samplingKey = 'x-datadog-sampling-priority'
27
- const tagsKey = 'x-datadog-tags'
28
- const baggagePrefix = 'ot-baggage-'
29
- const b3TraceKey = 'x-b3-traceid'
30
55
  const b3TraceExpr = /^([0-9a-f]{16}){1,2}$/i
31
- const b3SpanKey = 'x-b3-spanid'
32
56
  const b3SpanExpr = /^[0-9a-f]{16}$/i
33
- const b3ParentKey = 'x-b3-parentspanid'
34
- const b3SampledKey = 'x-b3-sampled'
35
- const b3FlagsKey = 'x-b3-flags'
36
- const b3HeaderKey = 'b3'
37
- const sqsdHeaderHey = 'x-aws-sqsd-attr-_datadog'
38
57
  const b3HeaderExpr = /^(([0-9a-f]{16}){1,2}-[0-9a-f]{16}(-[01d](-[0-9a-f]{16})?)?|[01d])$/i
39
58
  // W3C Baggage key grammar: key = token (RFC 7230).
40
59
  // Spec (up-to-date): "Propagation format for distributed context: Baggage" §3.3.1
@@ -43,19 +62,10 @@ const b3HeaderExpr = /^(([0-9a-f]{16}){1,2}-[0-9a-f]{16}(-[01d](-[0-9a-f]{16})?)
43
62
  const baggageTokenExpr = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/
44
63
  const tagKeyExpr = /^_dd\.p\.[\x21-\x2B\x2D-\x7E]+$/ // ASCII minus spaces and commas
45
64
  const tagValueExpr = /^[\x20-\x2B\x2D-\x7E]*$/ // ASCII minus commas
46
- // RFC7230 token (used by HTTP header field-name) and compatible with Node's header name validation.
47
- // See https://www.rfc-editor.org/rfc/rfc7230#section-3.2.6
48
- const httpHeaderNameExpr = /^[0-9A-Za-z!#$%&'*+\-.^_`|~]+$/
49
65
  // Compatible with Node's internal header value validation (allows HTAB, SP-~, and \x80-\xFF only)
50
66
  // https://github.com/nodejs/node/blob/main/lib/_http_common.js
51
67
  const invalidHeaderValueCharExpr = /[^\t\x20-\x7E\x80-\xFF]/
52
68
  const traceparentExpr = /^([a-f0-9]{2})-([a-f0-9]{32})-([a-f0-9]{16})-([a-f0-9]{2})(-.*)?$/i
53
- const traceparentKey = 'traceparent'
54
- const tracestateKey = 'tracestate'
55
- const ddKeys = [traceKey, spanKey, samplingKey, originKey]
56
- const b3Keys = [b3TraceKey, b3SpanKey, b3ParentKey, b3SampledKey, b3FlagsKey, b3HeaderKey]
57
- const w3cKeys = [traceparentKey, tracestateKey]
58
- const logKeys = [...ddKeys, ...b3Keys, ...w3cKeys]
59
69
  // Dispatch table for `_extractSpanContext`. `'b3'` resolves to the matching
60
70
  // single/multi extractor per instance — see `#b3MethodName` — so it is not in
61
71
  // this table. `'baggage'` is consumed by `_extractBaggageItems`, not the loop.
@@ -146,7 +156,7 @@ class TextMapPropagator {
146
156
  if (injectCh.hasSubscribers) injectCh.publish({ spanContext, carrier })
147
157
 
148
158
  // eslint-disable-next-line eslint-rules/eslint-log-printf-style
149
- log.debug(() => `Inject into carrier: ${JSON.stringify(pick(carrier, logKeys))}.`)
159
+ log.debug(() => `Inject into carrier: ${JSON.stringify(pickTextMap(carrier))}.`)
150
160
 
151
161
  return carrier
152
162
  }
@@ -161,7 +171,7 @@ class TextMapPropagator {
161
171
 
162
172
  // eslint-disable-next-line eslint-rules/eslint-log-printf-style
163
173
  log.debug(() => {
164
- const keys = JSON.stringify(pick(carrier, logKeys))
174
+ const keys = JSON.stringify(pickTextMap(carrier))
165
175
  const styles = this._config.tracePropagationStyle.extract.join(', ')
166
176
 
167
177
  return `Extract from carrier (${styles}): ${keys}.`
@@ -179,8 +189,8 @@ class TextMapPropagator {
179
189
  if (!this._hasPropagationStyle('inject', 'datadog')) return
180
190
 
181
191
  carrier ??= {}
182
- carrier[traceKey] = spanContext.toTraceId()
183
- carrier[spanKey] = spanContext.toSpanId()
192
+ writeDatadogTraceId(carrier, spanContext.toTraceId())
193
+ writeDatadogParentId(carrier, spanContext.toSpanId())
184
194
 
185
195
  this._injectOrigin(spanContext, carrier)
186
196
  this._injectSamplingPriority(spanContext, carrier)
@@ -193,7 +203,7 @@ class TextMapPropagator {
193
203
  const origin = spanContext._trace.origin
194
204
 
195
205
  if (origin) {
196
- carrier[originKey] = origin
206
+ writeDatadogOrigin(carrier, origin)
197
207
  }
198
208
  }
199
209
 
@@ -201,7 +211,7 @@ class TextMapPropagator {
201
211
  const priority = spanContext._sampling.priority
202
212
 
203
213
  if (Number.isInteger(priority)) {
204
- carrier[samplingKey] = priority.toString()
214
+ writeDatadogSamplingPriority(carrier, priority.toString())
205
215
  }
206
216
  }
207
217
 
@@ -216,22 +226,17 @@ class TextMapPropagator {
216
226
  const baggageItems = spanContext?._baggageItems
217
227
  if (baggageItems) {
218
228
  for (const key of Object.keys(baggageItems)) {
219
- const headerName = baggagePrefix + key
220
-
221
- // Legacy OpenTracing baggage is propagated as individual headers (ot-baggage-*),
222
- // so it must always be representable as a valid HTTP header name.
223
- if (!httpHeaderNameExpr.test(headerName)) {
224
- tracerMetrics.count('context_header_style.malformed', ['header_style:baggage']).inc()
225
- continue
226
- }
227
-
228
229
  let headerValue = String(baggageItems[key])
229
230
  // Avoid Node throwing ERR_INVALID_CHAR when setting header values (e.g. newline from decoded OTEL baggage).
230
231
  if (invalidHeaderValueCharExpr.test(headerValue)) {
231
232
  headerValue = encodeURIComponent(headerValue)
232
233
  }
233
- injectedCarrier ??= carrier ?? {}
234
- injectedCarrier[headerName] = headerValue
234
+ const nextCarrier = writeLegacyBaggage(injectedCarrier ?? carrier, key, headerValue)
235
+ if (nextCarrier === undefined) {
236
+ tracerMetrics.count('context_header_style.malformed', ['header_style:baggage']).inc()
237
+ continue
238
+ }
239
+ injectedCarrier = nextCarrier
235
240
  }
236
241
  }
237
242
  }
@@ -271,7 +276,7 @@ class TextMapPropagator {
271
276
  baggage = baggage.slice(0, -1)
272
277
  if (baggage) {
273
278
  injectedCarrier ??= carrier ?? {}
274
- injectedCarrier.baggage = baggage
279
+ writeBaggage(injectedCarrier, baggage)
275
280
  tracerMetrics.count('context_header_style.injected', ['header_style:baggage']).inc()
276
281
  }
277
282
  }
@@ -305,7 +310,7 @@ class TextMapPropagator {
305
310
  if (header.length > this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
306
311
  log.error('Trace tags from span are too large, skipping injection.')
307
312
  } else if (header) {
308
- carrier[tagsKey] = header
313
+ writeDatadogTags(carrier, header)
309
314
  }
310
315
  }
311
316
 
@@ -321,16 +326,16 @@ class TextMapPropagator {
321
326
  if (!hasB3multi) return
322
327
 
323
328
  carrier ??= {}
324
- carrier[b3TraceKey] = spanContext._traceId.toTraceIdHex(spanContext._trace.tags['_dd.p.tid'])
325
- carrier[b3SpanKey] = spanContext._spanId.toString(16)
326
- carrier[b3SampledKey] = spanContext._sampling.priority >= AUTO_KEEP ? '1' : '0'
329
+ writeB3TraceId(carrier, spanContext._traceId.toTraceIdHex(spanContext._trace.tags['_dd.p.tid']))
330
+ writeB3SpanId(carrier, spanContext._spanId.toString(16))
331
+ writeB3Sampled(carrier, spanContext._sampling.priority >= AUTO_KEEP ? '1' : '0')
327
332
 
328
333
  if (spanContext._sampling.priority > AUTO_KEEP) {
329
- carrier[b3FlagsKey] = '1'
334
+ writeB3Flags(carrier, '1')
330
335
  }
331
336
 
332
337
  if (spanContext._parentId) {
333
- carrier[b3ParentKey] = spanContext._parentId.toString(16)
338
+ writeB3ParentId(carrier, spanContext._parentId.toString(16))
334
339
  }
335
340
 
336
341
  return carrier
@@ -352,10 +357,11 @@ class TextMapPropagator {
352
357
  const spanId = spanContext._spanId.toString(16)
353
358
  const sampled = spanContext._sampling.priority >= AUTO_KEEP ? '1' : '0'
354
359
 
355
- carrier[b3HeaderKey] = `${traceId}-${spanId}-${sampled}`
360
+ let header = `${traceId}-${spanId}-${sampled}`
356
361
  if (spanContext._parentId) {
357
- carrier[b3HeaderKey] += '-' + spanContext._parentId.toString(16)
362
+ header += '-' + spanContext._parentId.toString(16)
358
363
  }
364
+ writeB3(carrier, header)
359
365
 
360
366
  return carrier
361
367
  }
@@ -375,7 +381,7 @@ class TextMapPropagator {
375
381
  const header = tracestate.toString()
376
382
  if (!header) return
377
383
  carrier ??= {}
378
- carrier.tracestate = header
384
+ writeTracestate(carrier, header)
379
385
  return carrier
380
386
  }
381
387
 
@@ -386,7 +392,7 @@ class TextMapPropagator {
386
392
  _trace: { origin, tags: traceTags },
387
393
  } = spanContext
388
394
 
389
- carrier[traceparentKey] = spanContext.toTraceparent()
395
+ writeTraceparent(carrier, spanContext.toTraceparent())
390
396
 
391
397
  ts.forVendor('dd', state => {
392
398
  if (!spanContext._isRemote) {
@@ -426,7 +432,7 @@ class TextMapPropagator {
426
432
  }
427
433
  })
428
434
 
429
- carrier.tracestate = ts.toString()
435
+ writeTracestate(carrier, ts.toString())
430
436
 
431
437
  return carrier
432
438
  }
@@ -525,7 +531,12 @@ class TextMapPropagator {
525
531
  }
526
532
 
527
533
  _extractDatadogContext (carrier) {
528
- const spanContext = this._extractGenericContext(carrier, traceKey, spanKey, 10)
534
+ if (!carrier) return
535
+ const spanContext = this._extractGenericContext(
536
+ readDatadogTraceId(carrier),
537
+ readDatadogParentId(carrier),
538
+ 10
539
+ )
529
540
 
530
541
  if (!spanContext) return spanContext
531
542
 
@@ -553,19 +564,16 @@ class TextMapPropagator {
553
564
  }
554
565
 
555
566
  _extractB3SingleContext (carrier) {
556
- // `typeof === 'string'` first; otherwise the regex coerces `undefined` to
557
- // `'undefined'` and runs on every header-less request.
558
- const header = carrier[b3HeaderKey]
559
- if (typeof header !== 'string' || !b3HeaderExpr.test(header)) return
560
- const b3 = this._extractB3SingleHeader(carrier)
561
- if (b3 === undefined) return
562
- return this._extractB3Context(b3)
567
+ // Check the resolved value first so the regex does not run on header-less requests.
568
+ const header = readB3(carrier)
569
+ if (!header || !b3HeaderExpr.test(header)) return
570
+ return this._extractB3Context(this._extractB3SingleHeader(header))
563
571
  }
564
572
 
565
573
  _extractB3Context (b3) {
566
- const debug = b3[b3FlagsKey] === '1'
567
- const priority = this._getPriority(b3[b3SampledKey], debug)
568
- const spanContext = this._extractGenericContext(b3, b3TraceKey, b3SpanKey, 16)
574
+ const debug = b3.flags === '1'
575
+ const priority = this._getPriority(b3.sampled, debug)
576
+ const spanContext = this._extractGenericContext(b3.traceId, b3.spanId, 16)
569
577
 
570
578
  if (priority !== undefined) {
571
579
  if (!spanContext) {
@@ -581,13 +589,13 @@ class TextMapPropagator {
581
589
  spanContext._sampling.priority = priority
582
590
  }
583
591
 
584
- this._extract128BitTraceId(b3[b3TraceKey], spanContext)
592
+ this._extract128BitTraceId(b3.traceId, spanContext)
585
593
 
586
594
  return spanContext
587
595
  }
588
596
 
589
597
  _extractSqsdContext (carrier) {
590
- const headerValue = carrier[sqsdHeaderHey]
598
+ const headerValue = readSqsd(carrier)
591
599
  if (!headerValue) return
592
600
  let parsed
593
601
  try {
@@ -599,18 +607,14 @@ class TextMapPropagator {
599
607
  }
600
608
 
601
609
  _extractTraceparentContext (carrier) {
602
- const headerValue = carrier[traceparentKey]
603
- if (typeof headerValue !== 'string') return
610
+ const headerValue = readTraceparent(carrier)
611
+ if (!headerValue) return
604
612
  const matches = headerValue.trim().match(traceparentExpr)
605
613
  if (matches !== null) {
606
614
  const [, version, traceId, spanId, flags, tail] = matches
607
615
  const traceparent = { version }
608
616
  // W3C Trace Context §3.3.1.1: multiple tracestate fields MUST be combined per RFC 7230 §3.2.2.
609
- // `filter` drops non-string members (Symbol, throwing-toString) that would crash `join`.
610
- const rawTracestate = Array.isArray(carrier.tracestate)
611
- ? carrier.tracestate.filter(item => typeof item === 'string').join(',')
612
- : carrier.tracestate
613
- const tracestate = TraceState.fromString(rawTracestate)
617
+ const tracestate = TraceState.fromString(readTracestate(carrier))
614
618
  if (invalidSegment.test(traceId)) return
615
619
  if (invalidSegment.test(spanId)) return
616
620
 
@@ -683,75 +687,81 @@ class TextMapPropagator {
683
687
  }
684
688
  }
685
689
 
686
- _extractGenericContext (carrier, traceKey, spanKey, radix) {
687
- if (carrier && carrier[traceKey] && carrier[spanKey]) {
688
- if (invalidSegment.test(carrier[traceKey])) return
689
-
690
- return new DatadogSpanContext({
691
- traceId: id(carrier[traceKey], radix),
692
- spanId: id(carrier[spanKey], radix),
693
- isRemote: true,
694
- })
695
- }
690
+ /**
691
+ * @param {string | undefined} traceId
692
+ * @param {string | undefined} spanId
693
+ * @param {number} radix
694
+ * @returns {DatadogSpanContext | undefined}
695
+ */
696
+ _extractGenericContext (traceId, spanId, radix) {
697
+ if (!traceId || invalidSegment.test(traceId)) return
698
+ if (!spanId) return
699
+
700
+ return new DatadogSpanContext({
701
+ traceId: id(traceId, radix),
702
+ spanId: id(spanId, radix),
703
+ isRemote: true,
704
+ })
696
705
  }
697
706
 
698
707
  _extractB3MultipleHeaders (carrier) {
699
- // `b3ParentKey` is intentionally absent: this method never consults it,
708
+ // The parent-id field is intentionally absent: this method never consults it,
700
709
  // so a parent-id-only carrier should bail with the rest.
701
- if (carrier[b3TraceKey] === undefined &&
702
- carrier[b3SampledKey] === undefined &&
703
- carrier[b3FlagsKey] === undefined) {
710
+ const traceId = readB3TraceId(carrier)
711
+ const sampled = readB3Sampled(carrier)
712
+ const flags = readB3Flags(carrier)
713
+
714
+ if (traceId === undefined && sampled === undefined && flags === undefined) {
704
715
  return
705
716
  }
706
717
 
707
718
  let empty = true
708
719
  const b3 = {}
720
+ const spanId = readB3SpanId(carrier)
709
721
 
710
- if (b3TraceExpr.test(carrier[b3TraceKey]) && b3SpanExpr.test(carrier[b3SpanKey])) {
711
- b3[b3TraceKey] = carrier[b3TraceKey]
712
- b3[b3SpanKey] = carrier[b3SpanKey]
722
+ if (traceId && spanId && b3TraceExpr.test(traceId) && b3SpanExpr.test(spanId)) {
723
+ b3.traceId = traceId
724
+ b3.spanId = spanId
713
725
  empty = false
714
726
  }
715
727
 
716
- if (carrier[b3SampledKey]) {
717
- b3[b3SampledKey] = carrier[b3SampledKey]
728
+ if (sampled) {
729
+ b3.sampled = sampled
718
730
  empty = false
719
731
  }
720
732
 
721
- if (carrier[b3FlagsKey]) {
722
- b3[b3FlagsKey] = carrier[b3FlagsKey]
733
+ if (flags) {
734
+ b3.flags = flags
723
735
  empty = false
724
736
  }
725
737
 
726
738
  return empty ? undefined : b3
727
739
  }
728
740
 
729
- _extractB3SingleHeader (carrier) {
730
- const header = carrier[b3HeaderKey]
731
- if (!header) return
732
-
741
+ /** @param {string} header */
742
+ _extractB3SingleHeader (header) {
733
743
  const parts = header.split('-')
734
744
 
735
745
  if (parts[0] === 'd') {
736
746
  return {
737
- [b3SampledKey]: '1',
738
- [b3FlagsKey]: '1',
747
+ sampled: '1',
748
+ flags: '1',
739
749
  }
740
750
  } else if (parts.length === 1) {
741
751
  return {
742
- [b3SampledKey]: parts[0],
752
+ sampled: parts[0],
743
753
  }
744
754
  }
745
755
  const b3 = {
746
- [b3TraceKey]: parts[0],
747
- [b3SpanKey]: parts[1],
756
+ traceId: parts[0],
757
+ spanId: parts[1],
748
758
  }
749
759
 
750
760
  if (parts[2]) {
751
- b3[b3SampledKey] = parts[2] === '0' ? '0' : '1'
761
+ b3.sampled = parts[2] === '0' ? '0' : '1'
752
762
 
753
763
  if (parts[2] === 'd') {
754
- b3[b3FlagsKey] = '1'
764
+ b3.flags = '1'
755
765
  }
756
766
  }
757
767
 
@@ -759,29 +769,22 @@ class TextMapPropagator {
759
769
  }
760
770
 
761
771
  _extractOrigin (carrier, spanContext) {
762
- const origin = carrier[originKey]
772
+ const origin = readDatadogOrigin(carrier)
763
773
 
764
- if (typeof carrier[originKey] === 'string') {
774
+ if (typeof origin === 'string') {
765
775
  spanContext._trace.origin = origin
766
776
  }
767
777
  }
768
778
 
769
779
  _extractLegacyBaggageItems (carrier, spanContext) {
770
780
  if (!this._config.legacyBaggageEnabled) return
771
- for (const key of Object.keys(carrier)) {
772
- if (!key.startsWith(baggagePrefix)) continue
773
- const baggageKey = key.slice(baggagePrefix.length)
774
- if (baggageKey) {
775
- spanContext._baggageItems[baggageKey] = carrier[key]
776
- }
777
- }
781
+ readLegacyBaggage(carrier, spanContext._baggageItems)
778
782
  }
779
783
 
780
784
  _extractBaggageItems (carrier, spanContext) {
781
785
  removeAllBaggageItems()
782
- if (!this._hasPropagationStyle('extract', 'baggage')) return
783
- const baggageHeader = carrier?.baggage
784
- const header = Array.isArray(baggageHeader) ? baggageHeader.join(',') : baggageHeader
786
+ if (!carrier || !this._hasPropagationStyle('extract', 'baggage')) return
787
+ const header = readBaggage(carrier)
785
788
  if (!header) return
786
789
 
787
790
  const baggages = header.split(',')
@@ -853,7 +856,9 @@ class TextMapPropagator {
853
856
  }
854
857
 
855
858
  _extractSamplingPriority (carrier, spanContext) {
856
- const priority = Number.parseInt(carrier[samplingKey], 10)
859
+ const header = readDatadogSamplingPriority(carrier)
860
+ if (header === undefined) return
861
+ const priority = Number.parseInt(header, 10)
857
862
 
858
863
  if (Number.isInteger(priority)) {
859
864
  spanContext._sampling.priority = priority
@@ -861,16 +866,17 @@ class TextMapPropagator {
861
866
  }
862
867
 
863
868
  _extractTags (carrier, spanContext) {
864
- if (!carrier[tagsKey]) return
869
+ const header = readDatadogTags(carrier)
870
+ if (!header) return
865
871
 
866
872
  const trace = spanContext._trace
867
873
 
868
874
  if (this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) {
869
875
  log.debug('Trace tag propagation is disabled, skipping extraction.')
870
- } else if (carrier[tagsKey].length > this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
876
+ } else if (header.length > this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
871
877
  log.error('Trace tags from carrier are too large, skipping extraction.')
872
878
  } else {
873
- const pairs = carrier[tagsKey].split(',')
879
+ const pairs = header.split(',')
874
880
  const tags = {}
875
881
 
876
882
  for (const pair of pairs) {
@@ -1,13 +1,10 @@
1
1
  'use strict'
2
2
 
3
- const pick = require('../../../../datadog-core/src/utils/src/pick')
3
+ const { pickDsm } = require('../../carrier')
4
4
  const log = require('../../log')
5
5
 
6
6
  const { DsmPathwayCodec } = require('../../datastreams')
7
7
 
8
- const base64Key = 'dd-pathway-ctx-base64'
9
- const logKeys = [base64Key]
10
-
11
8
  class DSMTextMapPropagator {
12
9
  constructor (config) {
13
10
  this.config = config
@@ -24,11 +21,10 @@ class DSMTextMapPropagator {
24
21
  const injectedCarrier = DsmPathwayCodec.encode(ctx, carrier)
25
22
  if (injectedCarrier === undefined) return
26
23
 
27
- carrier = injectedCarrier
28
24
  // eslint-disable-next-line eslint-rules/eslint-log-printf-style
29
- log.debug(() => `Inject into carrier (DSM): ${JSON.stringify(pick(carrier, logKeys))}.`)
25
+ log.debug(() => `Inject into carrier (DSM): ${JSON.stringify(pickDsm(injectedCarrier))}.`)
30
26
 
31
- return carrier
27
+ return injectedCarrier
32
28
  }
33
29
 
34
30
  extract (carrier) {
@@ -39,7 +35,7 @@ class DSMTextMapPropagator {
39
35
  if (!dsmContext) return dsmContext
40
36
 
41
37
  // eslint-disable-next-line eslint-rules/eslint-log-printf-style
42
- log.debug(() => `Extract from carrier (DSM): ${JSON.stringify(pick(carrier, logKeys))}.`)
38
+ log.debug(() => `Extract from carrier (DSM): ${JSON.stringify(pickDsm(carrier))}.`)
43
39
  return dsmContext
44
40
  }
45
41
  }
@@ -165,6 +165,7 @@ module.exports = class PluginManager {
165
165
  codeOriginForSpans,
166
166
  dbmPropagationMode,
167
167
  dsmEnabled,
168
+ DD_TRACE_HTTP_SERVER_ERROR_STATUSES,
168
169
  clientIpEnabled,
169
170
  clientIpHeader,
170
171
  DD_TRACE_MEMCACHED_COMMAND_ENABLED,
@@ -194,6 +195,7 @@ module.exports = class PluginManager {
194
195
  site,
195
196
  url,
196
197
  headers: headerTags || [],
198
+ DD_TRACE_HTTP_SERVER_ERROR_STATUSES,
197
199
  clientIpHeader,
198
200
  DD_TEST_SESSION_NAME,
199
201
  DD_AGENTLESS_LOG_SUBMISSION_ENABLED,
@@ -169,7 +169,7 @@ function getTestSuiteLevelVisibilityTags (testSuiteSpan, testFramework) {
169
169
  }
170
170
 
171
171
  /**
172
- * Keeps non-TIA settings while disabling suite skipping and coverage collection.
172
+ * Keeps non-TIA settings while disabling suite skipping and per-suite coverage collection.
173
173
  *
174
174
  * @param {object} libraryConfig
175
175
  * @returns {object}
@@ -178,7 +178,6 @@ function disableTestImpactAnalysis (libraryConfig) {
178
178
  return Object.freeze({
179
179
  ...libraryConfig,
180
180
  isCodeCoverageEnabled: false,
181
- isCoverageReportUploadEnabled: false,
182
181
  isItrEnabled: false,
183
182
  isSuitesSkippingEnabled: false,
184
183
  })
@@ -260,6 +259,7 @@ module.exports = class CiPlugin extends Plugin {
260
259
  {
261
260
  ...this.testConfiguration,
262
261
  isCoverageReportUploadEnabled: this.libraryConfig?.isCoverageReportUploadEnabled,
262
+ isLineCoverageSupported: this.constructor.id !== 'vitest',
263
263
  },
264
264
  (err, skippableSuites, itrCorrelationId, skippableSuitesCoverage) => {
265
265
  if (err) {
@@ -461,12 +461,28 @@ module.exports = class CiPlugin extends Plugin {
461
461
  this.tracer._exporter.exportDiLogs(this.testEnvironmentMetadata, logMessage)
462
462
  }
463
463
  })
464
+
465
+ this.addSub(`ci:${this.constructor.id}:worker-report:telemetry`, data => {
466
+ const telemetryEvents = JSON.parse(data)
467
+ for (const event of telemetryEvents) {
468
+ if (event.type === 'ciVisEvent') {
469
+ this.telemetry.ciVisEvent(event.name, event.testLevel, {
470
+ ...event.tags,
471
+ testFramework: event.testFramework,
472
+ isUnsupportedCIProvider: event.isUnsupportedCIProvider,
473
+ })
474
+ } else if (event.type === 'count') {
475
+ this.telemetry.count(event.name, event.tags, event.value)
476
+ } else if (event.type === 'distribution') {
477
+ this.telemetry.distribution(event.name, event.tags, event.measure)
478
+ }
479
+ }
480
+ })
464
481
  }
465
482
 
466
483
  get telemetry () {
467
484
  const testFramework = this.testFramework || this.constructor.id
468
485
  const exporter = this.tracer?._exporter
469
- // TODO: only jest worker supported yet
470
486
  const isSupportedWorker = exporter && typeof exporter.exportTelemetry === 'function'
471
487
  const ciProviderName = this.ciProviderName
472
488
 
@@ -1157,11 +1173,11 @@ module.exports = class CiPlugin extends Plugin {
1157
1173
  return
1158
1174
  }
1159
1175
 
1160
- const { filePath, format } = coverageReports[reportIndex]
1176
+ const { filePath, fileDevice, fileInode, format } = coverageReports[reportIndex]
1161
1177
  reportIndex++
1162
1178
 
1163
1179
  this.tracer._exporter.uploadCoverageReport(
1164
- { filePath, format, testEnvironmentMetadata: this.testEnvironmentMetadata },
1180
+ { filePath, fileDevice, fileInode, format, testEnvironmentMetadata: this.testEnvironmentMetadata },
1165
1181
  (err) => {
1166
1182
  if (err) {
1167
1183
  failedCount++