dd-trace 5.110.0 → 5.111.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 (115) hide show
  1. package/README.md +13 -8
  2. package/ci/init.js +21 -2
  3. package/ci/vitest-no-worker-init-setup.mjs +430 -0
  4. package/ext/tags.js +2 -0
  5. package/index.d.ts +13 -0
  6. package/initialize.mjs +5 -6
  7. package/loader-hook.mjs +76 -55
  8. package/package.json +9 -9
  9. package/packages/datadog-instrumentations/src/fs.js +8 -6
  10. package/packages/datadog-instrumentations/src/graphql.js +26 -495
  11. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +201 -0
  12. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  13. package/packages/datadog-instrumentations/src/mongoose.js +14 -2
  14. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1293 -0
  15. package/packages/datadog-instrumentations/src/vitest-main.js +1567 -0
  16. package/packages/datadog-instrumentations/src/vitest-util.js +249 -0
  17. package/packages/datadog-instrumentations/src/vitest-worker.js +753 -0
  18. package/packages/datadog-instrumentations/src/vitest.js +11 -1855
  19. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/client.js +2 -2
  20. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +18 -10
  21. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +47 -11
  22. package/packages/datadog-plugin-cucumber/src/index.js +1 -1
  23. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +10 -4
  24. package/packages/datadog-plugin-cypress/src/support.js +45 -1
  25. package/packages/datadog-plugin-express/src/code_origin.js +1 -1
  26. package/packages/datadog-plugin-fastify/src/code_origin.js +1 -1
  27. package/packages/datadog-plugin-graphql/src/execute.js +627 -11
  28. package/packages/datadog-plugin-graphql/src/index.js +20 -8
  29. package/packages/datadog-plugin-graphql/src/parse.js +24 -4
  30. package/packages/datadog-plugin-graphql/src/validate.js +16 -5
  31. package/packages/datadog-plugin-http/src/index.js +6 -8
  32. package/packages/datadog-plugin-jest/src/index.js +1 -1
  33. package/packages/datadog-plugin-mocha/src/index.js +1 -1
  34. package/packages/datadog-plugin-openai/src/services.js +2 -2
  35. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  36. package/packages/datadog-plugin-vitest/src/index.js +69 -63
  37. package/packages/datadog-shimmer/src/shimmer.js +37 -16
  38. package/packages/dd-trace/src/aiguard/sdk.js +2 -2
  39. package/packages/dd-trace/src/appsec/api_security/sampler.js +3 -3
  40. package/packages/dd-trace/src/appsec/channels.js +3 -1
  41. package/packages/dd-trace/src/appsec/downstream_requests.js +4 -4
  42. package/packages/dd-trace/src/appsec/graphql.js +5 -5
  43. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +26 -19
  44. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
  45. package/packages/dd-trace/src/appsec/iast/telemetry/index.js +2 -1
  46. package/packages/dd-trace/src/appsec/index.js +10 -1
  47. package/packages/dd-trace/src/appsec/lambda.js +135 -0
  48. package/packages/dd-trace/src/appsec/reporter.js +49 -10
  49. package/packages/dd-trace/src/appsec/telemetry/index.js +1 -1
  50. package/packages/dd-trace/src/appsec/waf/index.js +16 -4
  51. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -4
  52. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +21 -6
  53. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +2 -2
  54. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  55. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  56. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +3 -2
  57. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
  58. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +55 -13
  59. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -2
  60. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +17 -0
  61. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +47 -26
  62. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +2 -2
  63. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +64 -53
  64. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +3 -3
  65. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +23 -5
  66. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +128 -0
  67. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +287 -0
  68. package/packages/dd-trace/src/config/defaults.js +3 -2
  69. package/packages/dd-trace/src/config/generated-config-types.d.ts +61 -57
  70. package/packages/dd-trace/src/config/helper.js +1 -0
  71. package/packages/dd-trace/src/config/index.js +35 -22
  72. package/packages/dd-trace/src/config/major-overrides.js +4 -2
  73. package/packages/dd-trace/src/config/remote_config.js +1 -1
  74. package/packages/dd-trace/src/config/supported-configurations.json +90 -56
  75. package/packages/dd-trace/src/constants.js +7 -0
  76. package/packages/dd-trace/src/datastreams/processor.js +11 -3
  77. package/packages/dd-trace/src/exporters/agent/index.js +1 -1
  78. package/packages/dd-trace/src/exporters/agentless/writer.js +4 -4
  79. package/packages/dd-trace/src/llmobs/index.js +1 -1
  80. package/packages/dd-trace/src/llmobs/plugins/base.js +4 -4
  81. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  82. package/packages/dd-trace/src/llmobs/sdk.js +3 -3
  83. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  84. package/packages/dd-trace/src/llmobs/tagger.js +3 -3
  85. package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
  86. package/packages/dd-trace/src/opentelemetry/metrics/index.js +54 -5
  87. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +40 -0
  88. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +169 -0
  89. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +38 -39
  90. package/packages/dd-trace/src/opentelemetry/trace/index.js +4 -0
  91. package/packages/dd-trace/src/opentelemetry/tracer_provider.js +1 -1
  92. package/packages/dd-trace/src/opentracing/tracer.js +6 -1
  93. package/packages/dd-trace/src/plugin_manager.js +7 -7
  94. package/packages/dd-trace/src/plugins/ci_plugin.js +12 -3
  95. package/packages/dd-trace/src/plugins/util/llm.js +6 -1
  96. package/packages/dd-trace/src/plugins/util/test.js +11 -9
  97. package/packages/dd-trace/src/profiling/exporter_cli.js +2 -2
  98. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +3 -3
  99. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  100. package/packages/dd-trace/src/proxy.js +8 -8
  101. package/packages/dd-trace/src/span_processor.js +5 -6
  102. package/packages/dd-trace/src/span_stats.js +96 -78
  103. package/packages/dd-trace/src/startup-log.js +2 -1
  104. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  105. package/packages/dd-trace/src/telemetry/endpoints.js +6 -4
  106. package/packages/dd-trace/src/telemetry/index.js +2 -2
  107. package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
  108. package/packages/dd-trace/src/telemetry/send-data.js +8 -8
  109. package/packages/dd-trace/src/telemetry/session-propagation.js +1 -1
  110. package/packages/dd-trace/src/telemetry/telemetry.js +9 -9
  111. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  112. package/vendor/dist/protobufjs/index.js +1 -1
  113. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  114. package/vendor/dist/shell-quote/index.js +1 -1
  115. package/packages/datadog-plugin-graphql/src/resolve.js +0 -170
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const ClientPlugin = require('../../dd-trace/src/plugins/client')
4
- const { addOpMeta, unwrapDurableError } = require('./util')
4
+ const { addOpMeta, getStepDataForNext, unwrapDurableError } = require('./util')
5
5
 
