dd-trace 5.35.0 → 5.36.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 (84) hide show
  1. package/index.d.ts +3 -7
  2. package/package.json +4 -4
  3. package/packages/datadog-core/index.js +1 -1
  4. package/packages/datadog-core/src/storage.js +76 -31
  5. package/packages/datadog-instrumentations/src/jest.js +3 -7
  6. package/packages/datadog-plugin-aerospike/src/index.js +1 -1
  7. package/packages/datadog-plugin-apollo/src/gateway/fetch.js +1 -1
  8. package/packages/datadog-plugin-apollo/src/gateway/index.js +1 -1
  9. package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -1
  10. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -3
  11. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -4
  12. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -2
  13. package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
  14. package/packages/datadog-plugin-couchbase/src/index.js +2 -2
  15. package/packages/datadog-plugin-cucumber/src/index.js +11 -11
  16. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +6 -1
  17. package/packages/datadog-plugin-cypress/src/support.js +36 -29
  18. package/packages/datadog-plugin-grpc/src/client.js +1 -1
  19. package/packages/datadog-plugin-grpc/src/server.js +1 -1
  20. package/packages/datadog-plugin-hapi/src/index.js +1 -1
  21. package/packages/datadog-plugin-http/src/client.js +1 -1
  22. package/packages/datadog-plugin-http/src/server.js +1 -1
  23. package/packages/datadog-plugin-http2/src/client.js +3 -3
  24. package/packages/datadog-plugin-http2/src/server.js +1 -1
  25. package/packages/datadog-plugin-jest/src/index.js +6 -11
  26. package/packages/datadog-plugin-langchain/src/tracing.js +1 -1
  27. package/packages/datadog-plugin-mariadb/src/index.js +3 -3
  28. package/packages/datadog-plugin-mocha/src/index.js +13 -13
  29. package/packages/datadog-plugin-next/src/index.js +4 -4
  30. package/packages/datadog-plugin-openai/src/tracing.js +1 -1
  31. package/packages/datadog-plugin-playwright/src/index.js +4 -4
  32. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  33. package/packages/datadog-plugin-router/src/index.js +2 -2
  34. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  35. package/packages/datadog-plugin-vitest/src/index.js +11 -11
  36. package/packages/dd-trace/src/appsec/graphql.js +6 -6
  37. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +1 -1
  38. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +6 -6
  39. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +2 -2
  40. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +5 -5
  41. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +2 -2
  42. package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +2 -2
  43. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +2 -2
  44. package/packages/dd-trace/src/appsec/iast/index.js +2 -2
  45. package/packages/dd-trace/src/appsec/iast/taint-tracking/constants.js +6 -0
  46. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +8 -8
  47. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +1 -1
  48. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +65 -0
  49. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +14 -5
  50. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +80 -2
  51. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
  52. package/packages/dd-trace/src/appsec/index.js +4 -4
  53. package/packages/dd-trace/src/appsec/rasp/command_injection.js +1 -1
  54. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +5 -5
  55. package/packages/dd-trace/src/appsec/rasp/lfi.js +1 -1
  56. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +2 -2
  57. package/packages/dd-trace/src/appsec/rasp/ssrf.js +1 -1
  58. package/packages/dd-trace/src/appsec/reporter.js +3 -3
  59. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  60. package/packages/dd-trace/src/appsec/waf/index.js +1 -1
  61. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +2 -0
  62. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +17 -10
  63. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +3 -3
  64. package/packages/dd-trace/src/config.js +2 -0
  65. package/packages/dd-trace/src/data_streams_context.js +2 -2
  66. package/packages/dd-trace/src/exporters/common/agents.js +1 -1
  67. package/packages/dd-trace/src/exporters/common/request.js +3 -3
  68. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +1 -1
  69. package/packages/dd-trace/src/log/writer.js +3 -3
  70. package/packages/dd-trace/src/noop/span.js +1 -1
  71. package/packages/dd-trace/src/opentracing/propagation/text_map.js +5 -4
  72. package/packages/dd-trace/src/opentracing/span.js +1 -1
  73. package/packages/dd-trace/src/plugin_manager.js +3 -1
  74. package/packages/dd-trace/src/plugins/apollo.js +1 -1
  75. package/packages/dd-trace/src/plugins/ci_plugin.js +35 -1
  76. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  77. package/packages/dd-trace/src/plugins/plugin.js +8 -8
  78. package/packages/dd-trace/src/plugins/tracing.js +3 -3
  79. package/packages/dd-trace/src/plugins/util/git.js +3 -3
  80. package/packages/dd-trace/src/plugins/util/test.js +5 -1
  81. package/packages/dd-trace/src/profiling/exporters/agent.js +3 -3
  82. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  83. package/packages/dd-trace/src/scope.js +5 -5
  84. package/packages/dd-trace/src/tracer.js +0 -14
