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
@@ -66,10 +66,16 @@ class DDOpenAIAgentsProcessor {
66
66
  const integration = this._getIntegration()
67
67
  if (!integration?.enabled) return RESOLVED
68
68
  if (!oaiSpan?.spanData) return RESOLVED // guard NoopSpan
69
- const kind = SPAN_KIND_BY_TYPE[oaiSpan.spanData.type]
70
- if (!kind) return RESOLVED // span types without an LLMObs kind are not traced
69
+ const type = oaiSpan.spanData.type
70
+ const kind = SPAN_KIND_BY_TYPE[type]
71
71
  try {
72
- integration.startSpan(oaiSpan, kind)
72
+ if (kind) {
73
+ integration.startSpan(oaiSpan, kind)
74
+ } else if (type === 'task' || type === 'turn') {
75
+ // agents-core >=0.14 nests real work under these structural spans, so
76
+ // their ancestry still has to be walkable for parent resolution.
77
+ integration.recordUntracedSpan(oaiSpan)
78
+ }
73
79
  } catch (err) {
74
80
  log.warn('[openai-agents] onSpanStart failed: %s', err)
75
81
  }
@@ -80,8 +86,14 @@ class DDOpenAIAgentsProcessor {
80
86
  const integration = this._getIntegration()
81
87
  if (!integration?.enabled) return RESOLVED
82
88
  if (!oaiSpan?.spanData) return RESOLVED
89
+ const type = oaiSpan.spanData.type
90
+ const kind = SPAN_KIND_BY_TYPE[type]
83
91
  try {
84
- integration.endSpan(oaiSpan)
92
+ if (kind) {
93
+ integration.endSpan(oaiSpan)
94
+ } else if (type === 'task' || type === 'turn') {
95
+ integration.endUntracedSpan(oaiSpan)
96
+ }
85
97
  } catch (err) {
86
98
  log.warn('[openai-agents] onSpanEnd failed: %s', err)
87
99
  }
@@ -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,53 @@ 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
+ startTime: ctx.startTime,
33
+ type: 'sql',
34
+ kind: 'client',
35
+ meta: {
36
+ 'db.type': 'postgres',
37
+ ...connectionMeta(params),
38
+ },
39
+ }, ctx)
40
+ })
41
+ this.addSub('apm:pg:pool:acquire:finish', ctx => {
42
+ const span = ctx.currentStore?.span
43
+ if (span === undefined) return
44
+
45
+ if (ctx.error) {
46
+ this.addError(ctx.error, span)
47
+ }
48
+ span.setTag('db.pool.wait_time_ms', ctx.poolWaitTime)
49
+ // `Pool` options carry only what the caller passed, so anything pg resolves later - a
50
+ // connection string, the default port, `PG*` environment variables - is known once the
51
+ // client exists.
52
+ if (ctx.params !== undefined) {
53
+ span.addTags(connectionMeta(ctx.params))
54
+ if (ctx.deferServiceResolution) {
55
+ const service = this.serviceName({ pluginConfig: this.config, params: ctx.params })
56
+ // A `service` callback may return no name, and the start-time fallback already carries
57
+ // the schema default every other pg span falls back to.
58
+ if (service.name) {
59
+ this.setServiceName(span, service.name)
60
+ span.setTag(SVC_SRC_KEY, service.source)
61
+ }
62
+ }
63
+ }
64
+ this.finish(ctx)
65
+ })
19
66
  }
20
67
 
21
68
  bindStart (ctx) {
@@ -42,10 +89,28 @@ class PGPlugin extends DatabasePlugin {
42
89
  span.setTag('db.stream', 1)
43
90
  }
44
91
 
92
+ if (ctx.poolWaitTime !== undefined) {
93
+ span.setTag('db.pool.wait_time_ms', ctx.poolWaitTime)
94
+ }
95
+
45
96
  ctx.injected = this.injectDbmQuery(span, originalText, service.name, !!query.name)
46
97
 
47
98
  return ctx.currentStore
48
99
  }
49
100
  }
50
101
 
