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
@@ -12,12 +12,145 @@ const {
12
12
  TELEMETRY_GIT_REQUESTS_SETTINGS_RESPONSE,
13
13
  } = require('../telemetry')
14
14
  const { writeSettingsToCache } = require('../test-optimization-cache')
15
- const { validateSettingsResponse } = require('../test-optimization-http-cache-schema')
15
+ const { MAX_RETRIES, validateSettingsResponse } = require('../test-optimization-http-cache-schema')
16
16
  const request = require('./request')
17
17
 
18
18
  const DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES = 2
19
- const DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES = { '5s': 10, '10s': 5, '30s': 3, '5m': 2 }
19
+ const DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES = Object.freeze({
20
+ '5s': 10,
21
+ '10s': 5,
22
+ '30s': 3,
23
+ '5m': 2,
24
+ })
20
25
  const DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD = 30
26
+ const EARLY_FLAKE_DETECTION_RETRY_BUCKETS = Object.keys(DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES)
27
+
28
+ /**
29
+ * @typedef {object} EarlyFlakeDetectionSettings
30
+ * @property {boolean} enabled
31
+ * @property {number} numRetries
32
+ * @property {Readonly<Record<string, number>>} slowTestRetries
33
+ * @property {number} faultyThreshold
34
+ */
35
+
36
+ /**
37
+ * @typedef {object} TestManagementSettings
38
+ * @property {boolean} enabled
39
+ * @property {number|undefined} attemptToFixRetries
40
+ */
41
+
42
+ /**
43
+ * @param {unknown} value
44
+ * @returns {value is Record<string, unknown>}
45
+ */
46
+ function isRecord (value) {
47
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
48
+ }
49
+
50
+ /**
51
+ * @param {unknown} value
52
+ * @returns {value is number}
53
+ */
54
+ function isNonNegativeInteger (value) {
55
+ return Number.isInteger(value) && value >= 0
56
+ }
57
+
58
+ /**
59
+ * @param {unknown} value
60
+ * @returns {value is number}
61
+ */
62
+ function isRetryCount (value) {
63
+ return isNonNegativeInteger(value) && value <= MAX_RETRIES
64
+ }
65
+
66
+ /**
67
+ * @param {unknown} value
68
+ * @returns {Readonly<Record<string, number>>|undefined}
69
+ */
70
+ function parseSlowTestRetries (value) {
71
+ if (!isRecord(value)) return
72
+
73
+ const slowTestRetries = {}
74
+ for (const bucket of EARLY_FLAKE_DETECTION_RETRY_BUCKETS) {
75
+ if (!Object.hasOwn(value, bucket)) continue
76
+
77
+ const retries = value[bucket]
78
+ if (!isRetryCount(retries)) return
79
+ slowTestRetries[bucket] = retries
80
+ }
81
+ return Object.freeze(slowTestRetries)
82
+ }
83
+
84
+ /**
85
+ * @param {unknown} value
86
+ * @param {boolean} isKnownTestsEnabled
87
+ * @returns {EarlyFlakeDetectionSettings}
88
+ */
89
+ function parseEarlyFlakeDetectionSettings (value, isKnownTestsEnabled) {
90
+ if (!isRecord(value) || value.enabled !== true) {
91
+ return {
92
+ enabled: false,
93
+ numRetries: DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES,
94
+ slowTestRetries: DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES,
95
+ faultyThreshold: DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
96
+ }
97
+ }
98
+
99
+ let isValid = true
100
+ let numRetries = DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES
101
+ let slowTestRetries = DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES
102
+ if (Object.hasOwn(value, 'slow_test_retries')) {
103
+ const parsedSlowTestRetries = parseSlowTestRetries(value.slow_test_retries)
104
+ if (parsedSlowTestRetries) {
105
+ slowTestRetries = parsedSlowTestRetries
106
+ numRetries = parsedSlowTestRetries['5s'] ?? DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES
107
+ } else {
108
+ isValid = false
109
+ }
110
+ }
111
+
112
+ let faultyThreshold = DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD
113
+ if (Object.hasOwn(value, 'faulty_session_threshold')) {
114
+ if (isNonNegativeInteger(value.faulty_session_threshold) && value.faulty_session_threshold <= 100) {
115
+ faultyThreshold = value.faulty_session_threshold
116
+ } else {
117
+ isValid = false
118
+ }
119
+ }
120
+
121
+ return {
122
+ enabled: isKnownTestsEnabled && isValid,
123
+ numRetries,
124
+ slowTestRetries,
125
+ faultyThreshold,
126
+ }
127
+ }
128
+
129
+ /**
130
+ * @param {unknown} value
131
+ * @returns {TestManagementSettings}
132
+ */
133
+ function parseTestManagementSettings (value) {
134
+ if (!isRecord(value) || value.enabled !== true) {
135
+ return {
136
+ enabled: false,
137
+ attemptToFixRetries: undefined,
138
+ }
139
+ }
140
+
141
+ const attemptToFixRetries = value.attempt_to_fix_retries
142
+ if (attemptToFixRetries !== undefined && !isRetryCount(attemptToFixRetries)) {
143
+ return {
144
+ enabled: false,
145
+ attemptToFixRetries: undefined,
146
+ }
147
+ }
148
+
149
+ return {
150
+ enabled: true,
151
+ attemptToFixRetries,
152
+ }
153
+ }
21
154
 
