dd-trace 4.16.0 → 4.17.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/LICENSE-3rdparty.csv +1 -0
- package/package.json +4 -3
- package/packages/datadog-instrumentations/src/body-parser.js +2 -1
- package/packages/datadog-instrumentations/src/cucumber.js +24 -4
- package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +45 -0
- package/packages/datadog-instrumentations/src/express.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
- package/packages/datadog-instrumentations/src/jest.js +20 -11
- package/packages/datadog-instrumentations/src/knex.js +62 -1
- package/packages/datadog-instrumentations/src/mocha.js +19 -4
- package/packages/datadog-instrumentations/src/mongodb.js +63 -0
- package/packages/datadog-instrumentations/src/mongoose.js +140 -1
- package/packages/datadog-instrumentations/src/next.js +40 -0
- package/packages/datadog-instrumentations/src/playwright.js +11 -2
- package/packages/datadog-plugin-cucumber/src/index.js +17 -5
- package/packages/datadog-plugin-cypress/src/plugin.js +38 -8
- package/packages/datadog-plugin-jest/src/index.js +19 -4
- package/packages/datadog-plugin-jest/src/util.js +45 -2
- package/packages/datadog-plugin-memcached/src/index.js +10 -5
- package/packages/datadog-plugin-mocha/src/index.js +19 -6
- package/packages/dd-trace/src/appsec/channels.js +3 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +166 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +21 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +3 -3
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -2
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +4 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +25 -12
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +4 -4
- package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks-generator.js +13 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +2 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +16 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -4
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +9 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +13 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +169 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +31 -13
- package/packages/dd-trace/src/appsec/remote_config/manager.js +11 -3
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +14 -1
- package/packages/dd-trace/src/config.js +8 -0
- package/packages/dd-trace/src/format.js +3 -0
- package/packages/dd-trace/src/plugin_manager.js +3 -1
- package/packages/dd-trace/src/plugins/util/ci.js +17 -0
- package/packages/dd-trace/src/plugins/util/git.js +26 -4
- package/packages/dd-trace/src/plugins/util/test.js +16 -1
- package/packages/dd-trace/src/profiling/config.js +36 -5
- package/packages/dd-trace/src/profiling/profilers/wall.js +7 -1
- package/packages/dd-trace/src/service-naming/extra-services.js +24 -0
- package/packages/dd-trace/src/telemetry/metrics.js +0 -5
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -14,6 +14,7 @@ require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
|
|
|
14
14
|
require,int64-buffer,MIT,Copyright 2015-2016 Yusuke Kawasaki
|
|
15
15
|
require,ipaddr.js,MIT,Copyright 2011-2017 whitequark
|
|
16
16
|
require,istanbul-lib-coverage,BSD-3-Clause,Copyright 2012-2015 Yahoo! Inc.
|
|
17
|
+
require,jest-docblock,MIT,Copyright Meta Platforms, Inc. and affiliates.
|
|
17
18
|
require,koalas,MIT,Copyright 2013-2017 Brian Woodward
|
|
18
19
|
require,limiter,MIT,Copyright 2011 John Hurliman
|
|
19
20
|
require,lodash.kebabcase,MIT,Copyright JS Foundation and other contributors
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.17.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -70,9 +70,9 @@
|
|
|
70
70
|
"dependencies": {
|
|
71
71
|
"@datadog/native-appsec": "^4.0.0",
|
|
72
72
|
"@datadog/native-iast-rewriter": "2.1.3",
|
|
73
|
-
"@datadog/native-iast-taint-tracking": "1.
|
|
73
|
+
"@datadog/native-iast-taint-tracking": "1.6.1",
|
|
74
74
|
"@datadog/native-metrics": "^2.0.0",
|
|
75
|
-
"@datadog/pprof": "
|
|
75
|
+
"@datadog/pprof": "4.0.0",
|
|
76
76
|
"@datadog/sketches-js": "^2.1.0",
|
|
77
77
|
"@opentelemetry/api": "^1.0.0",
|
|
78
78
|
"@opentelemetry/core": "^1.14.0",
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
"int64-buffer": "^0.1.9",
|
|
84
84
|
"ipaddr.js": "^2.1.0",
|
|
85
85
|
"istanbul-lib-coverage": "3.2.0",
|
|
86
|
+
"jest-docblock": "^29.7.0",
|
|
86
87
|
"koalas": "^1.0.2",
|
|
87
88
|
"limiter": "^1.1.4",
|
|
88
89
|
"lodash.kebabcase": "^4.1.1",
|
|
@@ -10,8 +10,9 @@ function publishRequestBodyAndNext (req, res, next) {
|
|
|
10
10
|
return function () {
|
|
11
11
|
if (bodyParserReadCh.hasSubscribers && req) {
|
|
12
12
|
const abortController = new AbortController()
|
|
13
|
+
const body = req.body
|
|
13
14
|
|
|
14
|
-
bodyParserReadCh.publish({ req, res, abortController })
|
|
15
|
+
bodyParserReadCh.publish({ req, res, body, abortController })
|
|
15
16
|
|
|
16
17
|
if (abortController.signal.aborted) return
|
|
17
18
|
}
|
|
@@ -31,6 +31,10 @@ const {
|
|
|
31
31
|
getTestSuitePath
|
|
32
32
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
33
33
|
|
|
34
|
+
const isMarkedAsUnskippable = (pickle) => {
|
|
35
|
+
return !!pickle.tags.find(tag => tag.name === '@datadog:unskippable')
|
|
36
|
+
}
|
|
37
|
+
|
|
34
38
|
// We'll preserve the original coverage here
|
|
35
39
|
const originalCoverageMap = createCoverageMap()
|
|
36
40
|
|
|
@@ -39,6 +43,9 @@ const patched = new WeakSet()
|
|
|
39
43
|
|
|
40
44
|
let pickleByFile = {}
|
|
41
45
|
const pickleResultByFile = {}
|
|
46
|
+
let skippableSuites = []
|
|
47
|
+
let isForcedToRun = false
|
|
48
|
+
let isUnskippable = false
|
|
42
49
|
|
|
43
50
|
function getSuiteStatusFromTestStatuses (testStatuses) {
|
|
44
51
|
if (testStatuses.some(status => status === 'fail')) {
|
|
@@ -91,7 +98,11 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
91
98
|
const testSuiteFullPath = this.pickle.uri
|
|
92
99
|
|
|
93
100
|
if (!pickleResultByFile[testSuiteFullPath]) { // first test in suite
|
|
94
|
-
|
|
101
|
+
isUnskippable = isMarkedAsUnskippable(this.pickle)
|
|
102
|
+
const testSuitePath = getTestSuitePath(testSuiteFullPath, process.cwd())
|
|
103
|
+
isForcedToRun = isUnskippable && skippableSuites.includes(testSuitePath)
|
|
104
|
+
|
|
105
|
+
testSuiteStartCh.publish({ testSuitePath, isUnskippable, isForcedToRun })
|
|
95
106
|
}
|
|
96
107
|
|
|
97
108
|
const testSourceLine = this.gherkinDocument &&
|
|
@@ -221,8 +232,11 @@ function getFilteredPickles (runtime, suitesToSkip) {
|
|
|
221
232
|
return runtime.pickleIds.reduce((acc, pickleId) => {
|
|
222
233
|
const test = runtime.eventDataCollector.getPickle(pickleId)
|
|
223
234
|
const testSuitePath = getTestSuitePath(test.uri, process.cwd())
|
|
235
|
+
|
|
236
|
+
const isUnskippable = isMarkedAsUnskippable(test)
|
|
224
237
|
const isSkipped = suitesToSkip.includes(testSuitePath)
|
|
225
|
-
|
|
238
|
+
|
|
239
|
+
if (isSkipped && !isUnskippable) {
|
|
226
240
|
acc.skippedSuites.add(testSuitePath)
|
|
227
241
|
} else {
|
|
228
242
|
acc.picklesToRun.push(pickleId)
|
|
@@ -270,7 +284,11 @@ addHook({
|
|
|
270
284
|
skippableSuitesCh.publish({ onDone })
|
|
271
285
|
})
|
|
272
286
|
|
|
273
|
-
const
|
|
287
|
+
const skippableResponse = await skippableSuitesPromise
|
|
288
|
+
|
|
289
|
+
const err = skippableResponse.err
|
|
290
|
+
skippableSuites = skippableResponse.skippableSuites
|
|
291
|
+
|
|
274
292
|
let skippedSuites = []
|
|
275
293
|
let isSuitesSkipped = false
|
|
276
294
|
|
|
@@ -315,7 +333,9 @@ addHook({
|
|
|
315
333
|
status: success ? 'pass' : 'fail',
|
|
316
334
|
isSuitesSkipped,
|
|
317
335
|
testCodeCoverageLinesTotal,
|
|
318
|
-
numSkippedSuites: skippedSuites.length
|
|
336
|
+
numSkippedSuites: skippedSuites.length,
|
|
337
|
+
hasUnskippableSuites: isUnskippable,
|
|
338
|
+
hasForcedToRunSuites: isForcedToRun
|
|
319
339
|
})
|
|
320
340
|
})
|
|
321
341
|
return success
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
channel,
|
|
5
|
+
addHook
|
|
6
|
+
} = require('./helpers/instrument')
|
|
7
|
+
const shimmer = require('../../datadog-shimmer')
|
|
8
|
+
|
|
9
|
+
const sanitizeMethodFinished = channel('datadog:express-mongo-sanitize:sanitize:finish')
|
|
10
|
+
const sanitizeMiddlewareFinished = channel('datadog:express-mongo-sanitize:filter:finish')
|
|
11
|
+
|
|
12
|
+
const propertiesToSanitize = ['body', 'params', 'headers', 'query']
|
|
13
|
+
|
|
14
|
+
addHook({ name: 'express-mongo-sanitize', versions: ['>=1.0.0'] }, expressMongoSanitize => {
|
|
15
|
+
shimmer.wrap(expressMongoSanitize, 'sanitize', sanitize => function () {
|
|
16
|
+
const sanitizedObject = sanitize.apply(this, arguments)
|
|
17
|
+
|
|
18
|
+
if (sanitizeMethodFinished.hasSubscribers) {
|
|
19
|
+
sanitizeMethodFinished.publish({ sanitizedObject })
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return sanitizedObject
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
return shimmer.wrap(expressMongoSanitize, function () {
|
|
26
|
+
const middleware = expressMongoSanitize.apply(this, arguments)
|
|
27
|
+
|
|
28
|
+
return shimmer.wrap(middleware, function (req, res, next) {
|
|
29
|
+
if (!sanitizeMiddlewareFinished.hasSubscribers) {
|
|
30
|
+
return middleware.apply(this, arguments)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const wrappedNext = shimmer.wrap(next, function () {
|
|
34
|
+
sanitizeMiddlewareFinished.publish({
|
|
35
|
+
sanitizedProperties: propertiesToSanitize,
|
|
36
|
+
req
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return next.apply(this, arguments)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
return middleware.call(this, req, res, wrappedNext)
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
})
|
|
@@ -33,8 +33,9 @@ function publishQueryParsedAndNext (req, res, next) {
|
|
|
33
33
|
return function () {
|
|
34
34
|
if (queryParserReadCh.hasSubscribers && req) {
|
|
35
35
|
const abortController = new AbortController()
|
|
36
|
+
const query = req.query
|
|
36
37
|
|
|
37
|
-
queryParserReadCh.publish({ req, res, abortController })
|
|
38
|
+
queryParserReadCh.publish({ req, res, query, abortController })
|
|
38
39
|
|
|
39
40
|
if (abortController.signal.aborted) return
|
|
40
41
|
}
|
|
@@ -38,6 +38,7 @@ module.exports = {
|
|
|
38
38
|
'dns': () => require('../dns'),
|
|
39
39
|
'elasticsearch': () => require('../elasticsearch'),
|
|
40
40
|
'express': () => require('../express'),
|
|
41
|
+
'express-mongo-sanitize': () => require('../express-mongo-sanitize'),
|
|
41
42
|
'fastify': () => require('../fastify'),
|
|
42
43
|
'find-my-way': () => require('../find-my-way'),
|
|
43
44
|
'fs': () => require('../fs'),
|
|
@@ -68,7 +69,7 @@ module.exports = {
|
|
|
68
69
|
'mocha': () => require('../mocha'),
|
|
69
70
|
'mocha-each': () => require('../mocha'),
|
|
70
71
|
'moleculer': () => require('../moleculer'),
|
|
71
|
-
'mongodb': () => require('../mongodb
|
|
72
|
+
'mongodb': () => require('../mongodb'),
|
|
72
73
|
'mongodb-core': () => require('../mongodb-core'),
|
|
73
74
|
'mongoose': () => require('../mongoose'),
|
|
74
75
|
'mysql': () => require('../mysql'),
|
|
@@ -46,6 +46,8 @@ let isCodeCoverageEnabled = false
|
|
|
46
46
|
let isSuitesSkippingEnabled = false
|
|
47
47
|
let isSuitesSkipped = false
|
|
48
48
|
let numSkippedSuites = 0
|
|
49
|
+
let hasUnskippableSuites = false
|
|
50
|
+
let hasForcedToRunSuites = false
|
|
49
51
|
|
|
50
52
|
const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
51
53
|
|
|
@@ -205,15 +207,17 @@ addHook({
|
|
|
205
207
|
const [test] = shardedTests
|
|
206
208
|
const rootDir = test && test.context && test.context.config && test.context.config.rootDir
|
|
207
209
|
|
|
208
|
-
const
|
|
210
|
+
const jestSuitesToRun = getJestSuitesToRun(skippableSuites, shardedTests, rootDir || process.cwd())
|
|
211
|
+
hasUnskippableSuites = jestSuitesToRun.hasUnskippableSuites
|
|
212
|
+
hasForcedToRunSuites = jestSuitesToRun.hasForcedToRunSuites
|
|
209
213
|
|
|
210
|
-
isSuitesSkipped = suitesToRun.length !== shardedTests.length
|
|
211
|
-
numSkippedSuites = skippedSuites.length
|
|
214
|
+
isSuitesSkipped = jestSuitesToRun.suitesToRun.length !== shardedTests.length
|
|
215
|
+
numSkippedSuites = jestSuitesToRun.skippedSuites.length
|
|
212
216
|
|
|
213
|
-
itrSkippedSuitesCh.publish({ skippedSuites, frameworkVersion })
|
|
217
|
+
itrSkippedSuitesCh.publish({ skippedSuites: jestSuitesToRun.skippedSuites, frameworkVersion })
|
|
214
218
|
|
|
215
219
|
skippableSuites = []
|
|
216
|
-
return suitesToRun
|
|
220
|
+
return jestSuitesToRun.suitesToRun
|
|
217
221
|
})
|
|
218
222
|
return sequencerPackage
|
|
219
223
|
})
|
|
@@ -285,7 +289,9 @@ function cliWrapper (cli, jestVersion) {
|
|
|
285
289
|
isSuitesSkippingEnabled,
|
|
286
290
|
isCodeCoverageEnabled,
|
|
287
291
|
testCodeCoverageLinesTotal,
|
|
288
|
-
numSkippedSuites
|
|
292
|
+
numSkippedSuites,
|
|
293
|
+
hasUnskippableSuites,
|
|
294
|
+
hasForcedToRunSuites
|
|
289
295
|
})
|
|
290
296
|
})
|
|
291
297
|
|
|
@@ -500,16 +506,19 @@ addHook({
|
|
|
500
506
|
const testPaths = await getTestPaths.apply(this, arguments)
|
|
501
507
|
const { tests } = testPaths
|
|
502
508
|
|
|
503
|
-
const
|
|
509
|
+
const jestSuitesToRun = getJestSuitesToRun(skippableSuites, tests, rootDir)
|
|
504
510
|
|
|
505
|
-
|
|
506
|
-
|
|
511
|
+
hasUnskippableSuites = jestSuitesToRun.hasUnskippableSuites
|
|
512
|
+
hasForcedToRunSuites = jestSuitesToRun.hasForcedToRunSuites
|
|
507
513
|
|
|
508
|
-
|
|
514
|
+
isSuitesSkipped = jestSuitesToRun.suitesToRun.length !== tests.length
|
|
515
|
+
numSkippedSuites = jestSuitesToRun.skippedSuites.length
|
|
516
|
+
|
|
517
|
+
itrSkippedSuitesCh.publish({ skippedSuites: jestSuitesToRun.skippedSuites, frameworkVersion })
|
|
509
518
|
|
|
510
519
|
skippableSuites = []
|
|
511
520
|
|
|
512
|
-
return { ...testPaths, tests: suitesToRun }
|
|
521
|
+
return { ...testPaths, tests: jestSuitesToRun.suitesToRun }
|
|
513
522
|
})
|
|
514
523
|
|
|
515
524
|
return searchSourcePackage
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { addHook } = require('./helpers/instrument')
|
|
3
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
4
4
|
const { wrapThen } = require('./helpers/promise')
|
|
5
5
|
const shimmer = require('../../datadog-shimmer')
|
|
6
6
|
|
|
7
|
+
const startRawQueryCh = channel('datadog:knex:raw:start')
|
|
8
|
+
const finishRawQueryCh = channel('datadog:knex:raw:finish')
|
|
9
|
+
|
|
7
10
|
patch('lib/query/builder.js')
|
|
8
11
|
patch('lib/raw.js')
|
|
9
12
|
patch('lib/schema/builder.js')
|
|
@@ -18,3 +21,61 @@ function patch (file) {
|
|
|
18
21
|
return Builder
|
|
19
22
|
})
|
|
20
23
|
}
|
|
24
|
+
|
|
25
|
+
addHook({
|
|
26
|
+
name: 'knex',
|
|
27
|
+
versions: ['>=2'],
|
|
28
|
+
file: 'lib/knex-builder/Knex.js'
|
|
29
|
+
}, Knex => {
|
|
30
|
+
shimmer.wrap(Knex.Client.prototype, 'raw', raw => function () {
|
|
31
|
+
if (!startRawQueryCh.hasSubscribers) {
|
|
32
|
+
return raw.apply(this, arguments)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const sql = arguments[0]
|
|
36
|
+
|
|
37
|
+
// Skip query done by Knex to get the value used for undefined
|
|
38
|
+
if (sql === 'DEFAULT') {
|
|
39
|
+
return raw.apply(this, arguments)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function finish () {
|
|
43
|
+
finishRawQueryCh.publish()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
startRawQueryCh.publish({ sql, dialect: this.dialect })
|
|
47
|
+
|
|
48
|
+
const rawResult = raw.apply(this, arguments)
|
|
49
|
+
|
|
50
|
+
shimmer.wrap(rawResult, 'then', originalThen => function () {
|
|
51
|
+
arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
|
|
52
|
+
arguments[1] = wrapCallbackWithFinish(arguments[1], finish)
|
|
53
|
+
|
|
54
|
+
const originalThenResult = originalThen.apply(this, arguments)
|
|
55
|
+
|
|
56
|
+
shimmer.wrap(originalThenResult, 'catch', originalCatch => function () {
|
|
57
|
+
arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
|
|
58
|
+
return originalCatch.apply(this, arguments)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
return originalThenResult
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
shimmer.wrap(rawResult, 'asCallback', originalAsCallback => function () {
|
|
65
|
+
arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
|
|
66
|
+
return originalAsCallback.apply(this, arguments)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
return rawResult
|
|
70
|
+
})
|
|
71
|
+
return Knex
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
function wrapCallbackWithFinish (callback, finish) {
|
|
75
|
+
if (typeof callback !== 'function') return callback
|
|
76
|
+
|
|
77
|
+
return function () {
|
|
78
|
+
finish()
|
|
79
|
+
callback.apply(this, arguments)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const { createCoverageMap } = require('istanbul-lib-coverage')
|
|
2
2
|
|
|
3
|
+
const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util')
|
|
4
|
+
|
|
3
5
|
const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
4
6
|
const shimmer = require('../../datadog-shimmer')
|
|
5
7
|
const log = require('../../dd-trace/src/log')
|
|
6
|
-
|
|
7
8
|
const {
|
|
8
9
|
getCoveredFilenamesFromCoverage,
|
|
9
10
|
resetCoverage,
|
|
@@ -50,6 +51,8 @@ let suitesToSkip = []
|
|
|
50
51
|
let frameworkVersion
|
|
51
52
|
let isSuitesSkipped = false
|
|
52
53
|
let skippedSuites = []
|
|
54
|
+
const unskippableSuites = []
|
|
55
|
+
let isForcedToRun = false
|
|
53
56
|
|
|
54
57
|
function getSuitesByTestFile (root) {
|
|
55
58
|
const suitesByTestFile = {}
|
|
@@ -104,7 +107,8 @@ function getFilteredSuites (originalSuites) {
|
|
|
104
107
|
return originalSuites.reduce((acc, suite) => {
|
|
105
108
|
const testPath = getTestSuitePath(suite.file, process.cwd())
|
|
106
109
|
const shouldSkip = suitesToSkip.includes(testPath)
|
|
107
|
-
|
|
110
|
+
const isUnskippable = unskippableSuites.includes(suite.file)
|
|
111
|
+
if (shouldSkip && !isUnskippable) {
|
|
108
112
|
acc.skippedSuites.add(testPath)
|
|
109
113
|
} else {
|
|
110
114
|
acc.suitesToRun.push(suite)
|
|
@@ -151,7 +155,9 @@ function mochaHook (Runner) {
|
|
|
151
155
|
status,
|
|
152
156
|
isSuitesSkipped,
|
|
153
157
|
testCodeCoverageLinesTotal,
|
|
154
|
-
numSkippedSuites: skippedSuites.length
|
|
158
|
+
numSkippedSuites: skippedSuites.length,
|
|
159
|
+
hasForcedToRunSuites: isForcedToRun,
|
|
160
|
+
hasUnskippableSuites: !!unskippableSuites.length
|
|
155
161
|
})
|
|
156
162
|
}))
|
|
157
163
|
|
|
@@ -172,8 +178,10 @@ function mochaHook (Runner) {
|
|
|
172
178
|
if (!asyncResource) {
|
|
173
179
|
asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
174
180
|
testFileToSuiteAr.set(suite.file, asyncResource)
|
|
181
|
+
const isUnskippable = unskippableSuites.includes(suite.file)
|
|
182
|
+
isForcedToRun = isUnskippable && suitesToSkip.includes(getTestSuitePath(suite.file, process.cwd()))
|
|
175
183
|
asyncResource.runInAsyncScope(() => {
|
|
176
|
-
testSuiteStartCh.publish(suite)
|
|
184
|
+
testSuiteStartCh.publish({ testSuite: suite.file, isUnskippable, isForcedToRun })
|
|
177
185
|
})
|
|
178
186
|
}
|
|
179
187
|
})
|
|
@@ -370,6 +378,13 @@ addHook({
|
|
|
370
378
|
|
|
371
379
|
const runner = run.apply(this, arguments)
|
|
372
380
|
|
|
381
|
+
this.files.forEach(path => {
|
|
382
|
+
const isUnskippable = isMarkedAsUnskippable({ path })
|
|
383
|
+
if (isUnskippable) {
|
|
384
|
+
unskippableSuites.push(path)
|
|
385
|
+
}
|
|
386
|
+
})
|
|
387
|
+
|
|
373
388
|
const onReceivedSkippableSuites = ({ err, skippableSuites }) => {
|
|
374
389
|
if (err) {
|
|
375
390
|
suitesToSkip = []
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
require('./mongodb-core')
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
channel,
|
|
7
|
+
addHook,
|
|
8
|
+
AsyncResource
|
|
9
|
+
} = require('./helpers/instrument')
|
|
10
|
+
const shimmer = require('../../datadog-shimmer')
|
|
11
|
+
|
|
12
|
+
// collection methods with filter
|
|
13
|
+
const collectionMethodsWithFilter = [
|
|
14
|
+
'count',
|
|
15
|
+
'countDocuments',
|
|
16
|
+
'deleteMany',
|
|
17
|
+
'deleteOne',
|
|
18
|
+
'find',
|
|
19
|
+
'findOneAndDelete',
|
|
20
|
+
'findOneAndReplace',
|
|
21
|
+
'replaceOne'
|
|
22
|
+
] // findOne is ignored because it calls to find
|
|
23
|
+
|
|
24
|
+
const collectionMethodsWithTwoFilters = [
|
|
25
|
+
'findOneAndUpdate',
|
|
26
|
+
'updateMany',
|
|
27
|
+
'updateOne'
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
const startCh = channel('datadog:mongodb:collection:filter:start')
|
|
31
|
+
|
|
32
|
+
addHook({ name: 'mongodb', versions: ['>=3.3 <5', '5', '>=6'] }, mongodb => {
|
|
33
|
+
[...collectionMethodsWithFilter, ...collectionMethodsWithTwoFilters].forEach(methodName => {
|
|
34
|
+
if (!(methodName in mongodb.Collection.prototype)) return
|
|
35
|
+
|
|
36
|
+
const useTwoArguments = collectionMethodsWithTwoFilters.includes(methodName)
|
|
37
|
+
|
|
38
|
+
shimmer.wrap(mongodb.Collection.prototype, methodName, method => {
|
|
39
|
+
return function () {
|
|
40
|
+
if (!startCh.hasSubscribers) {
|
|
41
|
+
return method.apply(this, arguments)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
45
|
+
|
|
46
|
+
return asyncResource.runInAsyncScope(() => {
|
|
47
|
+
const filters = [arguments[0]]
|
|
48
|
+
if (useTwoArguments) {
|
|
49
|
+
filters.push(arguments[1])
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
startCh.publish({
|
|
53
|
+
filters,
|
|
54
|
+
methodName
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
return method.apply(this, arguments)
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
return mongodb
|
|
63
|
+
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { addHook } = require('./helpers/instrument')
|
|
3
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
4
4
|
const { wrapThen } = require('./helpers/promise')
|
|
5
5
|
const { AsyncResource } = require('./helpers/instrument')
|
|
6
6
|
const shimmer = require('../../datadog-shimmer')
|
|
@@ -26,5 +26,144 @@ addHook({
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
shimmer.wrap(mongoose.Collection.prototype, 'addQueue', wrapAddQueue)
|
|
29
|
+
|
|
29
30
|
return mongoose
|
|
30
31
|
})
|
|
32
|
+
|
|
33
|
+
const startCh = channel('datadog:mongoose:model:filter:start')
|
|
34
|
+
const finishCh = channel('datadog:mongoose:model:filter:finish')
|
|
35
|
+
|
|
36
|
+
const collectionMethodsWithFilter = [
|
|
37
|
+
'count',
|
|
38
|
+
'countDocuments',
|
|
39
|
+
'deleteMany',
|
|
40
|
+
'deleteOne',
|
|
41
|
+
'find',
|
|
42
|
+
'findOne',
|
|
43
|
+
'findOneAndDelete',
|
|
44
|
+
'findOneAndReplace',
|
|
45
|
+
'replaceOne',
|
|
46
|
+
'remove'
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
const collectionMethodsWithTwoFilters = [
|
|
50
|
+
'findOneAndUpdate',
|
|
51
|
+
'updateMany',
|
|
52
|
+
'updateOne'
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
addHook({
|
|
56
|
+
name: 'mongoose',
|
|
57
|
+
versions: ['>=4.6.4 <5', '5', '6', '>=7'],
|
|
58
|
+
file: 'lib/model.js'
|
|
59
|
+
}, Model => {
|
|
60
|
+
[...collectionMethodsWithFilter, ...collectionMethodsWithTwoFilters].forEach(methodName => {
|
|
61
|
+
const useTwoArguments = collectionMethodsWithTwoFilters.includes(methodName)
|
|
62
|
+
if (!(methodName in Model)) return
|
|
63
|
+
|
|
64
|
+
shimmer.wrap(Model, methodName, method => {
|
|
65
|
+
return function wrappedModelMethod () {
|
|
66
|
+
if (!startCh.hasSubscribers) {
|
|
67
|
+
return method.apply(this, arguments)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
71
|
+
|
|
72
|
+
const filters = [arguments[0]]
|
|
73
|
+
if (useTwoArguments) {
|
|
74
|
+
filters.push(arguments[1])
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const finish = asyncResource.bind(function () {
|
|
78
|
+
finishCh.publish()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
let callbackWrapped = false
|
|
82
|
+
const lastArgumentIndex = arguments.length - 1
|
|
83
|
+
|
|
84
|
+
if (typeof arguments[lastArgumentIndex] === 'function') {
|
|
85
|
+
// is a callback, wrap it to execute finish()
|
|
86
|
+
shimmer.wrap(arguments, lastArgumentIndex, originalCb => {
|
|
87
|
+
return function () {
|
|
88
|
+
finish()
|
|
89
|
+
|
|
90
|
+
return originalCb.apply(this, arguments)
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
callbackWrapped = true
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return asyncResource.runInAsyncScope(() => {
|
|
98
|
+
startCh.publish({
|
|
99
|
+
filters,
|
|
100
|
+
methodName
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const res = method.apply(this, arguments)
|
|
104
|
+
|
|
105
|
+
// if it is not callback, wrap exec method and its then
|
|
106
|
+
if (!callbackWrapped) {
|
|
107
|
+
shimmer.wrap(res, 'exec', originalExec => {
|
|
108
|
+
return function wrappedExec () {
|
|
109
|
+
const execResult = originalExec.apply(this, arguments)
|
|
110
|
+
|
|
111
|
+
// wrap them method, wrap resolve and reject methods
|
|
112
|
+
shimmer.wrap(execResult, 'then', originalThen => {
|
|
113
|
+
return function wrappedThen () {
|
|
114
|
+
const resolve = arguments[0]
|
|
115
|
+
const reject = arguments[1]
|
|
116
|
+
|
|
117
|
+
// not using shimmer here because resolve/reject could be empty
|
|
118
|
+
arguments[0] = function wrappedResolve () {
|
|
119
|
+
finish()
|
|
120
|
+
|
|
121
|
+
if (resolve) {
|
|
122
|
+
return resolve.apply(this, arguments)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
arguments[1] = function wrappedReject () {
|
|
127
|
+
finish()
|
|
128
|
+
|
|
129
|
+
if (reject) {
|
|
130
|
+
return reject.apply(this, arguments)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return originalThen.apply(this, arguments)
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
return execResult
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
return res
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
return Model
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
const sanitizeFilterFinishCh = channel('datadog:mongoose:sanitize-filter:finish')
|
|
152
|
+
|
|
153
|
+
addHook({
|
|
154
|
+
name: 'mongoose',
|
|
155
|
+
versions: ['6', '>=7'],
|
|
156
|
+
file: 'lib/helpers/query/sanitizeFilter.js'
|
|
157
|
+
}, sanitizeFilter => {
|
|
158
|
+
return shimmer.wrap(sanitizeFilter, function wrappedSanitizeFilter () {
|
|
159
|
+
const sanitizedObject = sanitizeFilter.apply(this, arguments)
|
|
160
|
+
|
|
161
|
+
if (sanitizeFilterFinishCh.hasSubscribers) {
|
|
162
|
+
sanitizeFilterFinishCh.publish({
|
|
163
|
+
sanitizedObject
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return sanitizedObject
|
|
168
|
+
})
|
|
169
|
+
})
|
|
@@ -10,6 +10,8 @@ const startChannel = channel('apm:next:request:start')
|
|
|
10
10
|
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
|
+
const bodyParsedChannel = channel('apm:next:body-parsed')
|
|
14
|
+
const queryParsedChannel = channel('apm:next:query-parsed')
|
|
13
15
|
|
|
14
16
|
const requests = new WeakSet()
|
|
15
17
|
|
|
@@ -212,3 +214,41 @@ addHook({
|
|
|
212
214
|
|
|
213
215
|
return nextServer
|
|
214
216
|
})
|
|
217
|
+
|
|
218
|
+
addHook({
|
|
219
|
+
name: 'next',
|
|
220
|
+
versions: ['>=13'],
|
|
221
|
+
file: 'dist/server/web/spec-extension/request.js'
|
|
222
|
+
}, request => {
|
|
223
|
+
const nextUrlDescriptor = Object.getOwnPropertyDescriptor(request.NextRequest.prototype, 'nextUrl')
|
|
224
|
+
shimmer.wrap(nextUrlDescriptor, 'get', function (originalGet) {
|
|
225
|
+
return function wrappedGet () {
|
|
226
|
+
const nextUrl = originalGet.apply(this, arguments)
|
|
227
|
+
if (queryParsedChannel.hasSubscribers) {
|
|
228
|
+
const query = {}
|
|
229
|
+
for (const key of nextUrl.searchParams.keys()) {
|
|
230
|
+
if (!query[key]) {
|
|
231
|
+
query[key] = nextUrl.searchParams.getAll(key)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
queryParsedChannel.publish({ query })
|
|
236
|
+
}
|
|
237
|
+
return nextUrl
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
Object.defineProperty(request.NextRequest.prototype, 'nextUrl', nextUrlDescriptor)
|
|
242
|
+
|
|
243
|
+
shimmer.massWrap(request.NextRequest.prototype, ['text', 'json'], function (originalMethod) {
|
|
244
|
+
return async function wrappedJson () {
|
|
245
|
+
const body = await originalMethod.apply(this, arguments)
|
|
246
|
+
bodyParsedChannel.publish({
|
|
247
|
+
body
|
|
248
|
+
})
|
|
249
|
+
return body
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
return request
|
|
254
|
+
})
|