dd-trace 5.35.0 → 5.37.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 (125) hide show
  1. package/LICENSE-3rdparty.csv +2 -1
  2. package/index.d.ts +8 -7
  3. package/loader-hook.mjs +0 -4
  4. package/package.json +15 -14
  5. package/packages/datadog-core/index.js +1 -1
  6. package/packages/datadog-core/src/storage.js +76 -31
  7. package/packages/datadog-instrumentations/src/cucumber.js +54 -1
  8. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
  9. package/packages/datadog-instrumentations/src/helpers/register.js +2 -2
  10. package/packages/datadog-instrumentations/src/jest.js +105 -11
  11. package/packages/datadog-instrumentations/src/mocha/main.js +46 -4
  12. package/packages/datadog-instrumentations/src/mocha/utils.js +35 -2
  13. package/packages/datadog-instrumentations/src/mocha/worker.js +7 -0
  14. package/packages/datadog-instrumentations/src/mysql2.js +3 -3
  15. package/packages/datadog-instrumentations/src/openai.js +8 -0
  16. package/packages/datadog-instrumentations/src/playwright.js +70 -22
  17. package/packages/datadog-instrumentations/src/vitest.js +60 -6
  18. package/packages/datadog-plugin-aerospike/src/index.js +1 -1
  19. package/packages/datadog-plugin-apollo/src/gateway/fetch.js +1 -1
  20. package/packages/datadog-plugin-apollo/src/gateway/index.js +1 -1
  21. package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -1
  22. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -3
  23. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -4
  24. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -2
  25. package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
  26. package/packages/datadog-plugin-couchbase/src/index.js +2 -2
  27. package/packages/datadog-plugin-cucumber/src/index.js +31 -14
  28. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +72 -7
  29. package/packages/datadog-plugin-cypress/src/support.js +36 -29
  30. package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -3
  31. package/packages/datadog-plugin-graphql/src/utils.js +8 -1
  32. package/packages/datadog-plugin-grpc/src/client.js +1 -1
  33. package/packages/datadog-plugin-grpc/src/server.js +1 -1
  34. package/packages/datadog-plugin-hapi/src/index.js +1 -1
  35. package/packages/datadog-plugin-http/src/client.js +1 -1
  36. package/packages/datadog-plugin-http/src/server.js +1 -1
  37. package/packages/datadog-plugin-http2/src/client.js +3 -3
  38. package/packages/datadog-plugin-http2/src/server.js +1 -1
  39. package/packages/datadog-plugin-jest/src/index.js +17 -12
  40. package/packages/datadog-plugin-langchain/src/tracing.js +1 -1
  41. package/packages/datadog-plugin-mariadb/src/index.js +3 -3
  42. package/packages/datadog-plugin-mocha/src/index.js +35 -16
  43. package/packages/datadog-plugin-mongodb-core/src/index.js +28 -2
  44. package/packages/datadog-plugin-next/src/index.js +4 -4
  45. package/packages/datadog-plugin-openai/src/tracing.js +2 -3
  46. package/packages/datadog-plugin-playwright/src/index.js +35 -9
  47. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  48. package/packages/datadog-plugin-router/src/index.js +2 -2
  49. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  50. package/packages/datadog-plugin-vitest/src/index.js +36 -12
  51. package/packages/dd-trace/src/appsec/graphql.js +6 -6
  52. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +3 -7
  53. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +15 -1
  54. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +17 -30
  55. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +2 -2
  56. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +7 -11
  57. package/packages/dd-trace/src/appsec/iast/analyzers/stored-injection-analyzer.js +11 -0
  58. package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +2 -6
  59. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +24 -4
  60. package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +2 -2
  61. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +2 -2
  62. package/packages/dd-trace/src/appsec/iast/index.js +4 -2
  63. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +187 -0
  64. package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +96 -0
  65. package/packages/dd-trace/src/appsec/iast/taint-tracking/constants.js +6 -0
  66. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -2
  67. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +8 -8
  68. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +1 -1
  69. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +65 -0
  70. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +14 -5
  71. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +80 -2
  72. package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks-generator.js +1 -1
  73. package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks.js +28 -0
  74. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
  75. package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +5 -0
  76. package/packages/dd-trace/src/appsec/iast/utils.js +24 -0
  77. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +8 -13
  78. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -0
  79. package/packages/dd-trace/src/appsec/index.js +4 -4
  80. package/packages/dd-trace/src/appsec/rasp/command_injection.js +5 -5
  81. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +5 -5
  82. package/packages/dd-trace/src/appsec/rasp/lfi.js +3 -3
  83. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +4 -4
  84. package/packages/dd-trace/src/appsec/rasp/ssrf.js +3 -3
  85. package/packages/dd-trace/src/appsec/reporter.js +3 -3
  86. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  87. package/packages/dd-trace/src/appsec/waf/index.js +1 -1
  88. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +2 -0
  89. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +31 -56
  90. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +20 -2
  91. package/packages/dd-trace/src/ci-visibility/quarantined-tests/get-quarantined-tests.js +62 -0
  92. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +5 -2
  93. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +3 -3
  94. package/packages/dd-trace/src/config.js +18 -3
  95. package/packages/dd-trace/src/data_streams_context.js +2 -2
  96. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +14 -7
  97. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +50 -0
  98. package/packages/dd-trace/src/debugger/devtools_client/state.js +38 -10
  99. package/packages/dd-trace/src/exporters/common/agents.js +1 -1
  100. package/packages/dd-trace/src/exporters/common/request.js +3 -3
  101. package/packages/dd-trace/src/iitm.js +2 -2
  102. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +1 -1
  103. package/packages/dd-trace/src/llmobs/tagger.js +12 -2
  104. package/packages/dd-trace/src/log/writer.js +3 -3
  105. package/packages/dd-trace/src/noop/span.js +1 -1
  106. package/packages/dd-trace/src/opentracing/propagation/text_map.js +5 -4
  107. package/packages/dd-trace/src/opentracing/span.js +3 -3
  108. package/packages/dd-trace/src/plugin_manager.js +3 -1
  109. package/packages/dd-trace/src/plugins/apollo.js +1 -1
  110. package/packages/dd-trace/src/plugins/ci_plugin.js +51 -4
  111. package/packages/dd-trace/src/plugins/database.js +14 -4
  112. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  113. package/packages/dd-trace/src/plugins/plugin.js +8 -8
  114. package/packages/dd-trace/src/plugins/tracing.js +3 -3
  115. package/packages/dd-trace/src/plugins/util/git.js +3 -3
  116. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +1 -3
  117. package/packages/dd-trace/src/plugins/util/test.js +10 -4
  118. package/packages/dd-trace/src/profiling/exporters/agent.js +3 -3
  119. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  120. package/packages/dd-trace/src/proxy.js +5 -1
  121. package/packages/dd-trace/src/ritm.js +2 -1
  122. package/packages/dd-trace/src/scope.js +5 -5
  123. package/packages/dd-trace/src/spanleak.js +0 -1
  124. package/packages/dd-trace/src/tracer.js +0 -14
  125. package/packages/memwatch/package.json +0 -9
