dd-trace 4.17.0 → 4.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 (82) hide show
  1. package/LICENSE-3rdparty.csv +2 -2
  2. package/README.md +3 -3
  3. package/ext/kinds.d.ts +1 -0
  4. package/ext/kinds.js +2 -1
  5. package/ext/tags.d.ts +2 -1
  6. package/ext/tags.js +6 -1
  7. package/index.d.ts +9 -1
  8. package/package.json +8 -8
  9. package/packages/datadog-core/src/storage/async_resource.js +1 -1
  10. package/packages/datadog-esbuild/index.js +1 -20
  11. package/packages/datadog-instrumentations/src/cucumber.js +5 -0
  12. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
  13. package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
  14. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  15. package/packages/datadog-instrumentations/src/jest.js +39 -10
  16. package/packages/datadog-instrumentations/src/knex.js +24 -17
  17. package/packages/datadog-instrumentations/src/mocha.js +16 -1
  18. package/packages/datadog-instrumentations/src/next.js +58 -23
  19. package/packages/datadog-instrumentations/src/playwright.js +11 -6
  20. package/packages/datadog-instrumentations/src/restify.js +14 -1
  21. package/packages/datadog-plugin-http/src/client.js +2 -0
  22. package/packages/datadog-plugin-jest/src/index.js +11 -3
  23. package/packages/datadog-plugin-kafkajs/src/consumer.js +8 -6
  24. package/packages/datadog-plugin-kafkajs/src/producer.js +9 -6
  25. package/packages/datadog-plugin-mocha/src/index.js +7 -1
  26. package/packages/datadog-plugin-next/src/index.js +4 -3
  27. package/packages/datadog-plugin-playwright/src/index.js +4 -1
  28. package/packages/dd-trace/src/appsec/channels.js +1 -1
  29. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  30. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-analyzer.js +60 -0
  31. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +269 -0
  32. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +5 -2
  33. package/packages/dd-trace/src/appsec/iast/analyzers/missing-header-analyzer.js +22 -4
  34. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +9 -2
  35. package/packages/dd-trace/src/appsec/iast/analyzers/xcontenttype-header-missing-analyzer.js +2 -2
  36. package/packages/dd-trace/src/appsec/iast/iast-log.js +9 -4
  37. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  38. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  39. package/packages/dd-trace/src/appsec/iast/path-line.js +7 -2
  40. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +13 -2
  41. package/packages/dd-trace/src/appsec/iast/telemetry/index.js +1 -14
  42. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +19 -0
  43. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +2 -1
  44. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  45. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +5 -1
  46. package/packages/dd-trace/src/appsec/recommended.json +272 -48
  47. package/packages/dd-trace/src/appsec/reporter.js +31 -34
  48. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +16 -4
  49. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -0
  50. package/packages/dd-trace/src/config.js +35 -17
  51. package/packages/dd-trace/src/datastreams/processor.js +60 -15
  52. package/packages/dd-trace/src/format.js +6 -1
  53. package/packages/dd-trace/src/git_properties.js +16 -15
  54. package/packages/dd-trace/src/iitm.js +1 -1
  55. package/packages/dd-trace/src/log/channels.js +1 -1
  56. package/packages/dd-trace/src/opentelemetry/span.js +95 -2
  57. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
  58. package/packages/dd-trace/src/opentracing/span.js +4 -0
  59. package/packages/dd-trace/src/opentracing/span_context.js +5 -2
  60. package/packages/dd-trace/src/plugin_manager.js +1 -1
  61. package/packages/dd-trace/src/plugins/database.js +1 -1
  62. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  63. package/packages/dd-trace/src/plugins/util/ci.js +6 -19
  64. package/packages/dd-trace/src/plugins/util/git.js +2 -1
  65. package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
  66. package/packages/dd-trace/src/plugins/util/test.js +29 -1
  67. package/packages/dd-trace/src/plugins/util/url.js +26 -0
  68. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -14
  69. package/packages/dd-trace/src/profiling/config.js +23 -20
  70. package/packages/dd-trace/src/profiling/profilers/events.js +161 -0
  71. package/packages/dd-trace/src/profiling/profilers/shared.js +9 -0
  72. package/packages/dd-trace/src/profiling/profilers/wall.js +84 -47
  73. package/packages/dd-trace/src/ritm.js +1 -1
  74. package/packages/dd-trace/src/span_processor.js +4 -0
  75. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  76. package/packages/dd-trace/src/telemetry/index.js +5 -1
  77. package/packages/dd-trace/src/telemetry/logs/index.js +65 -0
  78. package/packages/dd-trace/src/{appsec/iast/telemetry/log → telemetry/logs}/log-collector.js +9 -22
  79. package/packages/dd-trace/src/tracer.js +4 -2
  80. package/packages/dd-trace/src/appsec/iast/telemetry/log/index.js +0 -87
  81. package/packages/diagnostics_channel/index.js +0 -3
  82. package/packages/diagnostics_channel/src/index.js +0 -121