102
+ /**
103
+ * `Pool.options` and `Client.connectionParameters` are pg internals, so either can be missing.
104
+ *
105
+ * @param {{ database?: string, user?: string, host?: string, port?: number } | undefined} params
106
+ */
107
+ function connectionMeta (params) {
108
+ return {
109
+ 'db.name': params?.database,
110
+ 'db.user': params?.user,
111
+ 'out.host': params?.host,
112
+ [CLIENT_PORT_KEY]: params?.port,
113
+ }
114
+ }
115
+
51
116
  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,
@@ -2,20 +2,20 @@
2
2
 
3
3
  const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
4
4
  const { storage } = require('../../datadog-core')
5
+ const { writeDatadogParentId, writeDatadogTraceId } = require('../../dd-trace/src/carrier')
5
6
 
6
7
  const {
7
8
  TEST_STATUS,
8
9
  TEST_TYPE,
9
10
  VITEST_POOL,
11
+ addIntelligentTestRunnerSpanTags,
10
12
  finishAllTraceSpans,
11
13
  getTestSuitePath,
12
14
  getTestSuiteCommonTags,
13
15
  getTestLevelsMetadataTags,
14
16
  getTestSessionName,
15
- getIsFaultyEarlyFlakeDetection,
16
17
  TEST_SOURCE_FILE,
17
18
  TEST_IS_RETRY,
18
- TEST_CODE_COVERAGE_LINES_PCT,
19
19
  TEST_CODE_OWNERS,
20
20
  TEST_COMMAND,
21
21
  TEST_LEVELS_METADATA,
@@ -41,11 +41,21 @@ const {
41
41
  TEST_BROWSER_NAME,
42
42
  TEST_IS_RUM_ACTIVE,
43
43
  TEST_PARAMETERS,
44
+ TEST_ITR_UNSKIPPABLE,
45
+ TEST_ITR_FORCED_RUN,
46
+ ITR_CORRELATION_ID,
44
47
  } = require('../../dd-trace/src/plugins/util/test')
45
48
  const { COMPONENT } = require('../../dd-trace/src/constants')
49
+ const id = require('../../dd-trace/src/id')
46
50
  const {
47
51
  TELEMETRY_EVENT_CREATED,
48
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,
49
59
  TELEMETRY_TEST_SESSION,
50
60
  } = require('../../dd-trace/src/ci-visibility/telemetry')
51
61
  const { DD_MAJOR } = require('../../../version')
@@ -97,19 +107,6 @@ class VitestPlugin extends CiPlugin {
97
107
  })
98
108
  })
99
109
 