6
6
  class AwsDurableExecutionSdkJsClientPlugin extends ClientPlugin {
7
7
  static id = 'aws-durable-execution-sdk-js'
@@ -29,7 +29,7 @@ class AwsDurableExecutionSdkJsClientPlugin extends ClientPlugin {
29
29
  if (operationName) {
30
30
  meta['aws.durable.operation_name'] = operationName
31
31
  }
32
- addOpMeta(meta, ctx.self)
32
+ addOpMeta(meta, getStepDataForNext(ctx.self))
33
33
 
34
34
  this.startSpan(this.operationName(), {
35
35
  resource: operationName,
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { storage } = require('../../datadog-core')
4
4
  const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
5
- const { addOpMeta, unwrapDurableError } = require('./util')
5
+ const { addOpMeta, getOperationAttempt, getStepDataForNext, unwrapDurableError } = require('./util')
6
6
 
7
7
  // Span names whose direct children must keep the default resource.
8
8
  // These can have very high cardinality which is undesireable in the resource.
@@ -41,12 +41,18 @@ class BaseContextPlugin extends TracingPlugin {
41
41
  if (operationName) {
42
42
  meta['aws.durable.operation_name'] = operationName
43
43
  }
44
- addOpMeta(meta, ctx.self)
44
+ const stepInfo = getStepDataForNext(ctx.self)
45
+ addOpMeta(meta, stepInfo)
46
+
47
+ const metrics = this.constructor.retryable
48
+ ? { 'aws.durable.operation_attempt': getOperationAttempt(stepInfo.stepData) }
49
+ : undefined
45
50
 
46
51
  this.startSpan(spanName, {
47
52
  resource,
48
53
  kind: this.constructor.kind,
49
54
  meta,
55
+ metrics,
50
56
  }, ctx)
51
57
 
52
58
  return ctx.currentStore
@@ -71,11 +77,12 @@ class BaseContextPlugin extends TracingPlugin {
71
77
  }
72
78
  }
73
79
 
74
- function makeContextPlugin (method, spanName) {
80
+ function makeContextPlugin (method, spanName, { retryable }) {
75
81
  return class extends BaseContextPlugin {
76
82
  static prefix = `tracing:orchestrion:@aws/durable-execution-sdk-js:DurableContextImpl_${method}`
77
83
  static settleChannel = `apm:aws-durable-execution-sdk-js:${method}:settle`
78
84
  static spanName = spanName
85
+ static retryable = retryable
79
86
  }
80
87
  }
81
88
 
@@ -83,6 +90,7 @@ class RunInChildContextPlugin extends BaseContextPlugin {
83
90
  static prefix = 'tracing:orchestrion:@aws/durable-execution-sdk-js:DurableContextImpl_runInChildContext'
84
91
  static settleChannel = 'apm:aws-durable-execution-sdk-js:runInChildContext:settle'
85
92
  static spanName = 'aws.durable.child_context'
93
+ static retryable = false
86
94
 
87
95
  bindStart (ctx) {
88
96
  if (SUPPRESSED_CHILD_CONTEXT_SUBTYPES.has(getRunInChildContextSubType(ctx))) {
@@ -103,12 +111,12 @@ function getRunInChildContextSubType (ctx) {
103
111
  }
104
112
 
105
113
  module.exports = {
106
- step: makeContextPlugin('step', 'aws.durable.step'),
107
- wait: makeContextPlugin('wait', 'aws.durable.wait'),
108
- waitForCondition: makeContextPlugin('waitForCondition', 'aws.durable.wait_for_condition'),
109
- waitForCallback: makeContextPlugin('waitForCallback', 'aws.durable.wait_for_callback'),
110
- createCallback: makeContextPlugin('createCallback', 'aws.durable.create_callback'),
111
- map: makeContextPlugin('map', 'aws.durable.map'),
112
- parallel: makeContextPlugin('parallel', 'aws.durable.parallel'),
114
+ step: makeContextPlugin('step', 'aws.durable.step', { retryable: true }),
115
+ wait: makeContextPlugin('wait', 'aws.durable.wait', { retryable: false }),
116
+ waitForCondition: makeContextPlugin('waitForCondition', 'aws.durable.wait_for_condition', { retryable: true }),
117
+ waitForCallback: makeContextPlugin('waitForCallback', 'aws.durable.wait_for_callback', { retryable: false }),
118
+ createCallback: makeContextPlugin('createCallback', 'aws.durable.create_callback', { retryable: false }),
119
+ map: makeContextPlugin('map', 'aws.durable.map', { retryable: false }),
120
+ parallel: makeContextPlugin('parallel', 'aws.durable.parallel', { retryable: false }),
113
121
  runInChildContext: RunInChildContextPlugin,
114
122
  }
@@ -2,27 +2,63 @@
2
2
 
3
3
  const { createHash } = require('node:crypto')
4
4
 
5
+ // A checkpoint in one of these terminal states means the operation is served from the checkpoint
6
+ // on a replay rather than executed: the SDK reloads a SUCCEEDED result or re-raises a FAILED error
7
+ // without running the user function. Both also carry the 1-indexed attempt that reached the terminal
8
+ // state, so both need the same normalization to agree with the 0-indexed live run.
9
+ const REPLAYED_STATUSES = new Set(['SUCCEEDED', 'FAILED'])
10
+
5
11
  /**
6
- * Populates the replay and operation_id tags for the op the DurableContextImpl is about to
7
- * run, deriving both from a single `getNextStepId()` call. `aws.durable.replayed` is always
8
- * set ('true' when the next stepId already has a SUCCEEDED checkpoint entry, i.e. the op will
9
- * be served from the SDK's checkpoint). `aws.durable.operation_id` — the 16-hex-char MD5 of
10
- * the stepId, mirroring the SDK's internal calculation — is only added when a stepId exists.
11
- * @param {Record<string, string>} meta - The span meta/tags object to populate.
12
+ * Resolves the SDK's next stepId and its checkpoint entry in a single pass, so one span start can
13
+ * feed both addOpMeta and getOperationAttempt without traversing the SDK internals twice. `stepData`
14
+ * is undefined when there is no next stepId, or no checkpoint entry exists for it yet.
12
15
  * @param {object} [ctxImpl] - The DurableContextImpl about to run the op.
13
- * @returns {void}
16
+ * @returns {{ stepId: string | undefined, stepData: object | undefined }}
14
17
  */
15
- function addOpMeta (meta, ctxImpl) {
18
+ function getStepDataForNext (ctxImpl) {
16
19
  const stepId = ctxImpl?.getNextStepId?.()
20
+ const stepData = stepId ? ctxImpl?._executionContext?.getStepData?.(stepId) : undefined
21
+ return { stepId, stepData }
22
+ }
23
+
24
+ /**
25
+ * Populates the replay and operation_id tags from a pre-resolved step lookup (see
26
+ * getStepDataForNext). `aws.durable.replayed` is always set ('true' when the next stepId already
27
+ * has a terminal checkpoint entry — SUCCEEDED or FAILED — i.e. the op will be served from the SDK's
28
+ * checkpoint rather than executed). `aws.durable.operation_id` — the 16-hex-char MD5 of the stepId,
29
+ * mirroring the SDK's internal calculation — is only added when a stepId exists.
30
+ * @param {Record<string, string>} meta - The span meta/tags object to populate.
31
+ * @param {{ stepId?: string, stepData?: object }} stepInfo - Resolved next stepId and checkpoint entry.
32
+ * @returns {void}
33
+ */
34
+ function addOpMeta (meta, { stepId, stepData }) {
17
35
  if (!stepId) {
18
36
  meta['aws.durable.replayed'] = 'false'
19
37
  return
20
38
  }
21
- const stepData = ctxImpl?._executionContext?.getStepData?.(stepId)
22
- meta['aws.durable.replayed'] = String(stepData?.Status === 'SUCCEEDED')
39
+ meta['aws.durable.replayed'] = String(REPLAYED_STATUSES.has(stepData?.Status))
23
40
  meta['aws.durable.operation_id'] = createHash('md5').update(stepId).digest('hex').slice(0, 16)
24
41
  }
25
42
 
43
+ /**
44
+ * Returns the 0-indexed attempt number for the op (0 original, 1 first retry, …) from a pre-resolved
45
+ * checkpoint entry (see getStepDataForNext), defaulting to 0 before any checkpoint exists.
46
+ *
47
+ * StepDetails.Attempt is indexed differently depending on checkpoint status: on a pending/retry
48
+ * checkpoint it's the count of prior failed attempts (already 0-indexed), but on a terminal
49
+ * checkpoint read on replay (SUCCEEDED or FAILED) it's the 1-indexed attempt that reached that
50
+ * state. We subtract 1 in the terminal case so a replay agrees with the original run, flooring at
51
+ * 0 since the 1-indexing is observed server behavior, not an SDK guarantee.
52
+ *
53
+ * @param {object} [stepData] - The checkpoint entry for the next stepId.
54
+ * @returns {number}
55
+ */
56
+ function getOperationAttempt (stepData) {
57
+ const attempt = stepData?.StepDetails?.Attempt
58
+ if (!Number.isFinite(attempt)) return 0
59
+ return REPLAYED_STATUSES.has(stepData.Status) ? Math.max(0, attempt - 1) : attempt
60
+ }
61
+
26
62
  /**
27
63
  * The SDK wraps user errors in typed classes (StepError, ChildContextError, etc.); we follow the
28
64
  * `.cause` chain to recover the user's original Error. SDK wrappers expose a string `errorType`
@@ -40,4 +76,4 @@ function unwrapDurableError (ctx) {
40
76
  return err
41
77
  }
42
78
 
43
- module.exports = { addOpMeta, unwrapDurableError }
79
+ module.exports = { addOpMeta, getOperationAttempt, getStepDataForNext, unwrapDurableError }
@@ -130,7 +130,7 @@ class CucumberPlugin extends CiPlugin {
130
130
  finishAllTraceSpans(this.testSessionSpan)
131
131
  this.telemetry.count(TELEMETRY_TEST_SESSION, {
132
132
  provider: this.ciProviderName,
133
- autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
133
+ autoInjected: !!this._tracerConfig.testOptimization.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
134
134
  })
135
135
 
136
136
  this.libraryConfig = null
@@ -390,6 +390,7 @@ class CypressPlugin {
390
390
  earlyFlakeDetectionFaultyThreshold = 0
391
391
  testsToSkip = []
392
392
  skippedTests = []
393
+ skippedTestIds = new Set()
393
394
  skippableTestsCoverage = {}
394
395
  testSessionCoverageMap = createCoverageMap()
395
396
  hasForcedToRunSuites = false
@@ -473,6 +474,7 @@ class CypressPlugin {
473
474
  this.earlyFlakeDetectionFaultyThreshold = 0
474
475
  this.testsToSkip = []
475
476
  this.skippedTests = []
477
+ this.skippedTestIds = new Set()
476
478
  this.skippableTestsCoverage = {}
477
479
  this.testSessionCoverageMap = createCoverageMap()
478
480
  this.hasForcedToRunSuites = false
@@ -637,7 +639,7 @@ class CypressPlugin {
637
639
 
638
640
  this.isTestIsolationEnabled = getIsTestIsolationEnabled(cypressConfig)
639
641
 
640
- this.rumFlushWaitMillis = getConfig().DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS
642
+ this.rumFlushWaitMillis = getConfig().testOptimization.DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS
641
643
 
642
644
  if (!this.isTestIsolationEnabled) {
643
645
  log.warn('Test isolation is disabled, retries will not be enabled')
@@ -1148,7 +1150,7 @@ class CypressPlugin {
1148
1150
  this.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'session')
1149
1151
  incrementCountMetric(TELEMETRY_TEST_SESSION, {
1150
1152
  provider: this.ciProviderName,
1151
- autoInjected: !!getConfig().DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
1153
+ autoInjected: !!getConfig().testOptimization.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
1152
1154
  })
1153
1155
 
1154
1156
  finishAllTraceSpans(this.testSessionSpan)
@@ -1386,7 +1388,7 @@ class CypressPlugin {
1386
1388
  return suitePayload
1387
1389
  },
1388
1390
  'dd:beforeEach': (test) => {
1389
- const { testName, testSuite, isEfdRetry, efdRetryIndex } = test
1391
+ const { testId, testName, testSuite, isEfdRetry, efdRetryIndex } = test
1390
1392
  if (isEfdRetry && this.shouldSkipEfdRetry(testSuite, testName, efdRetryIndex)) {
1391
1393
  return { shouldSkip: true, shouldDiscard: true }
1392
1394
  }
@@ -1398,7 +1400,11 @@ class CypressPlugin {
1398
1400
  const { isAttemptToFix, isDisabled, isQuarantined } = this.getTestProperties(testSuite, testName)
1399
1401
  // skip test
1400
1402
  if (shouldSkip && !isUnskippable) {
1401
- this.skippedTests.push(test)
1403
+ const skippedTestId = `${testSuite}:${testId || testName}`
1404
+ if (!this.skippedTestIds.has(skippedTestId)) {
1405
+ this.skippedTestIds.add(skippedTestId)
1406
+ this.skippedTests.push(test)
1407
+ }
1402
1408
  this.isTestsSkipped = true
1403
1409
  return { shouldSkip: true }
1404
1410
  }
@@ -13,6 +13,8 @@ let testManagementTests = {}
13
13
  let isImpactedTestsEnabled = false
14
14
  let isModifiedTest = false
15
15
  let isTestIsolationEnabled = false
16
+ let hasWarnedMissingBeforeEachTaskResult = false
17
+ let hasWarnedMissingBeforeEachRetryResult = false
16
18
  // Array of test names that have been retried and the reason
17
19
  const retryReasonsByTestName = new Map()
18
20
  // Track test errors suppressed by test management so we can still report them to Datadog.
@@ -86,6 +88,47 @@ function getTestProperties (testName) {
86
88
  return { isAttemptToFix, isDisabled, isQuarantined }
87
89
  }
88
90
 
91
+ /**
92
+ * @param {string} message
93
+ * @returns {void}
94
+ */
95
+ function warnMissingBeforeEachTaskResult (message) {
96
+ // eslint-disable-next-line no-console
97
+ console.warn(message)
98
+ }
99
+
100
+ /**
101
+ * @param {object} test
102
+ * @returns {Cypress.Chainable<{ traceId?: string, shouldSkip?: boolean, shouldDiscard?: boolean }>}
103
+ */
104
+ function runBeforeEachTask (test) {
105
+ return cy.task('dd:beforeEach', test).then((taskResult) => {
106
+ if (taskResult !== undefined && taskResult !== null) {
107
+ return taskResult
108
+ }
109
+
110
+ if (!hasWarnedMissingBeforeEachTaskResult) {
111
+ hasWarnedMissingBeforeEachTaskResult = true
112
+ warnMissingBeforeEachTaskResult('Datadog Cypress dd:beforeEach task returned no result. Retrying once.')
113
+ }
114
+
115
+ return cy.task('dd:beforeEach', test).then((retryTaskResult) => {
116
+ if (retryTaskResult !== undefined && retryTaskResult !== null) {
117
+ return retryTaskResult
118
+ }
119
+
120
+ if (!hasWarnedMissingBeforeEachRetryResult) {
121
+ hasWarnedMissingBeforeEachRetryResult = true
122
+ warnMissingBeforeEachTaskResult(
123
+ 'Datadog Cypress dd:beforeEach task returned no result after retry. Continuing with an empty task result.'
124
+ )
125
+ }
126
+
127
+ return {}
128
+ })
129
+ })
130
+ }
131
+
89
132
  // Catch test failures for quarantined tests and suppress them
90
133
  // By not re-throwing the error, Cypress marks the test as passed
91
134
  // This allows quarantined tests to run but not affect the exit code
@@ -263,7 +306,8 @@ beforeEach(function () {
263
306
  originalWindow = win
264
307
  })
265
308
 
266
- cy.task('dd:beforeEach', {
309
+ runBeforeEachTask({
310
+ testId: currentTest.id,
267
311
  testName,
268
312
  testSuite: Cypress.mocha.getRootSuite().file,
269
313
  isEfdRetry: Cypress.mocha.getRunner().suite.ctx.currentTest._ddIsEfdRetry,
@@ -31,7 +31,7 @@ class ExpressCodeOriginForSpansPlugin extends Plugin {
31
31
  layerTags.set(layer, entryTags(topOfStackFunc))
32
32
  }
33
33
 
34
- if (this._tracerConfig.remoteConfig?.enabled) {
34
+ if (this._tracerConfig.remoteConfig.DD_REMOTE_CONFIGURATION_ENABLED) {
35
35
  // When RC is enabled, use manual subscriptions (always pre-compute)
36
36
  // This allows tags to be computed even when CO is disabled, so runtime enabling works
37
37
  dc.channel('apm:express:route:added').subscribe(handleRouteAdded)
@@ -20,7 +20,7 @@ class FastifyCodeOriginForSpansPlugin extends Plugin {
20
20
  web.getContext(req)?.span?.addTags(tags)
21
21
  })
22
22
 
23
- if (this._tracerConfig.remoteConfig?.enabled) {
23
+ if (this._tracerConfig.remoteConfig.DD_REMOTE_CONFIGURATION_ENABLED) {
24
24
  // When RC is enabled, use manual subscription (always pre-computes)
25
25
  // This allows tags to be computed even when CO is disabled, so runtime enabling works
26
26
  dc.channel('apm:fastify:route:added').subscribe(handleRouteAdded)