dd-trace 5.30.0 → 5.32.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 (74) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/README.md +9 -7
  3. package/package.json +7 -6
  4. package/packages/datadog-core/src/storage.js +11 -2
  5. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  6. package/packages/datadog-instrumentations/src/aws-sdk.js +2 -1
  7. package/packages/datadog-instrumentations/src/cucumber.js +14 -5
  8. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
  9. package/packages/datadog-instrumentations/src/jest.js +70 -36
  10. package/packages/datadog-instrumentations/src/mocha/utils.js +23 -7
  11. package/packages/datadog-instrumentations/src/node-serialize.js +22 -0
  12. package/packages/datadog-instrumentations/src/openai.js +2 -0
  13. package/packages/datadog-instrumentations/src/vitest.js +107 -59
  14. package/packages/datadog-instrumentations/src/vm.js +49 -0
  15. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime.js +295 -0
  16. package/packages/datadog-plugin-aws-sdk/src/services/index.js +1 -0
  17. package/packages/datadog-plugin-cucumber/src/index.js +30 -32
  18. package/packages/datadog-plugin-jest/src/index.js +34 -37
  19. package/packages/datadog-plugin-langchain/src/index.js +12 -80
  20. package/packages/datadog-plugin-langchain/src/tracing.js +89 -0
  21. package/packages/datadog-plugin-mocha/src/index.js +18 -36
  22. package/packages/datadog-plugin-vitest/src/index.js +20 -34
  23. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  24. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +2 -0
  25. package/packages/dd-trace/src/appsec/iast/analyzers/untrusted-deserialization-analyzer.js +16 -0
  26. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +9 -8
  27. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  28. package/packages/dd-trace/src/appsec/remote_config/manager.js +11 -1
  29. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +37 -0
  30. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +65 -28
  31. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +57 -17
  32. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +18 -3
  33. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +20 -3
  34. package/packages/dd-trace/src/config.js +39 -3
  35. package/packages/dd-trace/src/crashtracking/crashtracker.js +9 -0
  36. package/packages/dd-trace/src/crashtracking/noop.js +3 -0
  37. package/packages/dd-trace/src/datastreams/fnv.js +1 -1
  38. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -2
  39. package/packages/dd-trace/src/debugger/devtools_client/config.js +3 -1
  40. package/packages/dd-trace/src/debugger/devtools_client/defaults.js +1 -0
  41. package/packages/dd-trace/src/debugger/devtools_client/index.js +32 -14
  42. package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +36 -0
  43. package/packages/dd-trace/src/debugger/devtools_client/send.js +29 -10
  44. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +35 -1
  45. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +112 -0
  46. package/packages/dd-trace/src/debugger/devtools_client/status.js +20 -11
  47. package/packages/dd-trace/src/debugger/index.js +2 -13
  48. package/packages/dd-trace/src/llmobs/plugins/base.js +40 -11
  49. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +24 -0
  50. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +111 -0
  51. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +42 -0
  52. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +102 -0
  53. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/llm.js +32 -0
  54. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +131 -0
  55. package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -1
  56. package/packages/dd-trace/src/llmobs/sdk.js +90 -26
  57. package/packages/dd-trace/src/llmobs/tagger.js +11 -3
  58. package/packages/dd-trace/src/llmobs/util.js +7 -1
  59. package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +3 -3
  60. package/packages/dd-trace/src/log/index.js +8 -9
  61. package/packages/dd-trace/src/noop/proxy.js +2 -2
  62. package/packages/dd-trace/src/noop/span.js +1 -1
  63. package/packages/dd-trace/src/opentelemetry/context_manager.js +43 -3
  64. package/packages/dd-trace/src/opentracing/span.js +11 -1
  65. package/packages/dd-trace/src/opentracing/span_context.js +12 -0
  66. package/packages/dd-trace/src/plugins/ci_plugin.js +57 -27
  67. package/packages/dd-trace/src/plugins/util/test.js +42 -12
  68. package/packages/dd-trace/src/priority_sampler.js +7 -2
  69. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +21 -0
  70. package/packages/dd-trace/src/profiling/profiler.js +11 -8
  71. package/packages/dd-trace/src/profiling/profilers/events.js +17 -1
  72. package/packages/dd-trace/src/proxy.js +6 -3
  73. package/packages/dd-trace/src/scope.js +1 -1
  74. package/packages/dd-trace/src/telemetry/index.js +2 -0