100
- this.addSub('ci:vitest:is-early-flake-detection-faulty', ({
101
- knownTests,
102
- testFilepaths,
103
- onDone,
104
- }) => {
105
- const isFaulty = getIsFaultyEarlyFlakeDetection(
106
- testFilepaths.map(testFilepath => getTestSuitePath(testFilepath, this.repositoryRoot)),
107
- knownTests,
108
- this.libraryConfig.earlyFlakeDetectionFaultyThreshold
109
- )
110
- onDone(isFaulty)
111
- })
112
-
113
110
  this.addBind('ci:vitest:test:start', (ctx) => {
114
111
  const {
115
112
  testName,
@@ -343,7 +340,9 @@ class VitestPlugin extends CiPlugin {
343
340
  testName,
344
341
  testSuiteAbsolutePath,
345
342
  isNew,
343
+ isAttemptToFix,
346
344
  isDisabled,
345
+ isQuarantined,
347
346
  isRumActive,
348
347
  isTestFrameworkWorker,
349
348
  requestErrorTags,
@@ -362,7 +361,9 @@ class VitestPlugin extends CiPlugin {
362
361
  [TEST_SOURCE_START]: testStartLine || 1,
363
362
  [TEST_STATUS]: 'skip',
364
363
  [TEST_FINAL_STATUS]: 'skip',
364
+ ...(isAttemptToFix ? { [TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX]: 'true' } : {}),
365
365
  ...(isDisabled ? { [TEST_MANAGEMENT_IS_DISABLED]: 'true' } : {}),
366
+ ...(isQuarantined ? { [TEST_MANAGEMENT_IS_QUARANTINED]: 'true' } : {}),
366
367
  ...(isNew ? { [TEST_IS_NEW]: 'true' } : {}),
367
368
  ...(isRumActive ? { [TEST_IS_RUM_ACTIVE]: 'true' } : {}),
368
369
  ...(isTestFrameworkWorker ? { [TEST_IS_TEST_FRAMEWORK_WORKER]: 'true' } : {}),
@@ -393,10 +394,16 @@ class VitestPlugin extends CiPlugin {
393
394
  frameworkVersion,
394
395
  isTestFrameworkWorker,
395
396
  isVitestNoWorkerInitActive,
397
+ disableTestImpactAnalysis,
396
398
  isBrowserMode,
397
399
  browserDriver,
398
400
  browserName,
399
401
  browserProjectName,
402
+ isCodeCoverageEnabled,
403
+ coverageLibrary,
404
+ itrCorrelationId,
405
+ isUnskippable,
406
+ isForcedToRun,
400
407
  } = ctx
401
408
 
402
409
  const testCommand = ctx.testCommand || 'vitest run'
@@ -404,18 +411,20 @@ class VitestPlugin extends CiPlugin {
404
411
  this._setRepositoryRoot(repositoryRoot, codeOwnersEntries)
405
412
  this.command = testCommand
406
413
  this.frameworkVersion = frameworkVersion
407
- const testSessionSpanContext = testSessionId && testModuleId
408
- ? this.tracer.extract('text_map', {
409
- 'x-datadog-trace-id': testSessionId,
410
- 'x-datadog-parent-id': testModuleId,
411
- })
412
- : undefined
414
+ let testSessionSpanContext
415
+ if (testSessionId && testModuleId) {
416
+ const carrier = /** @type {Record<string, unknown>} */ ({})
417
+ writeDatadogTraceId(carrier, testSessionId)
418
+ writeDatadogParentId(carrier, testModuleId)
419
+ testSessionSpanContext = this.tracer.extract('text_map', carrier)
420
+ }
413
421
 
414
422
  const trimmedCommand = DD_MAJOR < 6 ? this.command : 'vitest run'
415
423
  // test suites run in a different process, so they also need to init the metadata dictionary
416
424
  const testSessionName = getTestSessionName(this.config, trimmedCommand, this.testEnvironmentMetadata)
417
425
  if (this.tracer._exporter.addMetadataTags) {
418
426
  const libraryCapabilitiesTags = this.getLibraryCapabilitiesTags(frameworkVersion, {
427
+ disableTestImpactAnalysis,
419
428
  isVitestNoWorkerInitActive,
420
429
  })
421
430
  this.tracer._exporter.addMetadataTags({
@@ -444,6 +453,20 @@ class VitestPlugin extends CiPlugin {
444
453
  if (isTestFrameworkWorker) {
445
454
  testSuiteMetadata[TEST_IS_TEST_FRAMEWORK_WORKER] = 'true'
446
455
  }
456
+ if (itrCorrelationId) {
457
+ testSuiteMetadata[ITR_CORRELATION_ID] = itrCorrelationId
458
+ }
459
+ if (isUnskippable) {
460
+ testSuiteMetadata[TEST_ITR_UNSKIPPABLE] = 'true'
461
+ this.telemetry.count(TELEMETRY_ITR_UNSKIPPABLE, { testLevel: 'suite' })
462
+ }
463
+ if (isForcedToRun) {
464
+ testSuiteMetadata[TEST_ITR_FORCED_RUN] = 'true'
465
+ this.telemetry.count(TELEMETRY_ITR_FORCED_TO_RUN, { testLevel: 'suite' })
466
+ }
467
+ if (isCodeCoverageEnabled) {
468
+ this.telemetry.ciVisEvent(TELEMETRY_CODE_COVERAGE_STARTED, 'suite', { library: coverageLibrary })
469
+ }
447
470
  setBrowserTags(testSuiteMetadata, {
448
471
  browserDriver,
449
472
  browserName,
@@ -473,9 +496,33 @@ class VitestPlugin extends CiPlugin {
473
496
  return ctx.currentStore
474
497
  })
475
498
 
476
- this.addSub('ci:vitest:test-suite:finish', ({ testSuiteSpan, status, deferFlush, onDone }) => {
499
+ this.addSub('ci:vitest:test-suite:finish', ({
500
+ testSuiteSpan,
501
+ status,
502
+ coverageFiles,
503
+ coverageLibrary,
504
+ testSuiteAbsolutePath,
505
+ deferFlush,
506
+ onDone,
507
+ }) => {
477
508
  if (testSuiteSpan) {
478
509
  testSuiteSpan.setTag(TEST_STATUS, status)
510
+ if (coverageFiles) {
511
+ if (!coverageFiles.length) {
512
+ this.telemetry.count(TELEMETRY_CODE_COVERAGE_EMPTY)
513
+ }
514
+ const files = new Set(coverageFiles)
515
+ files.add(testSuiteAbsolutePath)
516
+ const relativeFiles = [...files].map(filename => getTestSuitePath(filename, this.repositoryRoot))
517
+ const { _traceId, _spanId } = testSuiteSpan.context()
518
+ this.tracer._exporter.exportCoverage({
519
+ sessionId: _traceId,
520
+ suiteId: _spanId,
521
+ files: relativeFiles,
522
+ })
523
+ this.telemetry.ciVisEvent(TELEMETRY_CODE_COVERAGE_FINISHED, 'suite', { library: coverageLibrary })
524
+ this.telemetry.distribution(TELEMETRY_CODE_COVERAGE_NUM_FILES, {}, relativeFiles.length)
525
+ }
479
526
  testSuiteSpan.finish()
480
527
  finishAllTraceSpans(testSuiteSpan)
481
528
  }
@@ -490,6 +537,17 @@ class VitestPlugin extends CiPlugin {
490
537
  }
491
538
  })
492
539
 
540
+ this.addSub('ci:vitest:worker-report:coverage', data => {
541
+ const formattedCoverages = JSON.parse(data).map(coverage => ({
542
+ sessionId: id(coverage.sessionId),
543
+ suiteId: id(coverage.suiteId),
544
+ files: coverage.files,
545
+ }))
546
+ for (const formattedCoverage of formattedCoverages) {
547
+ this.tracer._exporter.exportCoverage(formattedCoverage)
548
+ }
549
+ })
550
+
493
551
  this.addBind('ci:vitest:test-suite:error', (ctx) => {
494
552
  const { error } = ctx
495
553
  const testSuiteSpan = ctx.currentStore?.testSuiteSpan
@@ -512,12 +570,18 @@ class VitestPlugin extends CiPlugin {
512
570
  isEarlyFlakeDetectionEnabled,
513
571
  isEarlyFlakeDetectionFaulty,
514
572
  isTestManagementTestsEnabled,
573
+ isCodeCoverageEnabled,
574
+ isSuitesSkippingEnabled,
575
+ isSuitesSkipped,
576
+ numSkippedSuites,
577
+ hasUnskippableSuites,
578
+ hasForcedToRunSuites,
515
579
  requestErrorTags,
516
580
  vitestPool,
517
581
  isVitestNoWorkerInitActive,
518
582
  onDone,
519
583
  }) => {
520
- for (const [tag, value] of Object.entries(requestErrorTags || {})) {
584
+ for (const [tag, value] of Object.entries(requestErrorTags)) {
521
585
  this.testSessionSpan.setTag(tag, value)
522
586
  this.testModuleSpan.setTag(tag, value)
523
587
  }
@@ -527,10 +591,20 @@ class VitestPlugin extends CiPlugin {
527
591
  this.testModuleSpan.setTag('error', error)
528
592
  this.testSessionSpan.setTag('error', error)
529
593
  }
530
- if (testCodeCoverageLinesTotal !== undefined) {
531
- this.testModuleSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
532
- this.testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
533
- }
594
+ addIntelligentTestRunnerSpanTags(
595
+ this.testSessionSpan,
596
+ this.testModuleSpan,
597
+ {
598
+ isSuitesSkipped,
599
+ isSuitesSkippingEnabled,
600
+ isCodeCoverageEnabled,
601
+ testCodeCoverageLinesTotal,
602
+ skippingType: 'suite',
603
+ skippingCount: numSkippedSuites,
604
+ hasUnskippableSuites,
605
+ hasForcedToRunSuites,
606
+ }
607
+ )
534
608
  if (isEarlyFlakeDetectionEnabled) {
535
609
  this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true')
536
610
  }
@@ -566,12 +640,14 @@ class VitestPlugin extends CiPlugin {
566
640
  * Returns Vitest library capability metadata tags.
567
641
  * @param {string} frameworkVersion - The Vitest version.
568
642
  * @param {object} [ctx] - Diagnostic channel context.
643
+ * @param {boolean} [ctx.disableTestImpactAnalysis] - Whether TIA is unsupported for this run.
569
644
  * @param {boolean} [ctx.isVitestNoWorkerInitActive] - Whether no-worker init is active for this run.
570
645
  * @returns {Record<string, string|undefined>}
571
646
  */
572
647
  getLibraryCapabilitiesTags (frameworkVersion, ctx = {}) {
573
648
  return getDefaultLibraryCapabilitiesTags(this.constructor.id, frameworkVersion, {
574
649
  omitFailedTestReplay: ctx.isVitestNoWorkerInitActive,
650
+ omitTestImpactAnalysis: ctx.disableTestImpactAnalysis || ctx.isVitestNoWorkerInitActive,
575
651
  })
576
652
  }
577
653
 
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const { readDatadogTraceId, readTraceparent } = require('../../dd-trace/src/carrier')
3
4
  const DatadogSpanContext = require('../../dd-trace/src/opentracing/span_context')
4
5
 
5
6
  const TRACE_ID_UPPER_TAG = '_dd.p.tid'
@@ -38,7 +39,7 @@ function createWebSocketSpanContext (spanContext) {
38
39
  * @returns {boolean}
39
40
  */
40
41
  function hasTraceHeaders (headers) {
41
- return !!(headers && (headers['x-datadog-trace-id'] || headers.traceparent))
42
+ return !!(headers && (readDatadogTraceId(headers) || readTraceparent(headers)))
42
43
  }
43
44
 
44
45
  /**
@@ -15,6 +15,10 @@ const skipMethodSize = skipMethods.size
15
15
 
16
16
  const nonConfigurableModuleExports = new WeakMap()
17
17
 
18
+ /**
19
+ * @typedef {NonNullable<ReturnType<typeof globalThis.Object.getOwnPropertyDescriptor>>} Descriptor
20
+ */
21
+
18
22
  // Reused descriptor scratch space for the `name` and `length` slots that
19
23
  // `copyProperties` and `wrapCallback` rewrite per wrap. `Object.defineProperty`
20
24
  // reads the descriptor's slots synchronously and does not retain the object,
@@ -46,7 +50,7 @@ function copyProperties (original, wrapped) {
46
50
  if (ownKeys.length !== 2) {
47
51
  for (const key of ownKeys) {
48
52
  if (skipMethods.has(key)) continue
49
- const descriptor = /** @type {PropertyDescriptor} */ (Object.getOwnPropertyDescriptor(original, key))
53
+ const descriptor = /** @type {Descriptor} */ (Object.getOwnPropertyDescriptor(original, key))
50
54
  if (descriptor.writable && descriptor.enumerable && descriptor.configurable) {
51
55
  wrapped[key] = original[key]
52
56
  } else if (descriptor.writable || descriptor.configurable || !Object.hasOwn(wrapped, key)) {
@@ -65,7 +69,7 @@ function copyObjectProperties (original, wrapped, skipKey) {
65
69
  const ownKeys = Reflect.ownKeys(original)
66
70
  for (const key of ownKeys) {
67
71
  if (key === skipKey) continue
68
- const descriptor = /** @type {PropertyDescriptor} */ (Object.getOwnPropertyDescriptor(original, key))
72
+ const descriptor = /** @type {Descriptor} */ (Object.getOwnPropertyDescriptor(original, key))
69
73
  if (descriptor.writable && descriptor.enumerable && descriptor.configurable) {
70
74
  wrapped[key] = original[key]
71
75
  } else if (descriptor.writable || descriptor.configurable || !Object.hasOwn(wrapped, key)) {
@@ -121,6 +121,9 @@ class AIGuard extends NoopAIGuard {
121
121
  *
122
122
  * - Clones each message so callers cannot mutate the data set in the meta struct.
123
123
  * - Truncates the list of messages and `content` fields emitting metrics accordingly.
124
+ *
125
+ * @param {import('../../../../index').aiguard.Message[]} messages
126
+ * @param {{ source: string, integration: string }} telemetryTags
124
127
  */
125
128
  #buildMessagesForMetaStruct (messages, telemetryTags) {
126
129
  const size = Math.min(messages.length, this.#maxMessagesLength)