dd-trace 4.11.1 → 4.12.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.
- package/index.d.ts +43 -0
- package/package.json +2 -1
- package/packages/datadog-esbuild/index.js +10 -4
- package/packages/datadog-instrumentations/src/cucumber.js +30 -11
- package/packages/datadog-instrumentations/src/jest.js +22 -11
- package/packages/datadog-instrumentations/src/mocha.js +30 -8
- package/packages/datadog-instrumentations/src/next.js +16 -14
- package/packages/datadog-instrumentations/src/pg.js +46 -0
- package/packages/datadog-plugin-cucumber/src/index.js +14 -2
- package/packages/datadog-plugin-cypress/src/plugin.js +17 -8
- package/packages/datadog-plugin-jest/src/index.js +10 -2
- package/packages/datadog-plugin-jest/src/util.js +10 -4
- package/packages/datadog-plugin-mocha/src/index.js +14 -2
- package/packages/datadog-plugin-next/src/index.js +11 -3
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +19 -4
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +1 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/index.js +14 -5
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +120 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +0 -1
- package/packages/dd-trace/src/dogstatsd.js +65 -5
- package/packages/dd-trace/src/exporters/agent/writer.js +9 -9
- package/packages/dd-trace/src/opentracing/span.js +13 -13
- package/packages/dd-trace/src/opentracing/tracer.js +3 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +22 -1
- package/packages/dd-trace/src/plugins/util/test.js +18 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +7 -5
- package/packages/dd-trace/src/proxy.js +23 -2
- package/packages/dd-trace/src/ritm.js +10 -2
- /package/packages/dd-trace/src/{metrics.js → runtime_metrics.js} +0 -0
package/index.d.ts
CHANGED
|
@@ -121,6 +121,8 @@ export declare interface Tracer extends opentracing.Tracer {
|
|
|
121
121
|
appsec: Appsec;
|
|
122
122
|
|
|
123
123
|
TracerProvider: opentelemetry.TracerProvider;
|
|
124
|
+
|
|
125
|
+
dogstatsd: DogStatsD;
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
export declare interface TraceOptions extends Analyzable {
|
|
@@ -642,6 +644,47 @@ export declare interface User {
|
|
|
642
644
|
[key: string]: string | undefined
|
|
643
645
|
}
|
|
644
646
|
|
|
647
|
+
export declare interface DogStatsD {
|
|
648
|
+
/**
|
|
649
|
+
* Increments a metric by the specified value, optionally specifying tags.
|
|
650
|
+
* @param {string} stat The dot-separated metric name.
|
|
651
|
+
* @param {number} value The amount to increment the stat by.
|
|
652
|
+
* @param {[tag:string]:string|number} tags Tags to pass along, such as `[ 'foo:bar' ]`. Values are combined with config.tags.
|
|
653
|
+
*/
|
|
654
|
+
increment(stat: string, value?: number, tags?: { [tag: string]: string|number }): void
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Decrements a metric by the specified value, optionally specifying tags.
|
|
658
|
+
* @param {string} stat The dot-separated metric name.
|
|
659
|
+
* @param {number} value The amount to decrement the stat by.
|
|
660
|
+
* @param {[tag:string]:string|number} tags Tags to pass along, such as `[ 'foo:bar' ]`. Values are combined with config.tags.
|
|
661
|
+
*/
|
|
662
|
+
decrement(stat: string, value?: number, tags?: { [tag: string]: string|number }): void
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Sets a distribution value, optionally specifying tags.
|
|
666
|
+
* @param {string} stat The dot-separated metric name.
|
|
667
|
+
* @param {number} value The amount to increment the stat by.
|
|
668
|
+
* @param {[tag:string]:string|number} tags Tags to pass along, such as `[ 'foo:bar' ]`. Values are combined with config.tags.
|
|
669
|
+
*/
|
|
670
|
+
distribution(stat: string, value?: number, tags?: { [tag: string]: string|number }): void
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Sets a gauge value, optionally specifying tags.
|
|
674
|
+
* @param {string} stat The dot-separated metric name.
|
|
675
|
+
* @param {number} value The amount to increment the stat by.
|
|
676
|
+
* @param {[tag:string]:string|number} tags Tags to pass along, such as `[ 'foo:bar' ]`. Values are combined with config.tags.
|
|
677
|
+
*/
|
|
678
|
+
gauge(stat: string, value?: number, tags?: { [tag: string]: string|number }): void
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Forces any unsent metrics to be sent
|
|
682
|
+
*
|
|
683
|
+
* @beta This method is experimental and could be removed in future versions.
|
|
684
|
+
*/
|
|
685
|
+
flush(): void
|
|
686
|
+
}
|
|
687
|
+
|
|
645
688
|
export declare interface Appsec {
|
|
646
689
|
/**
|
|
647
690
|
* Links a successful login event to the current trace. Will link the passed user to the current trace with Appsec.setUser() internally.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.12.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"test:integration:cypress": "mocha --colors --timeout 30000 \"integration-tests/cypress/*.spec.js\"",
|
|
38
38
|
"test:integration:playwright": "mocha --colors --timeout 30000 \"integration-tests/playwright/*.spec.js\"",
|
|
39
39
|
"test:integration:serverless": "mocha --colors --timeout 30000 \"integration-tests/serverless/*.spec.js\"",
|
|
40
|
+
"test:integration:plugins": "mocha --colors --timeout 30000 \"packages/datadog-plugin-*/test/integration-test/*.spec.js\"",
|
|
40
41
|
"test:shimmer": "mocha --colors 'packages/datadog-shimmer/test/**/*.spec.js'",
|
|
41
42
|
"test:shimmer:ci": "nyc --no-clean --include 'packages/datadog-shimmer/src/**/*.js' -- npm run test:shimmer",
|
|
42
43
|
"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'",
|
|
@@ -50,12 +50,18 @@ for (const pkg of INSTRUMENTED) {
|
|
|
50
50
|
module.exports.name = 'datadog-esbuild'
|
|
51
51
|
|
|
52
52
|
module.exports.setup = function (build) {
|
|
53
|
+
const externalModules = new Set(build.initialOptions.external || [])
|
|
53
54
|
build.onResolve({ filter: /.*/ }, args => {
|
|
55
|
+
if (externalModules.has(args.path)) {
|
|
56
|
+
if (DEBUG) console.log(`EXTERNAL: ${args.path}`)
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
54
60
|
let fullPathToModule
|
|
55
61
|
try {
|
|
56
62
|
fullPathToModule = dotFriendlyResolve(args.path, args.resolveDir)
|
|
57
63
|
} catch (err) {
|
|
58
|
-
console.warn(`Unable to find "${args.path}". Is the package dead code?`)
|
|
64
|
+
console.warn(`MISSING: Unable to find "${args.path}". Is the package dead code?`)
|
|
59
65
|
return
|
|
60
66
|
}
|
|
61
67
|
const extracted = extractPackageAndModulePath(fullPathToModule)
|
|
@@ -74,7 +80,7 @@ module.exports.setup = function (build) {
|
|
|
74
80
|
} catch (err) {
|
|
75
81
|
if (err.code === 'MODULE_NOT_FOUND') {
|
|
76
82
|
if (!internal) {
|
|
77
|
-
console.warn(`Unable to find "${extracted.pkg}/package.json". Is the package dead code?`)
|
|
83
|
+
console.warn(`MISSING: Unable to find "${extracted.pkg}/package.json". Is the package dead code?`)
|
|
78
84
|
}
|
|
79
85
|
return
|
|
80
86
|
} else {
|
|
@@ -84,7 +90,7 @@ module.exports.setup = function (build) {
|
|
|
84
90
|
|
|
85
91
|
const packageJson = require(pathToPackageJson)
|
|
86
92
|
|
|
87
|
-
if (DEBUG) console.log(`RESOLVE ${packageName}@${packageJson.version}`)
|
|
93
|
+
if (DEBUG) console.log(`RESOLVE: ${packageName}@${packageJson.version}`)
|
|
88
94
|
|
|
89
95
|
// https://esbuild.github.io/plugins/#on-resolve-arguments
|
|
90
96
|
return {
|
|
@@ -114,7 +120,7 @@ module.exports.setup = function (build) {
|
|
|
114
120
|
build.onLoad({ filter: /.*/, namespace: NAMESPACE }, args => {
|
|
115
121
|
const data = args.pluginData
|
|
116
122
|
|
|
117
|
-
if (DEBUG) console.log(`LOAD ${data.pkg}@${data.version}, pkg "${data.path}"`)
|
|
123
|
+
if (DEBUG) console.log(`LOAD: ${data.pkg}@${data.version}, pkg "${data.path}"`)
|
|
118
124
|
|
|
119
125
|
const path = data.raw !== data.pkg
|
|
120
126
|
? `${data.pkg}/${data.path}`
|
|
@@ -21,6 +21,8 @@ const skippableSuitesCh = channel('ci:cucumber:test-suite:skippable')
|
|
|
21
21
|
const sessionStartCh = channel('ci:cucumber:session:start')
|
|
22
22
|
const sessionFinishCh = channel('ci:cucumber:session:finish')
|
|
23
23
|
|
|
24
|
+
const itrSkippedSuitesCh = channel('ci:cucumber:itr:skipped-suites')
|
|
25
|
+
|
|
24
26
|
const {
|
|
25
27
|
getCoveredFilenamesFromCoverage,
|
|
26
28
|
resetCoverage,
|
|
@@ -37,7 +39,6 @@ const patched = new WeakSet()
|
|
|
37
39
|
|
|
38
40
|
let pickleByFile = {}
|
|
39
41
|
const pickleResultByFile = {}
|
|
40
|
-
let isSuitesSkipped = false
|
|
41
42
|
|
|
42
43
|
function getSuiteStatusFromTestStatuses (testStatuses) {
|
|
43
44
|
if (testStatuses.some(status => status === 'fail')) {
|
|
@@ -216,11 +217,18 @@ addHook({
|
|
|
216
217
|
file: 'lib/runtime/test_case_runner.js'
|
|
217
218
|
}, testCaseHook)
|
|
218
219
|
|
|
219
|
-
function
|
|
220
|
-
return runtime.pickleIds.
|
|
220
|
+
function getFilteredPickles (runtime, suitesToSkip) {
|
|
221
|
+
return runtime.pickleIds.reduce((acc, pickleId) => {
|
|
221
222
|
const test = runtime.eventDataCollector.getPickle(pickleId)
|
|
222
|
-
|
|
223
|
-
|
|
223
|
+
const testSuitePath = getTestSuitePath(test.uri, process.cwd())
|
|
224
|
+
const isSkipped = suitesToSkip.includes(testSuitePath)
|
|
225
|
+
if (isSkipped) {
|
|
226
|
+
acc.skippedSuites.add(testSuitePath)
|
|
227
|
+
} else {
|
|
228
|
+
acc.picklesToRun.push(pickleId)
|
|
229
|
+
}
|
|
230
|
+
return acc
|
|
231
|
+
}, { skippedSuites: new Set(), picklesToRun: [] })
|
|
224
232
|
}
|
|
225
233
|
|
|
226
234
|
function getPickleByFile (runtime) {
|
|
@@ -239,7 +247,7 @@ addHook({
|
|
|
239
247
|
name: '@cucumber/cucumber',
|
|
240
248
|
versions: ['>=7.0.0'],
|
|
241
249
|
file: 'lib/runtime/index.js'
|
|
242
|
-
}, (runtimePackage,
|
|
250
|
+
}, (runtimePackage, frameworkVersion) => {
|
|
243
251
|
shimmer.wrap(runtimePackage.default.prototype, 'start', start => async function () {
|
|
244
252
|
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
245
253
|
let onDone
|
|
@@ -263,11 +271,16 @@ addHook({
|
|
|
263
271
|
})
|
|
264
272
|
|
|
265
273
|
const { err, skippableSuites } = await skippableSuitesPromise
|
|
274
|
+
let skippedSuites = []
|
|
275
|
+
let isSuitesSkipped = false
|
|
266
276
|
|
|
267
277
|
if (!err) {
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
this.pickleIds
|
|
278
|
+
const filteredPickles = getFilteredPickles(this, skippableSuites)
|
|
279
|
+
const { picklesToRun } = filteredPickles
|
|
280
|
+
isSuitesSkipped = picklesToRun.length !== this.pickleIds.length
|
|
281
|
+
this.pickleIds = picklesToRun
|
|
282
|
+
|
|
283
|
+
skippedSuites = Array.from(filteredPickles.skippedSuites)
|
|
271
284
|
}
|
|
272
285
|
|
|
273
286
|
pickleByFile = getPickleByFile(this)
|
|
@@ -276,8 +289,13 @@ addHook({
|
|
|
276
289
|
const command = process.env.npm_lifecycle_script || `cucumber-js ${processArgv}`
|
|
277
290
|
|
|
278
291
|
asyncResource.runInAsyncScope(() => {
|
|
279
|
-
sessionStartCh.publish({ command, frameworkVersion
|
|
292
|
+
sessionStartCh.publish({ command, frameworkVersion })
|
|
280
293
|
})
|
|
294
|
+
|
|
295
|
+
if (!err && skippedSuites.length) {
|
|
296
|
+
itrSkippedSuitesCh.publish({ skippedSuites, frameworkVersion })
|
|
297
|
+
}
|
|
298
|
+
|
|
281
299
|
const success = await start.apply(this, arguments)
|
|
282
300
|
|
|
283
301
|
let testCodeCoverageLinesTotal
|
|
@@ -296,7 +314,8 @@ addHook({
|
|
|
296
314
|
sessionFinishCh.publish({
|
|
297
315
|
status: success ? 'pass' : 'fail',
|
|
298
316
|
isSuitesSkipped,
|
|
299
|
-
testCodeCoverageLinesTotal
|
|
317
|
+
testCodeCoverageLinesTotal,
|
|
318
|
+
numSkippedSuites: skippedSuites.length
|
|
300
319
|
})
|
|
301
320
|
})
|
|
302
321
|
return success
|
|
@@ -39,10 +39,13 @@ const testErrCh = channel('ci:jest:test:err')
|
|
|
39
39
|
const skippableSuitesCh = channel('ci:jest:test-suite:skippable')
|
|
40
40
|
const jestItrConfigurationCh = channel('ci:jest:itr-configuration')
|
|
41
41
|
|
|
42
|
+
const itrSkippedSuitesCh = channel('ci:jest:itr:skipped-suites')
|
|
43
|
+
|
|
42
44
|
let skippableSuites = []
|
|
43
45
|
let isCodeCoverageEnabled = false
|
|
44
46
|
let isSuitesSkippingEnabled = false
|
|
45
47
|
let isSuitesSkipped = false
|
|
48
|
+
let numSkippedSuites = 0
|
|
46
49
|
|
|
47
50
|
const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
48
51
|
|
|
@@ -102,7 +105,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
102
105
|
await super.handleTestEvent(event, state)
|
|
103
106
|
}
|
|
104
107
|
|
|
105
|
-
const setNameToParams = (name, params) => { this.nameToParams[name] = params }
|
|
108
|
+
const setNameToParams = (name, params) => { this.nameToParams[name] = [...params] }
|
|
106
109
|
|
|
107
110
|
if (event.name === 'setup') {
|
|
108
111
|
if (this.global.test) {
|
|
@@ -191,7 +194,7 @@ addHook({
|
|
|
191
194
|
addHook({
|
|
192
195
|
name: '@jest/test-sequencer',
|
|
193
196
|
versions: ['>=24.8.0']
|
|
194
|
-
}, sequencerPackage => {
|
|
197
|
+
}, (sequencerPackage, frameworkVersion) => {
|
|
195
198
|
shimmer.wrap(sequencerPackage.default.prototype, 'shard', shard => function () {
|
|
196
199
|
const shardedTests = shard.apply(this, arguments)
|
|
197
200
|
|
|
@@ -202,13 +205,15 @@ addHook({
|
|
|
202
205
|
const [test] = shardedTests
|
|
203
206
|
const rootDir = test && test.context && test.context.config && test.context.config.rootDir
|
|
204
207
|
|
|
205
|
-
const
|
|
208
|
+
const { skippedSuites, suitesToRun } = getJestSuitesToRun(skippableSuites, shardedTests, rootDir || process.cwd())
|
|
206
209
|
|
|
207
|
-
isSuitesSkipped =
|
|
210
|
+
isSuitesSkipped = suitesToRun.length !== shardedTests.length
|
|
211
|
+
numSkippedSuites = skippedSuites.length
|
|
208
212
|
|
|
209
|
-
|
|
213
|
+
itrSkippedSuitesCh.publish({ skippedSuites, frameworkVersion })
|
|
210
214
|
|
|
211
|
-
|
|
215
|
+
skippableSuites = []
|
|
216
|
+
return suitesToRun
|
|
212
217
|
})
|
|
213
218
|
return sequencerPackage
|
|
214
219
|
})
|
|
@@ -279,10 +284,13 @@ function cliWrapper (cli, jestVersion) {
|
|
|
279
284
|
isSuitesSkipped,
|
|
280
285
|
isSuitesSkippingEnabled,
|
|
281
286
|
isCodeCoverageEnabled,
|
|
282
|
-
testCodeCoverageLinesTotal
|
|
287
|
+
testCodeCoverageLinesTotal,
|
|
288
|
+
numSkippedSuites
|
|
283
289
|
})
|
|
284
290
|
})
|
|
285
291
|
|
|
292
|
+
numSkippedSuites = 0
|
|
293
|
+
|
|
286
294
|
return result
|
|
287
295
|
})
|
|
288
296
|
|
|
@@ -468,7 +476,7 @@ addHook({
|
|
|
468
476
|
name: '@jest/core',
|
|
469
477
|
versions: ['>=24.8.0'],
|
|
470
478
|
file: 'build/SearchSource.js'
|
|
471
|
-
}, searchSourcePackage => {
|
|
479
|
+
}, (searchSourcePackage, frameworkVersion) => {
|
|
472
480
|
const SearchSource = searchSourcePackage.default ? searchSourcePackage.default : searchSourcePackage
|
|
473
481
|
|
|
474
482
|
shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () {
|
|
@@ -492,13 +500,16 @@ addHook({
|
|
|
492
500
|
const testPaths = await getTestPaths.apply(this, arguments)
|
|
493
501
|
const { tests } = testPaths
|
|
494
502
|
|
|
495
|
-
const
|
|
503
|
+
const { skippedSuites, suitesToRun } = getJestSuitesToRun(skippableSuites, tests, rootDir)
|
|
504
|
+
|
|
505
|
+
isSuitesSkipped = suitesToRun.length !== tests.length
|
|
506
|
+
numSkippedSuites = skippedSuites.length
|
|
496
507
|
|
|
497
|
-
|
|
508
|
+
itrSkippedSuitesCh.publish({ skippedSuites, frameworkVersion })
|
|
498
509
|
|
|
499
510
|
skippableSuites = []
|
|
500
511
|
|
|
501
|
-
return { ...testPaths, tests:
|
|
512
|
+
return { ...testPaths, tests: suitesToRun }
|
|
502
513
|
})
|
|
503
514
|
|
|
504
515
|
return searchSourcePackage
|
|
@@ -30,6 +30,8 @@ const testSuiteFinishCh = channel('ci:mocha:test-suite:finish')
|
|
|
30
30
|
const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
|
|
31
31
|
const testSuiteCodeCoverageCh = channel('ci:mocha:test-suite:code-coverage')
|
|
32
32
|
|
|
33
|
+
const itrSkippedSuitesCh = channel('ci:mocha:itr:skipped-suites')
|
|
34
|
+
|
|
33
35
|
// TODO: remove when root hooks and fixtures are implemented
|
|
34
36
|
const patched = new WeakSet()
|
|
35
37
|
|
|
@@ -47,6 +49,7 @@ const originalCoverageMap = createCoverageMap()
|
|
|
47
49
|
let suitesToSkip = []
|
|
48
50
|
let frameworkVersion
|
|
49
51
|
let isSuitesSkipped = false
|
|
52
|
+
let skippedSuites = []
|
|
50
53
|
|
|
51
54
|
function getSuitesByTestFile (root) {
|
|
52
55
|
const suitesByTestFile = {}
|
|
@@ -97,10 +100,17 @@ function getTestAsyncResource (test) {
|
|
|
97
100
|
return testToAr.get(originalFn)
|
|
98
101
|
}
|
|
99
102
|
|
|
100
|
-
function
|
|
101
|
-
return originalSuites.
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
function getFilteredSuites (originalSuites) {
|
|
104
|
+
return originalSuites.reduce((acc, suite) => {
|
|
105
|
+
const testPath = getTestSuitePath(suite.file, process.cwd())
|
|
106
|
+
const shouldSkip = suitesToSkip.includes(testPath)
|
|
107
|
+
if (shouldSkip) {
|
|
108
|
+
acc.skippedSuites.add(testPath)
|
|
109
|
+
} else {
|
|
110
|
+
acc.suitesToRun.push(suite)
|
|
111
|
+
}
|
|
112
|
+
return acc
|
|
113
|
+
}, { suitesToRun: [], skippedSuites: new Set() })
|
|
104
114
|
}
|
|
105
115
|
|
|
106
116
|
function mochaHook (Runner) {
|
|
@@ -137,13 +147,21 @@ function mochaHook (Runner) {
|
|
|
137
147
|
global.__coverage__ = fromCoverageMapToCoverage(originalCoverageMap)
|
|
138
148
|
}
|
|
139
149
|
|
|
140
|
-
testSessionFinishCh.publish({
|
|
150
|
+
testSessionFinishCh.publish({
|
|
151
|
+
status,
|
|
152
|
+
isSuitesSkipped,
|
|
153
|
+
testCodeCoverageLinesTotal,
|
|
154
|
+
numSkippedSuites: skippedSuites.length
|
|
155
|
+
})
|
|
141
156
|
}))
|
|
142
157
|
|
|
143
158
|
this.once('start', testRunAsyncResource.bind(function () {
|
|
144
159
|
const processArgv = process.argv.slice(2).join(' ')
|
|
145
160
|
const command = `mocha ${processArgv}`
|
|
146
161
|
testSessionStartCh.publish({ command, frameworkVersion })
|
|
162
|
+
if (skippedSuites.length) {
|
|
163
|
+
itrSkippedSuitesCh.publish({ skippedSuites, frameworkVersion })
|
|
164
|
+
}
|
|
147
165
|
}))
|
|
148
166
|
|
|
149
167
|
this.on('suite', function (suite) {
|
|
@@ -359,9 +377,13 @@ addHook({
|
|
|
359
377
|
suitesToSkip = skippableSuites
|
|
360
378
|
}
|
|
361
379
|
// We remove the suites that we skip through ITR
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
380
|
+
const filteredSuites = getFilteredSuites(runner.suite.suites)
|
|
381
|
+
const { suitesToRun } = filteredSuites
|
|
382
|
+
|
|
383
|
+
isSuitesSkipped = suitesToRun.length !== runner.suite.suites.length
|
|
384
|
+
runner.suite.suites = suitesToRun
|
|
385
|
+
|
|
386
|
+
skippedSuites = Array.from(filteredSuites.skippedSuites)
|
|
365
387
|
|
|
366
388
|
global.run()
|
|
367
389
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// TODO: either instrument all or none of the render functions
|
|
4
4
|
|
|
5
|
-
const { channel, addHook
|
|
5
|
+
const { channel, addHook } = require('./helpers/instrument')
|
|
6
6
|
const shimmer = require('../../datadog-shimmer')
|
|
7
7
|
const { DD_MAJOR } = require('../../../version')
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ const finishChannel = channel('apm:next:request:finish')
|
|
|
11
11
|
const errorChannel = channel('apm:next:request:error')
|
|
12
12
|
const pageLoadChannel = channel('apm:next:page:load')
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const requests = new WeakSet()
|
|
15
15
|
|
|
16
16
|
function wrapHandleRequest (handleRequest) {
|
|
17
17
|
return function (req, res, pathname, query) {
|
|
@@ -105,38 +105,40 @@ function getPageFromPath (page, dynamicRoutes = []) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
function instrument (req, res, handler) {
|
|
108
|
-
|
|
108
|
+
req = req.originalRequest || req
|
|
109
|
+
res = res.originalResponse || res
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
if (requests.has(req)) return handler()
|
|
111
112
|
|
|
112
|
-
|
|
113
|
+
requests.add(req)
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
startChannel.publish({ req, res })
|
|
115
|
+
const ctx = { req, res }
|
|
116
116
|
|
|
117
|
+
return startChannel.runStores(ctx, () => {
|
|
117
118
|
try {
|
|
118
|
-
const promise = handler()
|
|
119
|
+
const promise = handler(ctx)
|
|
119
120
|
|
|
120
121
|
// promise should only reject when propagateError is true:
|
|
121
122
|
// https://github.com/vercel/next.js/blob/cee656238a/packages/next/server/api-utils/node.ts#L547
|
|
122
123
|
return promise.then(
|
|
123
|
-
result => finish(
|
|
124
|
-
err => finish(
|
|
124
|
+
result => finish(ctx, result),
|
|
125
|
+
err => finish(ctx, null, err)
|
|
125
126
|
)
|
|
126
127
|
} catch (e) {
|
|
127
128
|
// this will probably never happen as the handler caller is an async function:
|
|
128
129
|
// https://github.com/vercel/next.js/blob/cee656238a/packages/next/server/api-utils/node.ts#L420
|
|
129
|
-
return finish(
|
|
130
|
+
return finish(ctx, null, e)
|
|
130
131
|
}
|
|
131
132
|
})
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
function finish (
|
|
135
|
+
function finish (ctx, result, err) {
|
|
135
136
|
if (err) {
|
|
136
|
-
|
|
137
|
+
ctx.error = err
|
|
138
|
+
errorChannel.publish(ctx)
|
|
137
139
|
}
|
|
138
140
|
|
|
139
|
-
finishChannel.publish(
|
|
141
|
+
finishChannel.publish(ctx)
|
|
140
142
|
|
|
141
143
|
if (err) {
|
|
142
144
|
throw err
|
|
@@ -11,8 +11,12 @@ const startCh = channel('apm:pg:query:start')
|
|
|
11
11
|
const finishCh = channel('apm:pg:query:finish')
|
|
12
12
|
const errorCh = channel('apm:pg:query:error')
|
|
13
13
|
|
|
14
|
+
const startPoolQueryCh = channel('datadog:pg:pool:query:start')
|
|
15
|
+
const finishPoolQueryCh = channel('datadog:pg:pool:query:finish')
|
|
16
|
+
|
|
14
17
|
addHook({ name: 'pg', versions: ['>=8.0.3'] }, pg => {
|
|
15
18
|
shimmer.wrap(pg.Client.prototype, 'query', query => wrapQuery(query))
|
|
19
|
+
shimmer.wrap(pg.Pool.prototype, 'query', query => wrapPoolQuery(query))
|
|
16
20
|
return pg
|
|
17
21
|
})
|
|
18
22
|
|
|
@@ -97,3 +101,45 @@ function wrapQuery (query) {
|
|
|
97
101
|
})
|
|
98
102
|
}
|
|
99
103
|
}
|
|
104
|
+
|
|
105
|
+
function wrapPoolQuery (query) {
|
|
106
|
+
return function () {
|
|
107
|
+
if (!startPoolQueryCh.hasSubscribers) {
|
|
108
|
+
return query.apply(this, arguments)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
112
|
+
|
|
113
|
+
const pgQuery = arguments[0] && typeof arguments[0] === 'object' ? arguments[0] : { text: arguments[0] }
|
|
114
|
+
|
|
115
|
+
return asyncResource.runInAsyncScope(() => {
|
|
116
|
+
startPoolQueryCh.publish({
|
|
117
|
+
query: pgQuery
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const finish = asyncResource.bind(function () {
|
|
121
|
+
finishPoolQueryCh.publish()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
const cb = arguments[arguments.length - 1]
|
|
125
|
+
if (typeof cb === 'function') {
|
|
126
|
+
arguments[arguments.length - 1] = shimmer.wrap(cb, function () {
|
|
127
|
+
finish()
|
|
128
|
+
return cb.apply(this, arguments)
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const retval = query.apply(this, arguments)
|
|
133
|
+
|
|
134
|
+
if (retval && retval.then) {
|
|
135
|
+
retval.then(() => {
|
|
136
|
+
finish()
|
|
137
|
+
}).catch(() => {
|
|
138
|
+
finish()
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return retval
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -25,12 +25,24 @@ class CucumberPlugin extends CiPlugin {
|
|
|
25
25
|
|
|
26
26
|
this.sourceRoot = process.cwd()
|
|
27
27
|
|
|
28
|
-
this.addSub('ci:cucumber:session:finish', ({
|
|
28
|
+
this.addSub('ci:cucumber:session:finish', ({
|
|
29
|
+
status,
|
|
30
|
+
isSuitesSkipped,
|
|
31
|
+
numSkippedSuites,
|
|
32
|
+
testCodeCoverageLinesTotal
|
|
33
|
+
}) => {
|
|
29
34
|
const { isSuitesSkippingEnabled, isCodeCoverageEnabled } = this.itrConfig || {}
|
|
30
35
|
addIntelligentTestRunnerSpanTags(
|
|
31
36
|
this.testSessionSpan,
|
|
32
37
|
this.testModuleSpan,
|
|
33
|
-
{
|
|
38
|
+
{
|
|
39
|
+
isSuitesSkipped,
|
|
40
|
+
isSuitesSkippingEnabled,
|
|
41
|
+
isCodeCoverageEnabled,
|
|
42
|
+
testCodeCoverageLinesTotal,
|
|
43
|
+
skippingCount: numSkippedSuites,
|
|
44
|
+
skippingType: 'suite'
|
|
45
|
+
}
|
|
34
46
|
)
|
|
35
47
|
|
|
36
48
|
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
@@ -20,7 +20,8 @@ const {
|
|
|
20
20
|
finishAllTraceSpans,
|
|
21
21
|
getCoveredFilenamesFromCoverage,
|
|
22
22
|
getTestSuitePath,
|
|
23
|
-
addIntelligentTestRunnerSpanTags
|
|
23
|
+
addIntelligentTestRunnerSpanTags,
|
|
24
|
+
TEST_SKIPPED_BY_ITR
|
|
24
25
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
25
26
|
const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
|
|
26
27
|
const log = require('../../dd-trace/src/log')
|
|
@@ -120,6 +121,7 @@ function getSkippableTests (isSuitesSkippingEnabled, tracer, testConfiguration)
|
|
|
120
121
|
|
|
121
122
|
module.exports = (on, config) => {
|
|
122
123
|
let isTestsSkipped = false
|
|
124
|
+
const skippedTests = []
|
|
123
125
|
const tracer = require('../../dd-trace')
|
|
124
126
|
const testEnvironmentMetadata = getTestEnvironmentMetadata(TEST_FRAMEWORK_NAME)
|
|
125
127
|
|
|
@@ -248,19 +250,23 @@ module.exports = (on, config) => {
|
|
|
248
250
|
const cypressTests = tests || []
|
|
249
251
|
const finishedTests = finishedTestsByFile[spec.relative] || []
|
|
250
252
|
|
|
251
|
-
// Get tests that didn't go through `dd:afterEach`
|
|
253
|
+
// Get tests that didn't go through `dd:afterEach`
|
|
252
254
|
// and create a skipped test span for each of them
|
|
253
255
|
cypressTests.filter(({ title }) => {
|
|
254
256
|
const cypressTestName = title.join(' ')
|
|
255
|
-
const isSkippedByItr = testsToSkip.find(test =>
|
|
256
|
-
cypressTestName === test.name && spec.relative === test.suite
|
|
257
|
-
)
|
|
258
257
|
const isTestFinished = finishedTests.find(({ testName }) => cypressTestName === testName)
|
|
259
258
|
|
|
260
|
-
return !
|
|
259
|
+
return !isTestFinished
|
|
261
260
|
}).forEach(({ title }) => {
|
|
262
|
-
const
|
|
261
|
+
const cypressTestName = title.join(' ')
|
|
262
|
+
const isSkippedByItr = testsToSkip.find(test =>
|
|
263
|
+
cypressTestName === test.name && spec.relative === test.suite
|
|
264
|
+
)
|
|
265
|
+
const skippedTestSpan = getTestSpan(cypressTestName, spec.relative)
|
|
263
266
|
skippedTestSpan.setTag(TEST_STATUS, 'skip')
|
|
267
|
+
if (isSkippedByItr) {
|
|
268
|
+
skippedTestSpan.setTag(TEST_SKIPPED_BY_ITR, 'true')
|
|
269
|
+
}
|
|
264
270
|
skippedTestSpan.finish()
|
|
265
271
|
})
|
|
266
272
|
|
|
@@ -309,7 +315,9 @@ module.exports = (on, config) => {
|
|
|
309
315
|
{
|
|
310
316
|
isSuitesSkipped: isTestsSkipped,
|
|
311
317
|
isSuitesSkippingEnabled,
|
|
312
|
-
isCodeCoverageEnabled
|
|
318
|
+
isCodeCoverageEnabled,
|
|
319
|
+
skippingType: 'test',
|
|
320
|
+
skippingCount: skippedTests.length
|
|
313
321
|
}
|
|
314
322
|
)
|
|
315
323
|
|
|
@@ -353,6 +361,7 @@ module.exports = (on, config) => {
|
|
|
353
361
|
if (testsToSkip.find(test => {
|
|
354
362
|
return testName === test.name && testSuite === test.suite
|
|
355
363
|
})) {
|
|
364
|
+
skippedTests.push(test)
|
|
356
365
|
isTestsSkipped = true
|
|
357
366
|
return { shouldSkip: true }
|
|
358
367
|
}
|
|
@@ -49,7 +49,8 @@ class JestPlugin extends CiPlugin {
|
|
|
49
49
|
isSuitesSkipped,
|
|
50
50
|
isSuitesSkippingEnabled,
|
|
51
51
|
isCodeCoverageEnabled,
|
|
52
|
-
testCodeCoverageLinesTotal
|
|
52
|
+
testCodeCoverageLinesTotal,
|
|
53
|
+
numSkippedSuites
|
|
53
54
|
}) => {
|
|
54
55
|
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
55
56
|
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
@@ -57,7 +58,14 @@ class JestPlugin extends CiPlugin {
|
|
|
57
58
|
addIntelligentTestRunnerSpanTags(
|
|
58
59
|
this.testSessionSpan,
|
|
59
60
|
this.testModuleSpan,
|
|
60
|
-
{
|
|
61
|
+
{
|
|
62
|
+
isSuitesSkipped,
|
|
63
|
+
isSuitesSkippingEnabled,
|
|
64
|
+
isCodeCoverageEnabled,
|
|
65
|
+
testCodeCoverageLinesTotal,
|
|
66
|
+
skippingType: 'suite',
|
|
67
|
+
skippingCount: numSkippedSuites
|
|
68
|
+
}
|
|
61
69
|
)
|
|
62
70
|
|
|
63
71
|
this.testModuleSpan.finish()
|
|
@@ -48,10 +48,16 @@ function getJestTestName (test) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
function getJestSuitesToRun (skippableSuites, originalTests, rootDir) {
|
|
51
|
-
return originalTests.
|
|
52
|
-
const relativePath = getTestSuitePath(
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
return originalTests.reduce((acc, test) => {
|
|
52
|
+
const relativePath = getTestSuitePath(test.path, rootDir)
|
|
53
|
+
const shouldBeSkipped = skippableSuites.includes(relativePath)
|
|
54
|
+
if (shouldBeSkipped) {
|
|
55
|
+
acc.skippedSuites.push(relativePath)
|
|
56
|
+
} else {
|
|
57
|
+
acc.suitesToRun.push(test)
|
|
58
|
+
}
|
|
59
|
+
return acc
|
|
60
|
+
}, { skippedSuites: [], suitesToRun: [] })
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
module.exports = { getFormattedJestTestParameters, getJestTestName, getJestSuitesToRun }
|