dd-trace 6.7.0 → 6.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/ci/diagnose.js +27 -25
  2. package/ci/init.js +6 -6
  3. package/ci/runbook.md +114 -20
  4. package/ci/test-optimization-validation/approval-artifacts.js +36 -3
  5. package/ci/test-optimization-validation/approval.js +78 -22
  6. package/ci/test-optimization-validation/blocker-category.js +24 -0
  7. package/ci/test-optimization-validation/ci-discovery.js +23 -17
  8. package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
  9. package/ci/test-optimization-validation/ci-remediation.js +1 -1
  10. package/ci/test-optimization-validation/cli.js +280 -52
  11. package/ci/test-optimization-validation/command-blocker.js +159 -20
  12. package/ci/test-optimization-validation/command-output-policy.js +14 -8
  13. package/ci/test-optimization-validation/command-runner.js +9 -7
  14. package/ci/test-optimization-validation/environment.js +4 -2
  15. package/ci/test-optimization-validation/executable.js +15 -13
  16. package/ci/test-optimization-validation/execution-lock.js +70 -0
  17. package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
  18. package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
  19. package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
  20. package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
  21. package/ci/test-optimization-validation/generated-files.js +47 -37
  22. package/ci/test-optimization-validation/generated-test-contract.js +9 -7
  23. package/ci/test-optimization-validation/generated-verifier.js +24 -17
  24. package/ci/test-optimization-validation/literal-glob.js +52 -0
  25. package/ci/test-optimization-validation/manifest-loader.js +3 -0
  26. package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
  27. package/ci/test-optimization-validation/manifest-schema.js +80 -17
  28. package/ci/test-optimization-validation/offline-fixtures.js +13 -4
  29. package/ci/test-optimization-validation/offline-output.js +6 -6
  30. package/ci/test-optimization-validation/package-check.js +94 -0
  31. package/ci/test-optimization-validation/plan-writer.js +183 -10
  32. package/ci/test-optimization-validation/preflight-runner.js +110 -31
  33. package/ci/test-optimization-validation/project-build-artifact.js +31 -0
  34. package/ci/test-optimization-validation/redaction.js +18 -27
  35. package/ci/test-optimization-validation/report-writer.js +182 -48
  36. package/ci/test-optimization-validation/result-semantics.js +20 -3
  37. package/ci/test-optimization-validation/runner-command.js +41 -21
  38. package/ci/test-optimization-validation/runner-contract.js +79 -43
  39. package/ci/test-optimization-validation/safe-files.js +4 -4
  40. package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
  41. package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
  42. package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
  43. package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
  44. package/ci/test-optimization-validation/static-diagnosis.js +10 -3
  45. package/ci/test-optimization-validation/test-output.js +2 -1
  46. package/ci/test-optimization-validation/validation-blocker.js +21 -0
  47. package/ci/vitest-no-worker-init-setup.mjs +377 -84
  48. package/index.d.ts +175 -14
  49. package/init.js +1 -17
  50. package/initialize.mjs +11 -0
  51. package/loader-hook.mjs +6 -4
  52. package/package.json +12 -4
  53. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  54. package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
  55. package/packages/datadog-esbuild/index.js +4 -2
  56. package/packages/datadog-esbuild/src/utils.js +17 -2
  57. package/packages/datadog-instrumentations/src/ai.js +61 -34
  58. package/packages/datadog-instrumentations/src/bluebird.js +6 -6
  59. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
  60. package/packages/datadog-instrumentations/src/cucumber.js +131 -51
  61. package/packages/datadog-instrumentations/src/dns.js +21 -2
  62. package/packages/datadog-instrumentations/src/electron.js +1 -0
  63. package/packages/datadog-instrumentations/src/fastify.js +3 -1
  64. package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
  65. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
  66. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  67. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  68. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  69. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  70. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
  71. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  72. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
  73. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
  74. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
  75. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
  76. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  77. package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
  78. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  79. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  80. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
  81. package/packages/datadog-instrumentations/src/jest.js +986 -246
  82. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  83. package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
  84. package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
  85. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
  86. package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
  87. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  88. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  89. package/packages/datadog-instrumentations/src/next.js +155 -23
  90. package/packages/datadog-instrumentations/src/openai.js +14 -0
  91. package/packages/datadog-instrumentations/src/pg.js +180 -6
  92. package/packages/datadog-instrumentations/src/playwright.js +176 -81
  93. package/packages/datadog-instrumentations/src/promise-js.js +4 -4
  94. package/packages/datadog-instrumentations/src/promise.js +3 -3
  95. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  96. package/packages/datadog-instrumentations/src/router.js +195 -19
  97. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
  98. package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
  99. package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
  100. package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
  101. package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
  102. package/packages/datadog-instrumentations/src/when.js +3 -3
  103. package/packages/datadog-instrumentations/src/ws.js +5 -1
  104. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  105. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  106. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  107. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
  108. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  109. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  110. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  111. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  112. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  113. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  114. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
  115. package/packages/datadog-plugin-cucumber/src/index.js +5 -1
  116. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
  117. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  118. package/packages/datadog-plugin-cypress/src/support.js +7 -4
  119. package/packages/datadog-plugin-electron/src/net.js +10 -4
  120. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  121. package/packages/datadog-plugin-fs/src/index.js +0 -4
  122. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  123. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  124. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  125. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  126. package/packages/datadog-plugin-http/src/client.js +3 -2
  127. package/packages/datadog-plugin-http2/src/client.js +1 -1
  128. package/packages/datadog-plugin-jest/src/index.js +3 -21
  129. package/packages/datadog-plugin-jest/src/util.js +4 -1
  130. package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
  131. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  132. package/packages/datadog-plugin-mocha/src/index.js +342 -6
  133. package/packages/datadog-plugin-next/src/index.js +57 -9
  134. package/packages/datadog-plugin-openai/src/tracing.js +4 -0
  135. package/packages/datadog-plugin-pg/src/index.js +65 -1
  136. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  137. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  138. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  139. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  140. package/packages/datadog-plugin-undici/src/index.js +2 -1
  141. package/packages/datadog-plugin-vitest/src/index.js +179 -18
  142. package/packages/datadog-shimmer/src/shimmer.js +6 -2
  143. package/packages/datadog-webpack/index.js +2 -2
  144. package/packages/dd-trace/src/aiguard/sdk.js +3 -0
  145. package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
  146. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  147. package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
  148. package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
  149. package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
  150. package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
  151. package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
  152. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  153. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  154. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
  155. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  156. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  157. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
  158. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  159. package/packages/dd-trace/src/appsec/index.js +48 -476
  160. package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
  161. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  162. package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
  163. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
  164. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  165. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
  166. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
  167. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
  168. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  169. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  170. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
  171. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
  172. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  173. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
  174. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
  175. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
  176. package/packages/dd-trace/src/config/defaults.js +14 -6
  177. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
  178. package/packages/dd-trace/src/config/helper.js +2 -0
  179. package/packages/dd-trace/src/config/index.js +31 -5
  180. package/packages/dd-trace/src/config/parsers.js +19 -1
  181. package/packages/dd-trace/src/config/remote_config.js +1 -1
  182. package/packages/dd-trace/src/config/supported-configurations.json +13 -6
  183. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  184. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  185. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  186. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  187. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  188. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  189. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
  190. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  191. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  192. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  193. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  194. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  195. package/packages/dd-trace/src/flare/index.js +2 -2
  196. package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
  197. package/packages/dd-trace/src/guardrails/log.js +1 -10
  198. package/packages/dd-trace/src/id.js +1 -1
  199. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  200. package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
  201. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  202. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  203. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  204. package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
  205. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  206. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  207. package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
  208. package/packages/dd-trace/src/llmobs/noop.js +2 -0
  209. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
  210. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  211. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  212. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
  213. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  214. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  215. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  216. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  217. package/packages/dd-trace/src/llmobs/sdk.js +152 -78
  218. package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
  219. package/packages/dd-trace/src/llmobs/tagger.js +1 -2
  220. package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
  221. package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
  222. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  223. package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
  224. package/packages/dd-trace/src/log/channels.js +1 -9
  225. package/packages/dd-trace/src/log/levels.js +12 -0
  226. package/packages/dd-trace/src/noop/proxy.js +2 -2
  227. package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
  228. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  229. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
  230. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
  231. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  232. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
  233. package/packages/dd-trace/src/opentelemetry/span.js +4 -0
  234. package/packages/dd-trace/src/opentracing/span.js +1 -1
  235. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  236. package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
  237. package/packages/dd-trace/src/plugins/index.js +2 -0
  238. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  239. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  240. package/packages/dd-trace/src/plugins/util/ci.js +13 -6
  241. package/packages/dd-trace/src/plugins/util/git.js +7 -5
  242. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
  243. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
  244. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  245. package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
  246. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  247. package/packages/dd-trace/src/plugins/util/test.js +356 -86
  248. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  249. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  250. package/packages/dd-trace/src/plugins/util/web.js +24 -2
  251. package/packages/dd-trace/src/priority_sampler.js +6 -3
  252. package/packages/dd-trace/src/profiler.js +1 -1
  253. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
  254. package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
  255. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  256. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  257. package/packages/dd-trace/src/proxy.js +1 -0
  258. package/packages/dd-trace/src/ritm.js +10 -20
  259. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
  260. package/packages/dd-trace/src/sampling_rule.js +4 -2
  261. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
  262. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
  263. package/packages/dd-trace/src/startup-log.js +3 -0
  264. package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
  265. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  266. package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
  267. package/packages/dd-trace/src/util.js +16 -0
  268. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  269. package/vendor/dist/pprof-format/index.js +1 -1
  270. package/vendor/dist/source-map/index.js +1 -1
  271. package/version.js +10 -8
  272. /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