@@ -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
  })
@@ -28,7 +28,7 @@ module.exports = class DdTraceApiPlugin extends Plugin {
28
28
  })
29
29
 
30
30
  const handleEvent = (name) => {
31
- const counter = apiMetrics.count('dd_trace_api.called', [
31
+ const counter = apiMetrics.count('public_api.called', [
32
32
  `name:${name.replaceAll(':', '.')}`,
33
33
  'api_version:v1',
34
34
  injectionEnabledTag
@@ -74,8 +74,6 @@ module.exports = class DdTraceApiPlugin extends Plugin {
74
74
  const proxyVal = proxy()
75
75
  objectMap.set(proxyVal, ret.value)
76
76
  ret.value = proxyVal
77
- } else if (ret.value && typeof ret.value === 'object') {
78
- throw new TypeError(`Objects need proxies when returned via API (${name})`)
79
77
  }
80
78
  } catch (e) {
81
79
  ret.error = e
@@ -27,7 +27,14 @@ function extractErrorIntoSpanEvent (config, span, exc) {
27
27
  if (config.graphqlErrorExtensions) {
28
28
  for (const ext of config.graphqlErrorExtensions) {
29
29
  if (exc.extensions?.[ext]) {
30
- attributes[`extensions.${ext}`] = exc.extensions[ext].toString()
30
+ const value = exc.extensions[ext]
31
+
32
+ // We should only stringify the value if it is not of type number or boolean
33
+ if (typeof value === 'number' || typeof value === 'boolean') {
34
+ attributes[`extensions.${ext}`] = value
35
+ } else {
36
+ attributes[`extensions.${ext}`] = String(value)
37
+ }
31
38
  }
32
39
  }
33
40
  }
@@ -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)
@@ -17,7 +17,7 @@ class Http2ServerPlugin extends ServerPlugin {
17
17
  }
18
18
 
19
19
  start ({ req, res }) {
20
- const store = storage.getStore()
20
+ const store = storage('legacy').getStore()
21
21
  const span = web.startSpan(
22
22
  this.tracer,
23
23
  {
@@ -24,7 +24,9 @@ const {
24
24
  TEST_IS_RUM_ACTIVE,
25
25
  TEST_BROWSER_DRIVER,
26
26
  getFormattedError,
27
- TEST_RETRY_REASON
27
+ TEST_RETRY_REASON,
28
+ TEST_MANAGEMENT_ENABLED,
29
+ TEST_MANAGEMENT_IS_QUARANTINED
28
30
  } = require('../../dd-trace/src/plugins/util/test')
29
31
  const { COMPONENT } = require('../../dd-trace/src/constants')
30
32
  const id = require('../../dd-trace/src/id')
@@ -106,6 +108,7 @@ class JestPlugin extends CiPlugin {
106
108
  error,
107
109
  isEarlyFlakeDetectionEnabled,
108
110
  isEarlyFlakeDetectionFaulty,
111
+ isQuarantinedTestsEnabled,
109
112
  onDone
110
113
  }) => {
111
114
  this.testSessionSpan.setTag(TEST_STATUS, status)
@@ -137,6 +140,9 @@ class JestPlugin extends CiPlugin {
137
140
  if (isEarlyFlakeDetectionFaulty) {
138
141
  this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ABORT_REASON, 'faulty')
139
142
  }
143
+ if (isQuarantinedTestsEnabled) {
144
+ this.testSessionSpan.setTag(TEST_MANAGEMENT_ENABLED, 'true')
145
+ }
140
146
 
141
147
  this.testModuleSpan.finish()
142
148
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'module')
@@ -166,6 +172,7 @@ class JestPlugin extends CiPlugin {
166
172
  config._ddEarlyFlakeDetectionNumRetries = this.libraryConfig?.earlyFlakeDetectionNumRetries ?? 0
167
173
  config._ddRepositoryRoot = this.repositoryRoot
168
174
  config._ddIsFlakyTestRetriesEnabled = this.libraryConfig?.isFlakyTestRetriesEnabled ?? false
175
+ config._ddIsQuarantinedTestsEnabled = this.libraryConfig?.isQuarantinedTestsEnabled ?? false
169
176
  config._ddFlakyTestRetriesCount = this.libraryConfig?.flakyTestRetriesCount
170
177
  config._ddIsDiEnabled = this.libraryConfig?.isDiEnabled ?? false
171
178
  config._ddIsKnownTestsEnabled = this.libraryConfig?.isKnownTestsEnabled ?? false
@@ -291,6 +298,7 @@ class JestPlugin extends CiPlugin {
291
298
  if (isJestWorker) {
292
299
  this.tracer._exporter.flush()
293
300
  }
301
+ this.removeAllDiProbes()
294
302
  })
295
303
 
296
304
  /**
@@ -317,19 +325,22 @@ class JestPlugin extends CiPlugin {
317
325
  })
318
326
 
319
327
  this.addSub('ci:jest:test:start', (test) => {
320
- const store = storage.getStore()
328
+ const store = storage('legacy').getStore()
321
329
  const span = this.startTestSpan(test)
322
330
 
323
331
  this.enter(span, store)
324
332
  this.activeTestSpan = span
325
333
  })
326
334
 
327
- this.addSub('ci:jest:test:finish', ({ status, testStartLine, promises, shouldRemoveProbe }) => {
328
- const span = storage.getStore().span
335
+ this.addSub('ci:jest:test:finish', ({ status, testStartLine, isQuarantined }) => {
336
+ const span = storage('legacy').getStore().span
329
337
  span.setTag(TEST_STATUS, status)
330
338
  if (testStartLine) {
331
339
  span.setTag(TEST_SOURCE_START, testStartLine)
332
340
  }
341
+ if (isQuarantined) {
342
+ span.setTag(TEST_MANAGEMENT_IS_QUARANTINED, 'true')
343
+ }
333
344
 
334
345
  const spanTags = span.context()._tags
335
346
  this.telemetry.ciVisEvent(
@@ -346,15 +357,11 @@ class JestPlugin extends CiPlugin {
346
357
  span.finish()
347
358
  finishAllTraceSpans(span)
348
359
  this.activeTestSpan = null
349
- if (shouldRemoveProbe && this.runningTestProbeId) {
350
- promises.isProbeRemoved = withTimeout(this.removeDiProbe(this.runningTestProbeId), 2000)
351
- this.runningTestProbeId = null
352
- }
353
360
  })
354
361
 
355
362
  this.addSub('ci:jest:test:err', ({ error, shouldSetProbe, promises }) => {
356
363
  if (error) {
357
- const store = storage.getStore()
364
+ const store = storage('legacy').getStore()
358
365
  if (store && store.span) {
359
366
  const span = store.span
360
367
  span.setTag(TEST_STATUS, 'fail')
@@ -362,9 +369,7 @@ class JestPlugin extends CiPlugin {
362
369
  if (shouldSetProbe) {
363
370
  const probeInformation = this.addDiProbe(error)
364
371
  if (probeInformation) {
365
- const { probeId, setProbePromise, stackIndex } = probeInformation
366
- this.runningTestProbeId = probeId
367
- this.testErrorStackIndex = stackIndex
372
+ const { setProbePromise } = probeInformation
368
373
  promises.isProbeReady = withTimeout(setProbePromise, 2000)
369
374
  }
370
375
  }
@@ -61,7 +61,7 @@ class LangChainTracingPlugin extends TracingPlugin {
61
61
  }
62
62
  }, false)
63
63
 
64
- const store = storage.getStore() || {}
64
+ const store = storage('legacy').getStore() || {}
65
65
  ctx.currentStore = { ...store, span }
66
66
 
67
67
  return ctx.currentStore
@@ -13,12 +13,12 @@ class MariadbPlugin extends MySQLPlugin {
13
13
  super(...args)
14
14
 
15
15
  this.addSub(`apm:${this.component}:pool:skip`, () => {
16
- skippedStore = storage.getStore()
17
- storage.enterWith({ noop: true })
16
+ skippedStore = storage('legacy').getStore()
17
+ storage('legacy').enterWith({ noop: true })
18
18
  })
19
19
 
20
20
  this.addSub(`apm:${this.component}:pool:unskip`, () => {
21
- storage.enterWith(skippedStore)
21
+ storage('legacy').enterWith(skippedStore)
22
22
  skippedStore = undefined
23
23
  })
24
24
  }
@@ -31,7 +31,9 @@ const {
31
31
  MOCHA_IS_PARALLEL,
32
32
  TEST_IS_RUM_ACTIVE,
33
33
  TEST_BROWSER_DRIVER,
34
- TEST_RETRY_REASON
34
+ TEST_RETRY_REASON,
35
+ TEST_MANAGEMENT_ENABLED,
36
+ TEST_MANAGEMENT_IS_QUARANTINED
35
37
  } = require('../../dd-trace/src/plugins/util/test')
36
38
  const { COMPONENT } = require('../../dd-trace/src/constants')
37
39
  const {
@@ -48,6 +50,8 @@ const {
48
50
  const id = require('../../dd-trace/src/id')
49
51
  const log = require('../../dd-trace/src/log')
50
52
 
53
+ const BREAKPOINT_SET_GRACE_PERIOD_MS = 200
54
+
51
55
  function getTestSuiteLevelVisibilityTags (testSuiteSpan) {
52
56
  const testSuiteSpanContext = testSuiteSpan.context()
53
57
  const suiteTags = {
@@ -155,13 +159,13 @@ class MochaPlugin extends CiPlugin {
155
159
  if (itrCorrelationId) {
156
160
  testSuiteSpan.setTag(ITR_CORRELATION_ID, itrCorrelationId)
157
161
  }
158
- const store = storage.getStore()
162
+ const store = storage('legacy').getStore()
159
163
  this.enter(testSuiteSpan, store)
160
164
  this._testSuites.set(testSuite, testSuiteSpan)
161
165
  })
162
166
 
163
167
  this.addSub('ci:mocha:test-suite:finish', (status) => {
164
- const store = storage.getStore()
168
+ const store = storage('legacy').getStore()
165
169
  if (store && store.span) {
166
170
  const span = store.span
167
171
  // the test status of the suite may have been set in ci:mocha:test-suite:error already
@@ -174,7 +178,7 @@ class MochaPlugin extends CiPlugin {
174
178
  })
175
179
 
176
180
  this.addSub('ci:mocha:test-suite:error', (err) => {
177
- const store = storage.getStore()
181
+ const store = storage('legacy').getStore()
178
182
  if (store && store.span) {
179
183
  const span = store.span
180
184
  span.setTag('error', err)
@@ -183,7 +187,7 @@ class MochaPlugin extends CiPlugin {
183
187
  })
184
188
 
185
189
  this.addSub('ci:mocha:test:start', (testInfo) => {
186
- const store = storage.getStore()
190
+ const store = storage('legacy').getStore()
187
191
  const span = this.startTestSpan(testInfo)
188
192
 
189
193
  this.enter(span, store)
@@ -195,7 +199,7 @@ class MochaPlugin extends CiPlugin {
195
199
  })
196
200
 
197
201
  this.addSub('ci:mocha:test:finish', ({ status, hasBeenRetried, isLastRetry }) => {
198
- const store = storage.getStore()
202
+ const store = storage('legacy').getStore()
199
203
  const span = store?.span
200
204
 
201
205
  if (span) {
@@ -219,15 +223,15 @@ class MochaPlugin extends CiPlugin {
219
223
  span.finish()
220
224
  finishAllTraceSpans(span)
221
225
  this.activeTestSpan = null
222
- if (this.di && this.libraryConfig?.isDiEnabled && this.runningTestProbeId && isLastRetry) {
223
- this.removeDiProbe(this.runningTestProbeId)
224
- this.runningTestProbeId = null
226
+ if (this.di && this.libraryConfig?.isDiEnabled && this.runningTestProbe && isLastRetry) {
227
+ this.removeDiProbe(this.runningTestProbe)
228
+ this.runningTestProbe = null
225
229
  }
226
230
  }
227
231
  })
228
232
 
229
233
  this.addSub('ci:mocha:test:skip', (testInfo) => {
230
- const store = storage.getStore()
234
+ const store = storage('legacy').getStore()
231
235
  // skipped through it.skip, so the span is not created yet
232
236
  // for this test
233
237
  if (!store) {
@@ -237,7 +241,7 @@ class MochaPlugin extends CiPlugin {
237
241
  })
238
242
 
239
243
  this.addSub('ci:mocha:test:error', (err) => {
240
- const store = storage.getStore()
244
+ const store = storage('legacy').getStore()
241
245
  const span = store?.span
242
246
  if (err && span) {
243
247
  if (err.constructor.name === 'Pending' && !this.forbidPending) {
@@ -250,7 +254,7 @@ class MochaPlugin extends CiPlugin {
250
254
  })
251
255
 
252
256
  this.addSub('ci:mocha:test:retry', ({ isFirstAttempt, willBeRetried, err, test }) => {
253
- const store = storage.getStore()
257
+ const store = storage('legacy').getStore()
254
258
  const span = store?.span
255
259
  if (span) {
256
260
  span.setTag(TEST_STATUS, 'fail')
@@ -275,11 +279,16 @@ class MochaPlugin extends CiPlugin {
275
279
  if (isFirstAttempt && willBeRetried && this.di && this.libraryConfig?.isDiEnabled) {
276
280
  const probeInformation = this.addDiProbe(err)
277
281
  if (probeInformation) {
278
- const { probeId, stackIndex } = probeInformation
279
- this.runningTestProbeId = probeId
282
+ const { file, line, stackIndex } = probeInformation
283
+ this.runningTestProbe = { file, line }
280
284
  this.testErrorStackIndex = stackIndex
281
285
  test._ddShouldWaitForHitProbe = true
282
- // TODO: we're not waiting for setProbePromise to be resolved, so there might be race conditions
286
+ const waitUntil = Date.now() + BREAKPOINT_SET_GRACE_PERIOD_MS
287
+ while (Date.now() < waitUntil) {
288
+ // TODO: To avoid a race condition, we should wait until `probeInformation.setProbePromise` has resolved.
289
+ // However, Mocha doesn't have a mechanism for waiting asyncrounously here, so for now, we'll have to
290
+ // fall back to a fixed syncronous delay.
291
+ }
283
292
  }
284
293
  }
285
294
 
@@ -302,6 +311,7 @@ class MochaPlugin extends CiPlugin {
302
311
  error,
303
312
  isEarlyFlakeDetectionEnabled,
304
313
  isEarlyFlakeDetectionFaulty,
314
+ isQuarantinedTestsEnabled,
305
315
  isParallel
306
316
  }) => {
307
317
  if (this.testSessionSpan) {
@@ -318,6 +328,10 @@ class MochaPlugin extends CiPlugin {
318
328
  this.testSessionSpan.setTag(MOCHA_IS_PARALLEL, 'true')
319
329
  }
320
330
 
331
+ if (isQuarantinedTestsEnabled) {
332
+ this.testSessionSpan.setTag(TEST_MANAGEMENT_ENABLED, 'true')
333
+ }
334
+
321
335
  addIntelligentTestRunnerSpanTags(
322
336
  this.testSessionSpan,
323
337
  this.testModuleSpan,
@@ -390,7 +404,8 @@ class MochaPlugin extends CiPlugin {
390
404
  isNew,
391
405
  isEfdRetry,
392
406
  testStartLine,
393
- isParallel
407
+ isParallel,
408
+ isQuarantined
394
409
  } = testInfo
395
410
 
396
411
  const testName = removeEfdStringFromTestName(testInfo.testName)
@@ -409,6 +424,10 @@ class MochaPlugin extends CiPlugin {
409
424
  extraTags[MOCHA_IS_PARALLEL] = 'true'
410
425
  }
411
426
 
427
+ if (isQuarantined) {
428
+ extraTags[TEST_MANAGEMENT_IS_QUARANTINED] = 'true'
429
+ }
430
+
412
431
  const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.sourceRoot)
413
432
  const testSuiteSpan = this._testSuites.get(testSuite)
414
433
 
@@ -11,8 +11,9 @@ class MongodbCorePlugin extends DatabasePlugin {
11
11
  start ({ ns, ops, options = {}, name }) {
12
12
  const query = getQuery(ops)
13
13
  const resource = truncate(getResource(this, ns, query, name))
14
- this.startSpan(this.operationName(), {
15
- service: this.serviceName({ pluginConfig: this.config }),
14
+ const service = this.serviceName({ pluginConfig: this.config })
15
+ const span = this.startSpan(this.operationName(), {
16
+ service,
16
17
  resource,
17
18
  type: 'mongodb',
18
19
  kind: 'client',
@@ -24,6 +25,7 @@ class MongodbCorePlugin extends DatabasePlugin {
24
25
  'out.port': options.port
25
26
  }
26
27
  })
28
+ ops = this.injectDbmCommand(span, ops, service)
27
29
  }
28
30
 
29
31
  getPeerService (tags) {
@@ -34,6 +36,30 @@ class MongodbCorePlugin extends DatabasePlugin {
34
36
  }
35
37
  return super.getPeerService(tags)
36
38
  }
39
+
40
+ injectDbmCommand (span, command, serviceName) {
41
+ const dbmTraceComment = this.createDbmComment(span, serviceName)
42
+
43
+ if (!dbmTraceComment) {
44
+ return command
45
+ }
46
+
47
+ // create a copy of the command to avoid mutating the original
48
+ const dbmTracedCommand = { ...command }
49
+
50
+ if (dbmTracedCommand.comment) {
51
+ // if the command already has a comment, append the dbm trace comment
52
+ if (typeof dbmTracedCommand.comment === 'string') {
53
+ dbmTracedCommand.comment += `,${dbmTraceComment}`
54
+ } else if (Array.isArray(dbmTracedCommand.comment)) {
55
+ dbmTracedCommand.comment.push(dbmTraceComment)
56
+ } // do nothing if the comment is not a string or an array
57
+ } else {
58
+ dbmTracedCommand.comment = dbmTraceComment
59
+ }
60
+
61
+ return dbmTracedCommand
62
+ }
37
63
  }
38
64
 
39
65
  function sanitizeBigInt (data) {
@@ -20,7 +20,7 @@ class NextPlugin extends ServerPlugin {
20
20
  }
21
21
 
22
22
  bindStart ({ req, res }) {
23
- const store = storage.getStore()
23
+ const store = storage('legacy').getStore()
24
24
  const childOf = store ? store.span : store
25
25
  const span = this.tracer.startSpan(this.operationName(), {
26
26
  childOf,
@@ -43,7 +43,7 @@ class NextPlugin extends ServerPlugin {
43
43
 
44
44
  error ({ span, error }) {
45
45
  if (!span) {
46
- const store = storage.getStore()
46
+ const store = storage('legacy').getStore()
47
47
  if (!store) return
48
48
 
49
49
  span = store.span
@@ -53,7 +53,7 @@ class NextPlugin extends ServerPlugin {
53
53
  }
54
54
 
55
55
  finish ({ req, res, nextRequest = {} }) {
56
- const store = storage.getStore()
56
+ const store = storage('legacy').getStore()
57
57
 
58
58
  if (!store) return
59
59
 
@@ -85,7 +85,7 @@ class NextPlugin extends ServerPlugin {
85
85
  }
86
86
 
87
87
  pageLoad ({ page, isAppPath = false, isStatic = false }) {
88
- const store = storage.getStore()
88
+ const store = storage('legacy').getStore()
89
89
 
90
90
  if (!store) return
91
91
 
@@ -15,7 +15,6 @@ let normalize
15
15
 
16
16
  function safeRequire (path) {
17
17
  try {
18
- // eslint-disable-next-line import/no-extraneous-dependencies
19
18
  return require(path)
20
19
  } catch {
21
20
  return null
@@ -60,7 +59,7 @@ class OpenAiTracingPlugin extends TracingPlugin {
60
59
  bindStart (ctx) {
61
60
  const { methodName, args, basePath, apiKey } = ctx
62
61
  const payload = normalizeRequestPayload(methodName, args)
63
- const store = storage.getStore() || {}
62
+ const store = storage('legacy').getStore() || {}
64
63
 
65
64
  const span = this.startSpan('openai.request', {
66
65
  service: this.config.service,
@@ -796,7 +795,7 @@ function truncateApiKey (apiKey) {
796
795
 
797
796
  function tagChatCompletionRequestContent (contents, messageIdx, tags) {
798
797
  if (typeof contents === 'string') {
799
- tags[`openai.request.messages.${messageIdx}.content`] = contents
798
+ tags[`openai.request.messages.${messageIdx}.content`] = normalize(contents)
800
799
  } else if (Array.isArray(contents)) {
801
800
  // content can also be an array of objects
802
801
  // which represent text input or image url