dd-trace 5.17.0 → 5.19.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 (93) hide show
  1. package/LICENSE-3rdparty.csv +1 -2
  2. package/ext/exporters.d.ts +1 -1
  3. package/index.d.ts +105 -37
  4. package/init.js +40 -1
  5. package/initialize.mjs +8 -5
  6. package/package.json +29 -29
  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/child_process.js +2 -2
  11. package/packages/datadog-instrumentations/src/cucumber.js +76 -34
  12. package/packages/datadog-instrumentations/src/fs.js +1 -1
  13. package/packages/datadog-instrumentations/src/hapi.js +1 -1
  14. package/packages/datadog-instrumentations/src/helpers/hook.js +8 -3
  15. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  16. package/packages/datadog-instrumentations/src/helpers/instrument.js +4 -3
  17. package/packages/datadog-instrumentations/src/helpers/register.js +56 -5
  18. package/packages/datadog-instrumentations/src/http/client.js +1 -1
  19. package/packages/datadog-instrumentations/src/jest.js +17 -2
  20. package/packages/datadog-instrumentations/src/kafkajs.js +1 -1
  21. package/packages/datadog-instrumentations/src/ldapjs.js +2 -2
  22. package/packages/datadog-instrumentations/src/mocha/main.js +12 -1
  23. package/packages/datadog-instrumentations/src/mocha/utils.js +58 -14
  24. package/packages/datadog-instrumentations/src/mocha/worker.js +1 -0
  25. package/packages/datadog-instrumentations/src/mquery.js +2 -2
  26. package/packages/datadog-instrumentations/src/next.js +1 -1
  27. package/packages/datadog-instrumentations/src/pg.js +2 -2
  28. package/packages/datadog-instrumentations/src/playwright.js +47 -33
  29. package/packages/datadog-instrumentations/src/restify.js +1 -1
  30. package/packages/datadog-instrumentations/src/vitest.js +349 -0
  31. package/packages/datadog-plugin-aws-sdk/src/base.js +8 -1
  32. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -1
  33. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +9 -3
  34. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +6 -1
  35. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +23 -5
  36. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
  37. package/packages/datadog-plugin-child_process/src/index.js +1 -1
  38. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -4
  39. package/packages/datadog-plugin-cucumber/src/index.js +24 -1
  40. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +79 -42
  41. package/packages/datadog-plugin-cypress/src/plugin.js +4 -3
  42. package/packages/datadog-plugin-fs/src/index.js +1 -1
  43. package/packages/datadog-plugin-jest/src/index.js +7 -1
  44. package/packages/datadog-plugin-kafkajs/src/producer.js +1 -1
  45. package/packages/datadog-plugin-mocha/src/index.js +25 -4
  46. package/packages/datadog-plugin-mongodb-core/src/index.js +1 -1
  47. package/packages/datadog-plugin-openai/src/index.js +57 -35
  48. package/packages/datadog-plugin-openai/src/token-estimator.js +20 -0
  49. package/packages/datadog-plugin-playwright/src/index.js +4 -1
  50. package/packages/datadog-plugin-sharedb/src/index.js +1 -1
  51. package/packages/datadog-plugin-vitest/src/index.js +167 -0
  52. package/packages/dd-trace/src/analytics_sampler.js +1 -1
  53. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +1 -1
  54. package/packages/dd-trace/src/appsec/iast/path-line.js +2 -19
  55. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -2
  56. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +2 -2
  57. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +3 -1
  58. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -0
  59. package/packages/dd-trace/src/appsec/index.js +4 -4
  60. package/packages/dd-trace/src/appsec/passport.js +1 -1
  61. package/packages/dd-trace/src/appsec/rasp.js +32 -5
  62. package/packages/dd-trace/src/appsec/recommended.json +208 -3
  63. package/packages/dd-trace/src/appsec/reporter.js +60 -20
  64. package/packages/dd-trace/src/appsec/sdk/track_event.js +3 -0
  65. package/packages/dd-trace/src/appsec/stack_trace.js +90 -0
  66. package/packages/dd-trace/src/appsec/standalone.js +130 -0
  67. package/packages/dd-trace/src/appsec/telemetry.js +33 -1
  68. package/packages/dd-trace/src/appsec/waf/index.js +2 -2
  69. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +3 -3
  70. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
  71. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
  72. package/packages/dd-trace/src/config.js +136 -63
  73. package/packages/dd-trace/src/constants.js +3 -1
  74. package/packages/dd-trace/src/datastreams/processor.js +3 -2
  75. package/packages/dd-trace/src/exporters/agent/index.js +2 -2
  76. package/packages/dd-trace/src/format.js +1 -0
  77. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  78. package/packages/dd-trace/src/opentelemetry/tracer.js +6 -0
  79. package/packages/dd-trace/src/opentracing/propagation/text_map.js +12 -0
  80. package/packages/dd-trace/src/opentracing/span.js +4 -1
  81. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  82. package/packages/dd-trace/src/plugins/ci_plugin.js +7 -0
  83. package/packages/dd-trace/src/plugins/index.js +2 -0
  84. package/packages/dd-trace/src/plugins/util/test.js +5 -1
  85. package/packages/dd-trace/src/priority_sampler.js +2 -5
  86. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  87. package/packages/dd-trace/src/proxy.js +3 -1
  88. package/packages/dd-trace/src/rate_limiter.js +2 -2
  89. package/packages/dd-trace/src/span_stats.js +4 -3
  90. package/packages/dd-trace/src/telemetry/init-telemetry.js +75 -0
  91. package/packages/dd-trace/src/tracer.js +2 -2
  92. package/packages/dd-trace/src/util.js +6 -1
  93. package/packages/datadog-core/src/storage/async_hooks.js +0 -49
