dd-trace 5.66.0 → 5.68.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 +0 -3
- package/README.md +0 -2
- package/ci/init.js +52 -54
- package/ext/exporters.d.ts +2 -1
- package/ext/exporters.js +2 -1
- package/index.d.ts +85 -2
- package/initialize.mjs +1 -1
- package/package.json +8 -11
- package/packages/datadog-esbuild/index.js +56 -0
- package/packages/datadog-instrumentations/src/aws-sdk.js +42 -4
- package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
- package/packages/datadog-instrumentations/src/azure-service-bus.js +1 -1
- package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
- package/packages/datadog-instrumentations/src/connect.js +6 -2
- package/packages/datadog-instrumentations/src/cucumber.js +31 -6
- package/packages/datadog-instrumentations/src/express.js +5 -6
- package/packages/datadog-instrumentations/src/fastify.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/hook.js +28 -15
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +11 -2
- package/packages/datadog-instrumentations/src/helpers/register.js +10 -3
- package/packages/datadog-instrumentations/src/http2/client.js +1 -0
- package/packages/datadog-instrumentations/src/http2/server.js +0 -1
- package/packages/datadog-instrumentations/src/ioredis.js +12 -1
- package/packages/datadog-instrumentations/src/jest.js +48 -36
- package/packages/datadog-instrumentations/src/limitd-client.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +15 -7
- package/packages/datadog-instrumentations/src/mocha/utils.js +3 -0
- package/packages/datadog-instrumentations/src/mongoose.js +2 -1
- package/packages/datadog-instrumentations/src/oracledb.js +19 -13
- package/packages/datadog-instrumentations/src/pg.js +9 -5
- package/packages/datadog-instrumentations/src/pino.js +18 -6
- package/packages/datadog-instrumentations/src/playwright.js +15 -1
- package/packages/datadog-instrumentations/src/sequelize.js +1 -1
- package/packages/datadog-instrumentations/src/vitest.js +155 -62
- package/packages/datadog-plugin-ai/src/tracing.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +23 -8
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +101 -2
- package/packages/datadog-plugin-aws-sdk/src/util.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +4 -56
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +6 -2
- package/packages/datadog-plugin-cypress/src/support.js +4 -0
- package/packages/datadog-plugin-express/src/code_origin.js +2 -2
- package/packages/datadog-plugin-fastify/src/code_origin.js +1 -2
- package/packages/datadog-plugin-jest/src/index.js +0 -21
- package/packages/datadog-plugin-mocha/src/index.js +3 -57
- package/packages/datadog-plugin-mongodb-core/src/index.js +20 -7
- package/packages/datadog-plugin-playwright/src/index.js +11 -5
- package/packages/datadog-plugin-vitest/src/index.js +5 -1
- package/packages/datadog-plugin-ws/src/close.js +1 -1
- package/packages/datadog-plugin-ws/src/producer.js +6 -1
- package/packages/datadog-plugin-ws/src/receiver.js +6 -1
- package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +1 -1
- package/packages/dd-trace/src/appsec/telemetry/waf.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -4
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +11 -3
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +10 -1
- package/packages/dd-trace/src/config.js +69 -304
- package/packages/dd-trace/src/config_defaults.js +186 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -1
- package/packages/dd-trace/src/datastreams/fnv.js +2 -2
- package/packages/dd-trace/src/datastreams/writer.js +3 -2
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -1
- package/packages/dd-trace/src/dogstatsd.js +4 -3
- package/packages/dd-trace/src/encode/0.4.js +1 -5
- package/packages/dd-trace/src/exporter.js +1 -0
- package/packages/dd-trace/src/exporters/agent/index.js +3 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +3 -2
- package/packages/dd-trace/src/exporters/common/request.js +2 -1
- package/packages/dd-trace/src/exporters/span-stats/index.js +3 -2
- package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
- package/packages/dd-trace/src/llmobs/index.js +7 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +4 -3
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +40 -13
- package/packages/dd-trace/src/llmobs/plugins/openai.js +7 -1
- package/packages/dd-trace/src/llmobs/sdk.js +28 -0
- package/packages/dd-trace/src/llmobs/span_processor.js +124 -28
- package/packages/dd-trace/src/llmobs/tagger.js +8 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +9 -2
- package/packages/dd-trace/src/log/index.js +28 -17
- package/packages/dd-trace/src/log/log.js +29 -5
- package/packages/dd-trace/src/log/writer.js +5 -5
- package/packages/dd-trace/src/noop/span.js +1 -0
- package/packages/dd-trace/src/opentelemetry/span.js +14 -3
- package/packages/dd-trace/src/opentracing/span.js +18 -4
- package/packages/dd-trace/src/plugin_manager.js +20 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +97 -3
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/git-cache.js +129 -0
- package/packages/dd-trace/src/plugins/util/git.js +40 -26
- package/packages/dd-trace/src/plugins/util/test.js +37 -27
- package/packages/dd-trace/src/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/profiler.js +4 -1
- package/packages/dd-trace/src/profiling/config.js +73 -42
- package/packages/dd-trace/src/profiling/profiler.js +3 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -8
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -0
- package/packages/dd-trace/src/profiling/profilers/wall.js +196 -117
- package/packages/dd-trace/src/remote_config/capabilities.js +5 -0
- package/packages/dd-trace/src/remote_config/manager.js +3 -2
- package/packages/dd-trace/src/startup-log.js +2 -1
- package/packages/dd-trace/src/supported-configurations.json +3 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/register.js +1 -1
|
@@ -82,10 +82,14 @@ let testManagementAttemptToFixRetries = 0
|
|
|
82
82
|
let testManagementTests = {}
|
|
83
83
|
let modifiedTests = {}
|
|
84
84
|
let numTestRetries = 0
|
|
85
|
-
let knownTests =
|
|
85
|
+
let knownTests = {}
|
|
86
86
|
let skippedSuites = []
|
|
87
87
|
let isSuitesSkipped = false
|
|
88
88
|
|
|
89
|
+
function isValidKnownTests (receivedKnownTests) {
|
|
90
|
+
return !!receivedKnownTests.cucumber
|
|
91
|
+
}
|
|
92
|
+
|
|
89
93
|
function getSuiteStatusFromTestStatuses (testStatuses) {
|
|
90
94
|
if (testStatuses.includes('fail')) {
|
|
91
95
|
return 'fail'
|
|
@@ -123,7 +127,10 @@ function getStatusFromResultLatest (result) {
|
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
function isNewTest (testSuite, testName) {
|
|
126
|
-
|
|
130
|
+
if (!isValidKnownTests(knownTests)) {
|
|
131
|
+
return false
|
|
132
|
+
}
|
|
133
|
+
const testsForSuite = knownTests.cucumber[testSuite] || []
|
|
127
134
|
return !testsForSuite.includes(testName)
|
|
128
135
|
}
|
|
129
136
|
|
|
@@ -508,9 +515,9 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
508
515
|
pickleByFile = isCoordinator ? getPickleByFileNew(this) : getPickleByFile(this)
|
|
509
516
|
|
|
510
517
|
if (isKnownTestsEnabled) {
|
|
511
|
-
const isFaulty = getIsFaultyEarlyFlakeDetection(
|
|
518
|
+
const isFaulty = !isValidKnownTests(knownTests) || getIsFaultyEarlyFlakeDetection(
|
|
512
519
|
Object.keys(pickleByFile),
|
|
513
|
-
knownTests.cucumber
|
|
520
|
+
knownTests.cucumber,
|
|
514
521
|
earlyFlakeDetectionFaultyThreshold
|
|
515
522
|
)
|
|
516
523
|
if (isFaulty) {
|
|
@@ -592,6 +599,9 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
592
599
|
// Handles EFD in both the main process and the worker process.
|
|
593
600
|
function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = false, isWorker = false) {
|
|
594
601
|
return async function () {
|
|
602
|
+
if (!testSuiteFinishCh.hasSubscribers) {
|
|
603
|
+
return runTestCaseFunction.apply(this, arguments)
|
|
604
|
+
}
|
|
595
605
|
const pickle = isNewerCucumberVersion
|
|
596
606
|
? arguments[0].pickle
|
|
597
607
|
: this.eventDataCollector.getPickle(arguments[0])
|
|
@@ -747,6 +757,9 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
|
|
|
747
757
|
|
|
748
758
|
function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion) {
|
|
749
759
|
return function (worker, message) {
|
|
760
|
+
if (!testSuiteFinishCh.hasSubscribers) {
|
|
761
|
+
return parseWorkerMessageFunction.apply(this, arguments)
|
|
762
|
+
}
|
|
750
763
|
// If the message is an array, it's a dd-trace message, so we need to stop cucumber processing,
|
|
751
764
|
// or cucumber will throw an error
|
|
752
765
|
// TODO: identify the message better
|
|
@@ -972,10 +985,17 @@ addHook({
|
|
|
972
985
|
)
|
|
973
986
|
// EFD in parallel mode only supported in >=11.0.0
|
|
974
987
|
shimmer.wrap(adapterPackage.ChildProcessAdapter.prototype, 'startWorker', startWorker => function () {
|
|
975
|
-
if (isKnownTestsEnabled) {
|
|
988
|
+
if (isKnownTestsEnabled && isValidKnownTests(knownTests)) {
|
|
989
|
+
this.options.worldParameters._ddIsKnownTestsEnabled = true
|
|
976
990
|
this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
|
|
977
991
|
this.options.worldParameters._ddKnownTests = knownTests
|
|
978
992
|
this.options.worldParameters._ddEarlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
|
|
993
|
+
} else {
|
|
994
|
+
isEarlyFlakeDetectionEnabled = false
|
|
995
|
+
isKnownTestsEnabled = false
|
|
996
|
+
this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled = false
|
|
997
|
+
this.options.worldParameters._ddIsKnownTestsEnabled = false
|
|
998
|
+
this.options.worldParameters._ddEarlyFlakeDetectionNumRetries = 0
|
|
979
999
|
}
|
|
980
1000
|
|
|
981
1001
|
if (isImpactedTestsEnabled) {
|
|
@@ -1001,9 +1021,14 @@ addHook({
|
|
|
1001
1021
|
'initialize',
|
|
1002
1022
|
initialize => async function () {
|
|
1003
1023
|
await initialize.apply(this, arguments)
|
|
1004
|
-
isKnownTestsEnabled = !!this.options.worldParameters.
|
|
1024
|
+
isKnownTestsEnabled = !!this.options.worldParameters._ddIsKnownTestsEnabled
|
|
1005
1025
|
if (isKnownTestsEnabled) {
|
|
1006
1026
|
knownTests = this.options.worldParameters._ddKnownTests
|
|
1027
|
+
// if for whatever reason the worker does not receive valid known tests, we disable EFD and known tests
|
|
1028
|
+
if (!isValidKnownTests(knownTests)) {
|
|
1029
|
+
isKnownTestsEnabled = false
|
|
1030
|
+
knownTests = {}
|
|
1031
|
+
}
|
|
1007
1032
|
}
|
|
1008
1033
|
isEarlyFlakeDetectionEnabled = !!this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled
|
|
1009
1034
|
if (isEarlyFlakeDetectionEnabled) {
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { createWrapRouterMethod } = require('./router')
|
|
4
4
|
const shimmer = require('../../datadog-shimmer')
|
|
5
|
-
const { addHook, channel } = require('./helpers/instrument')
|
|
6
|
-
const tracingChannel = require('dc-polyfill').tracingChannel
|
|
5
|
+
const { addHook, channel, tracingChannel } = require('./helpers/instrument')
|
|
7
6
|
|
|
8
7
|
const handleChannel = channel('apm:express:request:handle')
|
|
9
8
|
|
|
@@ -57,7 +56,7 @@ function wrapResponseRender (render) {
|
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
addHook({ name: 'express', versions: ['>=4'] }, express => {
|
|
59
|
+
addHook({ name: 'express', versions: ['>=4'], file: ['lib/express.js'] }, express => {
|
|
61
60
|
shimmer.wrap(express.application, 'handle', wrapHandle)
|
|
62
61
|
|
|
63
62
|
shimmer.wrap(express.response, 'json', wrapResponseJson)
|
|
@@ -70,7 +69,7 @@ addHook({ name: 'express', versions: ['>=4'] }, express => {
|
|
|
70
69
|
// Express 5 does not rely on router in the same way as v4 and should not be instrumented anymore.
|
|
71
70
|
// It would otherwise produce spans for router and express, and so duplicating them.
|
|
72
71
|
// We now fall back to router instrumentation
|
|
73
|
-
addHook({ name: 'express', versions: ['4'] }, express => {
|
|
72
|
+
addHook({ name: 'express', versions: ['4'], file: 'lib/express.js' }, express => {
|
|
74
73
|
shimmer.wrap(express.Router, 'use', wrapRouterMethod)
|
|
75
74
|
shimmer.wrap(express.Router, 'route', wrapRouterMethod)
|
|
76
75
|
|
|
@@ -132,12 +131,12 @@ function wrapProcessParamsMethod (requestPositionInArguments) {
|
|
|
132
131
|
}
|
|
133
132
|
}
|
|
134
133
|
|
|
135
|
-
addHook({ name: 'express', versions: ['>=4.0.0 <4.3.0'] }, express => {
|
|
134
|
+
addHook({ name: 'express', versions: ['>=4.0.0 <4.3.0'], file: ['lib/express.js'] }, express => {
|
|
136
135
|
shimmer.wrap(express.Router, 'process_params', wrapProcessParamsMethod(1))
|
|
137
136
|
return express
|
|
138
137
|
})
|
|
139
138
|
|
|
140
|
-
addHook({ name: 'express', versions: ['>=4.3.0 <5.0.0'] }, express => {
|
|
139
|
+
addHook({ name: 'express', versions: ['>=4.3.0 <5.0.0'], file: ['lib/express.js'] }, express => {
|
|
141
140
|
shimmer.wrap(express.Router, 'process_params', wrapProcessParamsMethod(2))
|
|
142
141
|
return express
|
|
143
142
|
})
|
|
@@ -265,7 +265,7 @@ function canPublishResponsePayload (payload) {
|
|
|
265
265
|
!ArrayBuffer.isView(payload) // TypedArray
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
-
addHook({ name: 'fastify', versions: ['>=3'] }, fastify => {
|
|
268
|
+
addHook({ name: 'fastify', versions: ['>=3'] }, (fastify) => {
|
|
269
269
|
const wrapped = shimmer.wrapFunction(fastify, fastify => wrapFastify(fastify, true))
|
|
270
270
|
|
|
271
271
|
wrapped.fastify = wrapped
|
|
@@ -274,11 +274,11 @@ addHook({ name: 'fastify', versions: ['>=3'] }, fastify => {
|
|
|
274
274
|
return wrapped
|
|
275
275
|
})
|
|
276
276
|
|
|
277
|
-
addHook({ name: 'fastify', versions: ['2'] }, fastify => {
|
|
277
|
+
addHook({ name: 'fastify', versions: ['2'] }, (fastify) => {
|
|
278
278
|
return shimmer.wrapFunction(fastify, fastify => wrapFastify(fastify, true))
|
|
279
279
|
})
|
|
280
280
|
|
|
281
|
-
addHook({ name: 'fastify', versions: ['1'] }, fastify => {
|
|
281
|
+
addHook({ name: 'fastify', versions: ['1'] }, (fastify) => {
|
|
282
282
|
return shimmer.wrapFunction(fastify, fastify => wrapFastify(fastify, false))
|
|
283
283
|
})
|
|
284
284
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
|
|
3
|
-
const path = require('path')
|
|
4
2
|
const iitm = require('../../../dd-trace/src/iitm')
|
|
3
|
+
const path = require('path')
|
|
5
4
|
const ritm = require('../../../dd-trace/src/ritm')
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -20,29 +19,43 @@ function Hook (modules, hookOptions, onrequire) {
|
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
this._patched = Object.create(null)
|
|
22
|
+
const patched = new WeakMap()
|
|
23
23
|
|
|
24
|
-
const safeHook = (moduleExports, moduleName, moduleBaseDir, moduleVersion) => {
|
|
24
|
+
const safeHook = (moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm) => {
|
|
25
25
|
const parts = [moduleBaseDir, moduleName].filter(Boolean)
|
|
26
26
|
const filename = path.join(...parts)
|
|
27
27
|
|
|
28
|
-
if (this._patched[filename]
|
|
28
|
+
if (this._patched[filename] && patched.has(moduleExports)) {
|
|
29
|
+
return patched.get(moduleExports)
|
|
30
|
+
}
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
let defaultWrapResult
|
|
33
|
+
|
|
34
|
+
if (
|
|
35
|
+
isIitm &&
|
|
36
|
+
moduleExports.default &&
|
|
37
|
+
(typeof moduleExports.default === 'object' ||
|
|
38
|
+
typeof moduleExports.default === 'function')
|
|
39
|
+
) {
|
|
40
|
+
defaultWrapResult = onrequire(moduleExports.default, moduleName, moduleBaseDir, moduleVersion, isIitm)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const newExports = onrequire(moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm)
|
|
44
|
+
|
|
45
|
+
if (defaultWrapResult) newExports.default = defaultWrapResult
|
|
31
46
|
|
|
32
|
-
|
|
47
|
+
this._patched[filename] = true
|
|
48
|
+
if (newExports &&
|
|
49
|
+
(typeof newExports === 'object' ||
|
|
50
|
+
typeof newExports === 'function')) {
|
|
51
|
+
patched.set(moduleExports, newExports)
|
|
52
|
+
}
|
|
53
|
+
return newExports
|
|
33
54
|
}
|
|
34
55
|
|
|
35
56
|
this._ritmHook = ritm(modules, {}, safeHook)
|
|
36
57
|
this._iitmHook = iitm(modules, hookOptions, (moduleExports, moduleName, moduleBaseDir) => {
|
|
37
|
-
|
|
38
|
-
// modules and not ESM. In the meantime, all the modules we instrument are
|
|
39
|
-
// CommonJS modules for which the default export is always moved to
|
|
40
|
-
// `default` anyway.
|
|
41
|
-
if (moduleExports && moduleExports.default) {
|
|
42
|
-
moduleExports.default = safeHook(moduleExports.default, moduleName, moduleBaseDir)
|
|
43
|
-
return moduleExports
|
|
44
|
-
}
|
|
45
|
-
return safeHook(moduleExports, moduleName, moduleBaseDir)
|
|
58
|
+
return safeHook(moduleExports, moduleName, moduleBaseDir, null, true)
|
|
46
59
|
})
|
|
47
60
|
}
|
|
48
61
|
|
|
@@ -16,6 +16,7 @@ module.exports = {
|
|
|
16
16
|
'@graphql-tools/executor': () => require('../graphql'),
|
|
17
17
|
'@grpc/grpc-js': () => require('../grpc'),
|
|
18
18
|
'@hapi/hapi': () => require('../hapi'),
|
|
19
|
+
'@happy-dom/jest-environment': () => require('../jest'),
|
|
19
20
|
'@jest/core': () => require('../jest'),
|
|
20
21
|
'@jest/reporters': () => require('../jest'),
|
|
21
22
|
'@jest/test-sequencer': () => require('../jest'),
|
|
@@ -130,6 +131,7 @@ module.exports = {
|
|
|
130
131
|
sequelize: () => require('../sequelize'),
|
|
131
132
|
sharedb: () => require('../sharedb'),
|
|
132
133
|
tedious: () => require('../tedious'),
|
|
134
|
+
tinypool: { esmFirst: true, fn: () => require('../vitest') },
|
|
133
135
|
undici: () => require('../undici'),
|
|
134
136
|
url: () => require('../url'),
|
|
135
137
|
vitest: { esmFirst: true, fn: () => require('../vitest') },
|
|
@@ -13,6 +13,15 @@ exports.channel = function (name) {
|
|
|
13
13
|
return ch
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
const tracingChannelMap = {}
|
|
17
|
+
exports.tracingChannel = function (name) {
|
|
18
|
+
const maybe = tracingChannelMap[name]
|
|
19
|
+
if (maybe) return maybe
|
|
20
|
+
const tc = dc.tracingChannel(name)
|
|
21
|
+
tracingChannelMap[name] = tc
|
|
22
|
+
return tc
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
/**
|
|
17
26
|
* @param {string} args.name module name
|
|
18
27
|
* @param {string[]} args.versions array of semver range strings
|
|
@@ -20,7 +29,7 @@ exports.channel = function (name) {
|
|
|
20
29
|
* @param {string} args.filePattern pattern to match files within package to instrument
|
|
21
30
|
* @param Function hook
|
|
22
31
|
*/
|
|
23
|
-
exports.addHook = function addHook ({ name, versions, file, filePattern }, hook) {
|
|
32
|
+
exports.addHook = function addHook ({ name, versions, file, filePattern, patchDefault }, hook) {
|
|
24
33
|
if (typeof name === 'string') {
|
|
25
34
|
name = [name]
|
|
26
35
|
}
|
|
@@ -29,7 +38,7 @@ exports.addHook = function addHook ({ name, versions, file, filePattern }, hook)
|
|
|
29
38
|
if (!instrumentations[val]) {
|
|
30
39
|
instrumentations[val] = []
|
|
31
40
|
}
|
|
32
|
-
instrumentations[val].push({ name: val, versions, file, filePattern, hook })
|
|
41
|
+
instrumentations[val].push({ name: val, versions, file, filePattern, hook, patchDefault })
|
|
33
42
|
}
|
|
34
43
|
}
|
|
35
44
|
|
|
@@ -66,7 +66,7 @@ for (const packageName of names) {
|
|
|
66
66
|
// get the instrumentation file name to save all hooked versions
|
|
67
67
|
const instrumentationFileName = parseHookInstrumentationFileName(packageName)
|
|
68
68
|
|
|
69
|
-
Hook([packageName], hookOptions, (moduleExports, moduleName, moduleBaseDir, moduleVersion) => {
|
|
69
|
+
Hook([packageName], hookOptions, (moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm) => {
|
|
70
70
|
moduleName = moduleName.replace(pathSepExpr, '/')
|
|
71
71
|
|
|
72
72
|
// This executes the integration file thus adding its entries to `instrumentations`
|
|
@@ -77,7 +77,13 @@ for (const packageName of names) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const namesAndSuccesses = {}
|
|
80
|
-
for (const { name, file, versions, hook, filePattern } of instrumentations[packageName]) {
|
|
80
|
+
for (const { name, file, versions, hook, filePattern, patchDefault } of instrumentations[packageName]) {
|
|
81
|
+
if (patchDefault === false && !moduleExports.default && isIitm) {
|
|
82
|
+
return moduleExports
|
|
83
|
+
} else if (patchDefault === true && moduleExports.default && isIitm) {
|
|
84
|
+
moduleExports = moduleExports.default
|
|
85
|
+
}
|
|
86
|
+
|
|
81
87
|
let fullFilePattern = filePattern
|
|
82
88
|
const fullFilename = filename(name, file)
|
|
83
89
|
if (fullFilePattern) {
|
|
@@ -137,7 +143,8 @@ for (const packageName of names) {
|
|
|
137
143
|
// picked up due to the unification. Check what modules actually use the name.
|
|
138
144
|
// TODO(BridgeAR): Only replace moduleExports if the hook returns a new value.
|
|
139
145
|
// This allows to reduce the instrumentation code (no return needed).
|
|
140
|
-
|
|
146
|
+
|
|
147
|
+
moduleExports = hook(moduleExports, version, name, isIitm) ?? moduleExports
|
|
141
148
|
// Set the moduleExports in the hooks WeakSet
|
|
142
149
|
hook[HOOK_SYMBOL].add(moduleExports)
|
|
143
150
|
} catch (e) {
|
|
@@ -18,7 +18,6 @@ const names = ['http2', 'node:http2']
|
|
|
18
18
|
addHook({ name: names }, http2 => {
|
|
19
19
|
shimmer.wrap(http2, 'createSecureServer', wrapCreateServer)
|
|
20
20
|
shimmer.wrap(http2, 'createServer', wrapCreateServer)
|
|
21
|
-
return http2
|
|
22
21
|
})
|
|
23
22
|
|
|
24
23
|
function wrapCreateServer (createServer) {
|
|
@@ -10,7 +10,7 @@ const startCh = channel('apm:ioredis:command:start')
|
|
|
10
10
|
const finishCh = channel('apm:ioredis:command:finish')
|
|
11
11
|
const errorCh = channel('apm:ioredis:command:error')
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
function wrapRedis (Redis) {
|
|
14
14
|
shimmer.wrap(Redis.prototype, 'sendCommand', sendCommand => function (command, stream) {
|
|
15
15
|
if (!startCh.hasSubscribers) return sendCommand.apply(this, arguments)
|
|
16
16
|
|
|
@@ -35,8 +35,19 @@ addHook({ name: 'ioredis', versions: ['>=2'] }, Redis => {
|
|
|
35
35
|
})
|
|
36
36
|
})
|
|
37
37
|
return Redis
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
addHook({ name: 'ioredis', versions: ['>=2 <4'], file: 'lib/redis.js' }, wrapRedis)
|
|
41
|
+
|
|
42
|
+
addHook({ name: 'ioredis', versions: ['>=4 <4.11.0'], file: 'built/redis.js' }, wrapRedis)
|
|
43
|
+
|
|
44
|
+
addHook({ name: 'ioredis', versions: ['>=4.11.0 <5'], file: 'built/redis/index.js' }, (exports) => {
|
|
45
|
+
wrapRedis(exports.default)
|
|
46
|
+
return exports
|
|
38
47
|
})
|
|
39
48
|
|
|
49
|
+
addHook({ name: 'ioredis', versions: ['>=5'] }, wrapRedis)
|
|
50
|
+
|
|
40
51
|
function finish (finishCh, errorCh, ctx, error) {
|
|
41
52
|
if (error) {
|
|
42
53
|
ctx.error = error
|
|
@@ -160,15 +160,15 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
160
160
|
this.isImpactedTestsEnabled = this.testEnvironmentOptions._ddIsImpactedTestsEnabled
|
|
161
161
|
|
|
162
162
|
if (this.isKnownTestsEnabled) {
|
|
163
|
+
earlyFlakeDetectionNumRetries = this.testEnvironmentOptions._ddEarlyFlakeDetectionNumRetries
|
|
163
164
|
try {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
this.knownTestsForThisSuite
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
log.debug(`this.knownTestsForThisSuite is undefined: ${this.knownTestsForThisSuite === undefined}`)
|
|
165
|
+
this.knownTestsForThisSuite = this.getKnownTestsForSuite(this.testEnvironmentOptions._ddKnownTests)
|
|
166
|
+
|
|
167
|
+
if (!Array.isArray(this.knownTestsForThisSuite)) {
|
|
168
|
+
log.warn('this.knownTestsForThisSuite is not an array so new test and Early Flake detection is disabled.')
|
|
169
|
+
this.isEarlyFlakeDetectionEnabled = false
|
|
170
|
+
this.isKnownTestsEnabled = false
|
|
171
|
+
}
|
|
172
172
|
} catch {
|
|
173
173
|
// If there has been an error parsing the tests, we'll disable Early Flake Deteciton
|
|
174
174
|
this.isEarlyFlakeDetectionEnabled = false
|
|
@@ -224,19 +224,20 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
224
224
|
return hasSnapshotTests
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if
|
|
231
|
-
|
|
227
|
+
// This function returns an array if the known tests are valid and null otherwise.
|
|
228
|
+
getKnownTestsForSuite (suiteKnownTests) {
|
|
229
|
+
// `suiteKnownTests` is `this.testEnvironmentOptions._ddKnownTests`,
|
|
230
|
+
// which is only set if jest is configured to run in parallel.
|
|
231
|
+
if (suiteKnownTests) {
|
|
232
|
+
return suiteKnownTests
|
|
232
233
|
}
|
|
233
|
-
|
|
234
|
-
// If jest is
|
|
235
|
-
//
|
|
236
|
-
if (
|
|
237
|
-
|
|
234
|
+
// Global variable `knownTests` is set only in the main process.
|
|
235
|
+
// If jest is configured to run serially, the tests run in the same process, so `knownTests` is set.
|
|
236
|
+
// The assumption is that if the key `jest` is defined in the dictionary, the response is valid.
|
|
237
|
+
if (knownTests?.jest) {
|
|
238
|
+
return knownTests.jest[this.testSuite] || []
|
|
238
239
|
}
|
|
239
|
-
return
|
|
240
|
+
return null
|
|
240
241
|
}
|
|
241
242
|
|
|
242
243
|
getTestManagementTestsForSuite (testManagementTests) {
|
|
@@ -472,10 +473,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
472
473
|
}
|
|
473
474
|
}
|
|
474
475
|
if (this.isKnownTestsEnabled) {
|
|
475
|
-
|
|
476
|
-
// If it's null or undefined, we can't determine if the test is new.
|
|
477
|
-
const isNew = Array.isArray(this.knownTestsForThisSuite) &&
|
|
478
|
-
!this.knownTestsForThisSuite.includes(originalTestName)
|
|
476
|
+
const isNew = !this.knownTestsForThisSuite.includes(originalTestName)
|
|
479
477
|
if (isNew && !isSkipped && !retriedTestsToNumAttempts.has(originalTestName)) {
|
|
480
478
|
retriedTestsToNumAttempts.set(originalTestName, 0)
|
|
481
479
|
if (this.isEarlyFlakeDetectionEnabled) {
|
|
@@ -623,9 +621,17 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
623
621
|
function getTestEnvironment (pkg, jestVersion) {
|
|
624
622
|
if (pkg.default) {
|
|
625
623
|
const wrappedTestEnvironment = getWrappedEnvironment(pkg.default, jestVersion)
|
|
626
|
-
pkg
|
|
627
|
-
|
|
628
|
-
|
|
624
|
+
return new Proxy(pkg, {
|
|
625
|
+
get (target, prop) {
|
|
626
|
+
if (prop === 'default') {
|
|
627
|
+
return wrappedTestEnvironment
|
|
628
|
+
}
|
|
629
|
+
if (prop === 'TestEnvironment') {
|
|
630
|
+
return wrappedTestEnvironment
|
|
631
|
+
}
|
|
632
|
+
return target[prop]
|
|
633
|
+
}
|
|
634
|
+
})
|
|
629
635
|
}
|
|
630
636
|
return getWrappedEnvironment(pkg, jestVersion)
|
|
631
637
|
}
|
|
@@ -657,6 +663,11 @@ addHook({
|
|
|
657
663
|
versions: ['>=24.8.0']
|
|
658
664
|
}, getTestEnvironment)
|
|
659
665
|
|
|
666
|
+
addHook({
|
|
667
|
+
name: '@happy-dom/jest-environment',
|
|
668
|
+
versions: ['>=10.0.0']
|
|
669
|
+
}, getTestEnvironment)
|
|
670
|
+
|
|
660
671
|
function getWrappedScheduleTests (scheduleTests, frameworkVersion) {
|
|
661
672
|
// `scheduleTests` is an async function
|
|
662
673
|
return function (tests) {
|
|
@@ -681,8 +692,11 @@ function searchSourceWrapper (searchSourcePackage, frameworkVersion) {
|
|
|
681
692
|
|
|
682
693
|
if (isKnownTestsEnabled) {
|
|
683
694
|
const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
|
|
684
|
-
|
|
685
|
-
|
|
695
|
+
|
|
696
|
+
// If the `jest` key does not exist in the known tests response, we consider the Early Flake detection faulty.
|
|
697
|
+
const isFaulty = !knownTests?.jest ||
|
|
698
|
+
getIsFaultyEarlyFlakeDetection(projectSuites, knownTests.jest, earlyFlakeDetectionFaultyThreshold)
|
|
699
|
+
|
|
686
700
|
if (isFaulty) {
|
|
687
701
|
log.error('Early flake detection is disabled because the number of new suites is too high.')
|
|
688
702
|
isEarlyFlakeDetectionEnabled = false
|
|
@@ -1266,12 +1280,6 @@ const LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE = new Set([
|
|
|
1266
1280
|
'winston'
|
|
1267
1281
|
])
|
|
1268
1282
|
|
|
1269
|
-
function shouldBypassJestRequireEngine (moduleName) {
|
|
1270
|
-
return (
|
|
1271
|
-
LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)
|
|
1272
|
-
)
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
1283
|
addHook({
|
|
1276
1284
|
name: 'jest-runtime',
|
|
1277
1285
|
versions: ['>=24.8.0']
|
|
@@ -1283,6 +1291,10 @@ addHook({
|
|
|
1283
1291
|
const suiteFilePath = this._testPath
|
|
1284
1292
|
|
|
1285
1293
|
shimmer.wrap(result, 'mock', mock => function (moduleName) {
|
|
1294
|
+
// If the library is mocked with `jest.mock`, we don't want to bypass jest's own require engine
|
|
1295
|
+
if (LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)) {
|
|
1296
|
+
LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.delete(moduleName)
|
|
1297
|
+
}
|
|
1286
1298
|
if (suiteFilePath) {
|
|
1287
1299
|
const existingMockedFiles = testSuiteMockedFiles.get(suiteFilePath) || []
|
|
1288
1300
|
const suiteDir = path.dirname(suiteFilePath)
|
|
@@ -1297,7 +1309,7 @@ addHook({
|
|
|
1297
1309
|
|
|
1298
1310
|
shimmer.wrap(Runtime.prototype, 'requireModuleOrMock', requireModuleOrMock => function (from, moduleName) {
|
|
1299
1311
|
// TODO: do this for every library that we instrument
|
|
1300
|
-
if (
|
|
1312
|
+
if (LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)) {
|
|
1301
1313
|
// To bypass jest's own require engine
|
|
1302
1314
|
return this._requireCoreModule(moduleName)
|
|
1303
1315
|
}
|
|
@@ -1336,7 +1348,7 @@ function sendWrapper (send) {
|
|
|
1336
1348
|
// https://github.com/jestjs/jest/blob/1d682f21c7a35da4d3ab3a1436a357b980ebd0fa/packages/jest-worker/src/workers/ChildProcessWorker.ts#L424
|
|
1337
1349
|
if (type === CHILD_MESSAGE_CALL) {
|
|
1338
1350
|
// This is the message that the main process sends to the worker to run a test suite (=test file).
|
|
1339
|
-
// In here we modify the config.testEnvironmentOptions to include the known tests for the suite.
|
|
1351
|
+
// In here we modify the `config.testEnvironmentOptions` to include the known tests for the suite.
|
|
1340
1352
|
// This way the suite only knows about the tests that are part of it.
|
|
1341
1353
|
const args = request.at(-1)
|
|
1342
1354
|
if (args.length > 1) {
|
|
@@ -13,7 +13,8 @@ function wrapRequest (original) {
|
|
|
13
13
|
|
|
14
14
|
addHook({
|
|
15
15
|
name: 'limitd-client',
|
|
16
|
-
versions: ['>=2.8']
|
|
16
|
+
versions: ['>=2.8'],
|
|
17
|
+
file: ['client.js']
|
|
17
18
|
}, LimitdClient => {
|
|
18
19
|
shimmer.wrap(LimitdClient.prototype, '_directRequest', wrapRequest)
|
|
19
20
|
shimmer.wrap(LimitdClient.prototype, '_retriedRequest', wrapRequest)
|
|
@@ -663,14 +663,22 @@ addHook({
|
|
|
663
663
|
const newWorkerArgs = { ...workerArgs }
|
|
664
664
|
|
|
665
665
|
if (config.isKnownTestsEnabled) {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
666
|
+
if (config.knownTests?.mocha) {
|
|
667
|
+
const testSuiteKnownTests = config.knownTests.mocha[testPath] || []
|
|
668
|
+
newWorkerArgs._ddEfdNumRetries = config.earlyFlakeDetectionNumRetries
|
|
669
|
+
newWorkerArgs._ddIsEfdEnabled = config.isEarlyFlakeDetectionEnabled
|
|
670
|
+
newWorkerArgs._ddIsKnownTestsEnabled = true
|
|
671
|
+
newWorkerArgs._ddKnownTests = {
|
|
672
|
+
mocha: {
|
|
673
|
+
[testPath]: testSuiteKnownTests
|
|
674
|
+
}
|
|
673
675
|
}
|
|
676
|
+
} else {
|
|
677
|
+
config.isEarlyFlakeDetectionEnabled = false
|
|
678
|
+
config.isKnownTestsEnabled = false
|
|
679
|
+
newWorkerArgs._ddIsKnownTestsEnabled = false
|
|
680
|
+
newWorkerArgs._ddIsEfdEnabled = false
|
|
681
|
+
newWorkerArgs._ddKnownTests = {}
|
|
674
682
|
}
|
|
675
683
|
}
|
|
676
684
|
if (config.isTestManagementTestsEnabled) {
|
|
@@ -56,6 +56,9 @@ function getTestProperties (test, testManagementTests) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
function isNewTest (test, knownTests) {
|
|
59
|
+
if (!knownTests?.mocha) { // invalid response, so we won't consider it as new
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
59
62
|
const testSuite = getTestSuitePath(test.file, process.cwd())
|
|
60
63
|
const testName = removeEfdStringFromTestName(test.fullTitle())
|
|
61
64
|
const testsForSuite = knownTests.mocha?.[testSuite] || []
|
|
@@ -24,7 +24,8 @@ function wrapAddQueue (addQueue) {
|
|
|
24
24
|
|
|
25
25
|
addHook({
|
|
26
26
|
name: 'mongoose',
|
|
27
|
-
versions: ['>=4.6.4 <5', '5', '6', '>=7']
|
|
27
|
+
versions: ['>=4.6.4 <5', '5', '6', '>=7'],
|
|
28
|
+
file: 'lib/index.js'
|
|
28
29
|
}, mongoose => {
|
|
29
30
|
// As of Mongoose 7, custom promise libraries are no longer supported and mongoose.Promise may be undefined
|
|
30
31
|
if (mongoose.Promise && mongoose.Promise !== global.Promise) {
|
|
@@ -20,7 +20,7 @@ function finish (ctx) {
|
|
|
20
20
|
finishChannel.publish(ctx)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
addHook({ name: 'oracledb', versions: ['>=5'] }, oracledb => {
|
|
23
|
+
addHook({ name: 'oracledb', versions: ['>=5'], file: 'lib/oracledb.js' }, oracledb => {
|
|
24
24
|
shimmer.wrap(oracledb.Connection.prototype, 'execute', execute => {
|
|
25
25
|
return function wrappedExecute (dbQuery, ...args) {
|
|
26
26
|
if (!startChannel.hasSubscribers) {
|
|
@@ -40,22 +40,28 @@ addHook({ name: 'oracledb', versions: ['>=5'] }, oracledb => {
|
|
|
40
40
|
})
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
// The connAttrs are used to pass through the argument to the potential
|
|
44
|
-
// serviceName method a user might have passed through as well as parsing
|
|
45
|
-
// the connection string in v5.
|
|
46
|
-
const connAttrs = connectionAttributes.get(this)
|
|
47
|
-
|
|
48
|
-
const details = typeof this.hostName === 'string' ? this : this._impl
|
|
49
|
-
|
|
50
43
|
let hostname
|
|
51
44
|
let port
|
|
52
45
|
let dbInstance
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
try {
|
|
48
|
+
if (this.thin) {
|
|
49
|
+
const details = this._impl ?? this
|
|
50
|
+
// Prefer public getters when available (v6), fallback to nscon in v5.
|
|
51
|
+
dbInstance = this.serviceName ?? details.serviceName
|
|
52
|
+
hostname = this.hostName ?? details.nscon?.ntAdapter?.hostName
|
|
53
|
+
const p = this.port ?? details.nscon?.ntAdapter?.port
|
|
54
|
+
if (p != null) port = String(p)
|
|
55
|
+
} else {
|
|
56
|
+
// Avoid host/port getters in thick mode, as they may throw.
|
|
57
|
+
dbInstance = this.serviceName
|
|
58
|
+
}
|
|
59
|
+
} catch {}
|
|
60
|
+
|
|
61
|
+
// The connAttrs are used to pass through the argument to the potential
|
|
62
|
+
// serviceName method a user might have passed through as well as parsing
|
|
63
|
+
// the connection string in v5 as well as in thick mode.
|
|
64
|
+
const connAttrs = connectionAttributes.get(this)
|
|
59
65
|
|
|
60
66
|
const ctx = {
|
|
61
67
|
dbInstance,
|
|
@@ -15,17 +15,21 @@ const finishPoolQueryCh = channel('datadog:pg:pool:query:finish')
|
|
|
15
15
|
|
|
16
16
|
const { errorMonitor } = require('node:events')
|
|
17
17
|
|
|
18
|
-
addHook({ name: 'pg', versions: ['>=8.0.3'] },
|
|
19
|
-
shimmer.wrap(
|
|
20
|
-
|
|
21
|
-
return pg
|
|
18
|
+
addHook({ name: 'pg', versions: ['>=8.0.3'], file: 'lib/native/client.js' }, Client => {
|
|
19
|
+
shimmer.wrap(Client.prototype, 'query', query => wrapQuery(query))
|
|
20
|
+
return Client
|
|
22
21
|
})
|
|
23
22
|
|
|
24
|
-
addHook({ name: 'pg',
|
|
23
|
+
addHook({ name: 'pg', versions: ['>=8.0.3 <8.15.0', '>=8.15.0 <9'], file: 'lib/client.js' }, Client => {
|
|
25
24
|
shimmer.wrap(Client.prototype, 'query', query => wrapQuery(query))
|
|
26
25
|
return Client
|
|
27
26
|
})
|
|
28
27
|
|
|
28
|
+
addHook({ name: 'pg', versions: ['>=8.0.3'] }, pg => {
|
|
29
|
+
shimmer.wrap(pg.Pool.prototype, 'query', query => wrapPoolQuery(query))
|
|
30
|
+
return pg
|
|
31
|
+
})
|
|
32
|
+
|
|
29
33
|
function wrapQuery (query) {
|
|
30
34
|
return function () {
|
|
31
35
|
if (!startCh.hasSubscribers) {
|