dd-trace 5.96.0 → 5.98.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 (173) hide show
  1. package/index.d.ts +60 -2
  2. package/package.json +9 -7
  3. package/packages/datadog-esbuild/index.js +20 -9
  4. package/packages/datadog-instrumentations/src/child_process.js +7 -17
  5. package/packages/datadog-instrumentations/src/crypto.js +1 -2
  6. package/packages/datadog-instrumentations/src/cucumber.js +69 -4
  7. package/packages/datadog-instrumentations/src/cypress-config.js +318 -0
  8. package/packages/datadog-instrumentations/src/cypress.js +86 -4
  9. package/packages/datadog-instrumentations/src/dns.js +1 -2
  10. package/packages/datadog-instrumentations/src/express.js +4 -4
  11. package/packages/datadog-instrumentations/src/fs.js +27 -29
  12. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  13. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +41 -13
  14. package/packages/datadog-instrumentations/src/helpers/hook.js +31 -6
  15. package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -19
  16. package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -13
  17. package/packages/datadog-instrumentations/src/helpers/register.js +103 -142
  18. package/packages/datadog-instrumentations/src/http/client.js +2 -3
  19. package/packages/datadog-instrumentations/src/http/server.js +2 -5
  20. package/packages/datadog-instrumentations/src/http2/client.js +1 -3
  21. package/packages/datadog-instrumentations/src/http2/server.js +1 -3
  22. package/packages/datadog-instrumentations/src/jest.js +117 -16
  23. package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
  24. package/packages/datadog-instrumentations/src/mocha/utils.js +12 -1
  25. package/packages/datadog-instrumentations/src/net.js +2 -8
  26. package/packages/datadog-instrumentations/src/pino.js +1 -1
  27. package/packages/datadog-instrumentations/src/playwright.js +4 -1
  28. package/packages/datadog-instrumentations/src/prisma.js +1 -2
  29. package/packages/datadog-instrumentations/src/redis.js +12 -6
  30. package/packages/datadog-instrumentations/src/selenium.js +4 -1
  31. package/packages/datadog-instrumentations/src/sequelize.js +1 -1
  32. package/packages/datadog-instrumentations/src/url.js +1 -3
  33. package/packages/datadog-instrumentations/src/vitest.js +5 -1
  34. package/packages/datadog-instrumentations/src/vm.js +1 -3
  35. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -4
  36. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -0
  37. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
  38. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -0
  39. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -0
  40. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -0
  41. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -0
  42. package/packages/datadog-plugin-cucumber/src/index.js +13 -3
  43. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +166 -6
  44. package/packages/datadog-plugin-cypress/src/index.js +59 -2
  45. package/packages/datadog-plugin-fs/src/index.js +1 -1
  46. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -1
  47. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -7
  48. package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
  49. package/packages/datadog-plugin-http/src/client.js +1 -1
  50. package/packages/datadog-plugin-http/src/server.js +10 -2
  51. package/packages/datadog-plugin-http2/src/client.js +1 -1
  52. package/packages/datadog-plugin-http2/src/server.js +10 -2
  53. package/packages/datadog-plugin-jest/src/index.js +4 -2
  54. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +31 -4
  55. package/packages/datadog-plugin-mocha/src/index.js +5 -2
  56. package/packages/datadog-plugin-mongodb-core/src/index.js +3 -3
  57. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  58. package/packages/datadog-plugin-next/src/index.js +10 -16
  59. package/packages/datadog-plugin-openai/src/services.js +1 -0
  60. package/packages/datadog-plugin-pg/src/index.js +1 -1
  61. package/packages/datadog-plugin-tedious/src/index.js +1 -1
  62. package/packages/datadog-plugin-ws/src/close.js +1 -1
  63. package/packages/datadog-plugin-ws/src/receiver.js +1 -1
  64. package/packages/datadog-webpack/index.js +3 -3
  65. package/packages/dd-trace/index.js +12 -10
  66. package/packages/dd-trace/src/agent/url.js +2 -2
  67. package/packages/dd-trace/src/aiguard/sdk.js +26 -22
  68. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -3
  69. package/packages/dd-trace/src/appsec/blocking.js +64 -33
  70. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  71. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +1 -1
  72. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  73. package/packages/dd-trace/src/appsec/remote_config.js +1 -0
  74. package/packages/dd-trace/src/appsec/sdk/index.js +4 -0
  75. package/packages/dd-trace/src/appsec/sdk/set_user.js +1 -1
  76. package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -5
  77. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +2 -2
  78. package/packages/dd-trace/src/appsec/sdk/utils.js +4 -2
  79. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +6 -1
  80. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
  81. package/packages/dd-trace/src/config/defaults.js +315 -146
  82. package/packages/dd-trace/src/config/generated-config-types.d.ts +9 -1
  83. package/packages/dd-trace/src/config/helper.js +59 -10
  84. package/packages/dd-trace/src/config/index.js +587 -1496
  85. package/packages/dd-trace/src/config/parsers.js +256 -0
  86. package/packages/dd-trace/src/config/remote_config.js +59 -2
  87. package/packages/dd-trace/src/config/supported-configurations.json +406 -432
  88. package/packages/dd-trace/src/constants.js +1 -0
  89. package/packages/dd-trace/src/crashtracking/crashtracker.js +7 -1
  90. package/packages/dd-trace/src/crashtracking/index.js +1 -7
  91. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +5 -2
  92. package/packages/dd-trace/src/debugger/index.js +1 -1
  93. package/packages/dd-trace/src/dogstatsd.js +12 -9
  94. package/packages/dd-trace/src/encode/0.4.js +8 -7
  95. package/packages/dd-trace/src/encode/span-stats.js +4 -1
  96. package/packages/dd-trace/src/exporters/agent/writer.js +7 -1
  97. package/packages/dd-trace/src/exporters/common/request.js +9 -0
  98. package/packages/dd-trace/src/exporters/common/writer.js +12 -2
  99. package/packages/dd-trace/src/heap_snapshots.js +3 -0
  100. package/packages/dd-trace/src/index.js +5 -2
  101. package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -6
  102. package/packages/dd-trace/src/llmobs/index.js +4 -1
  103. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -1
  104. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +60 -12
  105. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +4 -2
  106. package/packages/dd-trace/src/llmobs/sdk.js +12 -8
  107. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  108. package/packages/dd-trace/src/llmobs/tagger.js +9 -6
  109. package/packages/dd-trace/src/llmobs/writers/base.js +2 -0
  110. package/packages/dd-trace/src/llmobs/writers/util.js +3 -0
  111. package/packages/dd-trace/src/log/index.js +20 -59
  112. package/packages/dd-trace/src/log/writer.js +7 -19
  113. package/packages/dd-trace/src/noop/proxy.js +8 -0
  114. package/packages/dd-trace/src/openfeature/remote_config.js +6 -1
  115. package/packages/dd-trace/src/opentelemetry/context_manager.js +6 -4
  116. package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
  117. package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
  118. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +17 -2
  119. package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +14 -2
  120. package/packages/dd-trace/src/opentelemetry/otlp/trace.proto +358 -0
  121. package/packages/dd-trace/src/opentelemetry/otlp/trace_service.proto +78 -0
  122. package/packages/dd-trace/src/opentelemetry/trace/index.js +75 -0
  123. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +66 -0
  124. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +332 -0
  125. package/packages/dd-trace/src/opentracing/propagation/text_map.js +9 -4
  126. package/packages/dd-trace/src/opentracing/tracer.js +9 -4
  127. package/packages/dd-trace/src/payload-tagging/config/index.js +6 -5
  128. package/packages/dd-trace/src/plugin_manager.js +8 -6
  129. package/packages/dd-trace/src/plugins/ci_plugin.js +4 -0
  130. package/packages/dd-trace/src/plugins/log_plugin.js +3 -0
  131. package/packages/dd-trace/src/plugins/plugin.js +11 -13
  132. package/packages/dd-trace/src/plugins/storage.js +2 -2
  133. package/packages/dd-trace/src/plugins/tracing.js +22 -5
  134. package/packages/dd-trace/src/plugins/util/test.js +2 -0
  135. package/packages/dd-trace/src/plugins/util/web.js +6 -88
  136. package/packages/dd-trace/src/process-tags/index.js +3 -0
  137. package/packages/dd-trace/src/profiler.js +27 -2
  138. package/packages/dd-trace/src/profiling/config.js +73 -241
  139. package/packages/dd-trace/src/profiling/exporter_cli.js +1 -4
  140. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +6 -2
  141. package/packages/dd-trace/src/profiling/profiler.js +78 -109
  142. package/packages/dd-trace/src/profiling/profilers/events.js +2 -3
  143. package/packages/dd-trace/src/profiling/profilers/wall.js +89 -6
  144. package/packages/dd-trace/src/profiling/ssi-heuristics.js +4 -1
  145. package/packages/dd-trace/src/propagation-hash/index.js +2 -1
  146. package/packages/dd-trace/src/proxy.js +40 -6
  147. package/packages/dd-trace/src/remote_config/index.js +3 -0
  148. package/packages/dd-trace/src/require-package-json.js +8 -4
  149. package/packages/dd-trace/src/ritm.js +58 -26
  150. package/packages/dd-trace/src/runtime_metrics/index.js +3 -0
  151. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +18 -11
  152. package/packages/dd-trace/src/sampler.js +1 -1
  153. package/packages/dd-trace/src/service-naming/index.js +1 -1
  154. package/packages/dd-trace/src/service-naming/schemas/definition.js +4 -1
  155. package/packages/dd-trace/src/service-naming/schemas/util.js +15 -1
  156. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +24 -1
  157. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +60 -0
  158. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +17 -1
  159. package/packages/dd-trace/src/service-naming/schemas/v0/websocket.js +5 -0
  160. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +17 -0
  161. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +11 -1
  162. package/packages/dd-trace/src/service-naming/schemas/v1/websocket.js +6 -0
  163. package/packages/dd-trace/src/span_stats.js +5 -1
  164. package/packages/dd-trace/src/standalone/index.js +3 -0
  165. package/packages/dd-trace/src/telemetry/index.js +2 -3
  166. package/packages/dd-trace/src/telemetry/send-data.js +5 -19
  167. package/packages/dd-trace/src/telemetry/session-propagation.js +19 -44
  168. package/packages/dd-trace/src/telemetry/telemetry.js +28 -171
  169. package/packages/dd-trace/src/tracer.js +2 -2
  170. package/packages/dd-trace/src/util.js +0 -9
  171. package/vendor/dist/@apm-js-collab/code-transformer/index.js +28 -6
  172. package/vendor/dist/protobufjs/index.js +1 -1
  173. package/packages/dd-trace/src/log/utils.js +0 -16
