dd-trace 5.17.0 → 5.18.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 (63) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/ext/exporters.d.ts +1 -1
  3. package/index.d.ts +47 -1
  4. package/init.js +40 -1
  5. package/initialize.mjs +8 -5
  6. package/package.json +24 -20
  7. package/packages/datadog-core/src/storage/index.js +1 -10
  8. package/packages/datadog-esbuild/index.js +5 -1
  9. package/packages/datadog-instrumentations/src/aws-sdk.js +2 -1
  10. package/packages/datadog-instrumentations/src/cucumber.js +76 -34
  11. package/packages/datadog-instrumentations/src/helpers/hook.js +8 -3
  12. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  13. package/packages/datadog-instrumentations/src/helpers/instrument.js +4 -3
  14. package/packages/datadog-instrumentations/src/helpers/register.js +56 -5
  15. package/packages/datadog-instrumentations/src/mocha/main.js +12 -1
  16. package/packages/datadog-instrumentations/src/mocha/utils.js +58 -14
  17. package/packages/datadog-instrumentations/src/mocha/worker.js +1 -0
  18. package/packages/datadog-instrumentations/src/playwright.js +1 -1
  19. package/packages/datadog-instrumentations/src/vitest.js +303 -0
  20. package/packages/datadog-plugin-aws-sdk/src/base.js +8 -1
  21. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +9 -3
  22. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +6 -1
  23. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +23 -5
  24. package/packages/datadog-plugin-child_process/src/index.js +1 -1
  25. package/packages/datadog-plugin-cucumber/src/index.js +24 -1
  26. package/packages/datadog-plugin-mocha/src/index.js +25 -4
  27. package/packages/datadog-plugin-openai/src/index.js +52 -30
  28. package/packages/datadog-plugin-openai/src/token-estimator.js +20 -0
  29. package/packages/datadog-plugin-vitest/src/index.js +156 -0
  30. package/packages/dd-trace/src/appsec/iast/path-line.js +2 -19
  31. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -0
  32. package/packages/dd-trace/src/appsec/index.js +1 -1
  33. package/packages/dd-trace/src/appsec/rasp.js +32 -5
  34. package/packages/dd-trace/src/appsec/recommended.json +208 -3
  35. package/packages/dd-trace/src/appsec/reporter.js +64 -20
  36. package/packages/dd-trace/src/appsec/sdk/track_event.js +3 -0
  37. package/packages/dd-trace/src/appsec/stack_trace.js +90 -0
  38. package/packages/dd-trace/src/appsec/standalone.js +130 -0
  39. package/packages/dd-trace/src/appsec/telemetry.js +33 -1
  40. package/packages/dd-trace/src/appsec/waf/index.js +2 -2
  41. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +2 -2
  42. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
  43. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
  44. package/packages/dd-trace/src/config.js +110 -40
  45. package/packages/dd-trace/src/constants.js +3 -1
  46. package/packages/dd-trace/src/datastreams/processor.js +2 -1
  47. package/packages/dd-trace/src/exporters/agent/index.js +2 -2
  48. package/packages/dd-trace/src/format.js +1 -0
  49. package/packages/dd-trace/src/opentracing/propagation/text_map.js +12 -0
  50. package/packages/dd-trace/src/opentracing/span.js +4 -1
  51. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  52. package/packages/dd-trace/src/plugins/ci_plugin.js +7 -0
  53. package/packages/dd-trace/src/plugins/index.js +2 -0
  54. package/packages/dd-trace/src/plugins/util/test.js +5 -1
  55. package/packages/dd-trace/src/priority_sampler.js +2 -5
  56. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  57. package/packages/dd-trace/src/proxy.js +3 -1
  58. package/packages/dd-trace/src/rate_limiter.js +2 -2
  59. package/packages/dd-trace/src/span_stats.js +4 -3
  60. package/packages/dd-trace/src/telemetry/init-telemetry.js +75 -0
  61. package/packages/dd-trace/src/tracer.js +2 -2
  62. package/packages/dd-trace/src/util.js +6 -1
  63. package/packages/datadog-core/src/storage/async_hooks.js +0 -49
