dd-trace 6.6.0 → 6.8.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 +162 -21
  2. package/ci/init.js +0 -1
  3. package/ci/runbook.md +187 -180
  4. package/ci/test-optimization-validation/approval-artifacts.js +3 -1
  5. package/ci/test-optimization-validation/approval.js +52 -15
  6. package/ci/test-optimization-validation/ci-command-candidate.js +26 -32
  7. package/ci/test-optimization-validation/ci-discovery.js +1 -1
  8. package/ci/test-optimization-validation/ci-package-scripts.js +141 -0
  9. package/ci/test-optimization-validation/ci-remediation.js +112 -39
  10. package/ci/test-optimization-validation/cli.js +516 -681
  11. package/ci/test-optimization-validation/command-blocker.js +188 -33
  12. package/ci/test-optimization-validation/command-output-policy.js +8 -31
  13. package/ci/test-optimization-validation/command-runner.js +189 -245
  14. package/ci/test-optimization-validation/environment.js +90 -0
  15. package/ci/test-optimization-validation/executable.js +159 -388
  16. package/ci/test-optimization-validation/framework-adapters/cucumber.js +119 -0
  17. package/ci/test-optimization-validation/framework-adapters/cypress.js +107 -0
  18. package/ci/test-optimization-validation/framework-adapters/playwright.js +181 -0
  19. package/ci/test-optimization-validation/generated-files.js +84 -22
  20. package/ci/test-optimization-validation/generated-test-contract.js +281 -0
  21. package/ci/test-optimization-validation/generated-verifier.js +49 -16
  22. package/ci/test-optimization-validation/literal-environment.js +57 -0
  23. package/ci/test-optimization-validation/manifest-loader.js +2 -22
  24. package/ci/test-optimization-validation/manifest-scaffold.js +815 -515
  25. package/ci/test-optimization-validation/manifest-schema.js +494 -702
  26. package/ci/test-optimization-validation/offline-fixtures.js +4 -1
  27. package/ci/test-optimization-validation/offline-output.js +6 -6
  28. package/ci/test-optimization-validation/plan-writer.js +243 -984
  29. package/ci/test-optimization-validation/preflight-runner.js +49 -55
  30. package/ci/test-optimization-validation/redaction.js +2 -1
  31. package/ci/test-optimization-validation/report-writer.js +391 -1357
  32. package/ci/test-optimization-validation/result-semantics.js +86 -0
  33. package/ci/test-optimization-validation/runner-command.js +249 -0
  34. package/ci/test-optimization-validation/runner-contract.js +664 -0
  35. package/ci/test-optimization-validation/safe-files.js +4 -4
  36. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +29 -3
  37. package/ci/test-optimization-validation/scenarios/basic-reporting.js +240 -543
  38. package/ci/test-optimization-validation/scenarios/ci-wiring.js +450 -670
  39. package/ci/test-optimization-validation/scenarios/early-flake-detection.js +4 -3
  40. package/ci/test-optimization-validation/scenarios/helpers.js +67 -9
  41. package/ci/test-optimization-validation/scenarios/test-management.js +6 -5
  42. package/ci/test-optimization-validation/source-text.js +87 -0
  43. package/ci/test-optimization-validation/test-output.js +12 -22
  44. package/ci/vitest-no-worker-init-setup.mjs +348 -51
  45. package/ext/tags.d.ts +1 -0
  46. package/index.d.ts +84 -13
  47. package/package.json +10 -4
  48. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  49. package/packages/datadog-esbuild/index.js +4 -2
  50. package/packages/datadog-esbuild/src/utils.js +1 -1
  51. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +4 -4
  52. package/packages/datadog-instrumentations/src/cucumber.js +9 -6
  53. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  54. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  55. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  56. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  57. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +1 -0
  58. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  59. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/openai-agents.js +31 -0
  60. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +57 -0
  61. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  62. package/packages/datadog-instrumentations/src/helpers/router-helper.js +1 -1
  63. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  64. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  65. package/packages/datadog-instrumentations/src/jest.js +8 -14
  66. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  67. package/packages/datadog-instrumentations/src/mocha/main.js +2 -42
  68. package/packages/datadog-instrumentations/src/mocha/utils.js +68 -2
  69. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +19 -0
  70. package/packages/datadog-instrumentations/src/mocha/worker.js +446 -42
  71. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  72. package/packages/datadog-instrumentations/src/openai-agents.js +159 -0
  73. package/packages/datadog-instrumentations/src/playwright.js +3 -2
  74. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  75. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +525 -56
  76. package/packages/datadog-instrumentations/src/vitest-main.js +90 -10
  77. package/packages/datadog-instrumentations/src/webdriverio.js +914 -0
  78. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  79. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  80. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  81. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  82. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  83. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  84. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  85. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  86. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  87. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +5 -8
  88. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  89. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  90. package/packages/datadog-plugin-fs/src/index.js +0 -4
  91. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  92. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  93. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  94. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  95. package/packages/datadog-plugin-http/src/client.js +2 -1
  96. package/packages/datadog-plugin-jest/src/index.js +2 -3
  97. package/packages/datadog-plugin-jest/src/util.js +2 -1
  98. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  99. package/packages/datadog-plugin-mocha/src/index.js +25 -6
  100. package/packages/datadog-plugin-openai-agents/src/index.js +74 -0
  101. package/packages/datadog-plugin-openai-agents/src/integration.js +503 -0
  102. package/packages/datadog-plugin-openai-agents/src/processor.js +108 -0
  103. package/packages/datadog-plugin-openai-agents/src/util.js +60 -0
  104. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  105. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  106. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  107. package/packages/datadog-plugin-undici/src/index.js +2 -1
  108. package/packages/datadog-plugin-vitest/src/index.js +84 -11
  109. package/packages/datadog-webpack/index.js +2 -2
  110. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  111. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  112. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  113. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  114. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  115. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  116. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  117. package/packages/dd-trace/src/appsec/sdk/track_event.js +1 -1
  118. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  119. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  120. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +50 -51
  121. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -1
  122. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +4 -0
  123. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  124. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  125. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +161 -33
  126. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  127. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +7 -5
  128. package/packages/dd-trace/src/config/defaults.js +14 -6
  129. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
  130. package/packages/dd-trace/src/config/index.js +15 -0
  131. package/packages/dd-trace/src/config/parsers.js +19 -1
  132. package/packages/dd-trace/src/config/supported-configurations.json +12 -6
  133. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  134. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  135. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  136. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  137. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  138. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  139. package/packages/dd-trace/src/encode/span-stats.js +7 -1
  140. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  141. package/packages/dd-trace/src/exporter.js +16 -9
  142. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  143. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  144. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  145. package/packages/dd-trace/src/flare/index.js +2 -2
  146. package/packages/dd-trace/src/id.js +1 -1
  147. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  148. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  149. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  150. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  151. package/packages/dd-trace/src/llmobs/experiments/index.js +51 -12
  152. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  153. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  154. package/packages/dd-trace/src/llmobs/experiments/util.js +218 -0
  155. package/packages/dd-trace/src/llmobs/index.js +9 -1
  156. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +104 -22
  157. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  158. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  159. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  160. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  161. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +5 -9
  162. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +20 -0
  163. package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +321 -0
  164. package/packages/dd-trace/src/llmobs/sdk.js +6 -12
  165. package/packages/dd-trace/src/llmobs/span_processor.js +14 -7
  166. package/packages/dd-trace/src/llmobs/tagger.js +24 -5
  167. package/packages/dd-trace/src/llmobs/util.js +56 -3
  168. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  169. package/packages/dd-trace/src/noop/proxy.js +2 -2
  170. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +3 -6
  171. package/packages/dd-trace/src/openfeature/configuration_source.js +5 -8
  172. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +5 -1
  173. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  174. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
  175. package/packages/dd-trace/src/opentracing/span.js +1 -1
  176. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  177. package/packages/dd-trace/src/plugins/ci_plugin.js +114 -23
  178. package/packages/dd-trace/src/plugins/index.js +2 -0
  179. package/packages/dd-trace/src/plugins/outbound.js +4 -1
  180. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  181. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  182. package/packages/dd-trace/src/plugins/util/ci.js +7 -6
  183. package/packages/dd-trace/src/plugins/util/git.js +1 -1
  184. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +1 -1
  185. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  186. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  187. package/packages/dd-trace/src/plugins/util/test.js +38 -12
  188. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  189. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  190. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  191. package/packages/dd-trace/src/priority_sampler.js +6 -3
  192. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  193. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  194. package/packages/dd-trace/src/ritm.js +5 -20
  195. package/packages/dd-trace/src/span_processor.js +1 -1
  196. package/packages/dd-trace/src/span_stats.js +22 -4
  197. package/packages/dd-trace/src/startup-log.js +3 -0
  198. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  199. package/packages/dd-trace/src/util.js +16 -0
  200. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  201. package/vendor/dist/pprof-format/index.js +1 -1
  202. package/vendor/dist/source-map/index.js +1 -1
  203. package/ci/test-optimization-validation/command-suitability.js +0 -471
  204. package/ci/test-optimization-validation/init-probe-preload.js +0 -163
  205. package/ci/test-optimization-validation/init-probe.js +0 -246
  206. package/ci/test-optimization-validation/late-initialization.js +0 -63
  207. package/ci/test-optimization-validation/local-command.js +0 -163
  208. package/ci/test-optimization-validation/setup-runner.js +0 -97
  209. package/ci/test-optimization-validation-manifest.schema.json +0 -1