@@ -30,6 +30,7 @@ require,rfdc,MIT,Copyright 2019 David Mark Clements
30
30
  require,semver,ISC,Copyright Isaac Z. Schlueter and Contributors
31
31
  require,shell-quote,mit,Copyright (c) 2013 James Halliday
32
32
  require,source-map,BSD-3-Clause,Copyright (c) 2009-2011, Mozilla Foundation and contributors
33
+ require,ttl-set,MIT,Copyright (c) 2024 Thomas Watson
33
34
  dev,@apollo/server,MIT,Copyright (c) 2016-2020 Apollo Graph, Inc. (Formerly Meteor Development Group, Inc.)
34
35
  dev,@types/node,MIT,Copyright Authors
35
36
  dev,@eslint/eslintrc,MIT,Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
package/README.md CHANGED
@@ -23,13 +23,15 @@ Most of the documentation for `dd-trace` is available on these webpages:
23
23
 
24
24
  ## Version Release Lines and Maintenance
25
25
 
26
- | Release Line | Latest Version | Node.js | Status |Initial Release | End of Life |
27
- | :---: | :---: | :---: | :---: | :---: | :---: |
28
- | [`v1`](https://github.com/DataDog/dd-trace-js/tree/v1.x) | ![npm v1](https://img.shields.io/npm/v/dd-trace/legacy-v1?color=white&label=%20&style=flat-square) | `>= v12` | **End of Life** | 2021-07-13 | 2022-02-25 |
29
- | [`v2`](https://github.com/DataDog/dd-trace-js/tree/v2.x) | ![npm v2](https://img.shields.io/npm/v/dd-trace/latest-node12?color=white&label=%20&style=flat-square) | `>= v12` | **End of Life** | 2022-01-28 | 2023-08-15 |
30
- | [`v3`](https://github.com/DataDog/dd-trace-js/tree/v3.x) | ![npm v3](https://img.shields.io/npm/v/dd-trace/latest-node14?color=white&label=%20&style=flat-square) | `>= v14` | **End of Life** | 2022-08-15 | 2024-05-15 |
31
- | [`v4`](https://github.com/DataDog/dd-trace-js/tree/v4.x) | ![npm v4](https://img.shields.io/npm/v/dd-trace/latest-node16?color=white&label=%20&style=flat-square) | `>= v16` | **Maintenance** | 2023-05-12 | 2025-01-11 |
32
- | [`v5`](https://github.com/DataDog/dd-trace-js/tree/v5.x) | ![npm v5](https://img.shields.io/npm/v/dd-trace/latest?color=white&label=%20&style=flat-square) | `>= v18` | **Current** | 2024-01-11 | Unknown |
26
+ | Release Line | Latest Version | Node.js | [SSI](https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/single-step-apm/?tab=linuxhostorvm) | [K8s Injection](https://docs.datadoghq.com/tracing/trace_collection/library_injection_local/?tab=kubernetes) |Status |Initial Release | End of Life |
27
+ | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
28
+ | [`v1`](https://github.com/DataDog/dd-trace-js/tree/v1.x) | ![npm v1](https://img.shields.io/npm/v/dd-trace/legacy-v1?color=white&label=%20&style=flat-square) | `>= v12` | NO | NO | **End of Life** | 2021-07-13 | 2022-02-25 |
29
+ | [`v2`](https://github.com/DataDog/dd-trace-js/tree/v2.x) | ![npm v2](https://img.shields.io/npm/v/dd-trace/latest-node12?color=white&label=%20&style=flat-square) | `>= v12` | NO | NO | **End of Life** | 2022-01-28 | 2023-08-15 |
30
+ | [`v3`](https://github.com/DataDog/dd-trace-js/tree/v3.x) | ![npm v3](https://img.shields.io/npm/v/dd-trace/latest-node14?color=white&label=%20&style=flat-square) | `>= v14` | NO | YES | **End of Life** | 2022-08-15 | 2024-05-15 |
31
+ | [`v4`](https://github.com/DataDog/dd-trace-js/tree/v4.x) | ![npm v4](https://img.shields.io/npm/v/dd-trace/latest-node16?color=white&label=%20&style=flat-square) | `>= v16` | YES | YES | **Maintenance** | 2023-05-12 | 2025-01-11 |
32
+ | [`v5`](https://github.com/DataDog/dd-trace-js/tree/v5.x) | ![npm v5](https://img.shields.io/npm/v/dd-trace/latest?color=white&label=%20&style=flat-square) | `>= v18` | YES | YES | **Current** | 2024-01-11 | Unknown |
33
+
34
+ * SSI = Single-Step Install
33
35
 
34
36
  We currently maintain two release lines, namely `v5`, and `v4`.
35
37
  Features and bug fixes that are merged are released to the `v5` line and, if appropriate, also `v4`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.30.0",
3
+ "version": "5.32.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -33,7 +33,7 @@
33
33
  "test:lambda:ci": "nyc --no-clean --include \"packages/dd-trace/src/lambda/**/*.js\" -- npm run test:lambda",
34
34
  "test:llmobs:sdk": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" --exclude \"packages/dd-trace/test/llmobs/plugins/**/*.spec.js\" \"packages/dd-trace/test/llmobs/**/*.spec.js\" ",
35
35
  "test:llmobs:sdk:ci": "nyc --no-clean --include \"packages/dd-trace/src/llmobs/**/*.js\" -- npm run test:llmobs:sdk",
36
- "test:llmobs:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/llmobs/plugins/**/*.spec.js\"",
36
+ "test:llmobs:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/llmobs/plugins/@($(echo $PLUGINS))/*.spec.js\"",
37
37
  "test:llmobs:plugins:ci": "yarn services && nyc --no-clean --include \"packages/dd-trace/src/llmobs/**/*.js\" -- npm run test:llmobs:plugins",
38
38
  "test:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-instrumentations/test/@($(echo $PLUGINS)).spec.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/**/*.spec.js\"",
39
39
  "test:plugins:ci": "yarn services && nyc --no-clean --include \"packages/datadog-instrumentations/src/@($(echo $PLUGINS)).js\" --include \"packages/datadog-instrumentations/src/@($(echo $PLUGINS))/**/*.js\" --include \"packages/datadog-plugin-@($(echo $PLUGINS))/src/**/*.js\" -- npm run test:plugins",
@@ -81,8 +81,8 @@
81
81
  "node": ">=18"
82
82
  },
83
83
  "dependencies": {
84
- "@datadog/libdatadog": "^0.3.0",
85
- "@datadog/native-appsec": "8.3.0",
84
+ "@datadog/libdatadog": "^0.4.0",
85
+ "@datadog/native-appsec": "8.4.0",
86
86
  "@datadog/native-iast-rewriter": "2.6.1",
87
87
  "@datadog/native-iast-taint-tracking": "3.2.0",
88
88
  "@datadog/native-metrics": "^3.1.0",
@@ -111,7 +111,8 @@
111
111
  "semver": "^7.5.4",
112
112
  "shell-quote": "^1.8.1",
113
113
  "source-map": "^0.7.4",
114
- "tlhunter-sorted-set": "^0.1.0"
114
+ "tlhunter-sorted-set": "^0.1.0",
115
+ "ttl-set": "^1.0.0"
115
116
  },
116
117
  "devDependencies": {
117
118
  "@apollo/server": "^4.11.0",
@@ -145,7 +146,7 @@
145
146
  "jszip": "^3.5.0",
146
147
  "knex": "^2.4.2",
147
148
  "mkdirp": "^3.0.1",
148
- "mocha": "^9",
149
+ "mocha": "^10",
149
150
  "msgpack-lite": "^0.1.26",
150
151
  "multer": "^1.4.5-lts.1",
151
152
  "nock": "^11.3.3",
@@ -21,8 +21,16 @@ class DatadogStorage {
21
21
  this._storage.exit(callback, ...args)
22
22
  }
23
23
 
24
- getStore () {
25
- const handle = this._storage.getStore()
24
+ // TODO: Refactor the Scope class to use a span-only store and remove this.
25
+ getHandle () {
26
+ return this._storage.getStore()
27
+ }
28
+
29
+ getStore (handle) {
30
+ if (!handle) {
31
+ handle = this._storage.getStore()
32
+ }
33
+
26
34
  return stores.get(handle)
27
35
  }
28
36
 
@@ -50,6 +58,7 @@ const storage = function (namespace) {
50
58
  storage.disable = legacyStorage.disable.bind(legacyStorage)
51
59
  storage.enterWith = legacyStorage.enterWith.bind(legacyStorage)
52
60
  storage.exit = legacyStorage.exit.bind(legacyStorage)
61
+ storage.getHandle = legacyStorage.getHandle.bind(legacyStorage)
53
62
  storage.getStore = legacyStorage.getStore.bind(legacyStorage)
54
63
  storage.run = legacyStorage.run.bind(legacyStorage)
55
64
 
@@ -40,7 +40,7 @@ function wrapProcess (process) {
40
40
  addHook({
41
41
  name: 'aerospike',
42
42
  file: 'lib/commands/command.js',
43
- versions: ['4', '5']
43
+ versions: ['4', '5', '6']
44
44
  },
45
45
  commandFactory => {
46
46
  return shimmer.wrapFunction(commandFactory, f => wrapCreateCommand(f))
@@ -167,7 +167,8 @@ function getChannelSuffix (name) {
167
167
  'sns',
168
168
  'sqs',
169
169
  'states',
170
- 'stepfunctions'
170
+ 'stepfunctions',
171
+ 'bedrock runtime'
171
172
  ].includes(name)
172
173
  ? name
173
174
  : 'default'
@@ -238,8 +238,9 @@ function wrapRun (pl, isLatestVersion) {
238
238
  asyncResource.runInAsyncScope(() => {
239
239
  testStartCh.publish(testStartPayload)
240
240
  })
241
+ const promises = {}
241
242
  try {
242
- this.eventBroadcaster.on('envelope', shimmer.wrapFunction(null, () => (testCase) => {
243
+ this.eventBroadcaster.on('envelope', shimmer.wrapFunction(null, () => async (testCase) => {
243
244
  // Only supported from >=8.0.0
244
245
  if (testCase?.testCaseFinished) {
245
246
  const { testCaseFinished: { willBeRetried } } = testCase
@@ -253,17 +254,22 @@ function wrapRun (pl, isLatestVersion) {
253
254
  }
254
255
 
255
256
  const failedAttemptAsyncResource = numAttemptToAsyncResource.get(numAttempt)
256
- const isRetry = numAttempt++ > 0
257
+ const isFirstAttempt = numAttempt++ === 0
258
+
259
+ if (promises.hitBreakpointPromise) {
260
+ await promises.hitBreakpointPromise
261
+ }
262
+
257
263
  failedAttemptAsyncResource.runInAsyncScope(() => {
258
264
  // the current span will be finished and a new one will be created
259
- testRetryCh.publish({ isRetry, error })
265
+ testRetryCh.publish({ isFirstAttempt, error })
260
266
  })
261
267
 
262
268
  const newAsyncResource = new AsyncResource('bound-anonymous-fn')
263
269
  numAttemptToAsyncResource.set(numAttempt, newAsyncResource)
264
270
 
265
271
  newAsyncResource.runInAsyncScope(() => {
266
- testStartCh.publish(testStartPayload) // a new span will be created
272
+ testStartCh.publish({ ...testStartPayload, promises }) // a new span will be created
267
273
  })
268
274
  }
269
275
  }
@@ -273,7 +279,7 @@ function wrapRun (pl, isLatestVersion) {
273
279
  asyncResource.runInAsyncScope(() => {
274
280
  promise = run.apply(this, arguments)
275
281
  })
276
- promise.finally(() => {
282
+ promise.finally(async () => {
277
283
  const result = this.getWorstStepResult()
278
284
  const { status, skipReason } = isLatestVersion
279
285
  ? getStatusFromResultLatest(result)
@@ -296,6 +302,9 @@ function wrapRun (pl, isLatestVersion) {
296
302
 
297
303
  const error = getErrorFromCucumberResult(result)
298
304
 
305
+ if (promises.hitBreakpointPromise) {
306
+ await promises.hitBreakpointPromise
307
+ }
299
308
  attemptAsyncResource.runInAsyncScope(() => {
300
309
  testFinishCh.publish({ status, skipReason, error, isNew, isEfdRetry, isFlakyRetry: numAttempt > 0 })
301
310
  })
@@ -88,6 +88,7 @@ module.exports = {
88
88
  mysql2: () => require('../mysql2'),
89
89
  net: () => require('../net'),
90
90
  next: () => require('../next'),
91
+ 'node-serialize': () => require('../node-serialize'),
91
92
  'node:child_process': () => require('../child_process'),
92
93
  'node:crypto': () => require('../crypto'),
93
94
  'node:dns': () => require('../dns'),
@@ -96,6 +97,7 @@ module.exports = {
96
97
  'node:https': () => require('../http'),
97
98
  'node:net': () => require('../net'),
98
99
  'node:url': () => require('../url'),
100
+ 'node:vm': () => require('../vm'),
99
101
  nyc: () => require('../nyc'),
100
102
  oracledb: () => require('../oracledb'),
101
103
  openai: () => require('../openai'),
@@ -122,6 +124,7 @@ module.exports = {
122
124
  undici: () => require('../undici'),
123
125
  url: () => require('../url'),
124
126
  vitest: { esmFirst: true, fn: () => require('../vitest') },
127
+ vm: () => require('../vm'),
125
128
  when: () => require('../when'),
126
129
  winston: () => require('../winston'),
127
130
  workerpool: () => require('../mocha')
@@ -12,7 +12,8 @@ const {
12
12
  getTestParametersString,
13
13
  addEfdStringToTestName,
14
14
  removeEfdStringFromTestName,
15
- getIsFaultyEarlyFlakeDetection
15
+ getIsFaultyEarlyFlakeDetection,
16
+ JEST_WORKER_LOGS_PAYLOAD_CODE
16
17
  } = require('../../dd-trace/src/plugins/util/test')
17
18
  const {
18
19
  getFormattedJestTestParameters,
@@ -30,12 +31,13 @@ const testSuiteFinishCh = channel('ci:jest:test-suite:finish')
30
31
 
31
32
  const workerReportTraceCh = channel('ci:jest:worker-report:trace')
32
33
  const workerReportCoverageCh = channel('ci:jest:worker-report:coverage')
34
+ const workerReportLogsCh = channel('ci:jest:worker-report:logs')
33
35
 
34
36
  const testSuiteCodeCoverageCh = channel('ci:jest:test-suite:code-coverage')
35
37
 
36
38
  const testStartCh = channel('ci:jest:test:start')
37
39
  const testSkippedCh = channel('ci:jest:test:skip')
38
- const testRunFinishCh = channel('ci:jest:test:finish')
40
+ const testFinishCh = channel('ci:jest:test:finish')
39
41
  const testErrCh = channel('ci:jest:test:err')
40
42
 
41
43
  const skippableSuitesCh = channel('ci:jest:test-suite:skippable')
@@ -75,6 +77,8 @@ const originalTestFns = new WeakMap()
75
77
  const retriedTestsToNumAttempts = new Map()
76
78
  const newTestsTestStatuses = new Map()
77
79
 
80
+ const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
81
+
78
82
  // based on https://github.com/facebook/jest/blob/main/packages/jest-circus/src/formatNodeAssertErrors.ts#L41
79
83
  function formatJestError (errors) {
80
84
  let error
@@ -274,46 +278,70 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
274
278
  }
275
279
  }
276
280
  if (event.name === 'test_done') {
277
- const probe = {}
281
+ let status = 'pass'
282
+ if (event.test.errors && event.test.errors.length) {
283
+ status = 'fail'
284
+ }
285
+ // restore in case it is retried
286
+ event.test.fn = originalTestFns.get(event.test)
287
+
288
+ // We'll store the test statuses of the retries
289
+ if (this.isEarlyFlakeDetectionEnabled) {
290
+ const testName = getJestTestName(event.test)
291
+ const originalTestName = removeEfdStringFromTestName(testName)
292
+ const isNewTest = retriedTestsToNumAttempts.has(originalTestName)
293
+ if (isNewTest) {
294
+ if (newTestsTestStatuses.has(originalTestName)) {
295
+ newTestsTestStatuses.get(originalTestName).push(status)
296
+ } else {
297
+ newTestsTestStatuses.set(originalTestName, [status])
298
+ }
299
+ }
300
+ }
301
+
302
+ const promises = {}
303
+ const numRetries = this.global[RETRY_TIMES]
304
+ const numTestExecutions = event.test?.invocations
305
+ const willBeRetried = numRetries > 0 && numTestExecutions - 1 < numRetries
306
+ const mightHitBreakpoint = this.isDiEnabled && numTestExecutions >= 2
307
+
278
308
  const asyncResource = asyncResources.get(event.test)
279
- asyncResource.runInAsyncScope(() => {
280
- let status = 'pass'
281
- if (event.test.errors && event.test.errors.length) {
282
- status = 'fail'
283
- const numRetries = this.global[RETRY_TIMES]
284
- const numTestExecutions = event.test?.invocations
285
- const willBeRetried = numRetries > 0 && numTestExecutions - 1 < numRetries
286
-
287
- const error = formatJestError(event.test.errors[0])
309
+
310
+ if (status === 'fail') {
311
+ asyncResource.runInAsyncScope(() => {
288
312
  testErrCh.publish({
289
- error,
290
- willBeRetried,
291
- probe,
292
- isDiEnabled: this.isDiEnabled
313
+ error: formatJestError(event.test.errors[0]),
314
+ shouldSetProbe: this.isDiEnabled && willBeRetried && numTestExecutions === 1,
315
+ promises
293
316
  })
294
- }
295
- testRunFinishCh.publish({
317
+ })
318
+ }
319
+
320
+ // After finishing it might take a bit for the snapshot to be handled.
321
+ // This means that tests retried with DI are BREAKPOINT_HIT_GRACE_PERIOD_MS slower at least.
322
+ if (status === 'fail' && mightHitBreakpoint) {
323
+ await new Promise(resolve => {
324
+ setTimeout(() => {
325
+ resolve()
326
+ }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
327
+ })
328
+ }
329
+
330
+ asyncResource.runInAsyncScope(() => {
331
+ testFinishCh.publish({
296
332
  status,
297
- testStartLine: getTestLineStart(event.test.asyncError, this.testSuite)
333
+ testStartLine: getTestLineStart(event.test.asyncError, this.testSuite),
334
+ promises,
335
+ shouldRemoveProbe: this.isDiEnabled && !willBeRetried
298
336
  })
299
- // restore in case it is retried
300
- event.test.fn = originalTestFns.get(event.test)
301
- // We'll store the test statuses of the retries
302
- if (this.isEarlyFlakeDetectionEnabled) {
303
- const testName = getJestTestName(event.test)
304
- const originalTestName = removeEfdStringFromTestName(testName)
305
- const isNewTest = retriedTestsToNumAttempts.has(originalTestName)
306
- if (isNewTest) {
307
- if (newTestsTestStatuses.has(originalTestName)) {
308
- newTestsTestStatuses.get(originalTestName).push(status)
309
- } else {
310
- newTestsTestStatuses.set(originalTestName, [status])
311
- }
312
- }
313
- }
314
337
  })
315
- if (probe.setProbePromise) {
316
- await probe.setProbePromise
338
+
339
+ if (promises.isProbeReady) {
340
+ await promises.isProbeReady
341
+ }
342
+
343
+ if (promises.isProbeRemoved) {
344
+ await promises.isProbeRemoved
317
345
  }
318
346
  }
319
347
  if (event.name === 'test_skip' || event.name === 'test_todo') {
@@ -953,6 +981,12 @@ addHook({
953
981
  })
954
982
  return
955
983
  }
984
+ if (code === JEST_WORKER_LOGS_PAYLOAD_CODE) { // datadog logs payload
985
+ sessionAsyncResource.runInAsyncScope(() => {
986
+ workerReportLogsCh.publish(data)
987
+ })
988
+ return
989
+ }
956
990
  return _onMessage.apply(this, arguments)
957
991
  })
958
992
  return childProcessWorker
@@ -19,6 +19,7 @@ const skipCh = channel('ci:mocha:test:skip')
19
19
  // suite channels
20
20
  const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
21
21
 
22
+ const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
22
23
  const testToAr = new WeakMap()
23
24
  const originalFns = new WeakMap()
24
25
  const testToStartLine = new WeakMap()
@@ -73,7 +74,7 @@ function isMochaRetry (test) {
73
74
  return test._currentRetry !== undefined && test._currentRetry !== 0
74
75
  }
75
76
 
76
- function isLastRetry (test) {
77
+ function getIsLastRetry (test) {
77
78
  return test._currentRetry === test._retries
78
79
  }
79
80
 
@@ -203,14 +204,28 @@ function getOnTestHandler (isMain) {
203
204
  }
204
205
 
205
206
  function getOnTestEndHandler () {
206
- return function (test) {
207
+ return async function (test) {
207
208
  const asyncResource = getTestAsyncResource(test)
208
209
  const status = getTestStatus(test)
209
210
 
211
+ // After finishing it might take a bit for the snapshot to be handled.
212
+ // This means that tests retried with DI are BREAKPOINT_HIT_GRACE_PERIOD_MS slower at least.
213
+ if (test._ddShouldWaitForHitProbe || test._retriedTest?._ddShouldWaitForHitProbe) {
214
+ await new Promise((resolve) => {
215
+ setTimeout(() => {
216
+ resolve()
217
+ }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
218
+ })
219
+ }
220
+
210
221
  // if there are afterEach to be run, we don't finish the test yet
211
222
  if (asyncResource && !test.parent._afterEach.length) {
212
223
  asyncResource.runInAsyncScope(() => {
213
- testFinishCh.publish({ status, hasBeenRetried: isMochaRetry(test) })
224
+ testFinishCh.publish({
225
+ status,
226
+ hasBeenRetried: isMochaRetry(test),
227
+ isLastRetry: getIsLastRetry(test)
228
+ })
214
229
  })
215
230
  }
216
231
  }
@@ -220,16 +235,17 @@ function getOnHookEndHandler () {
220
235
  return function (hook) {
221
236
  const test = hook.ctx.currentTest
222
237
  if (test && hook.parent._afterEach.includes(hook)) { // only if it's an afterEach
223
- const isLastAfterEach = hook.parent._afterEach.indexOf(hook) === hook.parent._afterEach.length - 1
224
- if (test._retries > 0 && !isLastRetry(test)) {
238
+ const isLastRetry = getIsLastRetry(test)
239
+ if (test._retries > 0 && !isLastRetry) {
225
240
  return
226
241
  }
242
+ const isLastAfterEach = hook.parent._afterEach.indexOf(hook) === hook.parent._afterEach.length - 1
227
243
  if (isLastAfterEach) {
228
244
  const status = getTestStatus(test)
229
245
  const asyncResource = getTestAsyncResource(test)
230
246
  if (asyncResource) {
231
247
  asyncResource.runInAsyncScope(() => {
232
- testFinishCh.publish({ status, hasBeenRetried: isMochaRetry(test) })
248
+ testFinishCh.publish({ status, hasBeenRetried: isMochaRetry(test), isLastRetry })
233
249
  })
234
250
  }
235
251
  }
@@ -286,7 +302,7 @@ function getOnTestRetryHandler () {
286
302
  const isFirstAttempt = test._currentRetry === 0
287
303
  const willBeRetried = test._currentRetry < test._retries
288
304
  asyncResource.runInAsyncScope(() => {
289
- testRetryCh.publish({ isFirstAttempt, err, willBeRetried })
305
+ testRetryCh.publish({ isFirstAttempt, err, willBeRetried, test })
290
306
  })
291
307
  }
292
308
  const key = getTestToArKey(test)
@@ -0,0 +1,22 @@
1
+ 'use strict'
2
+
3
+ const shimmer = require('../../datadog-shimmer')
4
+ const { channel, addHook } = require('./helpers/instrument')
5
+
6
+ const nodeUnserializeCh = channel('datadog:node-serialize:unserialize:start')
7
+
8
+ function wrapUnserialize (serialize) {
9
+ return function wrappedUnserialize (obj) {
10
+ if (nodeUnserializeCh.hasSubscribers) {
11
+ nodeUnserializeCh.publish({ obj })
12
+ }
13
+
14
+ return serialize.apply(this, arguments)
15
+ }
16
+ }
17
+
18
+ addHook({ name: 'node-serialize', versions: ['0.0.4'] }, serialize => {
19
+ shimmer.wrap(serialize, 'unserialize', wrapUnserialize)
20
+
21
+ return serialize
22
+ })
@@ -338,6 +338,8 @@ for (const shim of V4_PACKAGE_SHIMS) {
338
338
  })
339
339
  })
340
340
 
341
+ ch.end.publish(ctx)
342
+
341
343
  return apiProm
342
344
  })
343
345
  })