dd-trace 6.7.0 → 6.9.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 (272) 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 +14 -8
  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/playwright.js +5 -5
  20. package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
  21. package/ci/test-optimization-validation/generated-files.js +47 -37
  22. package/ci/test-optimization-validation/generated-test-contract.js +9 -7
  23. package/ci/test-optimization-validation/generated-verifier.js +24 -17
  24. package/ci/test-optimization-validation/literal-glob.js +52 -0
  25. package/ci/test-optimization-validation/manifest-loader.js +3 -0
  26. package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
  27. package/ci/test-optimization-validation/manifest-schema.js +80 -17
  28. package/ci/test-optimization-validation/offline-fixtures.js +13 -4
  29. package/ci/test-optimization-validation/offline-output.js +6 -6
  30. package/ci/test-optimization-validation/package-check.js +94 -0
  31. package/ci/test-optimization-validation/plan-writer.js +183 -10
  32. package/ci/test-optimization-validation/preflight-runner.js +110 -31
  33. package/ci/test-optimization-validation/project-build-artifact.js +31 -0
  34. package/ci/test-optimization-validation/redaction.js +18 -27
  35. package/ci/test-optimization-validation/report-writer.js +182 -48
  36. package/ci/test-optimization-validation/result-semantics.js +20 -3
  37. package/ci/test-optimization-validation/runner-command.js +41 -21
  38. package/ci/test-optimization-validation/runner-contract.js +79 -43
  39. package/ci/test-optimization-validation/safe-files.js +4 -4
  40. package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
  41. package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
  42. package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
  43. package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
  44. package/ci/test-optimization-validation/static-diagnosis.js +10 -3
  45. package/ci/test-optimization-validation/test-output.js +2 -1
  46. package/ci/test-optimization-validation/validation-blocker.js +21 -0
  47. package/ci/vitest-no-worker-init-setup.mjs +377 -84
  48. package/index.d.ts +175 -14
  49. package/init.js +1 -17
  50. package/initialize.mjs +11 -0
  51. package/loader-hook.mjs +6 -4
  52. package/package.json +12 -4
  53. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  54. package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
  55. package/packages/datadog-esbuild/index.js +4 -2
  56. package/packages/datadog-esbuild/src/utils.js +17 -2
  57. package/packages/datadog-instrumentations/src/ai.js +61 -34
  58. package/packages/datadog-instrumentations/src/bluebird.js +6 -6
  59. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
  60. package/packages/datadog-instrumentations/src/cucumber.js +131 -51
  61. package/packages/datadog-instrumentations/src/dns.js +21 -2
  62. package/packages/datadog-instrumentations/src/electron.js +1 -0
  63. package/packages/datadog-instrumentations/src/fastify.js +3 -1
  64. package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
  65. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
  66. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  67. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  68. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  69. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  70. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
  71. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  72. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
  73. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
  74. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
  75. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
  76. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  77. package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
  78. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  79. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  80. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
  81. package/packages/datadog-instrumentations/src/jest.js +986 -246
  82. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  83. package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
  84. package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
  85. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
  86. package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
  87. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  88. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  89. package/packages/datadog-instrumentations/src/next.js +155 -23
  90. package/packages/datadog-instrumentations/src/openai.js +14 -0
  91. package/packages/datadog-instrumentations/src/pg.js +180 -6
  92. package/packages/datadog-instrumentations/src/playwright.js +176 -81
  93. package/packages/datadog-instrumentations/src/promise-js.js +4 -4
  94. package/packages/datadog-instrumentations/src/promise.js +3 -3
  95. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  96. package/packages/datadog-instrumentations/src/router.js +195 -19
  97. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
  98. package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
  99. package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
  100. package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
  101. package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
  102. package/packages/datadog-instrumentations/src/when.js +3 -3
  103. package/packages/datadog-instrumentations/src/ws.js +5 -1
  104. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  105. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  106. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  107. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
  108. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  109. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  110. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  111. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  112. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  113. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  114. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
  115. package/packages/datadog-plugin-cucumber/src/index.js +5 -1
  116. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
  117. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  118. package/packages/datadog-plugin-cypress/src/support.js +7 -4
  119. package/packages/datadog-plugin-electron/src/net.js +10 -4
  120. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  121. package/packages/datadog-plugin-fs/src/index.js +0 -4
  122. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  123. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  124. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  125. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  126. package/packages/datadog-plugin-http/src/client.js +3 -2
  127. package/packages/datadog-plugin-http2/src/client.js +1 -1
  128. package/packages/datadog-plugin-jest/src/index.js +3 -21
  129. package/packages/datadog-plugin-jest/src/util.js +4 -1
  130. package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
  131. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  132. package/packages/datadog-plugin-mocha/src/index.js +342 -6
  133. package/packages/datadog-plugin-next/src/index.js +57 -9
  134. package/packages/datadog-plugin-openai/src/tracing.js +4 -0
  135. package/packages/datadog-plugin-pg/src/index.js +65 -1
  136. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  137. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  138. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  139. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  140. package/packages/datadog-plugin-undici/src/index.js +2 -1
  141. package/packages/datadog-plugin-vitest/src/index.js +179 -18
  142. package/packages/datadog-shimmer/src/shimmer.js +6 -2
  143. package/packages/datadog-webpack/index.js +2 -2
  144. package/packages/dd-trace/src/aiguard/sdk.js +3 -0
  145. package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
  146. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  147. package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
  148. package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
  149. package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
  150. package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
  151. package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
  152. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  153. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  154. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
  155. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  156. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  157. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
  158. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  159. package/packages/dd-trace/src/appsec/index.js +48 -476
  160. package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
  161. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  162. package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
  163. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
  164. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  165. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
  166. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
  167. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
  168. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  169. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  170. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
  171. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
  172. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  173. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
  174. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
  175. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
  176. package/packages/dd-trace/src/config/defaults.js +14 -6
  177. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
  178. package/packages/dd-trace/src/config/helper.js +2 -0
  179. package/packages/dd-trace/src/config/index.js +31 -5
  180. package/packages/dd-trace/src/config/parsers.js +19 -1
  181. package/packages/dd-trace/src/config/remote_config.js +1 -1
  182. package/packages/dd-trace/src/config/supported-configurations.json +13 -6
  183. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  184. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  185. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  186. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  187. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  188. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  189. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
  190. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  191. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  192. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  193. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  194. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  195. package/packages/dd-trace/src/flare/index.js +2 -2
  196. package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
  197. package/packages/dd-trace/src/guardrails/log.js +1 -10
  198. package/packages/dd-trace/src/id.js +1 -1
  199. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  200. package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
  201. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  202. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  203. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  204. package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
  205. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  206. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  207. package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
  208. package/packages/dd-trace/src/llmobs/noop.js +2 -0
  209. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
  210. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  211. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  212. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
  213. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  214. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  215. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  216. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  217. package/packages/dd-trace/src/llmobs/sdk.js +152 -78
  218. package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
  219. package/packages/dd-trace/src/llmobs/tagger.js +1 -2
  220. package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
  221. package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
  222. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  223. package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
  224. package/packages/dd-trace/src/log/channels.js +1 -9
  225. package/packages/dd-trace/src/log/levels.js +12 -0
  226. package/packages/dd-trace/src/noop/proxy.js +2 -2
  227. package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
  228. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  229. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
  230. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
  231. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  232. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
  233. package/packages/dd-trace/src/opentelemetry/span.js +4 -0
  234. package/packages/dd-trace/src/opentracing/span.js +1 -1
  235. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  236. package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
  237. package/packages/dd-trace/src/plugins/index.js +2 -0
  238. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  239. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  240. package/packages/dd-trace/src/plugins/util/ci.js +13 -6
  241. package/packages/dd-trace/src/plugins/util/git.js +7 -5
  242. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
  243. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
  244. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  245. package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
  246. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  247. package/packages/dd-trace/src/plugins/util/test.js +356 -86
  248. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  249. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  250. package/packages/dd-trace/src/plugins/util/web.js +24 -2
  251. package/packages/dd-trace/src/priority_sampler.js +6 -3
  252. package/packages/dd-trace/src/profiler.js +1 -1
  253. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
  254. package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
  255. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  256. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  257. package/packages/dd-trace/src/proxy.js +1 -0
  258. package/packages/dd-trace/src/ritm.js +10 -20
  259. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
  260. package/packages/dd-trace/src/sampling_rule.js +4 -2
  261. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
  262. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
  263. package/packages/dd-trace/src/startup-log.js +3 -0
  264. package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
  265. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  266. package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
  267. package/packages/dd-trace/src/util.js +16 -0
  268. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  269. package/vendor/dist/pprof-format/index.js +1 -1
  270. package/vendor/dist/source-map/index.js +1 -1
  271. package/version.js +10 -8
  272. /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