@@ -64,6 +64,7 @@ dev,sinon,BSD-3-Clause,Copyright 2010-2017 Christian Johansen
64
64
  dev,sinon-chai,WTFPL and BSD-2-Clause,Copyright 2004 Sam Hocevar 2012–2017 Domenic Denicola
65
65
  dev,tap,ISC,Copyright 2011-2022 Isaac Z. Schlueter and Contributors
66
66
  dev,tape,MIT,Copyright James Halliday
67
+ dev,tiktoken,MIT,Copyright (c) 2022 OpenAI, Shantanu Jain
67
68
  file,aws-lambda-nodejs-runtime-interface-client,Apache 2.0,Copyright 2019 Amazon.com Inc. or its affiliates. All Rights Reserved.
68
69
  file,profile.proto,Apache license 2.0,Copyright 2016 Google Inc.
69
70
  file,is-git-url,MIT,Copyright (c) 2017 Jon Schlinkert.
@@ -4,7 +4,7 @@ declare const exporters: {
4
4
  DATADOG: 'datadog',
5
5
  AGENT_PROXY: 'agent_proxy',
6
6
  JEST_WORKER: 'jest_worker',
7
- CUCUMBER_WORKER: 'cucumber_worker'
7
+ CUCUMBER_WORKER: 'cucumber_worker',
8
8
  MOCHA_WORKER: 'mocha_worker'
9
9
  }
10
10
 
package/index.d.ts CHANGED
@@ -198,6 +198,7 @@ interface Plugins {
198
198
  "sharedb": tracer.plugins.sharedb;
199
199
  "tedious": tracer.plugins.tedious;
200
200
  "undici": tracer.plugins.undici;
201
+ "vitest": tracer.plugins.vitest;
201
202
  "winston": tracer.plugins.winston;
202
203
  }
203
204
 
@@ -556,6 +557,19 @@ declare namespace tracer {
556
557
  */
557
558
  redactionValuePattern?: string
558
559
  }
560
+
561
+ appsec?: {
562
+ /**
563
+ * Configuration of Standalone ASM mode
564
+ */
565
+ standalone?: {
566
+ /**
567
+ * Whether to enable Standalone ASM.
568
+ * @default false
569
+ */
570
+ enabled?: boolean
571
+ }
572
+ }
559
573
  };
560
574
 
561
575
  /**
@@ -700,6 +714,25 @@ declare namespace tracer {
700
714
  * @default false
701
715
  */
702
716
  enabled?: boolean
717
+ },
718
+ /**
719
+ * Configuration for stack trace reporting
720
+ */
721
+ stackTrace?: {
722
+ /** Whether to enable stack trace reporting.
723
+ * @default true
724
+ */
725
+ enabled?: boolean,
726
+
727
+ /** Specifies the maximum number of stack traces to be reported.
728
+ * @default 2
729
+ */
730
+ maxStackTraces?: number,
731
+
732
+ /** Specifies the maximum depth of a stack trace to be reported.
733
+ * @default 32
734
+ */
735
+ maxDepth?: number,
703
736
  }
704
737
  };
705
738
 