@@ -1,6 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const { isLoopbackHost } = require('../exporters/common/url')
4
3
  const log = require('../log')
5
4
 
6
5
  const DEFAULT_AGENTLESS_PATH = '/api/v2/feature-flagging/config/rules-based/server'
@@ -27,9 +26,11 @@ function create (config, applyConfiguration) {
27
26
  return
28
27
  }
29
28
 
29
+ const hasCustomEndpoint = Boolean(baseUrl?.trim())
30
+
30
31
  try {
31
- if (!config.DD_API_KEY) {
32
- throw new Error('DD_API_KEY is required for Feature Flagging agentless delivery')
32
+ if (!hasCustomEndpoint && !config.DD_API_KEY) {
33
+ throw new Error('DD_API_KEY is required for the default Datadog Feature Flagging endpoint')
33
34
  }
34
35
 
35
36
  const AgentlessConfigurationSource = require('./agentless_configuration_source')
@@ -37,7 +38,7 @@ function create (config, applyConfiguration) {
37
38
  endpoint: endpoint(config, baseUrl),
38
39
  pollIntervalMs: Math.min(pollIntervalSeconds, MAX_POLL_INTERVAL_SECONDS) * 1000,
39
40
  requestTimeoutMs: requestTimeoutSeconds * 1000,
40
- apiKey: config.DD_API_KEY,
41
+ apiKey: hasCustomEndpoint ? undefined : config.DD_API_KEY,
41
42
  }, applyConfiguration)
42
43
  } catch (error) {
43
44
  log.error('Unable to configure Feature Flagging configuration source', error)
@@ -74,10 +75,6 @@ function endpoint (config, configuredBaseUrl) {
74
75
  if (url.protocol !== 'https:' && url.protocol !== 'http:') {
75
76
  throw new Error('Feature Flagging agentless URL must use HTTP or HTTPS')
76
77
  }
77
- if (url.protocol === 'http:' && !isLoopbackHost(url.hostname)) {
78
- throw new Error('Feature Flagging agentless URL must use HTTPS unless it targets loopback')
79
- }
80
-
81
78
  if (url.pathname === '' || url.pathname === '/') {
82
79
  url.pathname = DEFAULT_AGENTLESS_PATH
83
80
  }
@@ -3,6 +3,7 @@
3
3
  const { LogCollapsingLowestDenseDDSketch } = require('../../../../../vendor/dist/@datadog/sketches-js')
4
4
  const OtlpTransformerBase = require('../otlp/otlp_transformer_base')
5
5
  const { getProtobufTypes } = require('../otlp/protobuf_loader')
6
+ const { GRPC_STATUS_NAMES } = require('../../constants')
6
7
 
7
8
  const NS_PER_S = 1e9
8
9
 
@@ -152,7 +153,10 @@ class OtlpStatsTransformer extends OtlpTransformerBase {
152
153
  if (aggKey.method) raw['http.request.method'] = aggKey.method
153
154
  if (aggKey.endpoint) raw['http.route'] = aggKey.endpoint
154
155
  if (aggKey.rpcStatusCode !== '') {
155
- raw['rpc.response.status_code'] = String(aggKey.rpcStatusCode).toUpperCase()
156
+ const n = Number(aggKey.rpcStatusCode)
157
+ raw['rpc.response.status_code'] = Number.isInteger(n) && n >= 0 && n < GRPC_STATUS_NAMES.length
158
+ ? GRPC_STATUS_NAMES[n]
159
+ : String(aggKey.rpcStatusCode).toUpperCase()
156
160
  }
157
161
 
158
162
  if (!this.#otelSemanticsEnabled) {
@@ -198,7 +198,7 @@ class OtlpTransformer extends OtlpTransformerBase {
198
198
  if (isJson) {
199
199
  dataPoint.startTimeUnixNano = String(dataPoint.startTimeUnixNano)
200
200
  dataPoint.timeUnixNano = String(dataPoint.timeUnixNano)
201
- dataPoint.count = dataPoint.count || 0
201
+ dataPoint.count ||= 0
202
202
  }
203
203
 
204
204
  return dataPoint
@@ -253,7 +253,8 @@ class PeriodicMetricReader {
253
253
  #collectAndExport (callback = () => {}) {
254
254
  // Atomically drain measurements for export. New measurements can be recorded
255
255
  // during export without interfering with this batch.
256
- const allMeasurements = this.#measurements.splice(0)
256
+ const allMeasurements = this.#measurements
257
+ this.#measurements = []
257
258
 
258
259
  for (const instrument of this.observableInstruments) {
259
260
  const observableMeasurements = instrument.collect()
@@ -440,7 +440,7 @@ class DatadogSpan {
440
440
  }
441
441
  }
442
442
 
443
- spanContext._trace.ticks = spanContext._trace.ticks || now()
443
+ spanContext._trace.ticks ||= now()
444
444
  if (startTime) {
445
445
  spanContext._trace.startTime = startTime
446
446
  }
@@ -8,7 +8,7 @@ const TRACE_ID_128 = '_dd.p.tid'
8
8
 
9
9
  class DatadogSpanContext {
10
10
  constructor (props) {
11
- props = props || {}
11
+ props ||= {}
12
12
 
13
13
  this._traceId = props.traceId
14
14
  this._spanId = props.spanId
@@ -48,12 +48,16 @@ const {
48
48
  CI_APP_ORIGIN,
49
49
  getTestSessionCommonTags,
50
50
  getTestModuleCommonTags,
51
+ TEST_FRAMEWORK,
52
+ TEST_FRAMEWORK_ADAPTER,
53
+ TEST_FRAMEWORK_VERSION,
51
54
  TEST_SUITE_ID,
52
55
  TEST_MODULE_ID,
53
56
  TEST_SESSION_ID,
54
57
  TEST_COMMAND,
55
58
  TEST_LEVELS_METADATA,
56
59
  TEST_MODULE,
60
+ TEST_TYPE,
57
61
  TEST_SESSION_NAME,
58
62
  getTestSuiteCommonTags,
59
63
  TEST_STATUS,
@@ -62,6 +66,8 @@ const {
62
66
  ITR_CORRELATION_ID,
63
67
  TEST_SOURCE_FILE,
64
68
  TEST_SUITE,
69
+ TEST_SUITE_EXECUTION_ID,
70
+ getTestSuiteExecutionKey,
65
71
  getFileAndLineNumberFromError,
66
72
  DI_ERROR_DEBUG_INFO_CAPTURED,
67
73
  DI_DEBUG_ERROR_PREFIX,
@@ -101,6 +107,7 @@ const FRAMEWORK_TO_TRIMMED_COMMAND = {
101
107
  cucumber: 'cucumber-js',
102
108
  playwright: 'playwright test',
103
109
  jest: 'jest',
110
+ webdriverio: 'wdio',
104
111
  }
105
112
 
106
113
  const WORKER_EXPORTER_TO_TEST_FRAMEWORK = {
@@ -131,7 +138,8 @@ function withTimeout (promise, timeoutMs) {
131
138
  }
132
139
 
133
140
  function setItrSkippingEnabledTagFromLibraryConfig (plugin, frameworkVersion) {
134
- const libraryCapabilitiesTags = getDefaultLibraryCapabilitiesTags(plugin.constructor.id, frameworkVersion)
141
+ const testFramework = plugin.testFramework || plugin.constructor.id
142
+ const libraryCapabilitiesTags = getDefaultLibraryCapabilitiesTags(testFramework, frameworkVersion)
135
143
 
136
144
  if (!libraryCapabilitiesTags[DD_CAPABILITIES_TEST_IMPACT_ANALYSIS] ||
137
145
  !plugin.libraryConfig ||
@@ -160,6 +168,22 @@ function getTestSuiteLevelVisibilityTags (testSuiteSpan, testFramework) {
160
168
  return suiteTags
161
169
  }
162
170
 
171
+ /**
172
+ * Keeps non-TIA settings while disabling suite skipping and coverage collection.
173
+ *
174
+ * @param {object} libraryConfig
175
+ * @returns {object}
176
+ */
177
+ function disableTestImpactAnalysis (libraryConfig) {
178
+ return Object.freeze({
179
+ ...libraryConfig,
180
+ isCodeCoverageEnabled: false,
181
+ isCoverageReportUploadEnabled: false,
182
+ isItrEnabled: false,
183
+ isSuitesSkippingEnabled: false,
184
+ })
185
+ }
186
+
163
187
  module.exports = class CiPlugin extends Plugin {
164
188
  constructor (...args) {
165
189
  super(...args)
@@ -170,16 +194,32 @@ module.exports = class CiPlugin extends Plugin {
170
194
  this.rootDir = process.cwd() // fallback in case :session:start events are not emitted
171
195
  this._testSuiteSpansByTestSuite = new Map()
172
196
  this._pendingWorkerTracesByTestSuite = new Map()
197
+ this._workerTraceExecutionIds = new WeakMap()
173
198
  this._pendingRequestErrorTags = []
174
199
 
175
200
  this.addSub(`ci:${this.constructor.id}:library-configuration`, (ctx) => {
176
- const { onDone, frameworkVersion } = ctx
201
+ const {
202
+ basicReportingOnly,
203
+ disableTestImpactAnalysis: shouldDisableTestImpactAnalysis,
204
+ onDone,
205
+ frameworkVersion,
206
+ } = ctx
177
207
  ctx.currentStore = legacyStorage.getStore()
178
208
 
179
209
  if (!this.tracer._exporter || !this.tracer._exporter.getLibraryConfiguration) {
180
210
  return onDone({ err: new Error('Test optimization was not initialized correctly') })
181
211
  }
182
212
  this.tracer._exporter.getLibraryConfiguration(this.testConfiguration, (err, libraryConfig) => {
213
+ let effectiveLibraryConfig
214
+ if (!err) {
215
+ if (basicReportingOnly) {
216
+ effectiveLibraryConfig = {}
217
+ } else if (shouldDisableTestImpactAnalysis) {
218
+ effectiveLibraryConfig = disableTestImpactAnalysis(libraryConfig)
219
+ } else {
220
+ effectiveLibraryConfig = libraryConfig
221
+ }
222
+ }
183
223
  if (err) {
184
224
  this.libraryConfig = undefined
185
225
  this.itrCorrelationId = undefined
@@ -187,7 +227,7 @@ module.exports = class CiPlugin extends Plugin {
187
227
  log.error('Library configuration could not be fetched. %s', err.message)
188
228
  this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR_SETTINGS, err)
189
229
  } else {
190
- this.libraryConfig = libraryConfig
230
+ this.libraryConfig = effectiveLibraryConfig
191
231
  setItrSkippingEnabledTagFromLibraryConfig(this, frameworkVersion)
192
232
  }
193
233
 
@@ -201,7 +241,7 @@ module.exports = class CiPlugin extends Plugin {
201
241
  onDone({
202
242
  err,
203
243
  isTestDynamicInstrumentationEnabled: this.config.isTestDynamicInstrumentationEnabled,
204
- libraryConfig,
244
+ libraryConfig: effectiveLibraryConfig,
205
245
  repositoryRoot: this.repositoryRoot,
206
246
  requestErrorTags: this._getCurrentRequestErrorTags(),
207
247
  })
@@ -234,19 +274,28 @@ module.exports = class CiPlugin extends Plugin {
234
274
  )
235
275
  })
236
276
 
237
- this.addSub(`ci:${this.constructor.id}:session:start`, ({ command, frameworkVersion, rootDir }) => {
277
+ this.addSub(`ci:${this.constructor.id}:session:start`, ({
278
+ command,
279
+ frameworkVersion,
280
+ rootDir,
281
+ testFramework,
282
+ testFrameworkAdapter,
283
+ }) => {
284
+ const effectiveTestFramework = testFramework || this.constructor.id
238
285
  const childOf = getTestParentSpan(this.tracer)
239
- const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion, this.constructor.id)
240
- const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion, this.constructor.id)
286
+ const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion, effectiveTestFramework)
287
+ const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion, effectiveTestFramework)
241
288
 
242
289
  this.command = command
243
290
  this.frameworkVersion = frameworkVersion
291
+ this.testFramework = effectiveTestFramework
292
+ this.testFrameworkAdapter = testFrameworkAdapter
244
293
  // only for playwright
245
294
  this.rootDir = rootDir
246
295
 
247
296
  const testSessionName = getTestSessionName(
248
297
  this.config,
249
- DD_MAJOR < 6 ? this.command : FRAMEWORK_TO_TRIMMED_COMMAND[this.constructor.id],
298
+ DD_MAJOR < 6 ? this.command : FRAMEWORK_TO_TRIMMED_COMMAND[effectiveTestFramework],
250
299
  this.testEnvironmentMetadata
251
300
  )
252
301
 
@@ -296,7 +345,7 @@ module.exports = class CiPlugin extends Plugin {
296
345
  const testCommand = this.command
297
346
  for (const testSuite of skippedSuites) {
298
347
  const testSuiteMetadata = {
299
- ...getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite, this.constructor.id),
348
+ ...getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite, this.testFramework),
300
349
  ...getSessionRequestErrorTags(this.testSessionSpan),
301
350
  ...getSessionItrSkippingEnabledTags(this.testSessionSpan),
302
351
  }
@@ -332,8 +381,11 @@ module.exports = class CiPlugin extends Plugin {
332
381
  log.error('Known tests could not be fetched. %s', err.message)
333
382
  this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS, err)
334
383
  if (this.libraryConfig) {
335
- this.libraryConfig.isEarlyFlakeDetectionEnabled = false
336
- this.libraryConfig.isKnownTestsEnabled = false
384
+ this.libraryConfig = Object.freeze({
385
+ ...this.libraryConfig,
386
+ isEarlyFlakeDetectionEnabled: false,
387
+ isKnownTestsEnabled: false,
388
+ })
337
389
  }
338
390
  }
339
391
  onDone({ err, knownTests, requestErrorTags: this._getCurrentRequestErrorTags() })
@@ -353,7 +405,10 @@ module.exports = class CiPlugin extends Plugin {
353
405
  log.error('Test management tests could not be fetched. %s', err.message)
354
406
  this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS, err)
355
407
  if (this.libraryConfig) {
356
- this.libraryConfig.isTestManagementEnabled = false
408
+ this.libraryConfig = Object.freeze({
409
+ ...this.libraryConfig,
410
+ isTestManagementEnabled: false,
411
+ })
357
412
  }
358
413
  }
359
414
  onDone({ err, testManagementTests, requestErrorTags: this._getCurrentRequestErrorTags() })
@@ -386,10 +441,16 @@ module.exports = class CiPlugin extends Plugin {
386
441
  return onDone({ err: new Error('No modified tests could have been retrieved') })
387
442
  })
388
443
 
389
- this.addSub(`ci:${this.constructor.id}:worker-report:trace`, traces => {
444
+ this.addSub(`ci:${this.constructor.id}:worker-report:trace`, payload => {
445
+ const { traces, [TEST_SUITE_EXECUTION_ID]: testSuiteExecutionId } = typeof payload === 'string'
446
+ ? { traces: payload }
447
+ : payload
390
448
  const formattedTraces = JSON.parse(traces)
391
449
 
392
450
  for (const trace of formattedTraces) {
451
+ if (testSuiteExecutionId) {
452
+ this._workerTraceExecutionIds.set(trace, testSuiteExecutionId)
453
+ }
393
454
  this._prepareWorkerTrace(trace)
394
455
  this._exportWorkerTraceOrBuffer(trace)
395
456
  }
@@ -403,7 +464,7 @@ module.exports = class CiPlugin extends Plugin {
403
464
  }
404
465
 
405
466
  get telemetry () {
406
- const testFramework = this.constructor.id
467
+ const testFramework = this.testFramework || this.constructor.id
407
468
  const exporter = this.tracer?._exporter
408
469
  // TODO: only jest worker supported yet
409
470
  const isSupportedWorker = exporter && typeof exporter.exportTelemetry === 'function'
@@ -463,10 +524,19 @@ module.exports = class CiPlugin extends Plugin {
463
524
  /**
464
525
  * Returns library capability metadata tags for this test framework.
465
526
  * @param {string} frameworkVersion - The test framework version.
527
+ * @param {object} [ctx] - Diagnostic channel context.
528
+ * @param {boolean} [ctx.basicReportingOnly] - Whether advanced capabilities must be omitted.
529
+ * @param {string} [ctx.testFramework] - Effective framework when one framework is hosted by another.
466
530
  * @returns {Record<string, string|undefined>}
467
531
  */
468
- getLibraryCapabilitiesTags (frameworkVersion) {
469
- return getDefaultLibraryCapabilitiesTags(this.constructor.id, frameworkVersion)
532
+ getLibraryCapabilitiesTags (frameworkVersion, ctx = {}) {
533
+ if (ctx.basicReportingOnly) {
534
+ return {}
535
+ }
536
+ return getDefaultLibraryCapabilitiesTags(
537
+ ctx.testFramework || this.testFramework || this.constructor.id,
538
+ frameworkVersion
539
+ )
470
540
  }
471
541
 
472
542
  /**
@@ -586,17 +656,34 @@ module.exports = class CiPlugin extends Plugin {
586
656
  // test session, test module and test suite ids. We have to update them in the main process.
587
657
  if (span.name !== 'cucumber.test' && span.name !== 'mocha.test') continue
588
658
 
659
+ const testFramework = this.testFramework || this.constructor.id
660
+ span.meta[TEST_FRAMEWORK] = testFramework
661
+ span.meta[TEST_MODULE] = testFramework
662
+ const testType = this.testSessionSpan?.context().getTag(TEST_TYPE)
663
+ if (testType) {
664
+ span.meta[TEST_TYPE] = testType
665
+ }
666
+ if (this.frameworkVersion) {
667
+ span.meta[TEST_FRAMEWORK_VERSION] = this.frameworkVersion
668
+ }
669
+ if (this.testFrameworkAdapter) {
670
+ span.meta[TEST_FRAMEWORK_ADAPTER] = this.testFrameworkAdapter
671
+ }
672
+
589
673
  const testSuite = span.meta[TEST_SUITE]
590
- const testSuiteSpan = this._testSuiteSpansByTestSuite.get(testSuite)
591
- if (!testSuiteSpan) return testSuite
674
+ const testSuiteExecutionId = this._workerTraceExecutionIds.get(trace)
675
+ const testSuiteKey = getTestSuiteExecutionKey(testSuite, testSuiteExecutionId)
676
+ const testSuiteSpan = this._testSuiteSpansByTestSuite.get(testSuiteKey)
677
+ if (!testSuiteSpan) return testSuiteKey
592
678
 
593
- const testSuiteTags = getTestSuiteLevelVisibilityTags(testSuiteSpan, this.constructor.id)
679
+ const testSuiteTags = getTestSuiteLevelVisibilityTags(testSuiteSpan, testFramework)
594
680
  span.meta = {
595
681
  ...span.meta,
596
682
  ...testSuiteTags,
597
683
  ...getSessionRequestErrorTags(this.testSessionSpan),
598
684
  }
599
685
  }
686
+ this._workerTraceExecutionIds.delete(trace)
600
687
  }
601
688
 
602
689
  /**
@@ -755,19 +842,22 @@ module.exports = class CiPlugin extends Plugin {
755
842
  return codeOwners
756
843
  }
757
844
 
758
- startTestSpan (testName, testSuite, testSuiteSpan, extraTags = {}) {
759
- const childOf = getTestParentSpan(this.tracer)
845
+ startTestSpan (testName, testSuite, testSuiteSpan, extraTags = {}, testExecutionId, startTime) {
846
+ const childOf = getTestParentSpan(this.tracer, testExecutionId)
760
847
 
761
848
  let testTags = {
762
849
  ...getTestCommonTags(
763
850
  testName,
764
851
  testSuite,
765
852
  this.frameworkVersion,
766
- this.constructor.id
853
+ this.testFramework || this.constructor.id
767
854
  ),
768
855
  [COMPONENT]: this.constructor.id,
769
856
  ...extraTags,
770
857
  }
858
+ if (this.testFrameworkAdapter) {
859
+ testTags[TEST_FRAMEWORK_ADAPTER] = this.testFrameworkAdapter
860
+ }
771
861
 
772
862
  const codeOwners = this.getCodeOwners(testTags)
773
863
  if (codeOwners) {
@@ -784,7 +874,7 @@ module.exports = class CiPlugin extends Plugin {
784
874
  [TEST_SUITE_ID]: testSuiteSpan.context().toSpanId(),
785
875
  [TEST_SESSION_ID]: testSuiteSpan.context().toTraceId(),
786
876
  [TEST_COMMAND]: testSuiteSpan.context().getTag(TEST_COMMAND),
787
- [TEST_MODULE]: this.constructor.id,
877
+ [TEST_MODULE]: this.testFramework || this.constructor.id,
788
878
  ...getSessionRequestErrorTags(this.testSessionSpan),
789
879
  }
790
880
  if (testSuiteSpan.context()._parentId) {
@@ -804,6 +894,7 @@ module.exports = class CiPlugin extends Plugin {
804
894
  const testSpan = this.tracer
805
895
  .startSpan(`${this.constructor.id}.test`, {
806
896
  childOf,
897
+ startTime,
807
898
  tags: {
808
899
  ...this.testEnvironmentMetadata,
809
900
  ...testTags,
@@ -36,7 +36,9 @@ const plugins = {
36
36
  get '@smithy/core' () { return require('../../../datadog-plugin-aws-sdk/src') },
37
37
  get '@smithy/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
38
38
  get '@vitest/runner' () { return require('../../../datadog-plugin-vitest/src') },
39
+ get '@wdio/local-runner' () { return require('../../../datadog-plugin-mocha/src') },
39
40
  get '@langchain/langgraph' () { return require('../../../datadog-plugin-langgraph/src') },
41
+ get '@openai/agents' () { return require('../../../datadog-plugin-openai-agents/src') },
40
42
  get aerospike () { return require('../../../datadog-plugin-aerospike/src') },
41
43
  get ai () { return require('../../../datadog-plugin-ai/src') },
42
44
  get amqp10 () { return require('../../../datadog-plugin-amqp10/src') },
@@ -125,7 +125,10 @@ class OutboundPlugin extends TracingPlugin {
125
125
  */
126
126
  tagPeerService (span) {
127
127
  if (this._tracerConfig.spanComputePeerService) {
128
- const peerData = this.getPeerService(span.context().getTags())
128
+ const tags = span.context().getTags()
129
+ if (tags[PEER_SERVICE_SOURCE_KEY] !== undefined) return
130
+
131
+ const peerData = this.getPeerService(tags)
129
132
  if (peerData !== undefined) {
130
133
  span.addTags(this.getPeerServiceRemap(peerData))
131
134
  }
@@ -103,7 +103,7 @@ module.exports = class Plugin {
103
103
  * @returns {void}
104
104
  */
105
105
  enter (span, store) {
106
- store = store || legacyStorage.getStore()
106
+ store ||= legacyStorage.getStore()
107
107
  legacyStorage.enterWith({ ...store, span })
108
108
  }
109
109
 
@@ -265,6 +265,7 @@ class TracingPlugin extends Plugin {
265
265
  analyticsSampler.sample(span, config.measured)
266
266
 
267
267
  // TODO: Remove this after migration to TracingChannel is done.
268
+ // eslint-disable-next-line unicorn/no-unnecessary-boolean-comparison -- Context objects use the other branch.
268
269
  if (enterOrCtx === true) {
269
270
  legacyStorage.enterWith({ ...store, span })
270
271
  } else if (enterOrCtx) {
@@ -18,6 +18,7 @@ const {
18
18
  GIT_REPOSITORY_URL,
19
19
  CI_PIPELINE_ID,
20
20
  CI_PIPELINE_NAME,
21
+ CI_PIPELINE_DISPLAY_NAME,
21
22
  CI_PIPELINE_NUMBER,
22
23
  CI_PIPELINE_URL,
23
24
  CI_PROVIDER_NAME,
@@ -75,7 +76,7 @@ function normalizeRef (ref) {
75
76
  if (!ref) {
76
77
  return ref
77
78
  }
78
- return ref.replaceAll(/origin\/|refs\/heads\/|tags\//gm, '')
79
+ return ref.replaceAll(/origin\/|refs\/heads\/|tags\//g, '')
79
80
  }
80
81
 
81
82
  function resolveTilde (filePath) {
@@ -215,7 +216,7 @@ const githubWellKnownDiagnosticDirPatternsUnix = [
215
216
  ]
216
217
  const githubWellKnownDiagnosticDirPatternsWin = ['C:/actions-runner/*/_diag', 'C:/actions-runner/*/*/_diag']
217
218
 
218
- const githubJobIDRegex = /"job":\s*{[\s\S]*?"v"\s*:\s*(\d+)(?:\.0)?/
219
+ const githubJobIDRegex = /"job":\s*\{[\s\S]*?"v"\s*:\s*(\d+)(?:\.0)?/
219
220
 
220
221
  function getJobIDFromDiagFile () {
221
222
  const runnerTemp = getEnvironmentVariable('RUNNER_TEMP')
@@ -316,10 +317,8 @@ module.exports = {
316
317
  }
317
318
 
318
319
  if (NODE_LABELS) {
319
- let nodeLabels
320
320
  try {
321
- nodeLabels = JSON.stringify(NODE_LABELS.split(' '))
322
- tags[CI_NODE_LABELS] = nodeLabels
321
+ tags[CI_NODE_LABELS] = JSON.stringify(NODE_LABELS.split(' '))
323
322
  } catch {
324
323
  // ignore errors
325
324
  }
@@ -651,7 +650,7 @@ module.exports = {
651
650
  [GIT_TAG]: BITBUCKET_TAG,
652
651
  [GIT_REPOSITORY_URL]: BITBUCKET_GIT_SSH_ORIGIN || BITBUCKET_GIT_HTTP_ORIGIN,
653
652
  [CI_WORKSPACE_PATH]: BITBUCKET_CLONE_DIR,
654
- [CI_PIPELINE_ID]: BITBUCKET_PIPELINE_UUID && BITBUCKET_PIPELINE_UUID.replaceAll(/[{}]/gm, ''),
653
+ [CI_PIPELINE_ID]: BITBUCKET_PIPELINE_UUID && BITBUCKET_PIPELINE_UUID.replaceAll(/[{}]/g, ''),
655
654
  [GIT_PULL_REQUEST_BASE_BRANCH]: BITBUCKET_PR_DESTINATION_BRANCH,
656
655
  [PR_NUMBER]: BITBUCKET_PR_ID,
657
656
  }
@@ -699,6 +698,7 @@ module.exports = {
699
698
  BUILDKITE_TAG,
700
699
  BUILDKITE_BUILD_ID,
701
700
  BUILDKITE_PIPELINE_SLUG,
701
+ BUILDKITE_PIPELINE_NAME,
702
702
  BUILDKITE_BUILD_NUMBER,
703
703
  BUILDKITE_BUILD_URL,
704
704
  BUILDKITE_JOB_ID,
@@ -722,6 +722,7 @@ module.exports = {
722
722
  [CI_PROVIDER_NAME]: 'buildkite',
723
723
  [CI_PIPELINE_ID]: BUILDKITE_BUILD_ID,
724
724
  [CI_PIPELINE_NAME]: BUILDKITE_PIPELINE_SLUG,
725
+ [CI_PIPELINE_DISPLAY_NAME]: BUILDKITE_PIPELINE_NAME,
725
726
  [CI_PIPELINE_NUMBER]: BUILDKITE_BUILD_NUMBER,
726
727
  [CI_PIPELINE_URL]: BUILDKITE_BUILD_URL,
727
728
  [CI_JOB_URL]: `${BUILDKITE_BUILD_URL}#${BUILDKITE_JOB_ID}`,
@@ -62,7 +62,7 @@ function sanitizedExec (
62
62
  let result = cachedExec(cmd, flags, { stdio: 'pipe' }).toString()
63
63
 
64
64
  if (shouldTrim) {
65
- result = result.replaceAll(/(\r\n|\n|\r)/gm, '')
65
+ result = result.replaceAll(/(\r\n|\n|\r)/g, '')
66
66
  }
67
67
 
68
68
  if (durationMetric) {
@@ -258,7 +258,7 @@ function applyHttpOtelSemantics (formattedSpan) {
258
258
  // type): server spans are errors on 5xx only (4xx MUST be left unset per the
259
259
  // spec); client spans on any status >= 400.
260
260
  if (status !== undefined && newMeta[ERROR_TYPE] === undefined) {
261
- const isError = kind === 'server' ? statusCode >= 500 : statusCode >= 400
261
+ const isError = statusCode >= (kind === 'server' ? 500 : 400)
262
262
  if (isError) {
263
263
  newMeta[ERROR_TYPE] = status
264
264
  formattedSpan.error = 1
@@ -28,7 +28,7 @@ function normalize (text, limit = 128) {
28
28
  * Determines whether a prompt completion should be sampled based on the configured sampling rate.
29
29
  *
30
30
  * @param {Sampler} sampler
31
- * @param {import('index').Span|import('index').SpanContext} span
31
+ * @param {import('../../../../..').Span|import('../../../../..').SpanContext} span
32
32
  * @returns {boolean} `true` if the prompt completion should be sampled, otherwise `false`.
33
33
  */
34
34
  function isPromptCompletionSampled (sampler, span) {
@@ -51,7 +51,7 @@ module.exports = function makeUtilities (integrationName, tracerConfig) {
51
51
  /**
52
52
  * Determines whether a prompt completion should be sampled based on the configured sampling rate.
53
53
  *
54
- * @param {import('index').Span|import('index').SpanContext} span
54
+ * @param {import('../../../../..').Span|import('../../../../..').SpanContext} span
55
55
  * @returns {boolean} `true` if the prompt completion should be sampled, otherwise `false`.
56
56
  */
57
57
  isPromptCompletionSampled: (span) => isPromptCompletionSampled(sampler, span),
@@ -26,6 +26,7 @@ const GIT_PULL_REQUEST_BASE_BRANCH = 'git.pull_request.base_branch'
26
26
 
27
27
  const CI_PIPELINE_ID = 'ci.pipeline.id'
28
28
  const CI_PIPELINE_NAME = 'ci.pipeline.name'
29
+ const CI_PIPELINE_DISPLAY_NAME = 'ci.pipeline.display_name'
29
30
  const CI_PIPELINE_NUMBER = 'ci.pipeline.number'
30
31
  const CI_PIPELINE_URL = 'ci.pipeline.url'
31
32
  const CI_PROVIDER_NAME = 'ci.provider.name'
@@ -66,6 +67,7 @@ module.exports = {
66
67
  GIT_PULL_REQUEST_BASE_BRANCH,
67
68
  CI_PIPELINE_ID,
68
69
  CI_PIPELINE_NAME,
70
+ CI_PIPELINE_DISPLAY_NAME,
69
71
  CI_PIPELINE_NUMBER,
70
72
  CI_PIPELINE_URL,
71
73
  CI_PROVIDER_NAME,