@@ -5,8 +5,11 @@ const { storage } = require('../../datadog-core')
5
5
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
6
6
  const { COMPONENT, SVC_SRC_KEY } = require('../../dd-trace/src/constants')
7
7
  const web = require('../../dd-trace/src/plugins/util/web')
8
+ const { HTTP_ROUTE, RESOURCE_NAME } = require('../../../ext/tags')
8
9
 
9
10
  const errorPages = new Set(['/404', '/500', '/_error', '/_not-found', '/_not-found/page'])
11
+ const reusedNextRequestStores = new WeakSet()
12
+ const nextParentRoutes = new WeakMap()
10
13
 
11
14
  class NextPlugin extends ServerPlugin {
12
15
  static id = 'next'
@@ -18,7 +21,14 @@ class NextPlugin extends ServerPlugin {
18
21
 
19
22
  bindStart ({ req, res }) {
20
23
  const store = storage('legacy').getStore()
21
- const childOf = store ? store.span : store
24
+ const parentSpan = store?.span
25
+ if (parentSpan?._integrationName === this.constructor.id) {
26
+ const reusedStore = { ...store, span: parentSpan, req }
27
+ reusedNextRequestStores.add(reusedStore)
28
+ return reusedStore
29
+ }
30
+
31
+ const childOf = parentSpan || web.extractIncomingServerContext(this.tracer, req.headers)
22
32
  const { name: schemaServiceName, source: schemaServiceSource } = this.serviceName()
23
33
  const serviceName = this.config.service || schemaServiceName
24
34
  let serviceSource = this.config.service ? 'opt.plugin' : schemaServiceSource
@@ -42,7 +52,10 @@ class NextPlugin extends ServerPlugin {
42
52
 
43
53
  analyticsSampler.sample(span, this.config.measured, true)
44
54
 
45
- return { ...store, span, req }
55
+ const isHttpParent = parentSpan?._integrationName === 'http'
56
+ const httpParentSpan = isHttpParent ? parentSpan : undefined
57
+ const httpParentReq = isHttpParent ? web.getRequest(parentSpan) : undefined
58
+ return { ...store, span, req, httpParentSpan, httpParentReq }
46
59
  }
47
60
 
48
61
  error ({ span, error }) {
@@ -60,6 +73,7 @@ class NextPlugin extends ServerPlugin {
60
73
  const store = storage('legacy').getStore()
61
74
 
62
75
  if (!store) return
76
+ if (reusedNextRequestStores.has(store)) return
63
77
 
64
78
  const span = store.span
65
79
  const error = span.context().getTag('error')
@@ -88,12 +102,12 @@ class NextPlugin extends ServerPlugin {
88
102
  span.finish()
89
103
  }
90
104
 
91
- pageLoad ({ page, isAppPath = false, isStatic = false }) {
105
+ pageLoad ({ page, isAppPath = false, isStatic = false, isFilesystemPath = isAppPath }) {
92
106
  const store = storage('legacy').getStore()
93
107
 
94
108
  if (!store) return
95
109
 
96
- const { span, req } = store
110
+ const { span, req, httpParentReq, httpParentSpan } = store
97
111
 
98
112
  // safeguard against missing req in complicated timeout scenarios
99
113
  if (!req) return
@@ -106,10 +120,11 @@ class NextPlugin extends ServerPlugin {
106
120
  return
107
121
  }
108
122
 
109
- // remove ending /route or /page for appDir projects
110
- // need to check if not an error page too, as those are marked as app directory
111
- // in newer versions
112
- if (isAppPath && !isErrorPage) page = page.slice(0, Math.max(0, page.lastIndexOf('/')))
123
+ // Compiled runtimes may publish a normalized pathname rather than a filesystem path.
124
+ if (isFilesystemPath && !isErrorPage) {
125
+ if (isAppPath) page = normalizeAppPath(page)
126
+ page = normalizeIndexPage(page)
127
+ }
113
128
 
114
129
  // handle static resource
115
130
  if (isStatic) {
@@ -123,7 +138,10 @@ class NextPlugin extends ServerPlugin {
123
138
  'resource.name': `${req.method} ${page}`.trim(),
124
139
  'next.page': page,
125
140
  })
126
- web.setRoute(req, page)
141
+ const routeRequest = httpParentReq || req
142
+ web.setRouteOrEndpointTag(routeRequest)
143
+ setHttpParentRoute(httpParentSpan, req.method, page, isStatic)
144
+ web.setRoute(routeRequest, page)
127
145
  }
128
146
 
129
147
  configure (config) {
@@ -131,6 +149,36 @@ class NextPlugin extends ServerPlugin {
131
149
  }
132
150
  }
133
151
 
152
+ function normalizeIndexPage (page) {
153
+ if (typeof page !== 'string') return page
154
+ if (page === '/index') return '/'
155
+ if (page.endsWith('/index')) return page.slice(0, -'/index'.length) || '/'
156
+ return page
157
+ }
158
+
159
+ function normalizeAppPath (page) {
160
+ if (typeof page !== 'string') return page
161
+
162
+ for (const suffix of ['/page', '/route']) {
163
+ if (page === suffix) return '/'
164
+ if (page.endsWith(suffix)) return page.slice(0, -suffix.length) || '/'
165
+ }
166
+
167
+ return page
168
+ }
169
+
170
+ function setHttpParentRoute (span, method, page, isStatic) {
171
+ if (!span) return
172
+ const currentRoute = span.context().getTag(HTTP_ROUTE)
173
+
174
+ // Only refine a route that Next itself set; static resources are fallbacks.
175
+ if (currentRoute && (nextParentRoutes.get(span) !== currentRoute || isStatic)) return
176
+
177
+ span.setTag(HTTP_ROUTE, page)
178
+ span.setTag(RESOURCE_NAME, `${method} ${page}`.trim())
179
+ nextParentRoutes.set(span, page)
180
+ }
181
+
134
182
  function normalizeConfig (config) {
135
183
  const hooks = getHooks(config)
136
184
  const validateStatus = typeof config.validateStatus === 'function'
@@ -627,6 +627,10 @@ function lookupOperationEndpoint (operationId, methodName, url) {
627
627
  * This function essentially normalizes the OpenAI method interface. Many methods accept
628
628
  * a single object argument. The remaining ones take individual arguments. This function
629
629
  * turns the individual arguments into an object to make extracting properties consistent.
630
+ *
631
+ * @param {string} methodName SDK method name, e.g. `createChatCompletion` or `chat.completions.create`
632
+ * @param {unknown[]} args arguments the SDK method was called with
633
+ * @returns {Record<string, unknown>}
630
634
  */
631
635
  function normalizeRequestPayload (methodName, args) {
632
636
  switch (methodName) {
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { storage } = require('../../datadog-core')
4
- const { CLIENT_PORT_KEY } = require('../../dd-trace/src/constants')
4
+ const { CLIENT_PORT_KEY, SVC_SRC_KEY } = require('../../dd-trace/src/constants')
5
5
  const DatabasePlugin = require('../../dd-trace/src/plugins/database')
6
6
 
7
7
  class PGPlugin extends DatabasePlugin {
@@ -16,6 +16,52 @@ class PGPlugin extends DatabasePlugin {
16
16
  ctx.parentStore = storage('legacy').getStore()
17
17
  })
18
18
  this.addBind('apm:pg:pool:connect:finish', ctx => ctx.parentStore)
19
+
20
+ this.addSub('apm:pg:pool:acquire:start', ctx => {
21
+ const params = ctx.poolOptions
22
+ const operationName = this.operationName({ operation: 'pool.acquire' })
23
+ const deferServiceResolution = typeof this.config.service === 'function'
24
+ const service = deferServiceResolution
25
+ ? undefined
26
+ : this.serviceName({ pluginConfig: this.config, params })
27
+ ctx.deferServiceResolution = deferServiceResolution
28
+
29
+ this.startSpan(operationName, {
30
+ service,
31
+ resource: operationName,
32
+ type: 'sql',
33
+ kind: 'client',
34
+ meta: {
35
+ 'db.type': 'postgres',
36
+ ...connectionMeta(params),
37
+ },
38
+ }, ctx)
39
+ })
40
+ this.addSub('apm:pg:pool:acquire:finish', ctx => {
41
+ const span = ctx.currentStore?.span
42
+ if (span === undefined) return
43
+
44
+ if (ctx.error) {
45
+ this.addError(ctx.error, span)
46
+ }
47
+ span.setTag('db.pool.wait_time_ms', ctx.poolWaitTime)
48
+ // `Pool` options carry only what the caller passed, so anything pg resolves later - a
49
+ // connection string, the default port, `PG*` environment variables - is known once the
50
+ // client exists.
51
+ if (ctx.params !== undefined) {
52
+ span.addTags(connectionMeta(ctx.params))
53
+ if (ctx.deferServiceResolution) {
54
+ const service = this.serviceName({ pluginConfig: this.config, params: ctx.params })
55
+ // A `service` callback may return no name, and the start-time fallback already carries
56
+ // the schema default every other pg span falls back to.
57
+ if (service.name) {
58
+ this.setServiceName(span, service.name)
59
+ span.setTag(SVC_SRC_KEY, service.source)
60
+ }
61
+ }
62
+ }
63
+ this.finish(ctx)
64
+ })
19
65
  }
20
66
 
21
67
  bindStart (ctx) {
@@ -42,10 +88,28 @@ class PGPlugin extends DatabasePlugin {
42
88
  span.setTag('db.stream', 1)
43
89
  }
44
90
 
91
+ if (ctx.poolWaitTime !== undefined) {
92
+ span.setTag('db.pool.wait_time_ms', ctx.poolWaitTime)
93
+ }
94
+
45
95
  ctx.injected = this.injectDbmQuery(span, originalText, service.name, !!query.name)
46
96
 
47
97
  return ctx.currentStore
48
98
  }
49
99
  }
50
100
 
101
+ /**
102
+ * `Pool.options` and `Client.connectionParameters` are pg internals, so either can be missing.
103
+ *
104
+ * @param {{ database?: string, user?: string, host?: string, port?: number } | undefined} params
105
+ */
106
+ function connectionMeta (params) {
107
+ return {
108
+ 'db.name': params?.database,
109
+ 'db.user': params?.user,
110
+ 'out.host': params?.host,
111
+ [CLIENT_PORT_KEY]: params?.port,
112
+ }
113
+ }
114
+
51
115
  module.exports = PGPlugin
@@ -485,7 +485,7 @@ class PlaywrightPlugin extends CiPlugin {
485
485
  {
486
486
  hasCodeOwners: !!span.context().getTag(TEST_CODE_OWNERS),
487
487
  isNew,
488
- isRum: isRUMActive,
488
+ isRum: isRUMActive === 'true' || undefined,
489
489
  browserDriver: 'playwright',
490
490
  isQuarantined,
491
491
  isDisabled,
@@ -125,9 +125,13 @@ class PrismaPlugin extends DatabasePlugin {
125
125
  }
126
126
  }
127
127
 
128
+ /**
129
+ * @param {string} resource
130
+ * @param {{ name?: string, model?: string, method?: string }} [attributes]
131
+ */
128
132
  function formatResourceName (resource, attributes) {
129
133
  if (attributes?.name) {
130
- return `${attributes.name}`.trim()
134
+ return attributes.name.trim()
131
135
  }
132
136
  if (attributes?.model && attributes.method) {
133
137
  return `${attributes.model}.${attributes.method}`.trim()
@@ -15,12 +15,27 @@ class RheaConsumerPlugin extends ConsumerPlugin {
15
15
  })
16
16
  }
17
17
 
18
+ start (ctx) {
19
+ if (!this.config.dsmEnabled) return
20
+ const { msgObj } = ctx
21
+ if (!msgObj?.message?.delivery_annotations) return
22
+
23
+ const { span } = ctx.currentStore
24
+ const name = getResourceNameFromMessage(msgObj)
25
+ const payloadSize = getAmqpMessageSize(
26
+ { headers: msgObj.message.delivery_annotations, content: msgObj.message.body }
27
+ )
28
+ this.tracer.decodeDataStreamsContext(msgObj.message.delivery_annotations)
29
+ this.tracer
30
+ .setCheckpoint(['direction:in', `topic:${name}`, 'type:rabbitmq'], span, payloadSize)
31
+ }
32
+
18
33
  bindStart (ctx) {
19
34
  const { msgObj } = ctx
20
35
  const name = getResourceNameFromMessage(msgObj)
21
36
  const childOf = extractTextMap(msgObj, this.tracer)
22
37
 
23
- const span = this.startSpan({
38
+ this.startSpan({
24
39
  childOf,
25
40
  resource: name,
26
41
  type: 'worker',
@@ -31,18 +46,6 @@ class RheaConsumerPlugin extends ConsumerPlugin {
31
46
  },
32
47
  }, ctx)
33
48
 
34
- if (
35
- this.config.dsmEnabled &&
36
- msgObj?.message?.delivery_annotations
37
- ) {
38
- const payloadSize = getAmqpMessageSize(
39
- { headers: msgObj.message.delivery_annotations, content: msgObj.message.body }
40
- )
41
- this.tracer.decodeDataStreamsContext(msgObj.message.delivery_annotations)
42
- this.tracer
43
- .setCheckpoint(['direction:in', `topic:${name}`, 'type:rabbitmq'], span, payloadSize)
44
- }
45
-
46
49
  return ctx.currentStore
47
50
  }
48
51
  }
@@ -37,7 +37,7 @@ class RheaProducerPlugin extends ProducerPlugin {
37
37
 
38
38
  function addDeliveryAnnotations (msg, tracer, span) {
39
39
  if (msg) {
40
- msg.delivery_annotations = msg.delivery_annotations || {}
40
+ msg.delivery_annotations ||= {}
41
41
 
42
42
  tracer.inject(span, 'text_map', msg.delivery_annotations)
43
43
 
@@ -7,6 +7,7 @@ const formats = require('../../../ext/formats')
7
7
  const HTTP_HEADERS = formats.HTTP_HEADERS
8
8
  const log = require('../../dd-trace/src/log')
9
9
  const { buildClientHttpUrl } = require('../../dd-trace/src/plugins/util/url')
10
+ const { stripQueryAndFragment } = require('../../dd-trace/src/util')
10
11
  const { CLIENT_PORT_KEY } = require('../../dd-trace/src/constants')
11
12
 
12
13
  const {
@@ -62,7 +63,7 @@ class UndiciPlugin extends HttpClientPlugin {
62
63
 
63
64
  const host = port ? `${hostname}:${port}` : hostname
64
65
  const base = `${protocol}//${host}`
65
- const pathname = path.split(/[?#]/)[0]
66
+ const pathname = stripQueryAndFragment(path)
66
67
  const uri = `${base}${pathname}`
67
68
 
68
69
  const allowed = this.config.filter(uri)
@@ -5,7 +5,9 @@ const { storage } = require('../../datadog-core')
5
5
 
6
6
  const {
7
7
  TEST_STATUS,
8
+ TEST_TYPE,
8
9
  VITEST_POOL,
10
+ addIntelligentTestRunnerSpanTags,
9
11
  finishAllTraceSpans,
10
12
  getTestSuitePath,
11
13
  getTestSuiteCommonTags,
@@ -14,7 +16,6 @@ const {
14
16
  getIsFaultyEarlyFlakeDetection,
15
17
  TEST_SOURCE_FILE,
16
18
  TEST_IS_RETRY,
17
- TEST_CODE_COVERAGE_LINES_PCT,
18
19
  TEST_CODE_OWNERS,
19
20
  TEST_COMMAND,
20
21
  TEST_LEVELS_METADATA,
@@ -36,11 +37,25 @@ const {
36
37
  TEST_HAS_DYNAMIC_NAME,
37
38
  TEST_FINAL_STATUS,
38
39
  TEST_IS_TEST_FRAMEWORK_WORKER,
40
+ TEST_BROWSER_DRIVER,
41
+ TEST_BROWSER_NAME,
42
+ TEST_IS_RUM_ACTIVE,
43
+ TEST_PARAMETERS,
44
+ TEST_ITR_UNSKIPPABLE,
45
+ TEST_ITR_FORCED_RUN,
46
+ ITR_CORRELATION_ID,
39
47
  } = require('../../dd-trace/src/plugins/util/test')
40
48
  const { COMPONENT } = require('../../dd-trace/src/constants')
49
+ const id = require('../../dd-trace/src/id')
41
50
  const {
42
51
  TELEMETRY_EVENT_CREATED,
43
52
  TELEMETRY_EVENT_FINISHED,
53
+ TELEMETRY_CODE_COVERAGE_STARTED,
54
+ TELEMETRY_CODE_COVERAGE_FINISHED,
55
+ TELEMETRY_CODE_COVERAGE_EMPTY,
56
+ TELEMETRY_CODE_COVERAGE_NUM_FILES,
57
+ TELEMETRY_ITR_FORCED_TO_RUN,
58
+ TELEMETRY_ITR_UNSKIPPABLE,
44
59
  TELEMETRY_TEST_SESSION,
45
60
  } = require('../../dd-trace/src/ci-visibility/telemetry')
46
61
  const { DD_MAJOR } = require('../../../version')
@@ -50,6 +65,28 @@ const { DD_MAJOR } = require('../../../version')
50
65
  // This is because there's some loss of resolution.
51
66
  const MILLISECONDS_TO_SUBTRACT_FROM_FAILED_TEST_DURATION = 5
52
67
 
68
+ function setBrowserTags (tags, browserEnvironment, includeParameters) {
69
+ if (!browserEnvironment.isBrowserMode) return
70
+
71
+ tags[TEST_TYPE] = 'browser'
72
+ if (browserEnvironment.browserDriver) {
73
+ tags[TEST_BROWSER_DRIVER] = browserEnvironment.browserDriver
74
+ }
75
+ if (browserEnvironment.browserName) {
76
+ tags[TEST_BROWSER_NAME] = browserEnvironment.browserName
77
+ }
78
+ if (includeParameters && (browserEnvironment.browserName || browserEnvironment.browserProjectName)) {
79
+ const parameters = {}
80
+ if (browserEnvironment.browserName) {
81
+ parameters.browser = browserEnvironment.browserName
82
+ }
83
+ if (browserEnvironment.browserProjectName) {
84
+ parameters.project = browserEnvironment.browserProjectName
85
+ }
86
+ tags[TEST_PARAMETERS] = JSON.stringify({ arguments: parameters, metadata: {} })
87
+ }
88
+ }
89
+
53
90
  class VitestPlugin extends CiPlugin {
54
91
  static id = 'vitest'
55
92
 
@@ -100,6 +137,14 @@ class VitestPlugin extends CiPlugin {
100
137
  isModified,
101
138
  isTestFrameworkWorker,
102
139
  requestErrorTags,
140
+ isBrowserMode,
141
+ browserDriver,
142
+ browserName,
143
+ browserProjectName,
144
+ isRumActive,
145
+ testExecutionId,
146
+ testStartLine,
147
+ startTime,
103
148
  } = ctx
104
149
 
105
150
  const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
@@ -109,6 +154,7 @@ class VitestPlugin extends CiPlugin {
109
154
  const extraTags = {
110
155
  ...requestErrorTags,
111
156
  [TEST_SOURCE_FILE]: testSuite,
157
+ [TEST_SOURCE_START]: testStartLine || 1,
112
158
  }
113
159
  if (isRetry) {
114
160
  extraTags[TEST_IS_RETRY] = 'true'
@@ -143,12 +189,23 @@ class VitestPlugin extends CiPlugin {
143
189
  if (isTestFrameworkWorker) {
144
190
  extraTags[TEST_IS_TEST_FRAMEWORK_WORKER] = 'true'
145
191
  }
192
+ if (isRumActive) {
193
+ extraTags[TEST_IS_RUM_ACTIVE] = 'true'
194
+ }
195
+ setBrowserTags(extraTags, {
196
+ browserDriver,
197
+ browserName,
198
+ browserProjectName,
199
+ isBrowserMode,
200
+ }, true)
146
201
 
147
202
  const span = this.startTestSpan(
148
203
  testName,
149
204
  testSuite,
150
205
  testSuiteSpan,
151
- extraTags
206
+ extraTags,
207
+ testExecutionId,
208
+ startTime
152
209
  )
153
210
 
154
211
  ctx.parentStore = store
@@ -296,26 +353,46 @@ class VitestPlugin extends CiPlugin {
296
353
  testName,
297
354
  testSuiteAbsolutePath,
298
355
  isNew,
356
+ isAttemptToFix,
299
357
  isDisabled,
358
+ isQuarantined,
359
+ isRumActive,
300
360
  isTestFrameworkWorker,
301
361
  requestErrorTags,
302
362
  testSuiteSpan,
363
+ isBrowserMode,
364
+ browserDriver,
365
+ browserName,
366
+ browserProjectName,
367
+ testExecutionId,
368
+ testStartLine,
303
369
  }) => {
304
370
  const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
371
+ const extraTags = {
372
+ ...requestErrorTags,
373
+ [TEST_SOURCE_FILE]: testSuite,
374
+ [TEST_SOURCE_START]: testStartLine || 1,
375
+ [TEST_STATUS]: 'skip',
376
+ [TEST_FINAL_STATUS]: 'skip',
377
+ ...(isAttemptToFix ? { [TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX]: 'true' } : {}),
378
+ ...(isDisabled ? { [TEST_MANAGEMENT_IS_DISABLED]: 'true' } : {}),
379
+ ...(isQuarantined ? { [TEST_MANAGEMENT_IS_QUARANTINED]: 'true' } : {}),
380
+ ...(isNew ? { [TEST_IS_NEW]: 'true' } : {}),
381
+ ...(isRumActive ? { [TEST_IS_RUM_ACTIVE]: 'true' } : {}),
382
+ ...(isTestFrameworkWorker ? { [TEST_IS_TEST_FRAMEWORK_WORKER]: 'true' } : {}),
383
+ }
384
+ setBrowserTags(extraTags, {
385
+ browserDriver,
386
+ browserName,
387
+ browserProjectName,
388
+ isBrowserMode,
389
+ }, true)
305
390
  const testSpan = this.startTestSpan(
306
391
  testName,
307
392
  testSuite,
308
393
  testSuiteSpan || this.testSuiteSpan,
309
- {
310
- ...requestErrorTags,
311
- [TEST_SOURCE_FILE]: testSuite,
312
- [TEST_SOURCE_START]: 1, // we can't get the proper start line in vitest
313
- [TEST_STATUS]: 'skip',
314
- [TEST_FINAL_STATUS]: 'skip',
315
- ...(isDisabled ? { [TEST_MANAGEMENT_IS_DISABLED]: 'true' } : {}),
316
- ...(isNew ? { [TEST_IS_NEW]: 'true' } : {}),
317
- ...(isTestFrameworkWorker ? { [TEST_IS_TEST_FRAMEWORK_WORKER]: 'true' } : {}),
318
- }
394
+ extraTags,
395
+ testExecutionId
319
396
  )
320
397
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'test', this.getTestTelemetryTags(testSpan))
321
398
  testSpan.finish()
@@ -330,6 +407,16 @@ class VitestPlugin extends CiPlugin {
330
407
  frameworkVersion,
331
408
  isTestFrameworkWorker,
332
409
  isVitestNoWorkerInitActive,
410
+ disableTestImpactAnalysis,
411
+ isBrowserMode,
412
+ browserDriver,
413
+ browserName,
414
+ browserProjectName,
415
+ isCodeCoverageEnabled,
416
+ coverageLibrary,
417
+ itrCorrelationId,
418
+ isUnskippable,
419
+ isForcedToRun,
333
420
  } = ctx
334
421
 
335
422
  const testCommand = ctx.testCommand || 'vitest run'
@@ -349,6 +436,7 @@ class VitestPlugin extends CiPlugin {
349
436
  const testSessionName = getTestSessionName(this.config, trimmedCommand, this.testEnvironmentMetadata)
350
437
  if (this.tracer._exporter.addMetadataTags) {
351
438
  const libraryCapabilitiesTags = this.getLibraryCapabilitiesTags(frameworkVersion, {
439
+ disableTestImpactAnalysis,
352
440
  isVitestNoWorkerInitActive,
353
441
  })
354
442
  this.tracer._exporter.addMetadataTags({
@@ -377,6 +465,26 @@ class VitestPlugin extends CiPlugin {
377
465
  if (isTestFrameworkWorker) {
378
466
  testSuiteMetadata[TEST_IS_TEST_FRAMEWORK_WORKER] = 'true'
379
467
  }
468
+ if (itrCorrelationId) {
469
+ testSuiteMetadata[ITR_CORRELATION_ID] = itrCorrelationId
470
+ }
471
+ if (isUnskippable) {
472
+ testSuiteMetadata[TEST_ITR_UNSKIPPABLE] = 'true'
473
+ this.telemetry.count(TELEMETRY_ITR_UNSKIPPABLE, { testLevel: 'suite' })
474
+ }
475
+ if (isForcedToRun) {
476
+ testSuiteMetadata[TEST_ITR_FORCED_RUN] = 'true'
477
+ this.telemetry.count(TELEMETRY_ITR_FORCED_TO_RUN, { testLevel: 'suite' })
478
+ }
479
+ if (isCodeCoverageEnabled) {
480
+ this.telemetry.ciVisEvent(TELEMETRY_CODE_COVERAGE_STARTED, 'suite', { library: coverageLibrary })
481
+ }
482
+ setBrowserTags(testSuiteMetadata, {
483
+ browserDriver,
484
+ browserName,
485
+ browserProjectName,
486
+ isBrowserMode,
487
+ }, false)
380
488
 
381
489
  const codeOwners = this.getCodeOwners(testSuiteMetadata)
382
490
  if (codeOwners) {
@@ -400,9 +508,33 @@ class VitestPlugin extends CiPlugin {
400
508
  return ctx.currentStore
401
509
  })
402
510
 
403
- this.addSub('ci:vitest:test-suite:finish', ({ testSuiteSpan, status, deferFlush, onDone }) => {
511
+ this.addSub('ci:vitest:test-suite:finish', ({
512
+ testSuiteSpan,
513
+ status,
514
+ coverageFiles,
515
+ coverageLibrary,
516
+ testSuiteAbsolutePath,
517
+ deferFlush,
518
+ onDone,
519
+ }) => {
404
520
  if (testSuiteSpan) {
405
521
  testSuiteSpan.setTag(TEST_STATUS, status)
522
+ if (coverageFiles) {
523
+ if (!coverageFiles.length) {
524
+ this.telemetry.count(TELEMETRY_CODE_COVERAGE_EMPTY)
525
+ }
526
+ const files = new Set(coverageFiles)
527
+ files.add(testSuiteAbsolutePath)
528
+ const relativeFiles = [...files].map(filename => getTestSuitePath(filename, this.repositoryRoot))
529
+ const { _traceId, _spanId } = testSuiteSpan.context()
530
+ this.tracer._exporter.exportCoverage({
531
+ sessionId: _traceId,
532
+ suiteId: _spanId,
533
+ files: relativeFiles,
534
+ })
535
+ this.telemetry.ciVisEvent(TELEMETRY_CODE_COVERAGE_FINISHED, 'suite', { library: coverageLibrary })
536
+ this.telemetry.distribution(TELEMETRY_CODE_COVERAGE_NUM_FILES, {}, relativeFiles.length)
537
+ }
406
538
  testSuiteSpan.finish()
407
539
  finishAllTraceSpans(testSuiteSpan)
408
540
  }
@@ -417,6 +549,17 @@ class VitestPlugin extends CiPlugin {
417
549
  }
418
550
  })
419
551
 
552
+ this.addSub('ci:vitest:worker-report:coverage', data => {
553
+ const formattedCoverages = JSON.parse(data).map(coverage => ({
554
+ sessionId: id(coverage.sessionId),
555
+ suiteId: id(coverage.suiteId),
556
+ files: coverage.files,
557
+ }))
558
+ for (const formattedCoverage of formattedCoverages) {
559
+ this.tracer._exporter.exportCoverage(formattedCoverage)
560
+ }
561
+ })
562
+
420
563
  this.addBind('ci:vitest:test-suite:error', (ctx) => {
421
564
  const { error } = ctx
422
565
  const testSuiteSpan = ctx.currentStore?.testSuiteSpan
@@ -439,12 +582,18 @@ class VitestPlugin extends CiPlugin {
439
582
  isEarlyFlakeDetectionEnabled,
440
583
  isEarlyFlakeDetectionFaulty,
441
584
  isTestManagementTestsEnabled,
585
+ isCodeCoverageEnabled,
586
+ isSuitesSkippingEnabled,
587
+ isSuitesSkipped,
588
+ numSkippedSuites,
589
+ hasUnskippableSuites,
590
+ hasForcedToRunSuites,
442
591
  requestErrorTags,
443
592
  vitestPool,
444
593
  isVitestNoWorkerInitActive,
445
594
  onDone,
446
595
  }) => {
447
- for (const [tag, value] of Object.entries(requestErrorTags || {})) {
596
+ for (const [tag, value] of Object.entries(requestErrorTags)) {
448
597
  this.testSessionSpan.setTag(tag, value)
449
598
  this.testModuleSpan.setTag(tag, value)
450
599
  }
@@ -454,10 +603,20 @@ class VitestPlugin extends CiPlugin {
454
603
  this.testModuleSpan.setTag('error', error)
455
604
  this.testSessionSpan.setTag('error', error)
456
605
  }
457
- if (testCodeCoverageLinesTotal !== undefined) {
458
- this.testModuleSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
459
- this.testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
460
- }
606
+ addIntelligentTestRunnerSpanTags(
607
+ this.testSessionSpan,
608
+ this.testModuleSpan,
609
+ {
610
+ isSuitesSkipped,
611
+ isSuitesSkippingEnabled,
612
+ isCodeCoverageEnabled,
613
+ testCodeCoverageLinesTotal,
614
+ skippingType: 'suite',
615
+ skippingCount: numSkippedSuites,
616
+ hasUnskippableSuites,
617
+ hasForcedToRunSuites,
618
+ }
619
+ )
461
620
  if (isEarlyFlakeDetectionEnabled) {
462
621
  this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true')
463
622
  }
@@ -493,12 +652,14 @@ class VitestPlugin extends CiPlugin {
493
652
  * Returns Vitest library capability metadata tags.
494
653
  * @param {string} frameworkVersion - The Vitest version.
495
654
  * @param {object} [ctx] - Diagnostic channel context.
655
+ * @param {boolean} [ctx.disableTestImpactAnalysis] - Whether TIA is unsupported for this run.
496
656
  * @param {boolean} [ctx.isVitestNoWorkerInitActive] - Whether no-worker init is active for this run.
497
657
  * @returns {Record<string, string|undefined>}
498
658
  */
499
659
  getLibraryCapabilitiesTags (frameworkVersion, ctx = {}) {
500
660
  return getDefaultLibraryCapabilitiesTags(this.constructor.id, frameworkVersion, {
501
661
  omitFailedTestReplay: ctx.isVitestNoWorkerInitActive,
662
+ omitTestImpactAnalysis: ctx.disableTestImpactAnalysis || ctx.isVitestNoWorkerInitActive,
502
663
  })
503
664
  }
504
665