@@ -8,7 +8,7 @@ require,@datadog/sketches-js,Apache license 2.0,Copyright 2020 Datadog Inc.
8
8
  require,@opentelemetry/api,Apache license 2.0,Copyright OpenTelemetry Authors
9
9
  require,@opentelemetry/core,Apache license 2.0,Copyright OpenTelemetry Authors
10
10
  require,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
11
- require,diagnostics_channel,MIT,Copyright 2021 Simon D.
11
+ require,dc-polyfill,MIT,Copyright 2023 Datadog Inc.
12
12
  require,ignore,MIT,Copyright 2013 Kael Zhang and contributors
13
13
  require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
14
14
  require,int64-buffer,MIT,Copyright 2015-2016 Yusuke Kawasaki
@@ -28,6 +28,7 @@ require,msgpack-lite,MIT,Copyright 2015 Yusuke Kawasaki
28
28
  require,node-abort-controller,MIT,Copyright (c) 2019 Steve Faulkner
29
29
  require,opentracing,MIT,Copyright 2016 Resonance Labs Inc
30
30
  require,path-to-regexp,MIT,Copyright 2014 Blake Embrey
31
+ require,pprof-format,MIT,Copyright 2022 Stephen Belanger
31
32
  require,protobufjs,BSD-3-Clause,Copyright 2016 Daniel Wirtz
32
33
  require,retry,MIT,Copyright 2011 Tim Koschützki Felix Geisendörfer
33
34
  require,semver,ISC,Copyright Isaac Z. Schlueter and Contributors
@@ -62,7 +63,6 @@ dev,mocha,MIT,Copyright 2011-2018 JS Foundation and contributors https://js.foun
62
63
  dev,multer,MIT,Copyright 2014 Hage Yaapa
63
64
  dev,nock,MIT,Copyright 2017 Pedro Teixeira and other contributors
64
65
  dev,nyc,ISC,Copyright 2015 Contributors
65
- dev,pprof-format,MIT,Copyright 2022 Stephen Belanger
66
66
  dev,proxyquire,MIT,Copyright 2013 Thorsten Lorenz
67
67
  dev,rimraf,ISC,Copyright Isaac Z. Schlueter and Contributors
68
68
  dev,sinon,BSD-3-Clause,Copyright 2010-2017 Christian Johansen
package/README.md CHANGED
@@ -202,11 +202,11 @@ To get around this, one can treat all third party modules, or at least third par
202
202
 
203
203
  For these reasons it's necessary to have custom-built bundler plugins. Such plugins are able to instruct the bundler on how to behave, injecting intermediary code and otherwise intercepting the "translated" `require()` calls. The result is that many more packages are then included in the bundled JavaScript file. Some applications can have 100% of modules bundled, however native modules still need to remain external to the bundle.
204
204
 
205
- ### Esbuild Support
205
+ ### ESBuild Support
206
206
 
207
- This library provides experimental esbuild support in the form of an esbuild plugin, and currently requires at least Node.js v16.17 or v18.7. To use the plugin, make sure you have `dd-trace@3+` installed, and then require the `dd-trace/esbuild` module when building your bundle.
207
+ This library provides experimental ESBuild support in the form of an ESBuild plugin. Require the `dd-trace/esbuild` module when building your bundle to enable the plugin.
208
208
 
209
- Here's an example of how one might use `dd-trace` with esbuild:
209
+ Here's an example of how one might use `dd-trace` with ESBuild:
210
210
 