@@ -46,7 +46,6 @@ dev,eslint-plugin-import,MIT,Copyright 2015 Ben Mosher
46
46
  dev,eslint-plugin-mocha,MIT,Copyright 2014 Mathias Schreck
47
47
  dev,eslint-plugin-n,MIT,Copyright 2015 Toru Nagashima
48
48
  dev,eslint-plugin-promise,ISC,jden and other contributors
49
- dev,eslint-plugin-standard,MIT,Copyright 2015 Jamund Ferguson
50
49
  dev,express,MIT,Copyright 2009-2014 TJ Holowaychuk 2013-2014 Roman Shtylman 2014-2015 Douglas Christopher Wilson
51
50
  dev,get-port,MIT,Copyright Sindre Sorhus
52
51
  dev,glob,ISC,Copyright Isaac Z. Schlueter and Contributors
@@ -63,7 +62,7 @@ dev,rimraf,ISC,Copyright Isaac Z. Schlueter and Contributors
63
62
  dev,sinon,BSD-3-Clause,Copyright 2010-2017 Christian Johansen
64
63
  dev,sinon-chai,WTFPL and BSD-2-Clause,Copyright 2004 Sam Hocevar 2012–2017 Domenic Denicola
65
64
  dev,tap,ISC,Copyright 2011-2022 Isaac Z. Schlueter and Contributors
66
- dev,tape,MIT,Copyright James Halliday
65
+ dev,tiktoken,MIT,Copyright (c) 2022 OpenAI, Shantanu Jain
67
66
  file,aws-lambda-nodejs-runtime-interface-client,Apache 2.0,Copyright 2019 Amazon.com Inc. or its affiliates. All Rights Reserved.
68
67
  file,profile.proto,Apache license 2.0,Copyright 2016 Google Inc.
69
68
  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
 
@@ -517,44 +518,19 @@ declare namespace tracer {
517
518
  /**
518
519
  * Configuration of the IAST. Can be a boolean as an alias to `iast.enabled`.
519
520
  */
520
- iast?: boolean | {
521
- /**
522
- * Whether to enable IAST.
523
- * @default false
524
- */
525
- enabled?: boolean,
526
- /**
527
- * Controls the percentage of requests that iast will analyze
528
- * @default 30
529
- */
530
- requestSampling?: number,
531
- /**
532
- * Controls how many request can be analyzing code vulnerabilities at the same time
533
- * @default 2
534
- */
535
- maxConcurrentRequests?: number,
536
- /**
537
- * Controls how many code vulnerabilities can be detected in the same request
538
- * @default 2
539
- */
540
- maxContextOperations?: number,
541
- /**
542
- * Whether to enable vulnerability deduplication
543
- */
544
- deduplicationEnabled?: boolean,
545
- /**
546
- * Whether to enable vulnerability redaction
547
- * @default true
548
- */
549
- redactionEnabled?: boolean,
550
- /**
551
- * Specifies a regex that will redact sensitive source names in vulnerability reports.
552
- */
553
- redactionNamePattern?: string,
521
+ iast?: boolean | IastOptions
522
+
523
+ appsec?: {
554
524
  /**
555
- * Specifies a regex that will redact sensitive source values in vulnerability reports.
525
+ * Configuration of Standalone ASM mode
556
526
  */
557
- redactionValuePattern?: string
527
+ standalone?: {
528
+ /**
529
+ * Whether to enable Standalone ASM.
530
+ * @default false
531
+ */
532
+ enabled?: boolean
533
+ }
558
534
  }
559
535
  };
560
536
 
@@ -700,9 +676,33 @@ declare namespace tracer {
700
676
  * @default false
701
677
  */
702
678
  enabled?: boolean
679
+ },
680
+ /**
681
+ * Configuration for stack trace reporting
682
+ */
683
+ stackTrace?: {
684
+ /** Whether to enable stack trace reporting.
685
+ * @default true
686
+ */
687
+ enabled?: boolean,
688
+
689
+ /** Specifies the maximum number of stack traces to be reported.
690
+ * @default 2
691
+ */
692
+ maxStackTraces?: number,
693
+
694
+ /** Specifies the maximum depth of a stack trace to be reported.
695
+ * @default 32
696
+ */
697
+ maxDepth?: number,
703
698
  }
704
699
  };