@@ -1190,6 +1223,13 @@ declare namespace tracer {
1190
1223
  */
1191
1224
  splitByAwsService?: boolean;
1192
1225
 
1226
+ /**
1227
+ * Whether to inject all messages during batch AWS SQS, Kinesis, and SNS send operations. Normal
1228
+ * behavior is to inject the first message in batch send operations.
1229
+ * @default false
1230
+ */
1231
+ batchPropagationEnabled?: boolean;
1232
+
1193
1233
  /**
1194
1234
  * Hooks to run before spans are finished.
1195
1235
  */
@@ -1524,7 +1564,7 @@ declare namespace tracer {
1524
1564
 
1525
1565
  /**
1526
1566
  * This plugin automatically instruments the
1527
- * [jest](https://github.com/facebook/jest) module.
1567
+ * [jest](https://github.com/jestjs/jest) module.
1528
1568
  */
1529
1569
  interface jest extends Integration {}
1530
1570
 
@@ -1807,6 +1847,12 @@ declare namespace tracer {
1807
1847
  */
1808
1848
  interface undici extends HttpClient {}
1809
1849
 
1850
+ /**
1851
+ * This plugin automatically instruments the
1852
+ * [vitest](https://github.com/vitest-dev/vitest) module.
1853
+ */
1854
+ interface vitest extends Integration {}
1855
+
1810
1856
  /**
1811
1857
  * This plugin patches the [winston](https://github.com/winstonjs/winston)
1812
1858
  * to automatically inject trace identifiers in log records when the
package/init.js CHANGED
@@ -2,8 +2,26 @@
2
2
 
3
3
  const path = require('path')
4
4
  const Module = require('module')
5
+ const telemetry = require('./packages/dd-trace/src/telemetry/init-telemetry')
6
+ const semver = require('semver')
7
+
8
+ function isTrue (envVar) {
9
+ return ['1', 'true', 'True'].includes(envVar)
10
+ }
11
+
12
+ // eslint-disable-next-line no-console
13
+ let log = { info: isTrue(process.env.DD_TRACE_DEBUG) ? console.log : () => {} }
14
+ if (semver.satisfies(process.versions.node, '>=16')) {
15
+ const Config = require('./packages/dd-trace/src/config')
16
+ log = require('./packages/dd-trace/src/log')
17
+
18
+ // eslint-disable-next-line no-new
19
+ new Config() // we need this to initialize the logger
20
+ }
5
21
 
6
22
  let initBailout = false
23
+ let clobberBailout = false
24
+ const forced = isTrue(process.env.DD_INJECT_FORCE)
7
25
 
8
26
  if (process.env.DD_INJECTION_ENABLED) {
9
27
  // If we're running via single-step install, and we're not in the app's
@@ -19,13 +37,34 @@ if (process.env.DD_INJECTION_ENABLED) {
19
37
  if (resolvedInApp) {
20
38
  const ourselves = path.join(__dirname, 'index.js')
21
39
  if (ourselves !== resolvedInApp) {
40
+ clobberBailout = true
41
+ }
42
+ }
43
+
44
+ // If we're running via single-step install, and the runtime doesn't match
45
+ // the engines field in package.json, then we should not initialize the tracer.
46
+ if (!clobberBailout) {
47
+ const { engines } = require('./package.json')
48
+ const version = process.versions.node
49
+ if (!semver.satisfies(version, engines.node)) {
22
50
  initBailout = true
51
+ telemetry([
52
+ { name: 'abort', tags: ['reason:incompatible_runtime'] },
53
+ { name: 'abort.runtime', tags: [] }
54
+ ])
55
+ log.info('Aborting application instrumentation due to incompatible_runtime.')
56
+ log.info(`Found incompatible runtime nodejs ${version}, Supported runtimes: nodejs ${engines.node}.`)
57
+ if (forced) {
58
+ log.info('DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.')
59
+ }
23
60
  }
24
61
  }
25
62
  }
26
63
 
27
- if (!initBailout) {
64
+ if (!clobberBailout && (!initBailout || forced)) {
28
65
  const tracer = require('.')
29
66
  tracer.init()
30
67
  module.exports = tracer
68
+ telemetry('complete', [`injection_forced:${forced && initBailout ? 'true' : 'false'}`])
69
+ log.info('Application instrumentation bootstrapping complete')
31
70
  }
package/initialize.mjs CHANGED
@@ -44,9 +44,12 @@ export async function getSource (...args) {
44
44
  }
45
45
 
46
46
  if (isMainThread) {
47
- await import('./init.js')
48
- const { register } = await import('node:module')
49
- if (register) {
50
- register('./loader-hook.mjs', import.meta.url)
51
- }
47
+ // Need this IIFE for versions of Node.js without top-level await.
48
+ (async () => {
49
+ await import('./init.js')
50
+ const { register } = await import('node:module')
51
+ if (register) {
52
+ register('./loader-hook.mjs', import.meta.url)
53
+ }
54
+ })()
52
55
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.17.0",
3
+ "version": "5.18.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -14,34 +14,37 @@
14
14
  "type:test": "cd docs && yarn && yarn test",
15
15
  "lint": "node scripts/check_licenses.js && eslint . && yarn audit --groups dependencies",
16
16
  "services": "node ./scripts/install_plugin_modules && node packages/dd-trace/test/setup/services",
17
- "test": "SERVICES=* yarn services && mocha --colors --exit --expose-gc 'packages/dd-trace/test/setup/node.js' 'packages/*/test/**/*.spec.js'",
18
- "test:appsec": "mocha --colors --exit -r \"packages/dd-trace/test/setup/mocha.js\" --exclude \"packages/dd-trace/test/appsec/**/*.plugin.spec.js\" \"packages/dd-trace/test/appsec/**/*.spec.js\"",
17
+ "test": "SERVICES=* yarn services && mocha --expose-gc 'packages/dd-trace/test/setup/node.js' 'packages/*/test/**/*.spec.js'",
18
+ "test:appsec": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" --exclude \"packages/dd-trace/test/appsec/**/*.plugin.spec.js\" \"packages/dd-trace/test/appsec/**/*.spec.js\"",
19
19
  "test:appsec:ci": "nyc --no-clean --include \"packages/dd-trace/src/appsec/**/*.js\" --exclude \"packages/dd-trace/test/appsec/**/*.plugin.spec.js\" -- npm run test:appsec",
20
- "test:appsec:plugins": "mocha --colors --exit -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/appsec/**/*.@($(echo $PLUGINS)).plugin.spec.js\"",
20
+ "test:appsec:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/appsec/**/*.@($(echo $PLUGINS)).plugin.spec.js\"",
21
21
  "test:appsec:plugins:ci": "yarn services && nyc --no-clean --include \"packages/dd-trace/src/appsec/**/*.js\" -- npm run test:appsec:plugins",
22
22
  "test:trace:core": "tap packages/dd-trace/test/*.spec.js \"packages/dd-trace/test/{ci-visibility,datastreams,encode,exporters,opentelemetry,opentracing,plugins,service-naming,telemetry}/**/*.spec.js\"",
23
23
  "test:trace:core:ci": "npm run test:trace:core -- --coverage --nyc-arg=--include=\"packages/dd-trace/src/**/*.js\"",
24
- "test:instrumentations": "mocha --colors -r 'packages/dd-trace/test/setup/mocha.js' 'packages/datadog-instrumentations/test/**/*.spec.js'",
24
+ "test:instrumentations": "mocha -r 'packages/dd-trace/test/setup/mocha.js' 'packages/datadog-instrumentations/test/**/*.spec.js'",
25
25
  "test:instrumentations:ci": "nyc --no-clean --include 'packages/datadog-instrumentations/src/**/*.js' -- npm run test:instrumentations",
26
26
  "test:core": "tap \"packages/datadog-core/test/**/*.spec.js\"",
27
27
  "test:core:ci": "npm run test:core -- --coverage --nyc-arg=--include=\"packages/datadog-core/src/**/*.js\"",
28
- "test:lambda": "mocha --colors --exit -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/lambda/**/*.spec.js\"",
28
+ "test:lambda": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/lambda/**/*.spec.js\"",
29
29
  "test:lambda:ci": "nyc --no-clean --include \"packages/dd-trace/src/lambda/**/*.js\" -- npm run test:lambda",
30
- "test:plugins": "mocha --colors --exit -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-instrumentations/test/@($(echo $PLUGINS)).spec.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/**/*.spec.js\"",
30
+ "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\"",
31
31
  "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",
32
32
  "test:plugins:upstream": "node ./packages/dd-trace/test/plugins/suite.js",
33
33
  "test:profiler": "tap \"packages/dd-trace/test/profiling/**/*.spec.js\"",
34
34
  "test:profiler:ci": "npm run test:profiler -- --coverage --nyc-arg=--include=\"packages/dd-trace/src/profiling/**/*.js\"",
35
- "test:integration": "mocha --colors --timeout 30000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/*.spec.js\"",
36
- "test:integration:cucumber": "mocha --colors --timeout 30000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/cucumber/*.spec.js\"",
37
- "test:integration:cypress": "mocha --colors --timeout 30000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/cypress/*.spec.js\"",
38
- "test:integration:playwright": "mocha --colors --timeout 30000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/playwright/*.spec.js\"",
39
- "test:integration:selenium": "mocha --colors --timeout 30000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/selenium/*.spec.js\"",
40
- "test:integration:profiler": "mocha --colors --timeout 90000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/profiler/*.spec.js\"",
41
- "test:integration:serverless": "mocha --colors --timeout 30000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/serverless/*.spec.js\"",
42
- "test:integration:plugins": "mocha --colors --exit -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/integration-test/**/*.spec.js\"",
43
- "test:unit:plugins": "mocha --colors --exit -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-instrumentations/test/@($(echo $PLUGINS)).spec.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/**/*.spec.js\" --exclude \"packages/datadog-plugin-@($(echo $PLUGINS))/test/integration-test/**/*.spec.js\"",
44
- "test:shimmer": "mocha --colors 'packages/datadog-shimmer/test/**/*.spec.js'",
35
+ "test:integration": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/*.spec.js\"",
36
+ "test:integration:cucumber": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/cucumber/*.spec.js\"",
37
+ "test:integration:cypress": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/cypress/*.spec.js\"",
38
+ "test:integration:jest": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/jest/*.spec.js\"",
39
+ "test:integration:mocha": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/mocha/*.spec.js\"",
40
+ "test:integration:playwright": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/playwright/*.spec.js\"",
41
+ "test:integration:selenium": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/selenium/*.spec.js\"",
42
+ "test:integration:vitest": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/vitest/*.spec.js\"",
43
+ "test:integration:profiler": "mocha --timeout 180000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/profiler/*.spec.js\"",
44
+ "test:integration:serverless": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/serverless/*.spec.js\"",
45
+ "test:integration:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/integration-test/**/*.spec.js\"",
46
+ "test:unit: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\" --exclude \"packages/datadog-plugin-@($(echo $PLUGINS))/test/integration-test/**/*.spec.js\"",
47
+ "test:shimmer": "mocha 'packages/datadog-shimmer/test/**/*.spec.js'",
45
48
  "test:shimmer:ci": "nyc --no-clean --include 'packages/datadog-shimmer/src/**/*.js' -- npm run test:shimmer",
46
49
  "leak:core": "node ./scripts/install_plugin_modules && (cd packages/memwatch && yarn) && NODE_PATH=./packages/memwatch/node_modules node --no-warnings ./node_modules/.bin/tape 'packages/dd-trace/test/leak/**/*.js'",
47
50
  "leak:plugins": "yarn services && (cd packages/memwatch && yarn) && NODE_PATH=./packages/memwatch/node_modules node --no-warnings ./node_modules/.bin/tape \"packages/datadog-plugin-@($(echo $PLUGINS))/test/leak.js\""
@@ -72,7 +75,7 @@
72
75
  "dependencies": {
73
76
  "@datadog/native-appsec": "8.0.1",
74
77
  "@datadog/native-iast-rewriter": "2.3.1",
75
- "@datadog/native-iast-taint-tracking": "2.1.0",
78
+ "@datadog/native-iast-taint-tracking": "3.0.0",
76
79
  "@datadog/native-metrics": "^2.0.0",
77
80
  "@datadog/pprof": "5.3.0",
78
81
  "@datadog/sketches-js": "^2.1.0",
@@ -81,7 +84,7 @@
81
84
  "crypto-randomuuid": "^1.0.0",
82
85
  "dc-polyfill": "^0.1.4",
83
86
  "ignore": "^5.2.4",
84
- "import-in-the-middle": "^1.7.4",
87
+ "import-in-the-middle": "^1.8.1",
85
88
  "int64-buffer": "^0.1.9",
86
89
  "istanbul-lib-coverage": "3.2.0",
87
90
  "jest-docblock": "^29.7.0",
@@ -136,6 +139,7 @@
136
139
  "sinon": "^15.2.0",
137
140
  "sinon-chai": "^3.7.0",
138
141
  "tap": "^16.3.7",
139
- "tape": "^5.6.5"
142
+ "tape": "^5.6.5",
143
+ "tiktoken": "^1.0.15"
140
144
  }
141
145
  }
@@ -2,13 +2,4 @@
2
2
 
3
3
  // TODO: default to AsyncLocalStorage when it supports triggerAsyncResource
4
4
 
5
- const semver = require('semver')
6
-
7
- // https://github.com/nodejs/node/pull/33801
8
- const hasJavaScriptAsyncHooks = semver.satisfies(process.versions.node, '>=14.5')
9
-
10
- if (hasJavaScriptAsyncHooks) {
11
- module.exports = require('./async_resource')
12
- } else {
13
- module.exports = require('./async_hooks')
14
- }
5
+ module.exports = require('./async_resource')
@@ -7,7 +7,11 @@ const hooks = require('../datadog-instrumentations/src/helpers/hooks.js')
7
7
  const extractPackageAndModulePath = require('../datadog-instrumentations/src/utils/src/extract-package-and-module-path')
8
8
 
9
9
  for (const hook of Object.values(hooks)) {
10
- hook()
10
+ if (typeof hook === 'object') {
11
+ hook.fn()
12
+ } else {
13
+ hook()
14
+ }
11
15
  }
12
16
 
13
17
  const modulesOfInterest = new Set()
@@ -20,7 +20,8 @@ function wrapRequest (send) {
20
20
 
21
21
  return innerAr.runInAsyncScope(() => {
22
22
  this.on('complete', innerAr.bind(response => {
23
- channel(`apm:aws:request:complete:${channelSuffix}`).publish({ response })
23
+ const cbExists = typeof cb === 'function'
24
+ channel(`apm:aws:request:complete:${channelSuffix}`).publish({ response, cbExists })
24
25
  }))
25
26
 
26
27
  startCh.publish({
@@ -1,11 +1,13 @@
1
1
  'use strict'
2
2
  const { createCoverageMap } = require('istanbul-lib-coverage')
3
3
 
4
+ const { NUM_FAILED_TEST_RETRIES } = require('../../dd-trace/src/plugins/util/test')
4
5
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
5
6
  const shimmer = require('../../datadog-shimmer')
6
7
  const log = require('../../dd-trace/src/log')
7
8
 
8
9
  const testStartCh = channel('ci:cucumber:test:start')
10
+ const testRetryCh = channel('ci:cucumber:test:retry')
9
11
  const testFinishCh = channel('ci:cucumber:test:finish') // used for test steps too
10
12
 
11
13
  const testStepStartCh = channel('ci:cucumber:test-step:start')
@@ -47,6 +49,7 @@ const patched = new WeakSet()
47
49
 
48
50
  const lastStatusByPickleId = new Map()
49
51
  const numRetriesByPickleId = new Map()
52
+ const numAttemptToAsyncResource = new Map()
50
53
 
51
54
  let pickleByFile = {}
52
55
  const pickleResultByFile = {}
@@ -60,6 +63,7 @@ let isUnskippable = false
60
63
  let isSuitesSkippingEnabled = false
61
64
  let isEarlyFlakeDetectionEnabled = false
62
65
  let earlyFlakeDetectionNumRetries = 0
66
+ let isFlakyTestRetriesEnabled = false
63
67
  let knownTests = []
64
68
  let skippedSuites = []
65
69
  let isSuitesSkipped = false
@@ -162,47 +166,80 @@ function wrapRun (pl, isLatestVersion) {
162
166
  return run.apply(this, arguments)
163
167
  }
164
168
 
169
+ let numAttempt = 0
170
+
165
171
  const asyncResource = new AsyncResource('bound-anonymous-fn')
166
- return asyncResource.runInAsyncScope(() => {
167
- const testFileAbsolutePath = this.pickle.uri
168
172
 
169
- const testSourceLine = this.gherkinDocument?.feature?.location?.line
173
+ numAttemptToAsyncResource.set(numAttempt, asyncResource)
170
174
 
171
- testStartCh.publish({
172
- testName: this.pickle.name,
173
- testFileAbsolutePath,
174
- testSourceLine,
175
- isParallel: !!process.env.CUCUMBER_WORKER_ID
176
- })
177
- try {
178
- const promise = run.apply(this, arguments)
179
- promise.finally(() => {
180
- const result = this.getWorstStepResult()
181
- const { status, skipReason, errorMessage } = isLatestVersion
182
- ? getStatusFromResultLatest(result)
183
- : getStatusFromResult(result)
175
+ const testFileAbsolutePath = this.pickle.uri
184
176
 
185
- if (lastStatusByPickleId.has(this.pickle.id)) {
186
- lastStatusByPickleId.get(this.pickle.id).push(status)
187
- } else {
188
- lastStatusByPickleId.set(this.pickle.id, [status])
189
- }
190
- let isNew = false
191
- let isEfdRetry = false
192
- if (isEarlyFlakeDetectionEnabled && status !== 'skip') {
193
- const numRetries = numRetriesByPickleId.get(this.pickle.id)
177
+ const testSourceLine = this.gherkinDocument?.feature?.location?.line
194
178
 
195
- isNew = numRetries !== undefined
196
- isEfdRetry = numRetries > 0
179
+ const testStartPayload = {
180
+ testName: this.pickle.name,
181
+ testFileAbsolutePath,
182
+ testSourceLine,
183
+ isParallel: !!process.env.CUCUMBER_WORKER_ID
184
+ }
185
+ asyncResource.runInAsyncScope(() => {
186
+ testStartCh.publish(testStartPayload)
187
+ })
188
+ try {
189
+ this.eventBroadcaster.on('envelope', (testCase) => {
190
+ // Only supported from >=8.0.0
191
+ if (testCase?.testCaseFinished) {
192
+ const { testCaseFinished: { willBeRetried } } = testCase
193
+ if (willBeRetried) { // test case failed and will be retried
194
+ const failedAttemptAsyncResource = numAttemptToAsyncResource.get(numAttempt)
195
+ failedAttemptAsyncResource.runInAsyncScope(() => {
196
+ testRetryCh.publish(numAttempt++ > 0) // the current span will be finished and a new one will be created
197
+ })
198
+
199
+ const newAsyncResource = new AsyncResource('bound-anonymous-fn')
200
+ numAttemptToAsyncResource.set(numAttempt, newAsyncResource)
201
+
202
+ newAsyncResource.runInAsyncScope(() => {
203
+ testStartCh.publish(testStartPayload) // a new span will be created
204
+ })
197
205
  }
198
- testFinishCh.publish({ status, skipReason, errorMessage, isNew, isEfdRetry })
206
+ }
207
+ })
208
+ let promise
209
+
210
+ asyncResource.runInAsyncScope(() => {
211
+ promise = run.apply(this, arguments)
212
+ })
213
+ promise.finally(() => {
214
+ const result = this.getWorstStepResult()
215
+ const { status, skipReason, errorMessage } = isLatestVersion
216
+ ? getStatusFromResultLatest(result)
217
+ : getStatusFromResult(result)
218
+
219
+ if (lastStatusByPickleId.has(this.pickle.id)) {
220
+ lastStatusByPickleId.get(this.pickle.id).push(status)
221
+ } else {
222
+ lastStatusByPickleId.set(this.pickle.id, [status])
223
+ }
224
+ let isNew = false
225
+ let isEfdRetry = false
226
+ if (isEarlyFlakeDetectionEnabled && status !== 'skip') {
227
+ const numRetries = numRetriesByPickleId.get(this.pickle.id)
228
+
229
+ isNew = numRetries !== undefined
230
+ isEfdRetry = numRetries > 0
231
+ }
232
+ const attemptAsyncResource = numAttemptToAsyncResource.get(numAttempt)
233
+
234
+ attemptAsyncResource.runInAsyncScope(() => {
235
+ testFinishCh.publish({ status, skipReason, errorMessage, isNew, isEfdRetry, isFlakyRetry: numAttempt > 0 })
199
236
  })
200
- return promise
201
- } catch (err) {
202
- errorCh.publish(err)
203
- throw err
204
- }
205
- })
237
+ })
238
+ return promise
239
+ } catch (err) {
240
+ errorCh.publish(err)
241
+ throw err
242
+ }
206
243
  })
207
244
  shimmer.wrap(pl.prototype, 'runStep', runStep => function () {
208
245
  if (!testStepStartCh.hasSubscribers) {
@@ -267,6 +304,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false) {
267
304
  isEarlyFlakeDetectionEnabled = configurationResponse.libraryConfig?.isEarlyFlakeDetectionEnabled
268
305
  earlyFlakeDetectionNumRetries = configurationResponse.libraryConfig?.earlyFlakeDetectionNumRetries
269
306
  isSuitesSkippingEnabled = configurationResponse.libraryConfig?.isSuitesSkippingEnabled
307
+ isFlakyTestRetriesEnabled = configurationResponse.libraryConfig?.isFlakyTestRetriesEnabled
270
308
 
271
309
  if (isEarlyFlakeDetectionEnabled) {
272
310
  const knownTestsResponse = await getChannelPromise(knownTestsCh)
@@ -304,6 +342,10 @@ function getWrappedStart (start, frameworkVersion, isParallel = false) {
304
342
  const processArgv = process.argv.slice(2).join(' ')
305
343
  const command = process.env.npm_lifecycle_script || `cucumber-js ${processArgv}`
306
344
 
345
+ if (isFlakyTestRetriesEnabled && !this.options.retry) {
346
+ this.options.retry = NUM_FAILED_TEST_RETRIES
347
+ }
348
+
307
349
  sessionAsyncResource.runInAsyncScope(() => {
308
350
  sessionStartCh.publish({ command, frameworkVersion })
309
351
  })
@@ -11,8 +11,13 @@ const ritm = require('../../../dd-trace/src/ritm')
11
11
  * @param {string[]} modules list of modules to hook into
12
12
  * @param {Function} onrequire callback to be executed upon encountering module
13
13
  */
14
- function Hook (modules, onrequire) {
15
- if (!(this instanceof Hook)) return new Hook(modules, onrequire)
14
+ function Hook (modules, hookOptions, onrequire) {
15
+ if (!(this instanceof Hook)) return new Hook(modules, hookOptions, onrequire)
16
+
17
+ if (typeof hookOptions === 'function') {
18
+ onrequire = hookOptions
19
+ hookOptions = {}
20
+ }
16
21
 
17
22
  this._patched = Object.create(null)
18
23
 
@@ -28,7 +33,7 @@ function Hook (modules, onrequire) {
28
33
  }
29
34
 
30
35
  this._ritmHook = ritm(modules, {}, safeHook)
31
- this._iitmHook = iitm(modules, {}, (moduleExports, moduleName, moduleBaseDir) => {
36
+ this._iitmHook = iitm(modules, hookOptions, (moduleExports, moduleName, moduleBaseDir) => {
32
37
  // TODO: Move this logic to import-in-the-middle and only do it for CommonJS
33
38
  // modules and not ESM. In the meantime, all the modules we instrument are
34
39
  // CommonJS modules for which the default export is always moved to
@@ -23,6 +23,7 @@ module.exports = {
23
23
  '@opentelemetry/sdk-trace-node': () => require('../otel-sdk-trace'),
24
24
  '@redis/client': () => require('../redis'),
25
25
  '@smithy/smithy-client': () => require('../aws-sdk'),
26
+ '@vitest/runner': { esmFirst: true, fn: () => require('../vitest') },
26
27
  aerospike: () => require('../aerospike'),
27
28
  amqp10: () => require('../amqp10'),
28
29
  amqplib: () => require('../amqplib'),
@@ -110,6 +111,7 @@ module.exports = {
110
111
  sharedb: () => require('../sharedb'),
111
112
  tedious: () => require('../tedious'),
112
113
  undici: () => require('../undici'),
114
+ vitest: { esmFirst: true, fn: () => require('../vitest') },
113
115
  when: () => require('../when'),
114
116
  winston: () => require('../winston')
115
117
  }
@@ -17,10 +17,11 @@ exports.channel = function (name) {
17
17
  /**
18
18
  * @param {string} args.name module name
19
19
  * @param {string[]} args.versions array of semver range strings
20
- * @param {string} args.file path to file within package to instrument?
20
+ * @param {string} args.file path to file within package to instrument
21
+ * @param {string} args.filePattern pattern to match files within package to instrument
21
22
  * @param Function hook
22
23
  */
23
- exports.addHook = function addHook ({ name, versions, file }, hook) {
24
+ exports.addHook = function addHook ({ name, versions, file, filePattern }, hook) {
24
25
  if (typeof name === 'string') {
25
26
  name = [name]
26
27
  }
@@ -29,7 +30,7 @@ exports.addHook = function addHook ({ name, versions, file }, hook) {
29
30
  if (!instrumentations[val]) {
30
31
  instrumentations[val] = []
31
32
  }
32
- instrumentations[val].push({ name: val, versions, file, hook })
33
+ instrumentations[val].push({ name: val, versions, file, filePattern, hook })
33
34
  }
34
35
  }
35
36