@@ -3,6 +3,7 @@
3
3
  const getConfig = require('../../config')
4
4
  const id = require('../../id')
5
5
  const log = require('../../log')
6
+ const { EARLY_FLAKE_DETECTION_RETRY_BUCKETS, createEfdRetryPolicy } = require('../efd-retry-policy')
6
7
  const {
7
8
  incrementCountMetric,
8
9
  distributionMetric,
@@ -15,21 +16,20 @@ const { writeSettingsToCache } = require('../test-optimization-cache')
15
16
  const { MAX_RETRIES, validateSettingsResponse } = require('../test-optimization-http-cache-schema')
16
17
  const request = require('./request')
17
18
 
18
- const DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES = 2
19
19
  const DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES = Object.freeze({
20
20
  '5s': 10,
21
21
  '10s': 5,
22
22
  '30s': 3,
23
23
  '5m': 2,
24
24
  })
25
+ const DEFAULT_EARLY_FLAKE_DETECTION_RETRY_POLICY =
26
+ createEfdRetryPolicy(DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES)
25
27
  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
 
28
29
  /**
29
30
  * @typedef {object} EarlyFlakeDetectionSettings
30
31
  * @property {boolean} enabled
31
- * @property {number} numRetries
32
- * @property {Readonly<Record<string, number>>} slowTestRetries
32
+ * @property {import('../efd-retry-policy').EfdRetryPolicy} retryPolicy
33
33
  * @property {number} faultyThreshold
34
34
  */
35
35
 
@@ -90,20 +90,17 @@ function parseEarlyFlakeDetectionSettings (value, isKnownTestsEnabled) {
90
90
  if (!isRecord(value) || value.enabled !== true) {
91
91
  return {
92
92
  enabled: false,
93
- numRetries: DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES,
94
- slowTestRetries: DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES,
93
+ retryPolicy: DEFAULT_EARLY_FLAKE_DETECTION_RETRY_POLICY,
95
94
  faultyThreshold: DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
96
95
  }
97
96
  }
98
97
 
99
98
  let isValid = true
100
- let numRetries = DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES
101
- let slowTestRetries = DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES
99
+ let retryPolicy = DEFAULT_EARLY_FLAKE_DETECTION_RETRY_POLICY
102
100
  if (Object.hasOwn(value, 'slow_test_retries')) {
103
101
  const parsedSlowTestRetries = parseSlowTestRetries(value.slow_test_retries)
104
102
  if (parsedSlowTestRetries) {
105
- slowTestRetries = parsedSlowTestRetries
106
- numRetries = parsedSlowTestRetries['5s'] ?? DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES
103
+ retryPolicy = createEfdRetryPolicy(parsedSlowTestRetries)
107
104
  } else {
108
105
  isValid = false
109
106
  }
@@ -120,8 +117,7 @@ function parseEarlyFlakeDetectionSettings (value, isKnownTestsEnabled) {
120
117
 
121
118
  return {
122
119
  enabled: isKnownTestsEnabled && isValid,
123
- numRetries,
124
- slowTestRetries,
120
+ retryPolicy,
125
121
  faultyThreshold,
126
122
  }
127
123
  }
@@ -180,8 +176,7 @@ function parseLibraryConfigurationResponse (rawJson, config = getConfig(), optio
180
176
  isItrEnabled: attributes.itr_enabled === true,
181
177
  requireGit: attributes.require_git === true,
182
178
  isEarlyFlakeDetectionEnabled: earlyFlakeDetection.enabled,
183
- earlyFlakeDetectionNumRetries: earlyFlakeDetection.numRetries,
184
- earlyFlakeDetectionSlowTestRetries: earlyFlakeDetection.slowTestRetries,
179
+ earlyFlakeDetectionRetryPolicy: earlyFlakeDetection.retryPolicy,
185
180
  earlyFlakeDetectionFaultyThreshold: earlyFlakeDetection.faultyThreshold,
186
181
  isFlakyTestRetriesEnabled,
187
182
  isDiEnabled: attributes.di_enabled === true && isFlakyTestRetriesEnabled,
@@ -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
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { readFileSync } = require('node:fs')
3
+ const { closeSync, constants, fstatSync, openSync, readFileSync } = require('node:fs')
4
4
  const { gzipSync } = require('node:zlib')
5
5
 
6
6
  const getConfig = require('../../config')
@@ -17,12 +17,18 @@ const {
17
17
  } = require('../telemetry')
18
18
 
19
19
  const UPLOAD_TIMEOUT_MS = 30_000
20
+ const COVERAGE_FILE_OPEN_FLAGS = constants.O_RDONLY |
21
+ (constants.O_NOFOLLOW || 0) |
22
+ constants.O_NONBLOCK
23
+ const BIGINT_STAT_OPTIONS = { bigint: true }
20
24
 
21
25
  /**
22
26
  * Uploads a single coverage report to the Datadog CI intake.
23
27
  * One file per request with field names 'coverage' and 'event'.
24
28
  * @param {object} options - Upload options
25
29
  * @param {string} options.filePath - Path to the coverage report file
30
+ * @param {bigint} options.fileDevice - Device containing the discovered report
31
+ * @param {bigint} options.fileInode - Inode of the discovered report
26
32
  * @param {string} options.format - Format of the coverage report (e.g., 'lcov', 'cobertura')
27
33
  * @param {string[]} [options.flags] - Optional coverage report grouping flags
28
34
  * @param {object} options.testEnvironmentMetadata - Test environment metadata containing git/CI tags
@@ -32,7 +38,7 @@ const UPLOAD_TIMEOUT_MS = 30_000
32
38
  * @param {(error: Error|null) => void} callback - Callback function
33
39
  */
34
40
  function uploadCoverageReport (
35
- { filePath, format, flags, testEnvironmentMetadata, url, isEvpProxy, evpProxyPrefix },
41
+ { filePath, fileDevice, fileInode, format, flags, testEnvironmentMetadata, url, isEvpProxy, evpProxyPrefix },
36
42
  callback
37
43
  ) {
38
44
  const { DD_API_KEY } = getConfig()
@@ -43,10 +49,20 @@ function uploadCoverageReport (
43
49
 
44
50
  let compressedCoverage
45
51
  try {
46
- const coverageContent = readFileSync(filePath)
52
+ const fileDescriptor = openSync(filePath, COVERAGE_FILE_OPEN_FLAGS)
53
+ let coverageContent
54
+ try {
55
+ const fileStats = fstatSync(fileDescriptor, BIGINT_STAT_OPTIONS)
56
+ if (!fileStats.isFile() || fileStats.dev !== fileDevice || fileStats.ino !== fileInode) {
57
+ throw new Error('Coverage report changed after discovery')
58
+ }
59
+ coverageContent = readFileSync(fileDescriptor)
60
+ } finally {
61
+ closeSync(fileDescriptor)
62
+ }
47
63
  compressedCoverage = gzipSync(coverageContent)
48
- } catch (err) {
49
- return callback(new Error(`Failed to read coverage report at ${filePath}: ${err.message}`))
64
+ } catch (error) {
65
+ return callback(new Error(`Failed to read coverage report at ${filePath}: ${error.message}`))
50
66
  }
51
67
 
52
68
  // Build the event payload with format, type, and all tags from test environment metadata
@@ -26,7 +26,7 @@ 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
@@ -137,7 +137,7 @@ function validateSkippableTestsResponse (response, options = {}) {
137
137
  if (response.meta !== undefined) {
138
138
  assertObject(response.meta, 'Invalid skippable tests response: meta must be an object')
139
139
  }
140
- if (response.meta?.coverage !== undefined) {
140
+ if (response.meta?.coverage !== undefined && response.meta.coverage !== null) {
141
141
  assertObject(response.meta.coverage, 'Invalid skippable tests response: meta.coverage must be an object')
142
142
  }
143
143
  if (response.meta?.correlation_id !== undefined && typeof response.meta.correlation_id !== 'string') {
@@ -145,7 +145,11 @@ class TestOptimizationHttpCache {
145
145
  validationMode: Boolean(this._validationManifestPath),
146
146
  })
147
147
  const testLevel = options.testLevel || 'suite'
148
- logSkippableSuitesResponse(result, testLevel)
148
+ logSkippableSuitesResponse(
149
+ result,
150
+ testLevel,
151
+ options.isCoverageReportUploadEnabled && options.isLineCoverageSupported !== false
152
+ )
149
153
  const skippableItems = parsedResponse.data.filter(({ type }) => type === testLevel)
150
154
  incrementCountMetric(
151
155
  testLevel === 'test'
@@ -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)
@@ -434,7 +434,7 @@ export interface GeneratedConfig {
434
434
  };
435
435
  };
436
436
  featureFlags: {
437
- DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: "agentless" | "remote_config";
437
+ DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: string;
438
438
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL: string | undefined;
439
439
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS: number;
440
440
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS: number;
@@ -579,6 +579,7 @@ export interface GeneratedConfig {
579
579
  DD_TEST_LOCAL_CONFIG_PATH: string | undefined;
580
580
  DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES: number;
581
581
  DD_TEST_MANAGEMENT_ENABLED: boolean;
582
+ DD_TEST_MANAGEMENT_REPORT_ENABLED: boolean | undefined;
582
583
  };
583
584
  traceId128BitGenerationEnabled: boolean;
584
585
  traceId128BitLoggingEnabled: boolean;
@@ -700,7 +701,7 @@ export interface GeneratedEnvVarConfig {
700
701
  DD_EXPERIMENTAL_TEST_OPT_VITEST_NO_WORKER_INIT: boolean | undefined;
701
702
  DD_EXPERIMENTAL_TEST_REQUESTS_FS_CACHE: boolean;
702
703
  DD_EXTERNAL_ENV: string | undefined;
703
- DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: "agentless" | "remote_config";
704
+ DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: string;
704
705
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL: string | undefined;
705
706
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS: number;
706
707
  DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS: number;
@@ -821,6 +822,7 @@ export interface GeneratedEnvVarConfig {
821
822
  DD_TEST_LOCAL_CONFIG_PATH: string | undefined;
822
823
  DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES: number;
823
824
  DD_TEST_MANAGEMENT_ENABLED: boolean;
825
+ DD_TEST_MANAGEMENT_REPORT_ENABLED: boolean | undefined;
824
826
  DD_TEST_SESSION_NAME: string | undefined;
825
827
  DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED: boolean;
826
828
  DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED: boolean;
@@ -307,6 +307,8 @@ module.exports = {
307
307
  *
308
308
  * This should only be called once in config.js to avoid copying the object frequently.
309
309
  *
310
+ * @param {typeof process.env} [source] The environment to read from
311
+ * @param {boolean} [internalOnly] Only return configurations marked as internal
310
312
  * @returns {TracerEnv} The environment variables
311
313
  */
312
314
  getEnvironmentVariables (source = process.env, internalOnly = false) {
@@ -4,6 +4,7 @@ const fs = require('node:fs')
4
4
  const os = require('node:os')
5
5
  const { URL, format } = require('node:url')
6
6
 
7
+ const exporters = require('../../../../ext/exporters')
7
8
  const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false })
8
9
  const uuid = require('../../../../vendor/dist/crypto-randomuuid') // we need to keep the old uuid dep because of cypress
9
10
  const set = require('../../../datadog-core/src/utils/src/set')
@@ -41,6 +42,13 @@ const { normalizeService } = require('./normalize-service')
41
42
  const { programmaticTypeCoercions, transformers } = require('./parsers')
42
43
 
43
44
  const RUNTIME_ID = uuid()
45
+ const TEST_OPTIMIZATION_WORKER_EXPORTERS = new Set([
46
+ exporters.CUCUMBER_WORKER,
47
+ exporters.JEST_WORKER,
48
+ exporters.MOCHA_WORKER,
49
+ exporters.PLAYWRIGHT_WORKER,
50
+ exporters.VITEST_WORKER,
51
+ ])
44
52
 
45
53
  const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
46
54
 
@@ -194,8 +202,11 @@ class Config extends ConfigBase {
194
202
  this.debug = log.configure(options)
195
203
 
196
204
  // Process stable config warnings, if any
197
- for (const warning of this.stableConfig?.warnings ?? []) {
198
- log.warn(warning)
205
+ const stableConfigWarnings = this.stableConfig?.warnings
206
+ if (stableConfigWarnings) {
207
+ for (const warning of stableConfigWarnings) {
208
+ log.warn(warning)
209
+ }
199
210
  }
200
211
 
201
212
  this.#applyDefaults()
@@ -343,6 +354,21 @@ class Config extends ConfigBase {
343
354
  }
344
355
  }
345
356
 
357
+ const configurationSource = this.featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE
358
+ if (this.featureFlags.DD_FEATURE_FLAGS_ENABLED &&
359
+ configurationSource !== 'agentless' &&
360
+ configurationSource !== 'remote_config') {
361
+ warnInvalidValue(
362
+ configurationSource,
363
+ 'DD_FEATURE_FLAGS_CONFIGURATION_SOURCE',
364
+ this.getOrigin('featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE'),
365
+ 'Unsupported Feature Flagging configuration source',
366
+ undefined,
367
+ 'provider disabled'
368
+ )
369
+ setAndTrack(this, 'featureFlags.DD_FEATURE_FLAGS_ENABLED', false)
370
+ }
371
+
346
372
  if (this.url ||
347
373
  os.type() !== 'Windows_NT' &&
348
374
  !trackedConfigOrigins.has('hostname') &&
@@ -578,9 +604,9 @@ class Config extends ConfigBase {
578
604
  setAndTrack(this, 'remoteConfig.DD_REMOTE_CONFIGURATION_ENABLED', false)
579
605
  }
580
606
 
581
- // TODO: Should this unconditionally be disabled?
582
- if (getEnvironmentVariable('JEST_WORKER_ID') &&
583
- !trackedConfigOrigins.has('telemetry.DD_INSTRUMENTATION_TELEMETRY_ENABLED')) {
607
+ const isTestOptimizationWorker = this.isCiVisibility &&
608
+ TEST_OPTIMIZATION_WORKER_EXPORTERS.has(this.experimental.exporter)
609
+ if (isTestOptimizationWorker) {
584
610
  setAndTrack(this, 'telemetry.DD_INSTRUMENTATION_TELEMETRY_ENABLED', false)
585
611
  }
586
612
 
@@ -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
@@ -236,7 +236,7 @@ const optionLookupTable = {
236
236
 
237
237
  const transformers = {
238
238
  tracing_sampling_rules (samplingRules) {
239
- for (const rule of (samplingRules || [])) {
239
+ for (const rule of samplingRules) {
240
240
  if (rule.tags) {
241
241
  const reformattedTags = {}
242
242
  for (const tag of rule.tags) {
@@ -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
  }
@@ -1942,6 +1941,14 @@
1942
1941
  "namespace": "testOptimization"
1943
1942
  }
1944
1943
  ],
1944
+ "DD_TEST_MANAGEMENT_REPORT_ENABLED": [
1945
+ {
1946
+ "implementation": "A",
1947
+ "type": "boolean",
1948
+ "default": null,
1949
+ "namespace": "testOptimization"
1950
+ }
1951
+ ],
1945
1952
  "DD_TEST_SESSION_NAME": [
1946
1953
  {
1947
1954
  "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, '')
@@ -32,7 +32,7 @@ const STATUSES = {
32
32
  INSTALLED: 'INSTALLED',
33
33
  EMITTING: 'EMITTING',
34
34
  ERROR: 'ERROR',
35
- BLOCKED: 'BLOCKED', // TODO: Implement once support for allow list, deny list or max probe limit has been added
35
+ // TODO: Add BLOCKED once support for allow list, deny list or max probe limit has been added
36
36
  }
37
37
 
38
38
  function ackReceived ({ id: probeId, version }) {
@@ -110,7 +110,6 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
110
110
  _encodePayloadStart (bytes) {
111
111
  const payload = {
112
112
  version: COVERAGE_PAYLOAD_VERSION,
113
- coverages: [],
114
113
  }
115
114
  bytes.writeMapPrefix(COVERAGE_KEYS_LENGTH)
116
115
  this._encodeString(bytes, 'version')
@@ -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
  }
@@ -32,11 +32,9 @@ function parseUrl (urlObjOrString) {
32
32
  // `urlToHttpOptions` returns `pathname` at runtime, but @types/node narrows it
33
33
  // to `ClientRequestArgs`, which omits it; cast so the named-pipe fold below can
34
34
  // read and rewrite it.
35
- const url = /** @type {import('node:http').ClientRequestArgs & { pathname: string }} */ (
36
- urlObjOrString !== null && typeof urlObjOrString === 'object'
37
- ? urlToHttpOptions(urlObjOrString)
38
- : urlToHttpOptions(new URL(urlObjOrString))
39
- )
35
+ const url = /** @type {import('node:http').ClientRequestArgs & { pathname: string }} */ (urlToHttpOptions(
36
+ urlObjOrString !== null && typeof urlObjOrString === 'object' ? urlObjOrString : new URL(urlObjOrString)
37
+ ))
40
38
 
41
39
  if (url.protocol === 'unix:' && url.hostname === '.') {
42
40
  url.path = url.pathname = `//.${url.pathname}`
@@ -16,6 +16,8 @@ class ElectronExporter {
16
16
  }
17
17
 
18
18
  export (spans) {
19
+ if (!traceChannel.hasSubscribers) return
20
+
19
21
  this.#traces.push(spans)
20
22
 
21
23
  const { flushInterval } = this._config
@@ -35,7 +37,8 @@ class ElectronExporter {
35
37
  clearTimeout(this.#timer)
36
38
  this.#timer = undefined
37
39
 
38
- const traces = this.#traces.splice(0)
40
+ const traces = this.#traces
41
+ this.#traces = []
39
42
 
40
43
  if (traces.length > 0 && traceChannel.hasSubscribers) {
41
44
  const formattedTraces = traces.map(spans => spans.map(span => normalizeSpan(truncateSpan(span))))
@@ -78,7 +78,6 @@ class ExternalLogger {
78
78
 
79
79
  // Flushes logs with optional callback for when the call is complete
80
80
  flush (cb = () => {}) {
81
- let logs
82
81
  let numLogs
83
82
  let encodedLogs
84
83
 
@@ -88,7 +87,7 @@ class ExternalLogger {
88
87
  }
89
88
 
90
89
  try {
91
- logs = this.queue
90
+ const logs = this.queue
92
91
  this.queue = []
93
92
 
94
93
  numLogs = logs.length
@@ -39,8 +39,8 @@ const flare = {
39
39
  logChannel?.unsubscribe(logger)
40
40
  logChannel = new LogChannel(logLevel)
41
41
  logChannel.subscribe(logger)
42
- tracerLogs = tracerLogs || new FlareFile()
43
- timer = timer || setTimeout(flare.cleanup, TIMEOUT)
42
+ tracerLogs ||= new FlareFile()
43
+ timer ||= setTimeout(flare.cleanup, TIMEOUT)
44
44
  },
45
45
 
46
46
  send (task) {