@@ -1,5 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realSetTimeout = setTimeout
5
+
3
6
  const path = require('path')
4
7
  const shimmer = require('../../datadog-shimmer')
5
8
  const log = require('../../dd-trace/src/log')
@@ -8,6 +11,7 @@ const {
8
11
  JEST_WORKER_TRACE_PAYLOAD_CODE,
9
12
  JEST_WORKER_COVERAGE_PAYLOAD_CODE,
10
13
  JEST_WORKER_TELEMETRY_PAYLOAD_CODE,
14
+ JEST_WORKER_QUARANTINE_PAYLOAD_CODE,
11
15
  getTestLineStart,
12
16
  getTestSuitePath,
13
17
  getTestParametersString,
@@ -111,6 +115,8 @@ const efdDeterminedRetries = new Map()
111
115
  const efdSlowAbortedTests = new Set()
112
116
  // Tests added as EFD new-test candidates (not ATF, not impacted).
113
117
  const efdNewTestCandidates = new Set()
118
+ // Tests that are genuinely new (not in known tests list).
119
+ const newTests = new Set()
114
120
  const testSuiteAbsolutePathsWithFastCheck = new Set()
115
121
  const testSuiteJestObjects = new Map()
116
122
 
@@ -118,6 +124,38 @@ const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
118
124
  const ATR_RETRY_SUPPRESSION_FLAG = '_ddDisableAtrRetry'
119
125
  const atrSuppressedErrors = new Map()
120
126
 
127
+ // Track quarantined tests whose errors were suppressed, keyed by "suite › testName"
128
+ const quarantinedFailingTests = new Set()
129
+
130
+ /**
131
+ * Sends suppressed quarantine test names from a worker process to the main process.
132
+ * Supports both child_process (process.send) and worker_threads (parentPort.postMessage).
133
+ * Returns true if the data was sent (worker mode), false if in main process (runInBand).
134
+ *
135
+ * @param {string[]} testNames
136
+ * @returns {boolean}
137
+ */
138
+ function sendQuarantineInfoToMainProcess (testNames) {
139
+ const payload = [JEST_WORKER_QUARANTINE_PAYLOAD_CODE, JSON.stringify(testNames)]
140
+
141
+ if (process.send) {
142
+ process.send(payload)
143
+ return true
144
+ }
145
+
146
+ try {
147
+ const { isMainThread, parentPort } = require('node:worker_threads')
148
+ if (!isMainThread && parentPort) {
149
+ parentPort.postMessage(payload)
150
+ return true
151
+ }
152
+ } catch {
153
+ // Not in a worker context
154
+ }
155
+
156
+ return false
157
+ }
158
+
121
159
  // based on https://github.com/facebook/jest/blob/main/packages/jest-circus/src/formatNodeAssertErrors.ts#L41
122
160
  function formatJestError (errors) {
123
161
  let error
@@ -485,7 +523,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
485
523
  }
486
524
 
487
525
  if (this.isKnownTestsEnabled) {
488
- isNewTest = retriedTestsToNumAttempts.has(testName)
526
+ isNewTest = newTests.has(testName)
489
527
  }
490
528
 
491
529
  const willRunEfd = this.isEarlyFlakeDetectionEnabled && (isNewTest || isModified)
@@ -605,6 +643,9 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
605
643
  }