22
155
  function parseJsonResponse (rawJson) {
23
156
  return typeof rawJson === 'string' ? JSON.parse(rawJson) : rawJson
@@ -28,40 +161,35 @@ function parseLibraryConfigurationResponse (rawJson, config = getConfig(), optio
28
161
  if (options.validateRequiredFields) {
29
162
  validateSettingsResponse(parsedResponse, options)
30
163
  }
31
- const {
32
- code_coverage: isCodeCoverageEnabled,
33
- tests_skipping: isSuitesSkippingEnabled,
34
- itr_enabled: isItrEnabled,
35
- require_git: requireGit,
36
- early_flake_detection: earlyFlakeDetectionConfig,
37
- flaky_test_retries_enabled: isFlakyTestRetriesEnabled,
38
- di_enabled: isDiEnabled,
39
- known_tests_enabled: isKnownTestsEnabled,
40
- test_management: testManagementConfig,
41
- impacted_tests_enabled: isImpactedTestsEnabled,
42
- coverage_report_upload_enabled: isCoverageReportUploadEnabled,
43
- } = parsedResponse?.data?.attributes ?? parsedResponse
164
+ const parsedAttributes = parsedResponse?.data?.attributes ?? parsedResponse
165
+ if (!isRecord(parsedAttributes)) {
166
+ throw new TypeError('Invalid settings response: attributes must be an object')
167
+ }
168
+ const attributes = parsedAttributes
169
+ const isKnownTestsEnabled = attributes.known_tests_enabled === true
170
+ const isFlakyTestRetriesEnabled = attributes.flaky_test_retries_enabled === true
171
+ const earlyFlakeDetection = parseEarlyFlakeDetectionSettings(
172
+ attributes.early_flake_detection,
173
+ isKnownTestsEnabled
174
+ )
175
+ const testManagement = parseTestManagementSettings(attributes.test_management)
44
176
 
45
177
  const settings = {
46
- isCodeCoverageEnabled,
47
- isSuitesSkippingEnabled,
48
- isItrEnabled,
49
- requireGit,
50
- isEarlyFlakeDetectionEnabled: isKnownTestsEnabled && (earlyFlakeDetectionConfig?.enabled ?? false),
51
- earlyFlakeDetectionNumRetries:
52
- earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] ?? DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES,
53
- earlyFlakeDetectionSlowTestRetries:
54
- earlyFlakeDetectionConfig?.slow_test_retries ?? DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES,
55
- earlyFlakeDetectionFaultyThreshold:
56
- earlyFlakeDetectionConfig?.faulty_session_threshold ?? DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
178
+ isCodeCoverageEnabled: attributes.code_coverage === true,
179
+ isSuitesSkippingEnabled: attributes.tests_skipping === true,
180
+ isItrEnabled: attributes.itr_enabled === true,
181
+ requireGit: attributes.require_git === true,
182
+ isEarlyFlakeDetectionEnabled: earlyFlakeDetection.enabled,
183
+ earlyFlakeDetectionNumRetries: earlyFlakeDetection.numRetries,
184
+ earlyFlakeDetectionSlowTestRetries: earlyFlakeDetection.slowTestRetries,
185
+ earlyFlakeDetectionFaultyThreshold: earlyFlakeDetection.faultyThreshold,
57
186
  isFlakyTestRetriesEnabled,
58
- isDiEnabled: isDiEnabled && isFlakyTestRetriesEnabled,
187
+ isDiEnabled: attributes.di_enabled === true && isFlakyTestRetriesEnabled,
59
188
  isKnownTestsEnabled,
60
- isTestManagementEnabled: (testManagementConfig?.enabled ?? false),
61
- testManagementAttemptToFixRetries:
62
- testManagementConfig?.attempt_to_fix_retries,
63
- isImpactedTestsEnabled,
64
- isCoverageReportUploadEnabled: isCoverageReportUploadEnabled ?? false,
189
+ isTestManagementEnabled: testManagement.enabled,
190
+ testManagementAttemptToFixRetries: testManagement.attemptToFixRetries,
191
+ isImpactedTestsEnabled: attributes.impacted_tests_enabled === true,
192
+ isCoverageReportUploadEnabled: attributes.coverage_report_upload_enabled === true,
65
193
  }
66
194
 
67
195
  log.debug('Remote settings: %j', settings)
@@ -82,7 +210,7 @@ function parseLibraryConfigurationResponse (rawJson, config = getConfig(), optio
82
210
  log.debug('Code coverage report upload was disabled by the environment variable')
83
211
  }
84
212
 
85
- return settings
213
+ return Object.freeze(settings)
86
214
  }