package/index.d.ts CHANGED
@@ -85,10 +85,6 @@ interface Tracer extends opentracing.Tracer {
85
85
  * span will finish when that callback is called.
86
86
  * * The function doesn't accept a callback and doesn't return a promise, in
87
87
  * which case the span will finish at the end of the function execution.
88
- *
89
- * If the `orphanable` option is set to false, the function will not be traced
90
- * unless there is already an active span or `childOf` option. Note that this
91
- * option is deprecated and has been removed in version 4.0.
92
88
  */
93
89
  trace<T> (name: string, fn: (span: tracer.Span) => T): T;
94
90
  trace<T> (name: string, fn: (span: tracer.Span, done: (error?: Error) => void) => T): T;
@@ -659,13 +655,13 @@ declare namespace tracer {
659
655
  * * 'anonymous': will hash user IDs and user logins before collecting them
660
656
  * * 'anon': alias for 'anonymous'
661
657
  * * 'safe': deprecated alias for 'anonymous'
662
- *
658
+ *
663
659
  * * 'identification': will collect user IDs and logins without redaction
664
660
  * * 'ident': alias for 'identification'
665
661
  * * 'extended': deprecated alias for 'identification'
666
- *
662
+ *
667
663
  * * 'disabled': will not collect user IDs and logins
668
- *
664
+ *
669
665
  * Unknown values will be considered as 'disabled'
670
666
  * @default 'identification'
671
667
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.35.0",
3
+ "version": "5.36.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -13,7 +13,7 @@
13
13
  "type:doc": "cd docs && yarn && yarn build",
14
14
  "type:test": "cd docs && yarn && yarn test",
15
15
  "lint": "node scripts/check_licenses.js && eslint . && yarn audit",
16
- "lint-fix": "node scripts/check_licenses.js && eslint . --fix && yarn audit",
16
+ "lint:fix": "node scripts/check_licenses.js && eslint . --fix && yarn audit",
17
17
  "release:proposal": "node scripts/release/proposal",
18
18
  "services": "node ./scripts/install_plugin_modules && node packages/dd-trace/test/setup/services",
19
19
  "test": "SERVICES=* yarn services && mocha --expose-gc 'packages/dd-trace/test/setup/node.js' 'packages/*/test/**/*.spec.js'",
@@ -83,7 +83,7 @@
83
83
  "dependencies": {
84
84
  "@datadog/libdatadog": "^0.4.0",
85
85
  "@datadog/native-appsec": "8.4.0",
86
- "@datadog/native-iast-rewriter": "2.6.1",
86
+ "@datadog/native-iast-rewriter": "2.8.0",
87
87
  "@datadog/native-iast-taint-tracking": "3.2.0",
88
88
  "@datadog/native-metrics": "^3.1.0",
89
89
  "@datadog/pprof": "5.5.1",
@@ -117,7 +117,7 @@
117
117
  "devDependencies": {
118
118
  "@apollo/server": "^4.11.0",
119
119
  "@eslint/eslintrc": "^3.1.0",
120
- "@eslint/js": "^9.11.1",
120
+ "@eslint/js": "^8.57.1",
121
121
  "@msgpack/msgpack": "^3.0.0-beta3",
122
122
  "@stylistic/eslint-plugin-js": "^2.8.0",
123
123
  "@types/node": "^16.0.0",
@@ -1,5 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const storage = require('./src/storage')
3
+ const { storage } = require('./src/storage')
4
4
 
5
5
  module.exports = { storage }
@@ -2,66 +2,111 @@
2
2
 
3
3
  const { AsyncLocalStorage } = require('async_hooks')
4
4
 
5
- class DatadogStorage {
6
- constructor () {
7
- this._storage = new AsyncLocalStorage()
8
- }
9
-
10
- disable () {
11
- this._storage.disable()
12
- }
13
-
5
+ /**
6
+ * This is exactly the same as AsyncLocalStorage, with the exception that it
7
+ * uses a WeakMap to store the store object. This is because ALS stores the
8
+ * store object as a property of the resource object, which causes all sorts
9
+ * of problems with logging and memory. We substitute the `store` object with
10
+ * a "handle" object, which is used as a key in a WeakMap, where the values
11
+ * are the real store objects.
12
+ *
13
+ * @template T
14
+ */
15
+ class DatadogStorage extends AsyncLocalStorage {
16
+ /**
17
+ *
18
+ * @param store {DatadogStorage}
19
+ */
14
20
  enterWith (store) {
15
21
  const handle = {}
16
22
  stores.set(handle, store)
17
- this._storage.enterWith(handle)
18
- }
19
-
20
- exit (callback, ...args) {
21
- this._storage.exit(callback, ...args)
23
+ super.enterWith(handle)
22
24
  }
23
25
 
24
- // TODO: Refactor the Scope class to use a span-only store and remove this.
26
+ /**
27
+ * This is method is a passthrough to the real `getStore()`, so that, when we
28
+ * need it, we can use the handle rather than our mapped store.
29
+ *
30
+ * It's only here because stores are currently used for a bunch of things,
31
+ * and we don't want to hold on to all of them in spans
32
+ * (see opentracing/span.js). Using a namespaced storage for spans would
33
+ * solve this.
34
+ *
35
+ * TODO: Refactor the Scope class to use a span-only store and remove this.
36
+ *
37
+ * @returns {{}}
38
+ */
25
39
  getHandle () {
26
- return this._storage.getStore()
40
+ return super.getStore()
27
41
  }
28
42
 
43
+ /**
44
+ * Here, we replicate the behavior of the original `getStore()` method by
45
+ * passing in the handle, which we retrieve by calling it on super. Handles
46
+ * retrieved through `getHandle()` can also be passed in to be used as the
47
+ * key. This is useful if you've stashed a handle somewhere and want to
48
+ * retrieve the store with it.
49
+ *
50
+ * @param handle {{}}
51
+ * @returns {T | undefined}
52
+ */
29
53
  getStore (handle) {
30
54
  if (!handle) {
31
- handle = this._storage.getStore()
55
+ handle = super.getStore()
32
56
  }
33
57
 
34
58
  return stores.get(handle)
35
59
  }
36
60
 
61
+ /**
62
+ * Here, we replicate the behavior of the original `run()` method. We ensure
63
+ * that our `enterWith()` is called internally, so that the handle to the
64
+ * store is set. As an optimization, we use super for getStore and enterWith
65
+ * when dealing with the parent store, so that we don't have to access the
66
+ * WeakMap.
67
+ * @template R
68
+ * @template TArgs extends any[]
69
+ * @param store {DatadogStorage}
70
+ * @param fn {() => R}
71
+ * @param args {TArgs}
72
+ * @returns {void}
73
+ */
37
74
  run (store, fn, ...args) {
38
- const prior = this._storage.getStore()
75
+ const prior = super.getStore()
39
76
  this.enterWith(store)
40
77
  try {
41
78
  return Reflect.apply(fn, null, args)
42
79
  } finally {
43
- this._storage.enterWith(prior)
80
+ super.enterWith(prior)
44
81
  }
45
82
  }
46
83
  }
47
84
 
85
+ /**
86
+ * This is the map from handles to real stores, used in the class above.
87
+ * @template T
88
+ * @type {WeakMap<WeakKey, T>}
89
+ */
90
+ const stores = new WeakMap()
91
+
92
+ /**
93
+ * For convenience, we use the `storage` function as a registry of namespaces
94
+ * corresponding to DatadogStorage instances. This lets us have separate
95
+ * storages for separate purposes.
96
+ * @type {Map<string, DatadogStorage>}
97
+ */
48
98
  const storages = Object.create(null)
49
- const legacyStorage = new DatadogStorage()
50
99
 
51
- const storage = function (namespace) {
100
+ /**
101
+ *
102
+ * @param namespace {string} the namespace to use
103
+ * @returns {DatadogStorage}
104
+ */
105
+ function storage (namespace) {
52
106
  if (!storages[namespace]) {
53
107
  storages[namespace] = new DatadogStorage()
54
108
  }
55
109
  return storages[namespace]
56
110
  }
57
111
 
58
- storage.disable = legacyStorage.disable.bind(legacyStorage)
59
- storage.enterWith = legacyStorage.enterWith.bind(legacyStorage)
60
- storage.exit = legacyStorage.exit.bind(legacyStorage)
61
- storage.getHandle = legacyStorage.getHandle.bind(legacyStorage)
62
- storage.getStore = legacyStorage.getStore.bind(legacyStorage)
63
- storage.run = legacyStorage.run.bind(legacyStorage)
64
-
65
- const stores = new WeakMap()
66
-
67
- module.exports = storage
112
+ module.exports = { storage }
@@ -313,10 +313,11 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
313
313
  const asyncResource = asyncResources.get(event.test)
314
314
 
315
315
  if (status === 'fail') {
316
+ const shouldSetProbe = this.isDiEnabled && willBeRetried && numTestExecutions === 1
316
317
  asyncResource.runInAsyncScope(() => {
317
318
  testErrCh.publish({
318
319
  error: formatJestError(event.test.errors[0]),
319
- shouldSetProbe: this.isDiEnabled && willBeRetried && numTestExecutions === 1,
320
+ shouldSetProbe,
320
321
  promises
321
322
  })
322
323
  })
@@ -336,18 +337,13 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
336
337
  testFinishCh.publish({
337
338
  status,
338
339
  testStartLine: getTestLineStart(event.test.asyncError, this.testSuite),
339
- promises,
340
- shouldRemoveProbe: this.isDiEnabled && !willBeRetried
340
+ promises
341
341
  })
342
342
  })
343
343
 
344
344
  if (promises.isProbeReady) {
345
345
  await promises.isProbeReady
346
346
  }
347
-
348
- if (promises.isProbeRemoved) {
349
- await promises.isProbeRemoved
350
- }
351
347
  }
352
348
  if (event.name === 'test_skip' || event.name === 'test_todo') {
353
349
  const asyncResource = new AsyncResource('bound-anonymous-fn')
@@ -20,7 +20,7 @@ class AerospikePlugin extends DatabasePlugin {
20
20
  bindStart (ctx) {
21
21
  const { commandName, commandArgs } = ctx
22
22
  const resourceName = commandName.slice(0, commandName.indexOf('Command'))
23
- const store = storage.getStore()
23
+ const store = storage('legacy').getStore()
24
24
  const childOf = store ? store.span : null
25
25
  const meta = getMeta(resourceName, commandArgs)
26
26
 
@@ -10,7 +10,7 @@ class ApolloGatewayFetchPlugin extends ApolloBasePlugin {
10
10
  }
11
11
 
12
12
  bindStart (ctx) {
13
- const store = storage.getStore()
13
+ const store = storage('legacy').getStore()
14
14
  const childOf = store ? store.span : null
15
15
 
16
16
  const spanData = {
@@ -25,7 +25,7 @@ class ApolloGatewayPlugin extends CompositePlugin {
25
25
  constructor (...args) {
26
26
  super(...args)
27
27
  this.addSub('apm:apollo:gateway:general:error', (ctx) => {
28
- const store = storage.getStore()
28
+ const store = storage('legacy').getStore()
29
29
  const span = store?.span
30
30
  if (!span) return
31
31
  span.setTag('error', ctx.error)
@@ -15,7 +15,7 @@ class ApolloGatewayRequestPlugin extends ApolloBasePlugin {
15
15
  }
16
16
 
17
17
  bindStart (ctx) {
18
- const store = storage.getStore()
18
+ const store = storage('legacy').getStore()
19
19
  const childOf = store ? store.span : null
20
20
  const spanData = {
21
21
  childOf,
@@ -67,13 +67,13 @@ class BaseAwsSdkPlugin extends ClientPlugin {
67
67
  span.addTags(requestTags)
68
68
  }
69
69
 
70
- const store = storage.getStore()
70
+ const store = storage('legacy').getStore()
71
71
 
72
72
  this.enter(span, store)
73
73
  })
74
74
 
75
75
  this.addSub(`apm:aws:request:region:${this.serviceIdentifier}`, region => {
76
- const store = storage.getStore()
76
+ const store = storage('legacy').getStore()
77
77
  if (!store) return
78
78
  const { span } = store
79
79
  if (!span) return
@@ -82,7 +82,7 @@ class BaseAwsSdkPlugin extends ClientPlugin {
82
82
  })
83
83
 
84
84
  this.addSub(`apm:aws:request:complete:${this.serviceIdentifier}`, ({ response, cbExists = false }) => {
85
- const store = storage.getStore()
85
+ const store = storage('legacy').getStore()
86
86
  if (!store) return
87
87
  const { span } = store
88
88
  if (!span) return
@@ -21,7 +21,7 @@ class Kinesis extends BaseAwsSdkPlugin {
21
21
 
22
22
  this.addSub('apm:aws:response:start:kinesis', obj => {
23
23
  const { request, response } = obj
24
- const store = storage.getStore()
24
+ const store = storage('legacy').getStore()
25
25
  const plugin = this
26
26
 
27
27
  // if we have either of these operations, we want to store the streamName param
@@ -49,7 +49,7 @@ class Kinesis extends BaseAwsSdkPlugin {
49
49
  }
50
50
 
51
51
  // get the stream name that should have been stored previously
52
- const { streamName } = storage.getStore()
52
+ const { streamName } = storage('legacy').getStore()
53
53
 
54
54
  // extract DSM context after as we might not have a parent-child but may have a DSM context
55
55
  this.responseExtractDSMContext(
@@ -59,7 +59,7 @@ class Kinesis extends BaseAwsSdkPlugin {
59
59
  })
60
60
 
61
61
  this.addSub('apm:aws:response:finish:kinesis', err => {
62
- const { span } = storage.getStore()
62
+ const { span } = storage('legacy').getStore()
63
63
  this.finish(span, null, err)
64
64
  })
65
65
  }
@@ -79,7 +79,7 @@ class Kinesis extends BaseAwsSdkPlugin {
79
79
  if (!params || !params.StreamName) return
80
80
 
81
81
  const streamName = params.StreamName
82
- storage.enterWith({ ...store, streamName })
82
+ storage('legacy').enterWith({ ...store, streamName })
83
83
  }
84
84
 
85
85
  responseExtract (params, operation, response) {
@@ -20,7 +20,7 @@ class Sqs extends BaseAwsSdkPlugin {
20
20
 
21
21
  this.addSub('apm:aws:response:start:sqs', obj => {
22
22
  const { request, response } = obj
23
- const store = storage.getStore()
23
+ const store = storage('legacy').getStore()
24
24
  const plugin = this
25
25
  const contextExtraction = this.responseExtract(request.params, request.operation, response)
26
26
  let span
@@ -47,7 +47,7 @@ class Sqs extends BaseAwsSdkPlugin {
47
47
  })
48
48
 
49
49
  this.addSub('apm:aws:response:finish:sqs', err => {
50
- const { span } = storage.getStore()
50
+ const { span } = storage('legacy').getStore()
51
51
  this.finish(span, null, err)
52
52
  })
53
53
  }
@@ -24,7 +24,7 @@ class AzureFunctionsPlugin extends TracingPlugin {
24
24
 
25
25
  bindStart (ctx) {
26
26
  const { functionName, methodName } = ctx
27
- const store = storage.getStore()
27
+ const store = storage('legacy').getStore()
28
28
 
29
29
  const span = this.startSpan(this.operationName(), {
30
30
  service: this.serviceName(),
@@ -42,7 +42,7 @@ class CouchBasePlugin extends StoragePlugin {
42
42
  super(...args)
43
43
 
44
44
  this.addSubs('query', ({ resource, bucket, seedNodes }) => {
45
- const store = storage.getStore()
45
+ const store = storage('legacy').getStore()
46
46
  const span = this.startSpan(
47
47
  'query', {
48
48
  'span.type': 'sql',
@@ -64,7 +64,7 @@ class CouchBasePlugin extends StoragePlugin {
64
64
 
65
65
  _addCommandSubs (name) {
66
66
  this.addSubs(name, ({ bucket, collection, seedNodes }) => {
67
- const store = storage.getStore()
67
+ const store = storage('legacy').getStore()
68
68
  const span = this.startSpan(name, {}, store, { bucket, collection, seedNodes })
69
69
  this.enter(span, store)
70
70
  })
@@ -213,7 +213,7 @@ class CucumberPlugin extends CiPlugin {
213
213
  isParallel,
214
214
  promises
215
215
  }) => {
216
- const store = storage.getStore()
216
+ const store = storage('legacy').getStore()
217
217
  const testSuite = getTestSuitePath(testFileAbsolutePath, this.sourceRoot)
218
218
  const testSourceFile = getTestSuitePath(testFileAbsolutePath, this.repositoryRoot)
219
219
 
@@ -231,7 +231,7 @@ class CucumberPlugin extends CiPlugin {
231
231
 
232
232
  this.activeTestSpan = testSpan
233
233
  // Time we give the breakpoint to be hit
234
- if (promises && this.runningTestProbeId) {
234
+ if (promises && this.runningTestProbe) {
235
235
  promises.hitBreakpointPromise = new Promise((resolve) => {
236
236
  setTimeout(resolve, BREAKPOINT_HIT_GRACE_PERIOD_MS)
237
237
  })
@@ -239,7 +239,7 @@ class CucumberPlugin extends CiPlugin {
239
239
  })
240
240
 
241
241
  this.addSub('ci:cucumber:test:retry', ({ isFirstAttempt, error }) => {
242
- const store = storage.getStore()
242
+ const store = storage('legacy').getStore()
243
243
  const span = store.span
244
244
  if (!isFirstAttempt) {
245
245
  span.setTag(TEST_IS_RETRY, 'true')
@@ -248,8 +248,8 @@ class CucumberPlugin extends CiPlugin {
248
248
  if (isFirstAttempt && this.di && error && this.libraryConfig?.isDiEnabled) {
249
249
  const probeInformation = this.addDiProbe(error)
250
250
  if (probeInformation) {
251
- const { probeId, stackIndex } = probeInformation
252
- this.runningTestProbeId = probeId
251
+ const { file, line, stackIndex } = probeInformation
252
+ this.runningTestProbe = { file, line }
253
253
  this.testErrorStackIndex = stackIndex
254
254
  // TODO: we're not waiting for setProbePromise to be resolved, so there might be race conditions
255
255
  }
@@ -260,7 +260,7 @@ class CucumberPlugin extends CiPlugin {
260
260
  })
261
261
 
262
262
  this.addSub('ci:cucumber:test-step:start', ({ resource }) => {
263
- const store = storage.getStore()
263
+ const store = storage('legacy').getStore()
264
264
  const childOf = store ? store.span : store
265
265
  const span = this.tracer.startSpan('cucumber.step', {
266
266
  childOf,
@@ -313,7 +313,7 @@ class CucumberPlugin extends CiPlugin {
313
313
  isEfdRetry,
314
314
  isFlakyRetry
315
315
  }) => {
316
- const span = storage.getStore().span
316
+ const span = storage('legacy').getStore().span
317
317
  const statusTag = isStep ? 'step.status' : TEST_STATUS
318
318
 
319
319
  span.setTag(statusTag, status)
@@ -359,16 +359,16 @@ class CucumberPlugin extends CiPlugin {
359
359
  this.tracer._exporter.flush()
360
360
  }
361
361
  this.activeTestSpan = null
362
- if (this.runningTestProbeId) {
363
- this.removeDiProbe(this.runningTestProbeId)
364
- this.runningTestProbeId = null
362
+ if (this.runningTestProbe) {
363
+ this.removeDiProbe(this.runningTestProbe)
364
+ this.runningTestProbe = null
365
365
  }
366
366
  }
367
367
  })
368
368
 
369
369
  this.addSub('ci:cucumber:error', (err) => {
370
370
  if (err) {
371
- const span = storage.getStore().span
371
+ const span = storage('legacy').getStore().span
372
372
  span.setTag('error', err)
373
373
  }
374
374
  })
@@ -32,7 +32,8 @@ const {
32
32
  getTestSessionName,
33
33
  TEST_SESSION_NAME,
34
34
  TEST_LEVEL_EVENT_TYPES,
35
- TEST_RETRY_REASON
35
+ TEST_RETRY_REASON,
36
+ DD_TEST_IS_USER_PROVIDED_SERVICE
36
37
  } = require('../../dd-trace/src/plugins/util/test')
37
38
  const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util')
38
39
  const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
@@ -222,6 +223,10 @@ class CypressPlugin {
222
223
  this.tracer = tracer
223
224
  this.cypressConfig = cypressConfig
224
225
 
226
+ // we have to do it here because the tracer is not initialized in the constructor
227
+ this.testEnvironmentMetadata[DD_TEST_IS_USER_PROVIDED_SERVICE] =
228
+ tracer._tracer._config.isServiceUserProvided ? 'true' : 'false'
229
+
225
230
  this.libraryConfigurationPromise = getLibraryConfiguration(this.tracer, this.testConfiguration)
226
231
  .then((libraryConfigurationResponse) => {
227
232
  if (libraryConfigurationResponse.err) {
@@ -4,6 +4,10 @@ let isKnownTestsEnabled = false
4
4
  let knownTestsForSuite = []
5
5
  let suiteTests = []
6
6
  let earlyFlakeDetectionNumRetries = 0
7
+ // We need to grab the original window as soon as possible,
8
+ // in case the test changes the origin. If the test does change the origin,
9
+ // any call to `cy.window()` will result in a cross origin error.
10
+ let originalWindow
7
11
 
8
12
  // If the test is using multi domain with cy.origin, trying to access
9
13
  // window properties will result in a cross origin error.
@@ -61,6 +65,9 @@ beforeEach(function () {
61
65
  this.skip()
62
66
  }
63
67
  })
68
+ cy.window().then(win => {
69
+ originalWindow = win
70
+ })
64
71
  })
65
72
 
66
73
  before(function () {
@@ -78,39 +85,39 @@ before(function () {
78
85
  })
79
86
 
80
87
  after(() => {
81
- cy.window().then(win => {
82
- if (safeGetRum(win)) {
83
- win.dispatchEvent(new Event('beforeunload'))
88
+ try {
89
+ if (safeGetRum(originalWindow)) {
90
+ originalWindow.dispatchEvent(new Event('beforeunload'))
84
91
  }
85
- })
92
+ } catch (e) {
93
+ // ignore error. It's usually a multi origin issue.
94
+ }
86
95
  })
87
96
 
88
97
 
89
98
  afterEach(function () {
90
- cy.window().then(win => {
91
- const currentTest = Cypress.mocha.getRunner().suite.ctx.currentTest
92
- const testInfo = {
93
- testName: currentTest.fullTitle(),
94
- testSuite: Cypress.mocha.getRootSuite().file,
95
- testSuiteAbsolutePath: Cypress.spec && Cypress.spec.absolute,
96
- state: currentTest.state,
97
- error: currentTest.err,
98
- isNew: currentTest._ddIsNew,
99
- isEfdRetry: currentTest._ddIsEfdRetry
100
- }
101
- try {
102
- testInfo.testSourceLine = Cypress.mocha.getRunner().currentRunnable.invocationDetails.line
103
- } catch (e) {}
99
+ const currentTest = Cypress.mocha.getRunner().suite.ctx.currentTest
100
+ const testInfo = {
101
+ testName: currentTest.fullTitle(),
102
+ testSuite: Cypress.mocha.getRootSuite().file,
103
+ testSuiteAbsolutePath: Cypress.spec && Cypress.spec.absolute,
104
+ state: currentTest.state,
105
+ error: currentTest.err,
106
+ isNew: currentTest._ddIsNew,
107
+ isEfdRetry: currentTest._ddIsEfdRetry
108
+ }
109
+ try {
110
+ testInfo.testSourceLine = Cypress.mocha.getRunner().currentRunnable.invocationDetails.line
111
+ } catch (e) {}
104
112
 
105
- if (safeGetRum(win)) {
106
- testInfo.isRUMActive = true
107
- }
108
- let coverage
109
- try {
110
- coverage = win.__coverage__
111
- } catch (e) {
112
- // ignore error and continue
113
- }
114
- cy.task('dd:afterEach', { test: testInfo, coverage })
115
- })
113
+ if (safeGetRum(originalWindow)) {
114
+ testInfo.isRUMActive = true
115
+ }
116
+ let coverage
117
+ try {
118
+ coverage = originalWindow.__coverage__
119
+ } catch (e) {
120
+ // ignore error and continue
121
+ }
122
+ cy.task('dd:afterEach', { test: testInfo, coverage })
116
123
  })
@@ -20,7 +20,7 @@ class GrpcClientPlugin extends ClientPlugin {
20
20
  }
21
21
 
22
22
  bindStart (message) {
23
- const store = storage.getStore()
23
+ const store = storage('legacy').getStore()
24
24
  const { metadata, path, type } = message
25
25
  const metadataFilter = this.config.metadataFilter
26
26
  const method = getMethodMetadata(path, type)
@@ -27,7 +27,7 @@ class GrpcServerPlugin extends ServerPlugin {
27
27
  }
28
28
 
29
29
  bindStart (message) {
30
- const store = storage.getStore()
30
+ const store = storage('legacy').getStore()
31
31
  const { name, metadata, type } = message
32
32
  const metadataFilter = this.config.metadataFilter
33
33
  const childOf = extract(this.tracer, metadata)
@@ -15,7 +15,7 @@ class HapiPlugin extends RouterPlugin {
15
15
  this._requestSpans = new WeakMap()
16
16
 
17
17
  this.addSub('apm:hapi:request:handle', ({ req }) => {
18
- const store = storage.getStore()
18
+ const store = storage('legacy').getStore()
19
19
  const span = store && store.span
20
20
 
21
21
  this.setFramework(req, 'hapi', this.config)
@@ -21,7 +21,7 @@ class HttpClientPlugin extends ClientPlugin {
21
21
 
22
22
  bindStart (message) {
23
23
  const { args, http = {} } = message
24
- const store = storage.getStore()
24
+ const store = storage('legacy').getStore()
25
25
  const options = args.options
26
26
  const agent = options.agent || options._defaultAgent || http.globalAgent || {}
27
27
  const protocol = options.protocol || agent.protocol || 'http:'
@@ -22,7 +22,7 @@ class HttpServerPlugin extends ServerPlugin {
22
22
  }
23
23
 
24
24
  start ({ req, res, abortController }) {
25
- const store = storage.getStore()
25
+ const store = storage('legacy').getStore()
26
26
  const span = web.startSpan(
27
27
  this.tracer,
28
28
  {
@@ -36,7 +36,7 @@ class Http2ClientPlugin extends ClientPlugin {
36
36
  const uri = `${sessionDetails.protocol}//${sessionDetails.host}:${sessionDetails.port}${pathname}`
37
37
  const allowed = this.config.filter(uri)
38
38
 
39
- const store = storage.getStore()
39
+ const store = storage('legacy').getStore()
40
40
  const childOf = store && allowed ? store.span : null
41
41
  const span = this.startSpan(this.operationName(), {
42
42
  childOf,
@@ -85,7 +85,7 @@ class Http2ClientPlugin extends ClientPlugin {
85
85
  return parentStore
86
86
  }
87
87
 
88
- return storage.getStore()
88
+ return storage('legacy').getStore()
89
89
  }
90
90
 
91
91
  configure (config) {
@@ -98,7 +98,7 @@ class Http2ClientPlugin extends ClientPlugin {
98
98
  store.span.setTag(HTTP_STATUS_CODE, status)
99
99
 
100
100
  if (!this.config.validateStatus(status)) {
101
- storage.run(store, () => this.addError())
101
+ storage('legacy').run(store, () => this.addError())
102
102
  }
103
103
 
104
104
  addHeaderTags(store.span, headers, HTTP_RESPONSE_HEADERS, this.config)