606
644
  if (!isAttemptToFix && this.isKnownTestsEnabled) {
607
645
  const isNew = !this.knownTestsForThisSuite.includes(testFullName)
646
+ if (isNew && !isSkipped) {
647
+ newTests.add(testFullName)
648
+ }
608
649
  if (isNew && !isSkipped && !retriedTestsToNumAttempts.has(testFullName)) {
609
650
  if (DYNAMIC_NAME_RE.test(testFullName)) {
610
651
  // Populated directly for runInBand; for parallel workers the main process
@@ -715,7 +756,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
715
756
  let isEfdRetry = false
716
757
  // We'll store the test statuses of the retries
717
758
  if (this.isKnownTestsEnabled) {
718
- const isNewTest = retriedTestsToNumAttempts.has(testName)
759
+ const isNewTest = newTests.has(testName)
719
760
  if (isNewTest) {
720
761
  if (newTestsTestStatuses.has(testName)) {
721
762
  newTestsTestStatuses.get(testName).push(status)
@@ -748,6 +789,18 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
748
789
  const willBeRetriedByFailedTestReplay = numRetries > 0 && numTestExecutions - 1 < numRetries
749
790
  const mightHitBreakpoint = this.isDiEnabled && numTestExecutions >= 2
750
791
 
792
+ // For quarantined tests, suppress errors so Jest doesn't count them as failures.
793
+ // This prevents --bail from stopping the test run on quarantined test failures.
794
+ // The actual status ('fail') is already captured above for dd-trace reporting.
795
+ // Only suppress on the final execution — not when ATR/EFD/ATF will retry the test.
796
+ if (!event.test?.[ATR_RETRY_SUPPRESSION_FLAG] && !willBeRetriedByFailedTestReplay) {
797
+ const quarantineCtx = testContexts.get(event.test)
798
+ if (quarantineCtx?.isQuarantined && event.test.errors?.length) {
799
+ quarantinedFailingTests.add(`${quarantineCtx.suite} › ${quarantineCtx.name}`)
800
+ event.test.errors = []
801
+ }
802
+ }
803
+
751
804
  const ctx = testContexts.get(event.test)
752
805
  if (!ctx) {
753
806
  log.warn('"ci:jest:test_done": no context found for test "%s"', testName)
@@ -776,7 +829,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
776
829
  // This means that tests retried with DI are BREAKPOINT_HIT_GRACE_PERIOD_MS slower at least.
777
830
  if (status === 'fail' && mightHitBreakpoint) {
778
831
  await new Promise(resolve => {
779
- setTimeout(() => {
832
+ realSetTimeout(() => {
780
833
  resolve()
781
834
  }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
782
835
  })
@@ -805,12 +858,29 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
805
858
  }
806
859
  if (event.name === 'run_finish') {
807
860
  for (const [test, errors] of atrSuppressedErrors) {
808
- test.errors = errors
861
+ // Do not restore errors for quarantined tests — they should stay suppressed
862
+ // so Jest doesn't see the failure (prevents --bail from stopping the run).
863
+ const ctx = testContexts.get(test)
864
+ if (ctx?.isQuarantined) {
865
+ const testName = getJestTestName(test, this.getShouldStripSeedFromTestName())
866
+ quarantinedFailingTests.add(`${ctx.suite} › ${testName}`)
867
+ } else {
868
+ test.errors = errors
869
+ }
809
870
  }
810
871
  atrSuppressedErrors.clear()
872
+
873
+ // In parallel mode, send suppressed quarantine info to the main process
874
+ // so it can include them in the session summary.
875
+ // In runInBand mode, keep the set — it will be consumed by the session-level code directly.
876
+ if (quarantinedFailingTests.size > 0 && sendQuarantineInfoToMainProcess([...quarantinedFailingTests])) {
877
+ quarantinedFailingTests.clear()
878
+ }
879
+
811
880
  efdDeterminedRetries.clear()
812
881
  efdSlowAbortedTests.clear()
813
882
  efdNewTestCandidates.clear()
883
+ newTests.clear()
814
884
  retriedTestsToNumAttempts.clear()
815
885
  attemptToFixRetriedTestsStatuses.clear()
816
886
  testsToBeRetried.clear()
@@ -1246,6 +1316,7 @@ function getCliWrapper (isNewJestVersion) {
1246
1316
 
1247
1317
  let numFailedQuarantinedTests = 0
1248
1318
  let numFailedQuarantinedOrDisabledAttemptedToFixTests = 0
1319
+ let numSuppressedQuarantinedTests = 0
1249
1320
  if (isTestManagementTestsEnabled) {
1250
1321
  const failedTests = result
1251
1322
  .results
@@ -1282,45 +1353,69 @@ function getCliWrapper (isNewJestVersion) {
1282
1353
  }
1283
1354
  }
1284
1355
 
1356
+ // Include quarantined tests whose errors were suppressed at test_done time.
1357
+ // These tests don't appear as failed in Jest's results because their errors were cleared
1358
+ // to prevent --bail from stopping the run, but they should still be counted for the summary.
1359
+ for (const name of quarantinedFailingTests) {
1360
+ if (!quarantineIgnoredNames.includes(name)) {
1361
+ numSuppressedQuarantinedTests++
1362
+ quarantineIgnoredNames.push(name)
1363
+ }
1364
+ }
1365
+ quarantinedFailingTests.clear()
1366
+
1285
1367
  // If every test that failed was quarantined, we'll consider the suite passed
1286
1368
  // Note that if a test is attempted to fix,
1287
1369
  // it's considered quarantined both if it's disabled and if it's quarantined
1288
1370
  // (it'll run but its status is ignored)
1289
1371
  // Skip if EFD block already flipped (to avoid logging twice)
1372
+ // Only use visible failures (from Jest results) for the flip check.
1373
+ // Suppressed quarantine failures are not in numFailedTests.
1374
+ const visibleQuarantineFailures = numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests
1290
1375
  if (
1291
1376
  !result.results.success &&
1292
1377
  !mustNotFlipSuccess &&
1293
- (numFailedQuarantinedOrDisabledAttemptedToFixTests !== 0 || numFailedQuarantinedTests !== 0) &&
1294
- result.results.numFailedTests ===
1295
- numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests
1378
+ visibleQuarantineFailures !== 0 &&
1379
+ result.results.numFailedTests === visibleQuarantineFailures
1296
1380
  ) {
1297
1381
  result.results.success = true
1298
- ignoredFailuresSummary = {
1299
- efdNames: [],
1300
- quarantineNames: quarantineIgnoredNames,
1301
- totalCount: numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests,
1382
+ }
1383
+
1384
+ const totalQuarantineFailures = visibleQuarantineFailures + numSuppressedQuarantinedTests
1385
+ if (totalQuarantineFailures > 0) {
1386
+ if (ignoredFailuresSummary) {
1387
+ ignoredFailuresSummary.quarantineNames = quarantineIgnoredNames
1388
+ ignoredFailuresSummary.totalCount += totalQuarantineFailures
1389
+ } else {
1390
+ ignoredFailuresSummary = {
1391
+ efdNames: [],
1392
+ quarantineNames: quarantineIgnoredNames,
1393
+ totalCount: totalQuarantineFailures,
1394
+ }
1302
1395
  }
1303
1396
  }
1304
1397
  }
1305
1398
 
1306
1399
  // Combined check: if all failed tests are accounted for by EFD (flaky retries) and/or quarantine,
1307
1400
  // we should consider the suite passed even when neither check alone covers all failures.
1401
+ // Only visible failures (in Jest results) are compared — suppressed quarantine failures
1402
+ // are already removed from numFailedTests at test_done time.
1308
1403
  if (
1309
1404
  !result.results.success &&
1310
1405
  !mustNotFlipSuccess &&
1311
1406
  (isEarlyFlakeDetectionEnabled || isTestManagementTestsEnabled)
1312
1407
  ) {
1313
- const totalIgnoredFailures =
1408
+ const visibleIgnoredFailures =
1314
1409
  numEfdFailedTestsToIgnore + numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests
1315
1410
  if (
1316
- totalIgnoredFailures !== 0 &&
1317
- result.results.numFailedTests === totalIgnoredFailures
1411
+ visibleIgnoredFailures !== 0 &&
1412
+ result.results.numFailedTests === visibleIgnoredFailures
1318
1413
  ) {
1319
1414
  result.results.success = true
1320
1415
  ignoredFailuresSummary = {
1321
1416
  efdNames: efdIgnoredNames,
1322
1417
  quarantineNames: quarantineIgnoredNames,
1323
- totalCount: totalIgnoredFailures,
1418
+ totalCount: visibleIgnoredFailures + numSuppressedQuarantinedTests,
1324
1419
  }
1325
1420
  }
1326
1421
  }
@@ -1345,7 +1440,7 @@ function getCliWrapper (isNewJestVersion) {
1345
1440
  })
1346
1441
 
1347
1442
  const timeoutPromise = new Promise((resolve) => {
1348
- timeoutId = setTimeout(() => {
1443
+ timeoutId = realSetTimeout(() => {
1349
1444
  resolve('timeout')
1350
1445
  }, FLUSH_TIMEOUT).unref()
1351
1446
  })
@@ -1856,6 +1951,12 @@ function onMessageWrapper (onMessage) {
1856
1951
  workerReportTelemetryCh.publish(data)
1857
1952
  return
1858
1953
  }
1954
+ if (code === JEST_WORKER_QUARANTINE_PAYLOAD_CODE) { // quarantined test failures suppressed in worker
1955
+ for (const name of JSON.parse(data)) {
1956
+ quarantinedFailingTests.add(name)
1957
+ }
1958
+ return
1959
+ }
1859
1960
  return onMessage.apply(this, arguments)
1860
1961
  }
1861
1962
  }
@@ -14,7 +14,7 @@ function wrapRequest (original) {
14
14
  addHook({
15
15
  name: 'limitd-client',
16
16
  versions: ['>=2.8'],
17
- file: ['client.js'],
17
+ file: 'client.js',
18
18
  }, LimitdClient => {
19
19
  shimmer.wrap(LimitdClient.prototype, '_directRequest', wrapRequest)
20
20
  shimmer.wrap(LimitdClient.prototype, '_retriedRequest', wrapRequest)
@@ -1,5 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realSetTimeout = setTimeout
5
+
3
6
  const { getTestSuitePath, DYNAMIC_NAME_RE } = require('../../../dd-trace/src/plugins/util/test')
4
7
  const { channel } = require('../helpers/instrument')
5
8
  const shimmer = require('../../../datadog-shimmer')
@@ -261,6 +264,14 @@ function getFinalStatus ({
261
264
  }) {
262
265
  // Note that intermediate executions DO NOT report a final status tag
263
266
 
267
+ // Intermediate EFD and ATF executions must not carry a final status, regardless of quarantine/disabled state
268
+ const isIntermediateExecution =
269
+ (isEfdRetry && !isLastEfdRetry) ||
270
+ (isAttemptToFix && !isLastAttemptToFix)
271
+ if (isIntermediateExecution) {
272
+ return
273
+ }
274
+
264
275
  // If the test is quarantined or disabled, regardless of its actual execution result or active retry features,
265
276
  // the final status of its last execution should be reported as 'skip'.
266
277
  if (isQuarantined || isDisabled) {
@@ -293,7 +304,7 @@ function getOnTestEndHandler (config) {
293
304
  // This means that tests retried with DI are BREAKPOINT_HIT_GRACE_PERIOD_MS slower at least.
294
305
  if (test._ddShouldWaitForHitProbe || test._retriedTest?._ddShouldWaitForHitProbe) {
295
306
  await new Promise((resolve) => {
296
- setTimeout(() => {
307
+ realSetTimeout(() => {
297
308
  resolve()
298
309
  }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
299
310
  })
@@ -16,16 +16,10 @@ const errorTCPCh = channel('apm:net:tcp:error')
16
16
  const readyCh = channel('apm:net:tcp:ready')
17
17
  const connectionCh = channel('apm:net:tcp:connection')
18
18
 
19
- const names = ['net', 'node:net']
20
-
21
- addHook({ name: names }, (net, version, name) => {
19
+ addHook({ name: 'net' }, (net) => {
22
20
  // explicitly require dns so that net gets an instrumented instance
23
21
  // so that we don't miss the dns calls
24
- if (name === 'net') {
25
- require('dns')
26
- } else {
27
- require('node:dns')
28
- }
22
+ require('node:dns')
29
23
 
30
24
  shimmer.wrap(net.Socket.prototype, 'connect', connect => function () {
31
25
  if (!startICPCh.hasSubscribers || !startTCPCh.hasSubscribers) {
@@ -97,7 +97,7 @@ addHook({ name: 'pino', versions: ['>=5.14.0 <6.8.0'] }, (pino) => {
97
97
  return wrapped
98
98
  })
99
99
 
100
- addHook({ name: 'pino', versions: ['>=6.8.0'], patchDefault: false }, (pino, _1, _2, isIitm) => {
100
+ addHook({ name: 'pino', versions: ['>=6.8.0'], patchDefault: false }, (pino) => {
101
101
  const mixinSym = pino.symbols.mixinSym
102
102
 
103
103
  const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(mixinSym, wrapMixin, pino))
@@ -1,5 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realSetTimeout = setTimeout
5
+
3
6
  const satisfies = require('../../../vendor/dist/semifies')
4
7
 
5
8
  const shimmer = require('../../datadog-shimmer')
@@ -1216,7 +1219,7 @@ addHook({
1216
1219
 
1217
1220
  if (isRumActive) {
1218
1221
  // Give some time RUM to flush data, similar to what we do in selenium
1219
- await new Promise(resolve => setTimeout(resolve, RUM_FLUSH_WAIT_TIME))
1222
+ await new Promise(resolve => realSetTimeout(resolve, RUM_FLUSH_WAIT_TIME))
1220
1223
  const url = page.url()
1221
1224
  if (url) {
1222
1225
  const domain = new URL(url).hostname
@@ -136,11 +136,10 @@ function resolveClientDbConfig (clientConfig, datasourceName, runtimeDbConfig) {
136
136
  /**
137
137
  * @param {unknown} runtime
138
138
  * @param {string} versions
139
- * @param {string} [name]
140
139
  * @param {boolean} [isIitm]
141
140
  * @returns {object}
142
141
  */
143
- const prismaHook = (runtime, versions, name, isIitm) => {
142
+ const prismaHook = (runtime, versions, isIitm) => {
144
143
  /**
145
144
  * @typedef {{ getPrismaClient?: (config: PrismaRuntimeConfig, ...args: unknown[]) => Function }} PrismaRuntime
146
145
  */
@@ -11,6 +11,8 @@ const finishCh = channel('apm:redis:command:finish')
11
11
  const errorCh = channel('apm:redis:command:error')
12
12
 
13
13
  let createClientUrl
14
+ let createClientName
15
+ const instanceInfo = new WeakMap()
14
16
 
15
17
  function wrapAddCommand (addCommand) {
16
18
  return function (command) {
@@ -21,7 +23,7 @@ function wrapAddCommand (addCommand) {
21
23
  const name = command[0]
22
24
  const args = command.slice(1)
23
25
 
24
- const ctx = getStartCtx(this, name, args, this._url)
26
+ const ctx = getStartCtx(this, name, args)
25
27
  return startCh.runStores(ctx, () => {
26
28
  const res = addCommand.apply(this, arguments)
27
29
 
@@ -36,17 +38,16 @@ function wrapCommandQueueClass (cls) {
36
38
  const ret = class RedisCommandQueue extends cls {
37
39
  constructor (...args) {
38
40
  super(...args)
41
+ let url = { host: 'localhost', port: 6379 }
39
42
  if (createClientUrl) {
40
43
  try {
41
44
  const parsed = new URL(createClientUrl)
42
- if (parsed) {
43
- this._url = { host: parsed.hostname, port: Number(parsed.port) || 6379 }
44
- }
45
+ url = { host: parsed.hostname, port: Number(parsed.port) || 6379 }
45
46
  } catch {
46
47
  // ignore
47
48
  }
48
49
  }
49
- this._url = this._url || { host: 'localhost', port: 6379 }
50
+ instanceInfo.set(this, { connectionName: createClientName, url })
50
51
  }
51
52
  }
52
53
  return ret
@@ -55,8 +56,10 @@ function wrapCommandQueueClass (cls) {
55
56
  function wrapCreateClient (request) {
56
57
  return function (opts) {
57
58
  createClientUrl = opts && opts.url
59
+ createClientName = opts && opts.name
58
60
  const ret = request.apply(this, arguments)
59
61
  createClientUrl = undefined
62
+ createClientName = undefined
60
63
  return ret
61
64
  }
62
65
  }
@@ -134,12 +137,15 @@ addHook({ name: 'redis', versions: ['>=0.12 <2.6'] }, redis => {
134
137
  return redis
135
138
  })
136
139
 
137
- function getStartCtx (client, command, args, url = {}) {
140
+ function getStartCtx (client, command, args) {
141
+ const { url, connectionName } = instanceInfo.get(client) || {}
142
+
138
143
  return {
139
144
  db: client.selected_db,
140
145
  command,
141
146
  args,
142
147
  connectionOptions: client.connection_options || client.connection_option || client.connectionOption || url,
148
+ connectionName,
143
149
  }
144
150
  }
145
151
 
@@ -1,5 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realSetTimeout = setTimeout
5
+
3
6
  const shimmer = require('../../datadog-shimmer')
4
7
  const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
5
8
  const { addHook, channel } = require('./helpers/instrument')
@@ -66,7 +69,7 @@ addHook({
66
69
  if (isRumActive) {
67
70
  // We'll have time for RUM to flush the events (there's no callback to know when it's done)
68
71
  await new Promise(resolve => {
69
- setTimeout(() => {
72
+ realSetTimeout(() => {
70
73
  resolve()
71
74
  }, DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS)
72
75
  })
@@ -6,7 +6,7 @@ const {
6
6
  addHook,
7
7
  } = require('./helpers/instrument')
8
8
 
9
- addHook({ name: 'sequelize', versions: ['>=4'], file: ['lib/sequelize.js'] }, Sequelize => {
9
+ addHook({ name: 'sequelize', versions: ['>=4'], file: 'lib/sequelize.js' }, Sequelize => {
10
10
  const startCh = channel('datadog:sequelize:query:start')
11
11
  const finishCh = channel('datadog:sequelize:query:finish')
12
12
 
@@ -2,13 +2,11 @@
2
2
 
3
3
  const shimmer = require('../../datadog-shimmer')
4
4
  const { addHook, channel } = require('./helpers/instrument')
5
- const names = ['url', 'node:url']
6
-
7
5
  const parseFinishedChannel = channel('datadog:url:parse:finish')
8
6
  const urlGetterChannel = channel('datadog:url:getter:finish')
9
7
  const instrumentedGetters = ['host', 'origin', 'hostname']
10
8
 
11
- addHook({ name: names }, function (url) {
9
+ addHook({ name: 'url' }, function (url) {
12
10
  shimmer.wrap(url, 'parse', (parse) => {
13
11
  return function wrappedParse (input) {
14
12
  const parsedValue = parse.apply(this, arguments)
@@ -1,4 +1,8 @@
1
1
  'use strict'
2
+
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realSetTimeout = setTimeout
5
+
2
6
  const path = require('node:path')
3
7
 
4
8
  const shimmer = require('../../datadog-shimmer')
@@ -83,7 +87,7 @@ function getTestCommand () {
83
87
 
84
88
  function waitForHitProbe () {
85
89
  return new Promise(resolve => {
86
- setTimeout(() => {
90
+ realSetTimeout(() => {
87
91
  resolve()
88
92
  }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
89
93
  })
@@ -2,12 +2,10 @@
2
2
 
3
3
  const shimmer = require('../../datadog-shimmer')
4
4
  const { channel, addHook } = require('./helpers/instrument')
5
- const names = ['vm', 'node:vm']
6
-
7
5
  const runScriptStartChannel = channel('datadog:vm:run-script:start')
8
6
  const sourceTextModuleStartChannel = channel('datadog:vm:source-text-module:start')
9
7
 
10
- addHook({ name: names }, function (vm) {
8
+ addHook({ name: 'vm' }, function (vm) {
11
9
  vm.Script = class extends vm.Script {
12
10
  constructor (code) {
13
11
  super(...arguments)
@@ -23,12 +23,13 @@ class BaseAwsSdkPlugin extends ClientPlugin {
23
23
  return id
24
24
  }
25
25
 
26
+ /** @type {import('../../dd-trace/src/config/config-types').ConfigProperties['cloudPayloadTagging']} */
26
27
  get cloudTaggingConfig () {
27
28
  return this._tracerConfig.cloudPayloadTagging
28
29
  }
29
30
 
30
31
  get payloadTaggingRules () {
31
- return this.cloudTaggingConfig.rules.aws?.[this.constructor.id]
32
+ return this.cloudTaggingConfig.rules?.aws?.[this.constructor.id]
32
33
  }
33
34
 
34
35
  constructor (...args) {
@@ -55,7 +56,6 @@ class BaseAwsSdkPlugin extends ClientPlugin {
55
56
 
56
57
  const meta = {
57
58
  'span.kind': 'client',
58
- 'service.name': this.serviceName(),
59
59
  'aws.operation': operation,
60
60
  'aws.region': awsRegion,
61
61
  region: awsRegion,
@@ -69,6 +69,7 @@ class BaseAwsSdkPlugin extends ClientPlugin {
69
69
  const span = this.startSpan(this.operationFromRequest(request), {
70
70
  childOf,
71
71
  meta,
72
+ service: this.serviceName(),
72
73
  integrationName: 'aws-sdk',
73
74
  }, ctx)
74
75
 
@@ -78,7 +79,7 @@ class BaseAwsSdkPlugin extends ClientPlugin {
78
79
  this.requestInject(span, request)
79
80
  })
80
81
 
81
- if (this.constructor.isPayloadReporter && this.cloudTaggingConfig.requestsEnabled) {
82
+ if (this.constructor.isPayloadReporter && this.cloudTaggingConfig.request) {
82
83
  const maxDepth = this.cloudTaggingConfig.maxDepth
83
84
  const requestTags = tagsFromRequest(this.payloadTaggingRules, request.params, { maxDepth })
84
85
  span.addTags(requestTags)
@@ -215,7 +216,7 @@ class BaseAwsSdkPlugin extends ClientPlugin {
215
216
 
216
217
  span.addTags(tags)
217
218
 
218
- if (this.constructor.isPayloadReporter && this.cloudTaggingConfig.responsesEnabled) {
219
+ if (this.constructor.isPayloadReporter && this.cloudTaggingConfig.response) {
219
220
  const maxDepth = this.cloudTaggingConfig.maxDepth
220
221
  const responseBody = this.extractResponseBody(response)
221
222
  const responseTags = tagsFromResponse(this.payloadTaggingRules, responseBody, { maxDepth })
@@ -40,6 +40,7 @@ class DynamoDb extends BaseAwsSdkPlugin {
40
40
 
41
41
  // Also add span type to match serverless convention
42
42
  tags['span.type'] = 'dynamodb'
43
+ tags['db.system'] = 'aws.dynamodb'
43
44
 
44
45
  return tags
45
46
  }
@@ -12,6 +12,7 @@ class EventBridge extends BaseAwsSdkPlugin {
12
12
  return {
13
13
  'resource.name': operation ? `${operation} ${params.source}` : params.source,
14
14
  'aws.eventbridge.source': `${params.source}`,
15
+ 'messaging.system': 'aws_eventbridge',
15
16
  rulename: `${rulename}`,
16
17
  }
17
18
  }
@@ -68,6 +68,7 @@ class Kinesis extends BaseAwsSdkPlugin {
68
68
  return {
69
69
  'resource.name': `${operation} ${params.StreamName}`,
70
70
  'aws.kinesis.stream_name': params.StreamName,
71
+ 'messaging.system': 'aws_kinesis',
71
72
  streamname: params.StreamName,
72
73
  }
73
74
  }
@@ -11,6 +11,7 @@ class Redshift extends BaseAwsSdkPlugin {
11
11
  return {
12
12
  'resource.name': `${operation} ${params.ClusterIdentifier}`,
13
13
  'aws.redshift.cluster_identifier': params.ClusterIdentifier,
14
+ 'db.system': 'aws.redshift',
14
15
  clusteridentifier: params.ClusterIdentifier,
15
16
  }
16
17
  }
@@ -24,6 +24,7 @@ class Sns extends BaseAwsSdkPlugin {
24
24
  return {
25
25
  'resource.name': `${operation} ${params.TopicArn || response.data.TopicArn}`,
26
26
  'aws.sns.topic_arn': TopicArn,
27
+ 'messaging.system': 'aws.sns',
27
28
  topicname: topicName,
28
29
  }
29
30
 
@@ -100,6 +100,7 @@ class Sqs extends BaseAwsSdkPlugin {
100
100
  const tags = {
101
101
  'resource.name': `${operation} ${params.QueueName || params.QueueUrl}`,
102
102
  'aws.sqs.queue_name': params.QueueName || params.QueueUrl,
103
+ 'messaging.system': 'aws_sqs',
103
104
  queuename: queueName,
104
105
  }
105
106
 
@@ -1,5 +1,9 @@
1
1
  'use strict'
2
2
 
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realDateNow = Date.now.bind(Date)
5
+ const realSetTimeout = setTimeout
6
+
3
7
  const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
4
8
  const { storage } = require('../../datadog-core')
5
9
  const { getEnvironmentVariable, getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
@@ -33,6 +37,7 @@ const {
33
37
  TEST_SOURCE_FILE,
34
38
  TEST_SOURCE_START,
35
39
  TEST_STATUS,
40
+ TEST_FINAL_STATUS,
36
41
  } = require('../../dd-trace/src/plugins/util/test')
37
42
  const { RESOURCE_NAME } = require('../../../ext/tags')
38
43
  const { COMPONENT, ERROR_MESSAGE } = require('../../dd-trace/src/constants')
@@ -229,7 +234,7 @@ class CucumberPlugin extends CiPlugin {
229
234
  // Time we give the breakpoint to be hit
230
235
  if (promises && this.runningTestProbe) {
231
236
  promises.hitBreakpointPromise = new Promise((resolve) => {
232
- setTimeout(resolve, BREAKPOINT_HIT_GRACE_PERIOD_MS)
237
+ realSetTimeout(resolve, BREAKPOINT_HIT_GRACE_PERIOD_MS)
233
238
  })
234
239
  }
235
240
 
@@ -252,8 +257,8 @@ class CucumberPlugin extends CiPlugin {
252
257
  const { file, line, stackIndex } = probeInformation
253
258
  this.runningTestProbe = { file, line }
254
259
  this.testErrorStackIndex = stackIndex
255
- const waitUntil = Date.now() + BREAKPOINT_SET_GRACE_PERIOD_MS
256
- while (Date.now() < waitUntil) {
260
+ const waitUntil = realDateNow() + BREAKPOINT_SET_GRACE_PERIOD_MS
261
+ while (realDateNow() < waitUntil) {
257
262
  // TODO: To avoid a race condition, we should wait until `probeInformation.setProbePromise` has resolved.
258
263
  // However, Cucumber doesn't have a mechanism for waiting asyncrounously here, so for now, we'll have to
259
264
  // fall back to a fixed syncronous delay.
@@ -303,11 +308,16 @@ class CucumberPlugin extends CiPlugin {
303
308
  isDisabled,
304
309
  isQuarantined,
305
310
  isModified,
311
+ finalStatus,
306
312
  }) => {
307
313
  const statusTag = isStep ? 'step.status' : TEST_STATUS
308
314
 
309
315
  span.setTag(statusTag, status)
310
316
 
317
+ if (finalStatus) {
318
+ span.setTag(TEST_FINAL_STATUS, finalStatus)
319
+ }
320
+
311
321
  if (isNew) {
312
322
  span.setTag(TEST_IS_NEW, 'true')
313
323
  if (isEfdRetry) {