87
215
 
88
216
  function getLibraryConfiguration ({
@@ -42,7 +42,7 @@ function request (data, options, callback) {
42
42
  if (url.protocol === 'unix:') {
43
43
  opts.socketPath = url.pathname
44
44
  } else {
45
- opts.path = opts.path ?? url.path
45
+ opts.path ??= url.path
46
46
  opts.protocol = url.protocol
47
47
  opts.hostname = url.hostname
48
48
  opts.port = url.port
@@ -100,9 +100,9 @@ function request (data, options, callback) {
100
100
  if (res.statusCode === 429 && !hasRetried) {
101
101
  const resetHeader = res.headers['x-ratelimit-reset']
102
102
  const resetTs = (resetHeader === null || resetHeader === undefined)
103
- ? Number.NaN
103
+ ? NaN
104
104
  : Number.parseInt(resetHeader, 10)
105
- const waitMs = Number.isFinite(resetTs) ? Math.max(0, resetTs * 1000 - Date.now()) : Number.NaN
105
+ const waitMs = Number.isFinite(resetTs) ? Math.max(0, resetTs * 1000 - Date.now()) : NaN
106
106
 
107
107
  if (Number.isFinite(waitMs) && waitMs <= RATE_LIMIT_MAX_WAIT_MS) {
108
108
  hasRetried = true
@@ -26,11 +26,11 @@ const SETTINGS_BOOLEAN_KEYS = [
26
26
  ]
27
27
  const EARLY_FLAKE_DETECTION_KEYS = ['enabled', 'faulty_session_threshold', 'slow_test_retries']
28
28
  const TEST_MANAGEMENT_KEYS = ['attempt_to_fix_retries', 'enabled']
29
- const RETRY_THRESHOLD_PATTERN = /^\d+(?:ms|s|m|h)$/
29
+ const RETRY_THRESHOLD_PATTERN = /^\d+(?:ms|[smh])$/
30
30
  const MAX_VALIDATION_MODULES = 1000
31
31
  const MAX_VALIDATION_SUITES = 10_000
32
32
  const MAX_VALIDATION_TESTS = 100_000
33
- const MAX_VALIDATION_RETRIES = 100
33
+ const MAX_RETRIES = 100
34
34
  const MAX_VALIDATION_STRING_BYTES = 4096
35
35
 
36
36
  function isObject (value) {
@@ -75,7 +75,8 @@ function validateSettingsResponse (response, options = {}) {
75
75
  assertBooleanFields(attributes.test_management, ['enabled'], 'settings test_management')
76
76
  assertOptionalBoundedNumber(
77
77
  attributes.early_flake_detection.faulty_session_threshold,
78
- 'settings early_flake_detection faulty_session_threshold'
78
+ 'settings early_flake_detection faulty_session_threshold',
79
+ { integer: true }
79
80
  )
80
81
  assertRetryMap(attributes.early_flake_detection.slow_test_retries)
81
82
  assertOptionalBoundedNumber(
@@ -216,8 +217,8 @@ function assertBooleanFields (object, keys, endpoint) {
216
217
  function assertOptionalBoundedNumber (value, endpoint, { integer = false } = {}) {
217
218
  if (value === undefined) return
218
219
  if (!Number.isFinite(value) || (integer && !Number.isInteger(value)) ||
219
- value < 0 || value > MAX_VALIDATION_RETRIES) {
220
- throw new TypeError(`Invalid ${endpoint}: value must be between 0 and ${MAX_VALIDATION_RETRIES}`)
220
+ value < 0 || value > MAX_RETRIES) {
221
+ throw new TypeError(`Invalid ${endpoint}: value must be between 0 and ${MAX_RETRIES}`)
221
222
  }
222
223
  }
223
224
 
@@ -249,6 +250,7 @@ function assertValidationString (value, field) {
249
250
  }
250
251
 
251
252
  module.exports = {
253
+ MAX_RETRIES,
252
254
  validateKnownTestsResponse,
253
255
  validateSettingsResponse,
254
256
  validateSkippableTestsResponse,
@@ -32,18 +32,26 @@ const parseErrors = new Map()
32
32
  * @param {string} source - The source of the value.
33
33
  * @param {string} baseMessage - The base message to use for the warning.
34
34
  * @param {Error} [error] - An error that was thrown while parsing the value.
35
+ * @param {string} [outcome] - The outcome after the invalid value is rejected.
35
36
  */
36
- function warnInvalidValue (value, optionName, source, baseMessage, error) {
37
- const canonicalName = (optionsTable[optionName]?.canonicalName ?? optionName) + source
37
+ function warnInvalidValue (value, optionName, source, baseMessage, error, outcome = 'picked default') {
38
+ const canonicalName = optionsTable[optionName]?.canonicalName ?? optionName
39
+ const telemetryKey = canonicalName + source
40
+ const telemetryEntry = configWithOrigin.get(telemetryKey)
38
41
  // Lazy load log module to avoid circular dependency
39
- if (!parseErrors.has(canonicalName)) {
40
- // TODO: Rephrase: It will fallback to former source (or default if not set)
41
- let message = `${baseMessage}: ${util.inspect(value)} for ${optionName} (source: ${source}), picked default`
42
+ if (!parseErrors.has(telemetryKey) && !telemetryEntry?.error) {
43
+ // TODO: Report the prior source when an invalid value does not use the default.
44
+ let message = `${baseMessage}: ${util.inspect(value)} for ${optionName} (source: ${source})`
45
+ if (outcome) message += `, ${outcome}`
42
46
  if (error) {
43
47
  error.stack = error.toString()
44
48
  message += `\n\n${util.inspect(error)}`
45
49
  }
46
- parseErrors.set(canonicalName, { message })
50
+ if (telemetryEntry) {
51
+ telemetryEntry.error = { message }
52
+ } else {
53
+ parseErrors.set(telemetryKey, { message })
54
+ }
47
55
  log ??= require('../log')
48
56
  const logLevel = error ? 'error' : 'warn'
49
57
  log[logLevel](message)
@@ -333,6 +333,7 @@ export interface GeneratedConfig {
333
333
  DD_TRACE_NODE_SERIALIZE_ENABLED: boolean;
334
334
  DD_TRACE_NYC_ENABLED: boolean;
335
335
  DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP: string;
336
+ DD_TRACE_OPENAI_AGENTS_ENABLED: boolean;
336
337
  DD_TRACE_OPENAI_ENABLED: boolean;
337
338
  DD_TRACE_OPENSEARCH_ENABLED: boolean;
338
339
  DD_TRACE_OPENSEARCH_PROJECT_OPENSEARCH_ENABLED: boolean;
@@ -433,7 +434,7 @@ export interface GeneratedConfig {
433
434
  };
434
435
  };
435
436
  featureFlags: {
436
- DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: "agentless" | "remote_config";
437
+ DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: string;
437
438
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL: string | undefined;
438
439
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS: number;
439
440
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS: number;
@@ -699,7 +700,7 @@ export interface GeneratedEnvVarConfig {
699
700
  DD_EXPERIMENTAL_TEST_OPT_VITEST_NO_WORKER_INIT: boolean | undefined;
700
701
  DD_EXPERIMENTAL_TEST_REQUESTS_FS_CACHE: boolean;
701
702
  DD_EXTERNAL_ENV: string | undefined;
702
- DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: "agentless" | "remote_config";
703
+ DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: string;
703
704
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL: string | undefined;
704
705
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS: number;
705
706
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS: number;
@@ -1028,6 +1029,7 @@ export interface GeneratedEnvVarConfig {
1028
1029
  DD_TRACE_NODE_SERIALIZE_ENABLED: boolean;
1029
1030
  DD_TRACE_NYC_ENABLED: boolean;
1030
1031
  DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP: string;
1032
+ DD_TRACE_OPENAI_AGENTS_ENABLED: boolean;
1031
1033
  DD_TRACE_OPENAI_ENABLED: boolean;
1032
1034
  DD_TRACE_OPENSEARCH_ENABLED: boolean;
1033
1035
  DD_TRACE_OPENSEARCH_PROJECT_OPENSEARCH_ENABLED: boolean;
@@ -343,6 +343,21 @@ class Config extends ConfigBase {
343
343
  }
344
344
  }
345
345
 
346
+ const configurationSource = this.featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE
347
+ if (this.featureFlags.DD_FEATURE_FLAGS_ENABLED &&
348
+ configurationSource !== 'agentless' &&
349
+ configurationSource !== 'remote_config') {
350
+ warnInvalidValue(
351
+ configurationSource,
352
+ 'DD_FEATURE_FLAGS_CONFIGURATION_SOURCE',
353
+ this.getOrigin('featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE'),
354
+ 'Unsupported Feature Flagging configuration source',
355
+ undefined,
356
+ 'provider disabled'
357
+ )
358
+ setAndTrack(this, 'featureFlags.DD_FEATURE_FLAGS_ENABLED', false)
359
+ }
360
+
346
361
  if (this.url ||
347
362
  os.type() !== 'Windows_NT' &&
348
363
  !trackedConfigOrigins.has('hostname') &&
@@ -58,6 +58,17 @@ const transformers = {
58
58
  toLowerCase (value) {
59
59
  return toCase(value, 'toLowerCase')
60
60
  },
61
+ /**
62
+ * Normalizes a Feature Flagging configuration source.
63
+ * A blank value is treated as unset so legacy configuration can still apply.
64
+ *
65
+ * @param {string} value
66
+ * @returns {string | undefined}
67
+ */
68
+ configurationSource (value) {
69
+ const normalized = value.trim().toLowerCase()
70
+ return normalized || undefined
71
+ },
61
72
  toUpperCase (value) {
62
73
  return toCase(value, 'toUpperCase')
63
74
  },
@@ -161,7 +172,14 @@ const transformers = {
161
172
  return transformers.stripColonWhitespace(item)
162
173
  })
163
174
  }
164
- return value.replaceAll(/\s*:\s*/g, ':')
175
+ // Only whitespace adjacent to a colon is removed; the outer whitespace of the first and
176
+ // last segment stays.
177
+ const parts = value.split(':')
178
+ for (let i = 0; i < parts.length; i++) {
179
+ if (i !== 0) parts[i] = parts[i].trimStart()
180
+ if (i !== parts.length - 1) parts[i] = parts[i].trimEnd()
181
+ }
182
+ return parts.join(':')
165
183
  },
166
184
  /**
167
185
  * @param {string} value
@@ -849,10 +849,9 @@
849
849
  "implementation": "A",
850
850
  "type": "string",
851
851
  "default": "agentless",
852
- "allowed": "agentless|remote_config",
853
- "description": "Experimental: Select where Feature Flagging loads Universal Flag Configuration. Supported values are agentless and remote_config.",
852
+ "description": "Select where Feature Flagging loads Universal Flag Configuration. Supported values are agentless and remote_config; offline is reserved and currently unsupported.",
854
853
  "namespace": "featureFlags",
855
- "transform": "toLowerCase"
854
+ "transform": "configurationSource"
856
855
  }
857
856
  ],
858
857
  "DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL": [
@@ -860,7 +859,7 @@
860
859
  "implementation": "A",
861
860
  "type": "string",
862
861
  "default": null,
863
- "description": "Experimental: Override the agentless Feature Flagging UFC endpoint or base URL.",
862
+ "description": "Override the agentless Feature Flagging UFC endpoint or base URL.",
864
863
  "namespace": "featureFlags",
865
864
  "sensitive": true
866
865
  }
@@ -870,7 +869,7 @@
870
869
  "implementation": "A",
871
870
  "type": "int",
872
871
  "default": "30",
873
- "description": "Experimental: Set the agentless Feature Flagging UFC polling interval in seconds, capped at one hour.",
872
+ "description": "Set the agentless Feature Flagging UFC polling interval in seconds, capped at one hour.",
874
873
  "allowed": "[1-9]\\d*",
875
874
  "namespace": "featureFlags"
876
875
  }
@@ -880,7 +879,7 @@
880
879
  "implementation": "A",
881
880
  "type": "int",
882
881
  "default": "5",
883
- "description": "Experimental: Set the agentless Feature Flagging UFC request timeout in seconds.",
882
+ "description": "Set the agentless Feature Flagging UFC request timeout in seconds.",
884
883
  "allowed": "[1-9]\\d*",
885
884
  "namespace": "featureFlags"
886
885
  }
@@ -3452,6 +3451,13 @@
3452
3451
  "default": "true"
3453
3452
  }
3454
3453
  ],
3454
+ "DD_TRACE_OPENAI_AGENTS_ENABLED": [
3455
+ {
3456
+ "implementation": "A",
3457
+ "type": "boolean",
3458
+ "default": "true"
3459
+ }
3460
+ ],
3455
3461
  "DD_TRACE_OPENSEARCH_ENABLED": [
3456
3462
  {
3457
3463
  "implementation": "A",
@@ -40,7 +40,7 @@ function encodeVarintInto (target, offset, value) {
40
40
  let i = offset
41
41
  const limit = offset + maxVarLen64 - 1
42
42
  // if first byte is 1, the number is negative in javascript, but we want to interpret it as positive
43
- while ((high !== 0 || low < 0 || low > 0x80) && i < limit) {
43
+ while ((high !== 0 || low < 0 || low > 0x7F) && i < limit) {
44
44
  target[i] = (low & 0x7F) | 0x80
45
45
  low >>>= 7
46
46
  low |= (high & 0x7F) << 25
@@ -88,7 +88,7 @@ function decodeUvarint64 (
88
88
  low |= n << s
89
89
  }
90
90
  if (s > 0) {
91
- high |= s - 32 > 0 ? n << (s - 32) : n >> (32 - s)
91
+ high |= s > 32 ? n << (s - 32) : n >> (32 - s)
92
92
  }
93
93
  return [low, high, bytes]
94
94
  }
@@ -96,8 +96,7 @@ function decodeUvarint64 (
96
96
  low |= (n & 0x7F) << s
97
97
  }
98
98
  if (s > 0) {
99
- high |=
100
- s - 32 > 0 ? (n & 0x7F) << (s - 32) : (n & 0x7F) >> (32 - s)
99
+ high |= s > 32 ? (n & 0x7F) << (s - 32) : (n & 0x7F) >> (32 - s)
101
100
  }
102
101
  s += 7
103
102
  }
@@ -20,11 +20,12 @@ const on = (level, ...args) => {
20
20
  const off = () => {}
21
21
 
22
22
  const threshold = LEVELS.indexOf(logLevel)
23
+ const isEnabled = debug && typeof logPort?.postMessage === 'function'
23
24
 
24
25
  /** @type {Logger} */
25
26
  module.exports = Object.fromEntries(
26
27
  LEVELS.map(level => [
27
28
  level,
28
- debug && threshold >= LEVELS.indexOf(level) ? on.bind(null, level) : off,
29
+ isEnabled && threshold >= LEVELS.indexOf(level) ? on.bind(null, level) : off,
29
30
  ])
30
31
  )
@@ -36,10 +36,7 @@ function getRemoveProbeExpression (id) {
36
36
  * @returns {string}
37
37
  */
38
38
  function compileBreakpointCondition (probes) {
39
- const probeConditions = []
40
- for (const probe of probes) {
41
- probeConditions.push(compileProbeCondition(probe))
42
- }
39
+ const probeConditions = probes.map(compileProbeCondition)
43
40
 
44
41
  // NOTE: $dd_sampler is read from the realm-local `globalThis` where it was installed (the main
45
42
  // realm). A probe whose code runs in a different V8 realm (e.g. a `vm.createContext` script with a
@@ -67,14 +67,13 @@ function send (message, logger, dd, snapshot, processTags) {
67
67
 
68
68
  if (pruned) {
69
69
  json = pruned
70
- size = Buffer.byteLength(json)
71
70
  } else {
72
71
  // Fallback if pruning fails
73
72
  const line = Object.keys(snapshot.captures.lines)[0]
74
73
  snapshot.captures.lines[line] = { pruned: true }
75
74
  json = JSON.stringify(payload)
76
- size = Buffer.byteLength(json)
77
75
  }
76
+ size = Buffer.byteLength(json)
78
77
  }
79
78
 
80
79
  jsonBuffer.write(json, size)
@@ -61,7 +61,7 @@ async function getLocalStateForCallFrame (callFrame, limits, deadlineNs = BIGINT
61
61
  // Delay calling `processRawState` so caller can resume the main thread before processing `rawState`
62
62
  return {
63
63
  processLocalState () {
64
- processedState = processedState ?? processRawState(rawState, maxLength)
64
+ processedState ??= processRawState(rawState, maxLength)
65
65
  return processedState
66
66
  },
67
67
  fatalErrors: ctx.fatalErrors,
@@ -155,7 +155,7 @@ async function evaluateCaptureExpressions (callFrame, expressions, deadlineNs =
155
155
  fatalErrors.push(...ctx.fatalErrors)
156
156
  }
157
157
 
158
- if (ctx.deadlineReached === true) {
158
+ if (ctx.deadlineReached) {
159
159
  // Add the current expression (properties may be incomplete due to timeout)
160
160
  rawResults.push({ name, remoteObject: result, maxLength })
161
161
  // Add stub entries for remaining uncaptured expressions
@@ -97,10 +97,24 @@ const REDACTED_IDENTIFIERS = new Set(
97
97
  'XSRF-TOKEN',
98
98
  ...config.dynamicInstrumentation.redactedIdentifiers,
99
99
  ]
100
- .map((name) => normalizeName(name))
101
- .filter((name) => excludedIdentifiers.has(name) === false)
100
+ .map(normalizeIdentifier)
101
+ .filter(isIncludedIdentifier)
102
102
  )
103
103
 
104
+ /**
105
+ * @param {string} name
106
+ */
107
+ function normalizeIdentifier (name) {
108
+ return normalizeName(name)
109
+ }
110
+
111
+ /**
112
+ * @param {string} name
113
+ */
114
+ function isIncludedIdentifier (name) {
115
+ return !excludedIdentifiers.has(name)
116
+ }
117
+
104
118
  function normalizeName (name, isSymbol) {
105
119
  if (isSymbol) name = name.slice(7, -1) // Remove `Symbol(` and `)`
106
120
  return name.toLowerCase().replaceAll(/[-_@$.]/g, '')
@@ -31,7 +31,7 @@ class SpanStatsEncoder extends AgentEncoder {
31
31
  }
32
32
 
33
33
  _encodeStat (bytes, stat) {
34
- bytes.writeMapPrefix(15)
34
+ bytes.writeMapPrefix(17)
35
35
 
36
36
  this._encodeString(bytes, 'Service')
37
37
  const service = stat.Service || DEFAULT_SERVICE_NAME
@@ -79,6 +79,12 @@ class SpanStatsEncoder extends AgentEncoder {
79
79
 
80
80
  this._encodeString(bytes, 'srv_src')
81
81
  this._encodeString(bytes, stat.srv_src || '')
82
+
83
+ this._encodeString(bytes, 'SpanKind')
84
+ this._encodeString(bytes, stat.SpanKind || '')
85
+
86
+ this._encodeString(bytes, 'GRPCStatusCode')
87
+ this._encodeString(bytes, stat.GRPCStatusCode || '')
82
88
  }
83
89
 
84
90
  _encodeBucket (bytes, bucket) {
@@ -60,11 +60,11 @@ function eventTimeNano (event) {
60
60
  }
61
61
 
62
62
  function normalizeSpan (span) {
63
- span.service = span.service || DEFAULT_SERVICE_NAME
63
+ span.service ||= DEFAULT_SERVICE_NAME
64
64
  if (span.service.length > MAX_SERVICE_LENGTH) {
65
65
  span.service = span.service.slice(0, MAX_SERVICE_LENGTH)
66
66
  }
67
- span.name = span.name || DEFAULT_SPAN_NAME
67
+ span.name ||= DEFAULT_SPAN_NAME
68
68
  if (span.name.length > MAX_NAME_LENGTH) {
69
69
  span.name = span.name.slice(0, MAX_NAME_LENGTH)
70
70
  }
@@ -4,6 +4,7 @@ const fs = require('fs')
4
4
  const exporters = require('../../../ext/exporters')
5
5
  const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
6
6
  const constants = require('./constants')
7
+ const { isTrue } = require('./util')
7
8
 
8
9
  module.exports = function getExporter (name) {
9
10
  switch (name) {
@@ -20,20 +21,26 @@ module.exports = function getExporter (name) {
20
21
  case exporters.AGENT_PROXY:
21
22
  return require('./ci-visibility/exporters/agent-proxy')
22
23
  case exporters.CI_VALIDATION:
23
- return require('./ci-visibility/exporters/ci-validation')
24
+ if (hasCiValidationEnvironment()) return require('./ci-visibility/exporters/ci-validation')
25
+ break
24
26
  case exporters.JEST_WORKER:
25
27
  case exporters.CUCUMBER_WORKER:
26
28
  case exporters.MOCHA_WORKER:
27
29
  case exporters.PLAYWRIGHT_WORKER:
28
30
  case exporters.VITEST_WORKER:
29
31
  return require('./ci-visibility/exporters/test-worker')
30
- default: {
31
- const inAWSLambda = getEnvironmentVariable('AWS_LAMBDA_FUNCTION_NAME') !== undefined
32
- const usingAgent = inAWSLambda && (
33
- fs.existsSync(constants.DATADOG_LAMBDA_EXTENSION_PATH) ||
34
- fs.existsSync(constants.DATADOG_MINI_AGENT_PATH)
35
- )
36
- return inAWSLambda && !usingAgent ? require('./exporters/log') : require('./exporters/agent')
37
- }
38
32
  }
33
+
34
+ const inAWSLambda = getEnvironmentVariable('AWS_LAMBDA_FUNCTION_NAME') !== undefined
35
+ const usingAgent = inAWSLambda && (
36
+ fs.existsSync(constants.DATADOG_LAMBDA_EXTENSION_PATH) ||
37
+ fs.existsSync(constants.DATADOG_MINI_AGENT_PATH)
38
+ )
39
+ return inAWSLambda && !usingAgent ? require('./exporters/log') : require('./exporters/agent')
40
+ }
41
+
42
+ function hasCiValidationEnvironment () {
43
+ return isTrue(getEnvironmentVariable('_DD_TEST_OPTIMIZATION_VALIDATION_MODE')) &&
44
+ getEnvironmentVariable('_DD_TEST_OPTIMIZATION_VALIDATION_MANIFEST_FILE') &&
45
+ getEnvironmentVariable('_DD_TEST_OPTIMIZATION_VALIDATION_OUTPUT_DIR')
39
46
  }