705
700
 
701
+ /**
702
+ * Configuration of the IAST. Can be a boolean as an alias to `iast.enabled`.
703
+ */
704
+ iast?: boolean | IastOptions
705
+
706
706
  /**
707
707
  * Configuration of ASM Remote Configuration
708
708
  */
@@ -1190,6 +1190,13 @@ declare namespace tracer {
1190
1190
  */
1191
1191
  splitByAwsService?: boolean;
1192
1192
 
1193
+ /**
1194
+ * Whether to inject all messages during batch AWS SQS, Kinesis, and SNS send operations. Normal
1195
+ * behavior is to inject the first message in batch send operations.
1196
+ * @default false
1197
+ */
1198
+ batchPropagationEnabled?: boolean;
1199
+
1193
1200
  /**
1194
1201
  * Hooks to run before spans are finished.
1195
1202
  */
@@ -1524,7 +1531,7 @@ declare namespace tracer {
1524
1531
 
1525
1532
  /**
1526
1533
  * This plugin automatically instruments the
1527
- * [jest](https://github.com/facebook/jest) module.
1534
+ * [jest](https://github.com/jestjs/jest) module.
1528
1535
  */
1529
1536
  interface jest extends Integration {}
1530
1537
 
@@ -1807,6 +1814,12 @@ declare namespace tracer {
1807
1814
  */
1808
1815
  interface undici extends HttpClient {}
1809
1816
 
1817
+ /**
1818
+ * This plugin automatically instruments the
1819
+ * [vitest](https://github.com/vitest-dev/vitest) module.
1820
+ */
1821
+ interface vitest extends Integration {}
1822
+
1810
1823
  /**
1811
1824
  * This plugin patches the [winston](https://github.com/winstonjs/winston)
1812
1825
  * to automatically inject trace identifiers in log records when the
@@ -2091,6 +2104,61 @@ declare namespace tracer {
2091
2104
  export type TimeInput = otel.TimeInput;
2092
2105
  export type TraceState = otel.TraceState;
2093
2106
  }
2107
+
2108
+ /**
2109
+ * Iast configuration used in `tracer` and `tracer.experimental` options
2110
+ */
2111
+ interface IastOptions {
2112
+ /**
2113
+ * Whether to enable IAST.
2114
+ * @default false
2115
+ */
2116
+ enabled?: boolean,
2117
+
2118
+ /**
2119
+ * Controls the percentage of requests that iast will analyze
2120
+ * @default 30
2121
+ */
2122
+ requestSampling?: number,
2123
+
2124
+ /**
2125
+ * Controls how many request can be analyzing code vulnerabilities at the same time
2126
+ * @default 2
2127
+ */
2128
+ maxConcurrentRequests?: number,
2129
+
2130
+ /**
2131
+ * Controls how many code vulnerabilities can be detected in the same request
2132
+ * @default 2
2133
+ */
2134
+ maxContextOperations?: number,
2135
+
2136
+ /**
2137
+ * Whether to enable vulnerability deduplication
2138
+ */
2139
+ deduplicationEnabled?: boolean,
2140
+
2141
+ /**
2142
+ * Whether to enable vulnerability redaction
2143
+ * @default true
2144
+ */
2145
+ redactionEnabled?: boolean,
2146
+
2147
+ /**
2148
+ * Specifies a regex that will redact sensitive source names in vulnerability reports.
2149
+ */
2150
+ redactionNamePattern?: string,
2151
+
2152
+ /**
2153
+ * Specifies a regex that will redact sensitive source values in vulnerability reports.
2154
+ */
2155
+ redactionValuePattern?: string,
2156
+
2157
+ /**
2158
+ * Specifies the verbosity of the sent telemetry. Default 'INFORMATION'
2159
+ */
2160
+ telemetryVerbosity?: string
2161
+ }
2094
2162
  }
2095
2163
 
2096
2164
  /**
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.19.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -14,37 +14,38 @@
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'",
45
- "test:shimmer:ci": "nyc --no-clean --include 'packages/datadog-shimmer/src/**/*.js' -- npm run test:shimmer",
46
- "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
- "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\""
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'",
48
+ "test:shimmer:ci": "nyc --no-clean --include 'packages/datadog-shimmer/src/**/*.js' -- npm run test:shimmer"
48
49
  },
49
50
  "repository": {
50
51
  "type": "git",
@@ -72,7 +73,7 @@
72
73
  "dependencies": {
73
74
  "@datadog/native-appsec": "8.0.1",
74
75
  "@datadog/native-iast-rewriter": "2.3.1",
75
- "@datadog/native-iast-taint-tracking": "2.1.0",
76
+ "@datadog/native-iast-taint-tracking": "3.0.0",
76
77
  "@datadog/native-metrics": "^2.0.0",
77
78
  "@datadog/pprof": "5.3.0",
78
79
  "@datadog/sketches-js": "^2.1.0",
@@ -81,7 +82,7 @@
81
82
  "crypto-randomuuid": "^1.0.0",
82
83
  "dc-polyfill": "^0.1.4",
83
84
  "ignore": "^5.2.4",
84
- "import-in-the-middle": "^1.7.4",
85
+ "import-in-the-middle": "^1.8.1",
85
86
  "int64-buffer": "^0.1.9",
86
87
  "istanbul-lib-coverage": "3.2.0",
87
88
  "jest-docblock": "^29.7.0",
@@ -113,13 +114,12 @@
113
114
  "cli-table3": "^0.6.3",
114
115
  "dotenv": "16.3.1",
115
116
  "esbuild": "0.16.12",
116
- "eslint": "^8.23.0",
117
+ "eslint": "^8.57.0",
117
118
  "eslint-config-standard": "^17.1.0",
118
- "eslint-plugin-import": "^2.8.0",
119
- "eslint-plugin-mocha": "^10.1.0",
120
- "eslint-plugin-n": "^15.7.0",
121
- "eslint-plugin-promise": "^3.6.0",
122
- "eslint-plugin-standard": "^3.0.1",
119
+ "eslint-plugin-import": "^2.29.1",
120
+ "eslint-plugin-mocha": "^10.4.3",
121
+ "eslint-plugin-n": "^16.6.2",
122
+ "eslint-plugin-promise": "^6.4.0",
123
123
  "express": "^4.18.2",
124
124
  "get-port": "^3.2.0",
125
125
  "glob": "^7.1.6",
@@ -136,6 +136,6 @@
136
136
  "sinon": "^15.2.0",
137
137
  "sinon-chai": "^3.7.0",
138
138
  "tap": "^16.3.7",
139
- "tape": "^5.6.5"
139
+ "tiktoken": "^1.0.15"
140
140
  }
141
141
  }
@@ -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({
@@ -39,10 +39,10 @@ function normalizeArgs (args, shell) {
39
39
 
40
40
  if (Array.isArray(args[1])) {
41
41
  childProcessInfo.command = childProcessInfo.command + ' ' + args[1].join(' ')
42
- if (args[2] != null && typeof args[2] === 'object') {
42
+ if (args[2] !== null && typeof args[2] === 'object') {
43
43
  childProcessInfo.options = args[2]
44
44
  }
45
- } else if (args[1] != null && typeof args[1] === 'object') {
45
+ } else if (args[1] !== null && typeof args[1] === 'object') {
46
46
  childProcessInfo.options = args[1]
47
47
  }
48
48
  childProcessInfo.shell = shell ||
@@ -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
  })
@@ -272,7 +272,7 @@ function createWrapFunction (prefix = '', override = '') {
272
272
  const outerResource = new AsyncResource('bound-anonymous-fn')
273
273
 
274
274
  arguments[lastIndex] = innerResource.bind(function (e) {
275
- if (typeof e === 'object') { // fs.exists receives a boolean
275
+ if (e !== null && typeof e === 'object') { // fs.exists receives a boolean
276
276
  errorChannel.publish(e)
277
277
  }
278
278
 
@@ -38,7 +38,7 @@ function wrapStart (start) {
38
38
 
39
39
  function wrapExt (ext) {
40
40
  return function (events, method, options) {
41
- if (typeof events === 'object') {
41
+ if (events !== null && typeof events === 'object') {
42
42
  arguments[0] = wrapEvents(events)
43
43
  } else {
44
44
  arguments[1] = wrapExtension(method)