211
211
  ```javascript
212
212
  const ddPlugin = require('dd-trace/esbuild')
package/ext/kinds.d.ts CHANGED
@@ -3,6 +3,7 @@ declare const kinds: {
3
3
  CLIENT: 'client'
4
4
  PRODUCER: 'producer'
5
5
  CONSUMER: 'consumer'
6
+ INTERNAL: 'internal'
6
7
  }
7
8
 
8
9
  export = kinds
package/ext/kinds.js CHANGED
@@ -4,5 +4,6 @@ module.exports = {
4
4
  SERVER: 'server',
5
5
  CLIENT: 'client',
6
6
  PRODUCER: 'producer',
7
- CONSUMER: 'consumer'
7
+ CONSUMER: 'consumer',
8
+ INTERNAL: 'internal'
8
9
  }
package/ext/tags.d.ts CHANGED
@@ -17,7 +17,8 @@ declare const tags: {
17
17
  HTTP_REQUEST_HEADERS: 'http.request.headers'
18
18
  HTTP_RESPONSE_HEADERS: 'http.response.headers'
19
19
  HTTP_USERAGENT: 'http.useragent',
20
- HTTP_CLIENT_IP: 'http.client_ip'
20
+ HTTP_CLIENT_IP: 'http.client_ip',
21
+ PATHWAY_HASH: 'pathway.hash'
21
22
  }
22
23
 
23
24
  export = tags
package/ext/tags.js CHANGED
@@ -22,7 +22,12 @@ const tags = {
22
22
  HTTP_REQUEST_HEADERS: 'http.request.headers',
23
23
  HTTP_RESPONSE_HEADERS: 'http.response.headers',
24
24
  HTTP_USERAGENT: 'http.useragent',
25
- HTTP_CLIENT_IP: 'http.client_ip'
25
+ HTTP_CLIENT_IP: 'http.client_ip',
26
+
27
+ // Messaging
28
+
29
+ // DSM Specific
30
+ PATHWAY_HASH: 'pathway.hash'
26
31
  }
27
32
 
28
33
  // Deprecated
package/index.d.ts CHANGED
@@ -453,7 +453,15 @@ export declare interface TracerOptions {
453
453
  * Whether to enable vulnerability redaction
454
454
  * @default true
455
455
  */
456
- redactionEnabled?: boolean
456
+ redactionEnabled?: boolean,
457
+ /**
458
+ * Specifies a regex that will redact sensitive source names in vulnerability reports.
459
+ */
460
+ redactionNamePattern?: string,
461
+ /**
462
+ * Specifies a regex that will redact sensitive source values in vulnerability reports.
463
+ */
464
+ redactionValuePattern?: string
457
465
  }
458
466
  };
459
467
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "4.17.0",
3
+ "version": "4.19.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -19,7 +19,7 @@
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
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\"",
21
21
  "test:appsec:plugins:ci": "yarn services && nyc --no-clean --include \"packages/dd-trace/src/appsec/**/*.js\" -- npm run test:appsec:plugins",
22
- "test:trace:core": "tap packages/dd-trace/test/*.spec.js \"packages/dd-trace/test/{ci-visibility,encode,exporters,opentelemetry,opentracing,plugins,service-naming,telemetry}/**/*.spec.js\"",
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
24
  "test:instrumentations": "mocha --colors -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",
@@ -68,16 +68,16 @@
68
68
  "node": ">=16"
69
69
  },
70
70
  "dependencies": {
71
- "@datadog/native-appsec": "^4.0.0",
72
- "@datadog/native-iast-rewriter": "2.1.3",
73
- "@datadog/native-iast-taint-tracking": "1.6.1",
71
+ "@datadog/native-appsec": "4.0.0",
72
+ "@datadog/native-iast-rewriter": "2.2.1",
73
+ "@datadog/native-iast-taint-tracking": "1.6.4",
74
74
  "@datadog/native-metrics": "^2.0.0",
75
- "@datadog/pprof": "4.0.0",
75
+ "@datadog/pprof": "4.0.1",
76
76
  "@datadog/sketches-js": "^2.1.0",
77
77
  "@opentelemetry/api": "^1.0.0",
78
78
  "@opentelemetry/core": "^1.14.0",
79
79
  "crypto-randomuuid": "^1.0.0",
80
- "diagnostics_channel": "^1.1.0",
80
+ "dc-polyfill": "^0.1.2",
81
81
  "ignore": "^5.2.4",
82
82
  "import-in-the-middle": "^1.4.2",
83
83
  "int64-buffer": "^0.1.9",
@@ -97,6 +97,7 @@
97
97
  "node-abort-controller": "^3.1.1",
98
98
  "opentracing": ">=0.12.1",
99
99
  "path-to-regexp": "^0.1.2",
100
+ "pprof-format": "^2.0.7",
100
101
  "protobufjs": "^7.2.4",
101
102
  "retry": "^0.13.1",
102
103
  "semver": "^7.5.4"
@@ -133,7 +134,6 @@
133
134
  "multer": "^1.4.5-lts.1",
134
135
  "nock": "^11.3.3",
135
136
  "nyc": "^15.1.0",
136
- "pprof-format": "^2.0.7",
137
137
  "proxyquire": "^1.8.0",
138
138
  "rimraf": "^3.0.0",
139
139
  "sinon": "^15.2.0",
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { createHook, executionAsyncResource } = require('async_hooks')
4
- const { channel } = require('../../../diagnostics_channel')
4
+ const { channel } = require('dc-polyfill')
5
5
 
6
6
  const beforeCh = channel('dd-trace:storage:before')
7
7
  const afterCh = channel('dd-trace:storage:after')
@@ -5,8 +5,6 @@
5
5
  const instrumentations = require('../datadog-instrumentations/src/helpers/instrumentations.js')
6
6
  const hooks = require('../datadog-instrumentations/src/helpers/hooks.js')
7
7
 
8
- warnIfUnsupported()
9
-
10
8
  for (const hook of Object.values(hooks)) {
11
9
  hook()
12
10
  }
@@ -144,7 +142,7 @@ module.exports.setup = function (build) {
144
142
  ${fileCode}
145
143
  })(...arguments);
146
144
  {
147
- const dc = require('diagnostics_channel');
145
+ const dc = require('dc-polyfill');
148
146
  const ch = dc.channel('${CHANNEL}');
149
147
  const mod = module.exports
150
148
  const payload = {
@@ -167,23 +165,6 @@ module.exports.setup = function (build) {
167
165
  })
168
166
  }
169
167
 
170
- // Currently esbuild support requires Node.js >=v16.17 or >=v18.7
171
- // Better yet it would support Node >=v14.17 or >=v16
172
- // Of course, the most ideal would be to support all versions of Node that dd-trace supports.
173
- // Version constraints based on Node's diagnostics_channel support
174
- function warnIfUnsupported () {
175
- const [major, minor] = process.versions.node.split('.').map(Number)
176
- if (
177
- major < 16 ||
178
- (major === 16 && minor < 17) ||
179
- (major === 18 && minor < 7)) {
180
- console.error('WARNING: Esbuild support isn\'t available for older versions of Node.js.')
181
- console.error(`Expected: Node.js >=v16.17 or >=v18.7. Actual: Node.js = ${process.version}.`)
182
- console.error('This application may build properly with this version of Node.js, but unless a')
183
- console.error('more recent version is used at runtime, third party packages won\'t be instrumented.')
184
- }
185
- }
186
-
187
168
  // @see https://github.com/nodejs/node/issues/47000
188
169
  function dotFriendlyResolve (path, directory) {
189
170
  if (path === '.') {
@@ -296,6 +296,11 @@ addHook({
296
296
  const filteredPickles = getFilteredPickles(this, skippableSuites)
297
297
  const { picklesToRun } = filteredPickles
298
298
  isSuitesSkipped = picklesToRun.length !== this.pickleIds.length
299
+
300
+ log.debug(
301
+ () => `${picklesToRun.length} out of ${this.pickleIds.length} suites are going to run.`
302
+ )
303
+
299
304
  this.pickleIds = picklesToRun
300
305
 
301
306
  skippedSuites = Array.from(filteredPickles.skippedSuites)
@@ -1,7 +1,6 @@
1
1
  'use strict'
2
2
 
3
- // eslint-disable-next-line n/no-restricted-require
4
- const dc = require('diagnostics_channel')
3
+ const dc = require('dc-polyfill')
5
4
 
6
5
  const {
7
6
  filename,
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const dc = require('../../../diagnostics_channel')
3
+ const dc = require('dc-polyfill')
4
4
  const semver = require('semver')
5
5
  const instrumentations = require('./instrumentations')
6
6
  const { AsyncResource } = require('async_hooks')
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { channel } = require('../../../diagnostics_channel')
3
+ const { channel } = require('dc-polyfill')
4
4
  const path = require('path')
5
5
  const semver = require('semver')
6
6
  const Hook = require('./hook')
@@ -208,6 +208,11 @@ addHook({
208
208
  const rootDir = test && test.context && test.context.config && test.context.config.rootDir
209
209
 
210
210
  const jestSuitesToRun = getJestSuitesToRun(skippableSuites, shardedTests, rootDir || process.cwd())
211
+
212
+ log.debug(
213
+ () => `${jestSuitesToRun.suitesToRun.length} out of ${shardedTests.length} suites are going to run.`
214
+ )
215
+
211
216
  hasUnskippableSuites = jestSuitesToRun.hasUnskippableSuites
212
217
  hasForcedToRunSuites = jestSuitesToRun.hasForcedToRunSuites
213
218
 
@@ -272,7 +277,16 @@ function cliWrapper (cli, jestVersion) {
272
277
 
273
278
  const result = await runCLI.apply(this, arguments)
274
279
 
275
- const { results: { success, coverageMap } } = result
280
+ const {
281
+ results: {
282
+ success,
283
+ coverageMap,
284
+ numFailedTestSuites,
285
+ numFailedTests,
286
+ numTotalTests,
287
+ numTotalTestSuites
288
+ }
289
+ } = result
276
290
 
277
291
  let testCodeCoverageLinesTotal
278
292
  try {
@@ -281,17 +295,30 @@ function cliWrapper (cli, jestVersion) {
281
295
  } catch (e) {
282
296
  // ignore errors
283
297
  }
298
+ let status, error
299
+
300
+ if (success) {
301
+ if (numTotalTests === 0 && numTotalTestSuites === 0) {
302
+ status = 'skip'
303
+ } else {
304
+ status = 'pass'
305
+ }
306
+ } else {
307
+ status = 'fail'
308
+ error = new Error(`Failed test suites: ${numFailedTestSuites}. Failed tests: ${numFailedTests}`)
309
+ }
284
310
 
285
311
  sessionAsyncResource.runInAsyncScope(() => {
286
312
  testSessionFinishCh.publish({
287
- status: success ? 'pass' : 'fail',
313
+ status,
288
314
  isSuitesSkipped,
289
315
  isSuitesSkippingEnabled,
290
316
  isCodeCoverageEnabled,
291
317
  testCodeCoverageLinesTotal,
292
318
  numSkippedSuites,
293
319
  hasUnskippableSuites,
294
- hasForcedToRunSuites
320
+ hasForcedToRunSuites,
321
+ error
295
322
  })
296
323
  })
297
324
 
@@ -363,23 +390,23 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
363
390
  status = 'fail'
364
391
  }
365
392
 
366
- const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
367
- .map(filename => getTestSuitePath(filename, environment.rootDir))
368
-
369
393
  /**
370
394
  * Child processes do not each request ITR configuration, so the jest's parent process
371
395
  * needs to pass them the configuration. This is done via _ddTestCodeCoverageEnabled, which
372
396
  * controls whether coverage is reported.
373
- */
374
- if (coverageFiles &&
375
- environment.testEnvironmentOptions &&
376
- environment.testEnvironmentOptions._ddTestCodeCoverageEnabled) {
397
+ */
398
+ if (environment.testEnvironmentOptions?._ddTestCodeCoverageEnabled) {
399
+ const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
400
+ .map(filename => getTestSuitePath(filename, environment.rootDir))
377
401
  asyncResource.runInAsyncScope(() => {
378
402
  testSuiteCodeCoverageCh.publish([...coverageFiles, environment.testSuite])
379
403
  })
380
404
  }
381
405
  testSuiteFinishCh.publish({ status, errorMessage })
382
406
  return suiteResults
407
+ }).catch(error => {
408
+ testSuiteFinishCh.publish({ status: 'fail', error })
409
+ throw error
383
410
  })
384
411
  })
385
412
  })
@@ -508,6 +535,8 @@ addHook({
508
535
 
509
536
  const jestSuitesToRun = getJestSuitesToRun(skippableSuites, tests, rootDir)
510
537
 
538
+ log.debug(() => `${jestSuitesToRun.suitesToRun.length} out of ${tests.length} suites are going to run.`)
539
+
511
540
  hasUnskippableSuites = jestSuitesToRun.hasUnskippableSuites
512
541
  hasForcedToRunSuites = jestSuitesToRun.hasForcedToRunSuites
513
542
 
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { addHook, channel } = require('./helpers/instrument')
3
+ const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
4
  const { wrapThen } = require('./helpers/promise')
5
5
  const shimmer = require('../../datadog-shimmer')
6
6
 
@@ -39,34 +39,41 @@ addHook({
39
39
  return raw.apply(this, arguments)
40
40
  }
41
41
 
42
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
43
+
42
44
  function finish () {
43
45
  finishRawQueryCh.publish()
44
46
  }
45
47
 
46
- startRawQueryCh.publish({ sql, dialect: this.dialect })
48
+ return asyncResource.runInAsyncScope(() => {
49
+ startRawQueryCh.publish({ sql, dialect: this.dialect })
47
50
 
48
- const rawResult = raw.apply(this, arguments)
51
+ const rawResult = raw.apply(this, arguments)
52
+ shimmer.wrap(rawResult, 'then', originalThen => function () {
53
+ return asyncResource.runInAsyncScope(() => {
54
+ arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
55
+ if (arguments[1]) arguments[1] = wrapCallbackWithFinish(arguments[1], finish)
49
56
 
50
- shimmer.wrap(rawResult, 'then', originalThen => function () {
51
- arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
52
- arguments[1] = wrapCallbackWithFinish(arguments[1], finish)
57
+ const originalThenResult = originalThen.apply(this, arguments)
53
58
 
54
- const originalThenResult = originalThen.apply(this, arguments)
59
+ shimmer.wrap(originalThenResult, 'catch', originalCatch => function () {
60
+ arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
61
+ return originalCatch.apply(this, arguments)
62
+ })
55
63
 
56
- shimmer.wrap(originalThenResult, 'catch', originalCatch => function () {
57
- arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
58
- return originalCatch.apply(this, arguments)
64
+ return originalThenResult
65
+ })
59
66
  })
60
67
 
61
- return originalThenResult
62
- })
68
+ shimmer.wrap(rawResult, 'asCallback', originalAsCallback => function () {
69
+ return asyncResource.runInAsyncScope(() => {
70
+ arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
71
+ return originalAsCallback.apply(this, arguments)
72
+ })
73
+ })
63
74
 
64
- shimmer.wrap(rawResult, 'asCallback', originalAsCallback => function () {
65
- arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
66
- return originalAsCallback.apply(this, arguments)
75
+ return rawResult
67
76
  })
68
-
69
- return rawResult
70
77
  })
71
78
  return Knex
72
79
  })
@@ -133,11 +133,20 @@ function mochaHook (Runner) {
133
133
 
134
134
  this.once('end', testRunAsyncResource.bind(function () {
135
135
  let status = 'pass'
136
+ let error
136
137
  if (this.stats) {
137
138
  status = this.stats.failures === 0 ? 'pass' : 'fail'
139
+ if (this.stats.tests === 0) {
140
+ status = 'skip'
141
+ }
138
142
  } else if (this.failures !== 0) {
139
143
  status = 'fail'
140
144
  }
145
+
146
+ if (status === 'fail') {
147
+ error = new Error(`Failed tests: ${this.failures}.`)
148
+ }
149
+
141
150
  testFileToSuiteAr.clear()
142
151
 
143
152
  let testCodeCoverageLinesTotal
@@ -157,7 +166,8 @@ function mochaHook (Runner) {
157
166
  testCodeCoverageLinesTotal,
158
167
  numSkippedSuites: skippedSuites.length,
159
168
  hasForcedToRunSuites: isForcedToRun,
160
- hasUnskippableSuites: !!unskippableSuites.length
169
+ hasUnskippableSuites: !!unskippableSuites.length,
170
+ error
161
171
  })
162
172
  }))
163
173
 
@@ -396,6 +406,11 @@ addHook({
396
406
  const { suitesToRun } = filteredSuites
397
407
 
398
408
  isSuitesSkipped = suitesToRun.length !== runner.suite.suites.length
409
+
410
+ log.debug(
411
+ () => `${suitesToRun.length} out of ${runner.suite.suites.length} suites are going to run.`
412
+ )
413
+
399
414
  runner.suite.suites = suitesToRun
400
415
 
401
416
  skippedSuites = Array.from(filteredSuites.skippedSuites)
@@ -1,7 +1,5 @@
1
1
  'use strict'
2
2
 
3
- // TODO: either instrument all or none of the render functions
4
-
5
3
  const { channel, addHook } = require('./helpers/instrument')
6
4
  const shimmer = require('../../datadog-shimmer')
7
5
  const { DD_MAJOR } = require('../../../version')
@@ -14,6 +12,9 @@ const bodyParsedChannel = channel('apm:next:body-parsed')
14
12
  const queryParsedChannel = channel('apm:next:query-parsed')
15
13
 
16
14
  const requests = new WeakSet()
15
+ const nodeNextRequestsToNextRequests = new WeakMap()
16
+
17
+ const MIDDLEWARE_HEADER = 'x-middleware-invoke'
17
18
 
18
19
  function wrapHandleRequest (handleRequest) {
19
20
  return function (req, res, pathname, query) {
@@ -56,18 +57,6 @@ function wrapHandleApiRequestWithMatch (handleApiRequest) {
56
57
  }
57
58
  }
58
59
 
59
- function wrapRenderToResponse (renderToResponse) {
60
- return function (ctx) {
61
- return instrument(ctx.req, ctx.res, () => renderToResponse.apply(this, arguments))
62
- }
63
- }
64
-
65
- function wrapRenderErrorToResponse (renderErrorToResponse) {
66
- return function (ctx) {
67
- return instrument(ctx.req, ctx.res, () => renderErrorToResponse.apply(this, arguments))
68
- }
69
- }
70
-
71
60
  function wrapRenderToHTML (renderToHTML) {
72
61
  return function (req, res, pathname, query, parsedUrl) {
73
62
  return instrument(req, res, () => renderToHTML.apply(this, arguments))
@@ -80,6 +69,18 @@ function wrapRenderErrorToHTML (renderErrorToHTML) {
80
69
  }
81
70
  }
82
71
 
72
+ function wrapRenderToResponse (renderToResponse) {
73
+ return function (ctx) {
74
+ return instrument(ctx.req, ctx.res, () => renderToResponse.apply(this, arguments))
75
+ }
76
+ }
77
+
78
+ function wrapRenderErrorToResponse (renderErrorToResponse) {
79
+ return function (ctx) {
80
+ return instrument(ctx.req, ctx.res, () => renderErrorToResponse.apply(this, arguments))
81
+ }
82
+ }
83
+
83
84
  function wrapFindPageComponents (findPageComponents) {
84
85
  return function (pathname, query) {
85
86
  const result = findPageComponents.apply(this, arguments)
@@ -114,7 +115,9 @@ function instrument (req, res, handler) {
114
115
  req = req.originalRequest || req
115
116
  res = res.originalResponse || res
116
117
 
117
- if (requests.has(req)) return handler()
118
+ // TODO support middleware properly in the future?
119
+ const isMiddleware = req.headers[MIDDLEWARE_HEADER]
120
+ if (isMiddleware || requests.has(req)) return handler()
118
121
 
119
122
  requests.add(req)
120
123
 
@@ -154,6 +157,11 @@ function finish (ctx, result, err) {
154
157
  errorChannel.publish(ctx)
155
158
  }
156
159
 
160
+ const maybeNextRequest = nodeNextRequestsToNextRequests.get(ctx.req)
161
+ if (maybeNextRequest) {
162
+ ctx.nextRequest = maybeNextRequest
163
+ }
164
+
157
165
  finishChannel.publish(ctx)
158
166
 
159
167
  if (err) {
@@ -163,6 +171,24 @@ function finish (ctx, result, err) {
163
171
  return result
164
172
  }
165
173
 
174
+ // also wrapped in dist/server/future/route-handlers/app-route-route-handler.js
175
+ // in versions below 13.3.0 that support middleware,
176
+ // however, it is not provided as a class function or exported property
177
+ addHook({
178
+ name: 'next',
179
+ versions: ['>=13.3.0'],
180
+ file: 'dist/server/web/spec-extension/adapters/next-request.js'
181
+ }, NextRequestAdapter => {
182
+ shimmer.wrap(NextRequestAdapter.NextRequestAdapter, 'fromNodeNextRequest', fromNodeNextRequest => {
183
+ return function (nodeNextRequest) {
184
+ const nextRequest = fromNodeNextRequest.apply(this, arguments)
185
+ nodeNextRequestsToNextRequests.set(nodeNextRequest.originalRequest, nextRequest)
186
+ return nextRequest
187
+ }
188
+ })
189
+ return NextRequestAdapter
190
+ })
191
+
166
192
  addHook({
167
193
  name: 'next',
168
194
  versions: ['>=11.1'],
@@ -175,27 +201,32 @@ addHook({
175
201
  file: 'dist/next-server/server/serve-static.js'
176
202
  }, serveStatic => shimmer.wrap(serveStatic, 'serveStatic', wrapServeStatic))
177
203
 
178
- addHook({ name: 'next', versions: ['>=13.2'], file: 'dist/server/next-server.js' }, nextServer => {
204
+ addHook({ name: 'next', versions: ['>=11.1'], file: 'dist/server/next-server.js' }, nextServer => {
179
205
  const Server = nextServer.default
180
206
 
181
207
  shimmer.wrap(Server.prototype, 'handleRequest', wrapHandleRequest)
182
- shimmer.wrap(Server.prototype, 'handleApiRequest', wrapHandleApiRequestWithMatch)
208
+
209
+ // Wrapping these makes sure any public API render methods called in a custom server
210
+ // are traced properly
211
+ // (instead of wrapping the top-level API methods, just wrapping these covers them all)
183
212
  shimmer.wrap(Server.prototype, 'renderToResponse', wrapRenderToResponse)
184
213
  shimmer.wrap(Server.prototype, 'renderErrorToResponse', wrapRenderErrorToResponse)
214
+
185
215
  shimmer.wrap(Server.prototype, 'findPageComponents', wrapFindPageComponents)
186
216
 
187
217
  return nextServer
188
218
  })
189
219
 
190
- addHook({ name: 'next', versions: ['>=11.1 <13.2'], file: 'dist/server/next-server.js' }, nextServer => {
220
+ // `handleApiRequest` changes parameters/implementation at 13.2.0
221
+ addHook({ name: 'next', versions: ['>=13.2'], file: 'dist/server/next-server.js' }, nextServer => {
191
222
  const Server = nextServer.default
223
+ shimmer.wrap(Server.prototype, 'handleApiRequest', wrapHandleApiRequestWithMatch)
224
+ return nextServer
225
+ })
192
226
 
193
- shimmer.wrap(Server.prototype, 'handleRequest', wrapHandleRequest)
227
+ addHook({ name: 'next', versions: ['>=11.1 <13.2'], file: 'dist/server/next-server.js' }, nextServer => {
228
+ const Server = nextServer.default
194
229
  shimmer.wrap(Server.prototype, 'handleApiRequest', wrapHandleApiRequest)
195
- shimmer.wrap(Server.prototype, 'renderToResponse', wrapRenderToResponse)
196
- shimmer.wrap(Server.prototype, 'renderErrorToResponse', wrapRenderErrorToResponse)
197
- shimmer.wrap(Server.prototype, 'findPageComponents', wrapFindPageComponents)
198
-
199
230
  return nextServer
200
231
  })
201
232
 
@@ -208,8 +239,12 @@ addHook({
208
239
 
209
240
  shimmer.wrap(Server.prototype, 'handleRequest', wrapHandleRequest)
210
241
  shimmer.wrap(Server.prototype, 'handleApiRequest', wrapHandleApiRequest)
242
+
243
+ // Likewise with newer versions, these correlate to public API render methods for custom servers
244
+ // all public ones use these methods somewhere in their code path
211
245
  shimmer.wrap(Server.prototype, 'renderToHTML', wrapRenderToHTML)
212
246
  shimmer.wrap(Server.prototype, 'renderErrorToHTML', wrapRenderErrorToHTML)
247
+
213
248
  shimmer.wrap(Server.prototype, 'findPageComponents', wrapFindPageComponents)
214
249
 
215
250
  return nextServer