dd-trace 5.103.0 → 5.104.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 +25 -3
- package/package.json +4 -3
- package/packages/datadog-instrumentations/src/aws-sdk.js +2 -2
- package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
- package/packages/datadog-instrumentations/src/cucumber.js +103 -30
- package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
- package/packages/datadog-instrumentations/src/graphql.js +0 -5
- package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/kafka.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -5
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +14 -13
- package/packages/datadog-instrumentations/src/http/client.js +2 -2
- package/packages/datadog-instrumentations/src/ioredis.js +3 -3
- package/packages/datadog-instrumentations/src/jest.js +33 -36
- package/packages/datadog-instrumentations/src/kafkajs.js +25 -6
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/memcached.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +272 -91
- package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
- package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
- package/packages/datadog-instrumentations/src/mongoose.js +10 -12
- package/packages/datadog-instrumentations/src/mysql.js +2 -2
- package/packages/datadog-instrumentations/src/mysql2.js +1 -1
- package/packages/datadog-instrumentations/src/pg.js +1 -1
- package/packages/datadog-instrumentations/src/playwright.js +22 -5
- package/packages/datadog-instrumentations/src/router.js +4 -2
- package/packages/datadog-instrumentations/src/vitest.js +246 -149
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +26 -19
- package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
- package/packages/datadog-plugin-graphql/src/utils.js +4 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +32 -0
- package/packages/datadog-plugin-mongodb-core/src/index.js +54 -19
- package/packages/datadog-plugin-redis/src/index.js +37 -2
- package/packages/datadog-plugin-undici/src/index.js +19 -0
- package/packages/datadog-plugin-vitest/src/index.js +19 -7
- package/packages/datadog-shimmer/src/shimmer.js +35 -0
- package/packages/dd-trace/src/appsec/blocking.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +10 -3
- package/packages/dd-trace/src/appsec/reporter.js +19 -5
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
- package/packages/dd-trace/src/config/generated-config-types.d.ts +1 -0
- package/packages/dd-trace/src/config/supported-configurations.json +9 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
- package/packages/dd-trace/src/datastreams/context.js +4 -2
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +26 -19
- package/packages/dd-trace/src/exporters/common/agents.js +3 -1
- package/packages/dd-trace/src/exporters/common/request.js +3 -1
- package/packages/dd-trace/src/id.js +17 -4
- package/packages/dd-trace/src/lambda/handler.js +2 -4
- package/packages/dd-trace/src/llmobs/sdk.js +10 -0
- package/packages/dd-trace/src/log/writer.js +3 -1
- package/packages/dd-trace/src/noop/span.js +3 -1
- package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
- package/packages/dd-trace/src/plugins/apollo.js +3 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +3 -13
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -1
- package/packages/dd-trace/src/plugins/tracing.js +5 -3
- package/packages/dd-trace/src/plugins/util/git.js +3 -1
- package/packages/dd-trace/src/plugins/util/test.js +82 -0
- package/packages/dd-trace/src/plugins/util/web.js +11 -0
- package/packages/dd-trace/src/scope.js +7 -5
- package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
- package/vendor/dist/opentracing/LICENSE +0 -201
- package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
- package/vendor/dist/opentracing/constants.d.ts +0 -61
- package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
- package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
- package/vendor/dist/opentracing/functions.d.ts +0 -20
- package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
- package/vendor/dist/opentracing/index.d.ts +0 -12
- package/vendor/dist/opentracing/index.js +0 -1
- package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
- package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
- package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
- package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
- package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
- package/vendor/dist/opentracing/noop.d.ts +0 -8
- package/vendor/dist/opentracing/reference.d.ts +0 -33
- package/vendor/dist/opentracing/span.d.ts +0 -147
- package/vendor/dist/opentracing/span_context.d.ts +0 -26
- package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
- package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
- package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
- package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
- package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
- package/vendor/dist/opentracing/tracer.d.ts +0 -127
package/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ClientRequest, IncomingMessage, OutgoingMessage, ServerResponse } from "http";
|
|
2
2
|
import { LookupFunction } from 'net';
|
|
3
|
-
import * as opentracing from "
|
|
3
|
+
import * as opentracing from "opentracing";
|
|
4
4
|
import * as otel from "@opentelemetry/api";
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -2849,13 +2849,13 @@ declare namespace tracer {
|
|
|
2849
2849
|
* [mocha](https://mochajs.org/) module.
|
|
2850
2850
|
*/
|
|
2851
2851
|
interface mocha extends Integration {}
|
|
2852
|
-
|
|
2852
|
+
|
|
2853
2853
|
/**
|
|
2854
2854
|
* This plugin automatically instruments the
|
|
2855
2855
|
* [modelcontextprotocol-sdk](https://github.com/npmjs/package/@modelcontextprotocol/sdk) library.
|
|
2856
2856
|
*/
|
|
2857
2857
|
interface modelcontextprotocol_sdk extends Instrumentation {}
|
|
2858
|
-
|
|
2858
|
+
|
|
2859
2859
|
/**
|
|
2860
2860
|
* This plugin automatically instruments the
|
|
2861
2861
|
* [moleculer](https://moleculer.services/) module.
|
|
@@ -2887,6 +2887,24 @@ declare namespace tracer {
|
|
|
2887
2887
|
*/
|
|
2888
2888
|
heartbeatEnabled?: boolean;
|
|
2889
2889
|
|
|
2890
|
+
/**
|
|
2891
|
+
* How to mask primitive query values in the `mongodb.query` tag and the
|
|
2892
|
+
* resource name (when `queryInResourceName` is also enabled). Keys,
|
|
2893
|
+
* operator names, and array / pipeline shape are preserved so the masked
|
|
2894
|
+
* query is still a usable query signature.
|
|
2895
|
+
*
|
|
2896
|
+
* - `'types'`: replace each primitive leaf with its `typeof` name
|
|
2897
|
+
* (`'string'`, `'number'`, `'boolean'`, `'bigint'`, `'object'`,
|
|
2898
|
+
* `'null'`). Keeps the same redaction guarantee as `'redact'` but
|
|
2899
|
+
* preserves the value types so the rendered query can still be used
|
|
2900
|
+
* to design indexes.
|
|
2901
|
+
* - `'redact'`: replace each primitive leaf with `'?'`. Strictest masking.
|
|
2902
|
+
* - `'none'`: do not mask. Values land verbatim on the span.
|
|
2903
|
+
*
|
|
2904
|
+
* @default 'none'
|
|
2905
|
+
*/
|
|
2906
|
+
obfuscateQuery?: 'none' | 'types' | 'redact';
|
|
2907
|
+
|
|
2890
2908
|
/**
|
|
2891
2909
|
* Whether to include the query contents in the resource name.
|
|
2892
2910
|
*/
|
|
@@ -3584,11 +3602,15 @@ declare namespace tracer {
|
|
|
3584
3602
|
|
|
3585
3603
|
/**
|
|
3586
3604
|
* Enable LLM Observability tracing.
|
|
3605
|
+
*
|
|
3606
|
+
* @deprecated Enabling LLM Observability via `llmobs.enable()` is deprecated and will be removed in dd-trace@7.0.0. Please instantiate LLM Observability via DD_LLMOBS_ENABLED or `tracer.init({ llmobs: ...options })`.
|
|
3587
3607
|
*/
|
|
3588
3608
|
enable (options: LLMObsEnableOptions): void,
|
|
3589
3609
|
|
|
3590
3610
|
/**
|
|
3591
3611
|
* Disable LLM Observability tracing.
|
|
3612
|
+
*
|
|
3613
|
+
* @deprecated Disabling LLM Observability via `llmobs.disable()` is deprecated and will be removed in dd-trace@7.0.0. Set DD_LLMOBS_ENABLED=false to disable LLM Observability.
|
|
3592
3614
|
*/
|
|
3593
3615
|
disable (): void,
|
|
3594
3616
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.104.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"test:integration:aiguard:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/aiguard/*.spec.js\"",
|
|
73
73
|
"test:integration:appsec": "mocha --timeout 60000 \"integration-tests/appsec/*.spec.js\"",
|
|
74
74
|
"test:integration:appsec:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/appsec/*.spec.js\"",
|
|
75
|
+
"test:integration:crashtracking": "mocha --timeout 60000 \"integration-tests/crashtracking/*.spec.js\"",
|
|
75
76
|
"test:integration:bun": "mocha --timeout 60000 \"integration-tests/bun/*.spec.js\"",
|
|
76
77
|
"test:integration:cucumber": "mocha --timeout 60000 \"integration-tests/cucumber/*.spec.js\"",
|
|
77
78
|
"test:integration:cucumber:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/cucumber/*.spec.js\"",
|
|
@@ -161,7 +162,8 @@
|
|
|
161
162
|
],
|
|
162
163
|
"dependencies": {
|
|
163
164
|
"dc-polyfill": "^0.1.11",
|
|
164
|
-
"import-in-the-middle": "^3.0.1"
|
|
165
|
+
"import-in-the-middle": "^3.0.1",
|
|
166
|
+
"opentracing": ">=0.14.7"
|
|
165
167
|
},
|
|
166
168
|
"optionalDependencies": {
|
|
167
169
|
"@datadog/libdatadog": "0.9.3",
|
|
@@ -218,7 +220,6 @@
|
|
|
218
220
|
"node-preload": "^0.2.1",
|
|
219
221
|
"nyc": "^18.0.0",
|
|
220
222
|
"octokit": "^5.0.3",
|
|
221
|
-
"opentracing": ">=0.14.7",
|
|
222
223
|
"p-limit": "^7.2.0",
|
|
223
224
|
"proxyquire": "^2.1.3",
|
|
224
225
|
"retry": "^0.13.1",
|
|
@@ -198,7 +198,7 @@ function wrapSmithySend (send) {
|
|
|
198
198
|
})
|
|
199
199
|
|
|
200
200
|
if (typeof cb === 'function') {
|
|
201
|
-
args[args.length - 1] = shimmer.
|
|
201
|
+
args[args.length - 1] = shimmer.wrapCallback(cb, cb => function (err, result) {
|
|
202
202
|
addResponse(ctx, err, result)
|
|
203
203
|
|
|
204
204
|
handleCompletion(result, ctx, channels)
|
|
@@ -270,7 +270,7 @@ function handleCompletion (result, ctx, channels) {
|
|
|
270
270
|
|
|
271
271
|
function wrapCb (cb, channels, ctx) {
|
|
272
272
|
// eslint-disable-next-line n/handle-callback-err
|
|
273
|
-
return shimmer.
|
|
273
|
+
return shimmer.wrapCallback(cb, cb => function wrappedCb (err, response) {
|
|
274
274
|
ctx = { request: ctx.request, response }
|
|
275
275
|
return channels.responseStart.runStores(ctx, () => {
|
|
276
276
|
try {
|
|
@@ -29,9 +29,12 @@ addHook({ name: 'cassandra-driver', versions: ['>=3.0.0'] }, cassandra => {
|
|
|
29
29
|
|
|
30
30
|
try {
|
|
31
31
|
const res = batch.apply(this, arguments)
|
|
32
|
-
if (typeof res === 'function'
|
|
32
|
+
if (typeof res === 'function') {
|
|
33
33
|
return wrapCallback(finishCh, errorCh, startCtx, res)
|
|
34
34
|
}
|
|
35
|
+
if (!res) {
|
|
36
|
+
return res
|
|
37
|
+
}
|
|
35
38
|
return res.then(
|
|
36
39
|
() => finish(finishCh, errorCh, startCtx),
|
|
37
40
|
err => finish(finishCh, errorCh, startCtx, err)
|
|
@@ -162,7 +165,7 @@ function finish (finishCh, errorCh, ctx, error) {
|
|
|
162
165
|
}
|
|
163
166
|
|
|
164
167
|
function wrapCallback (finishCh, errorCh, ctx, callback) {
|
|
165
|
-
return shimmer.
|
|
168
|
+
return shimmer.wrapCallback(callback, callback => function (err) {
|
|
166
169
|
if (err) {
|
|
167
170
|
ctx.error = err
|
|
168
171
|
errorCh.publish(ctx)
|
|
@@ -15,10 +15,12 @@ const {
|
|
|
15
15
|
CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
|
|
16
16
|
getIsFaultyEarlyFlakeDetection,
|
|
17
17
|
getEfdRetryCount,
|
|
18
|
+
getMaxEfdRetryCount,
|
|
18
19
|
recordAttemptToFixExecution,
|
|
19
20
|
collectAttemptToFixExecutionsFromTraces,
|
|
20
21
|
logAttemptToFixTestExecution,
|
|
21
22
|
logTestOptimizationSummary,
|
|
23
|
+
getTestOptimizationRequestResults,
|
|
22
24
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
23
25
|
const satisfies = require('../../../vendor/dist/semifies')
|
|
24
26
|
const { addHook, channel } = require('./helpers/instrument')
|
|
@@ -51,6 +53,8 @@ const itrSkippedSuitesCh = channel('ci:cucumber:itr:skipped-suites')
|
|
|
51
53
|
|
|
52
54
|
const getCodeCoverageCh = channel('ci:nyc:get-coverage')
|
|
53
55
|
|
|
56
|
+
const DD_EFD_RETRY_COUNT_MESSAGE = '_ddEfdRetryCount'
|
|
57
|
+
|
|
54
58
|
const isMarkedAsUnskippable = (pickle) => {
|
|
55
59
|
return pickle.tags.some(tag => tag.name === '@datadog:unskippable')
|
|
56
60
|
}
|
|
@@ -67,7 +71,7 @@ const atrStatusesByScenarioKey = new Map()
|
|
|
67
71
|
const numRetriesByPickleId = new Map()
|
|
68
72
|
const efdRetryCountByPickleId = new Map()
|
|
69
73
|
const efdSlowAbortedPickleIds = new Set()
|
|
70
|
-
const
|
|
74
|
+
const finishedParallelSuites = new Set()
|
|
71
75
|
const numAttemptToCtx = new Map()
|
|
72
76
|
const newTestsByTestFullname = new Map()
|
|
73
77
|
const attemptToFixTestsByTestFullname = new Map()
|
|
@@ -117,6 +121,68 @@ function getSuiteStatusFromTestStatuses (testStatuses) {
|
|
|
117
121
|
return 'pass'
|
|
118
122
|
}
|
|
119
123
|
|
|
124
|
+
function getConfiguredEfdRetryCount () {
|
|
125
|
+
const maxSlowTestRetryCount = getMaxEfdRetryCount(earlyFlakeDetectionSlowTestRetries)
|
|
126
|
+
return maxSlowTestRetryCount || earlyFlakeDetectionNumRetries
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function publishWorkerEfdRetryCount (pickle, retryCount) {
|
|
130
|
+
if (typeof process.send !== 'function') return
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
process.send({
|
|
134
|
+
[DD_EFD_RETRY_COUNT_MESSAGE]: {
|
|
135
|
+
pickleId: pickle.id,
|
|
136
|
+
retryCount,
|
|
137
|
+
testFileAbsolutePath: pickle.uri,
|
|
138
|
+
testName: pickle.name,
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
} catch {
|
|
142
|
+
// ignore IPC errors
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function finishParallelSuiteIfDone (testFileAbsolutePath) {
|
|
147
|
+
const finished = pickleResultByFile[testFileAbsolutePath]
|
|
148
|
+
const expectedPickles = pickleByFile[testFileAbsolutePath]
|
|
149
|
+
|
|
150
|
+
if (!finished || !expectedPickles || finished.length !== expectedPickles.length) return
|
|
151
|
+
if (finishedParallelSuites.has(testFileAbsolutePath)) return
|
|
152
|
+
|
|
153
|
+
finishedParallelSuites.add(testFileAbsolutePath)
|
|
154
|
+
testSuiteFinishCh.publish({
|
|
155
|
+
status: getSuiteStatusFromTestStatuses(finished),
|
|
156
|
+
testSuitePath: getTestSuitePath(testFileAbsolutePath, process.cwd()),
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function maybeRecordFinalParallelEfdStatus ({ pickleId, testFileAbsolutePath, testFullname }) {
|
|
161
|
+
const efdRetryCount = efdRetryCountByPickleId.get(pickleId)
|
|
162
|
+
const testStatuses = newTestsByTestFullname.get(testFullname)
|
|
163
|
+
const finished = pickleResultByFile[testFileAbsolutePath]
|
|
164
|
+
|
|
165
|
+
if (efdRetryCount === undefined || !testStatuses || !finished) return
|
|
166
|
+
if (testStatuses.length !== efdRetryCount + 1) return
|
|
167
|
+
|
|
168
|
+
finished.push(getTestStatusFromRetries(testStatuses))
|
|
169
|
+
newTestsByTestFullname.delete(testFullname)
|
|
170
|
+
finishParallelSuiteIfDone(testFileAbsolutePath)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function handleEfdRetryCountMessage (message) {
|
|
174
|
+
const { pickleId, retryCount, testFileAbsolutePath, testName } = message
|
|
175
|
+
|
|
176
|
+
if (!pickleId || typeof retryCount !== 'number' || !testFileAbsolutePath || !testName) return
|
|
177
|
+
|
|
178
|
+
efdRetryCountByPickleId.set(pickleId, retryCount)
|
|
179
|
+
maybeRecordFinalParallelEfdStatus({
|
|
180
|
+
pickleId,
|
|
181
|
+
testFileAbsolutePath,
|
|
182
|
+
testFullname: `${testFileAbsolutePath}:${testName}`,
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
120
186
|
function getStatusFromResult (result) {
|
|
121
187
|
if (result.status === 1) {
|
|
122
188
|
return { status: 'pass' }
|
|
@@ -639,18 +705,31 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
639
705
|
testManagementAttemptToFixRetries = configurationResponse.libraryConfig?.testManagementAttemptToFixRetries
|
|
640
706
|
isImpactedTestsEnabled = configurationResponse.libraryConfig?.isImpactedTestsEnabled
|
|
641
707
|
|
|
708
|
+
const {
|
|
709
|
+
knownTestsResponse,
|
|
710
|
+
testManagementTestsResponse,
|
|
711
|
+
skippableSuitesResponse,
|
|
712
|
+
} = await getTestOptimizationRequestResults({
|
|
713
|
+
isKnownTestsEnabled,
|
|
714
|
+
isTestManagementTestsEnabled,
|
|
715
|
+
isSuitesSkippingEnabled,
|
|
716
|
+
getKnownTests: () => getChannelPromise(knownTestsCh),
|
|
717
|
+
getTestManagementTests: () => getChannelPromise(testManagementTestsCh),
|
|
718
|
+
getSkippableSuites: () => getChannelPromise(skippableSuitesCh),
|
|
719
|
+
})
|
|
720
|
+
|
|
642
721
|
if (isKnownTestsEnabled) {
|
|
643
|
-
const
|
|
644
|
-
if (
|
|
722
|
+
const currentKnownTestsResponse = knownTestsResponse || await getChannelPromise(knownTestsCh)
|
|
723
|
+
if (currentKnownTestsResponse.err) {
|
|
645
724
|
isEarlyFlakeDetectionEnabled = false
|
|
646
725
|
isKnownTestsEnabled = false
|
|
647
726
|
} else {
|
|
648
|
-
knownTests =
|
|
727
|
+
knownTests = currentKnownTestsResponse.knownTests
|
|
649
728
|
}
|
|
650
729
|
}
|
|
651
730
|
|
|
652
731
|
if (isSuitesSkippingEnabled) {
|
|
653
|
-
const skippableResponse = await getChannelPromise(skippableSuitesCh)
|
|
732
|
+
const skippableResponse = skippableSuitesResponse || await getChannelPromise(skippableSuitesCh)
|
|
654
733
|
|
|
655
734
|
errorSkippableRequest = skippableResponse.err
|
|
656
735
|
skippableSuites = skippableResponse.skippableSuites ?? []
|
|
@@ -694,11 +773,12 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
694
773
|
}
|
|
695
774
|
|
|
696
775
|
if (isTestManagementTestsEnabled) {
|
|
697
|
-
const
|
|
698
|
-
|
|
776
|
+
const currentTestManagementTestsResponse =
|
|
777
|
+
testManagementTestsResponse || await getChannelPromise(testManagementTestsCh)
|
|
778
|
+
if (currentTestManagementTestsResponse.err) {
|
|
699
779
|
isTestManagementTestsEnabled = false
|
|
700
780
|
} else {
|
|
701
|
-
testManagementTests =
|
|
781
|
+
testManagementTests = currentTestManagementTestsResponse.testManagementTests
|
|
702
782
|
}
|
|
703
783
|
}
|
|
704
784
|
|
|
@@ -720,7 +800,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
720
800
|
attemptToFixTestsByTestFullname.clear()
|
|
721
801
|
efdRetryCountByPickleId.clear()
|
|
722
802
|
efdSlowAbortedPickleIds.clear()
|
|
723
|
-
|
|
803
|
+
finishedParallelSuites.clear()
|
|
724
804
|
newTestsByTestFullname.clear()
|
|
725
805
|
sessionStartCh.publish({ command, frameworkVersion })
|
|
726
806
|
|
|
@@ -875,6 +955,9 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
|
|
|
875
955
|
efdSlowAbortedPickleIds.add(pickle.id)
|
|
876
956
|
}
|
|
877
957
|
}
|
|
958
|
+
if (isWorker) {
|
|
959
|
+
publishWorkerEfdRetryCount(pickle, efdRetryCount)
|
|
960
|
+
}
|
|
878
961
|
for (let retryIndex = 0; retryIndex < efdRetryCount; retryIndex++) {
|
|
879
962
|
numRetriesByPickleId.set(pickle.id, retryIndex + 1)
|
|
880
963
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -973,6 +1056,10 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
|
|
|
973
1056
|
return
|
|
974
1057
|
}
|
|
975
1058
|
}
|
|
1059
|
+
if (message[DD_EFD_RETRY_COUNT_MESSAGE]) {
|
|
1060
|
+
handleEfdRetryCountMessage(message[DD_EFD_RETRY_COUNT_MESSAGE])
|
|
1061
|
+
return
|
|
1062
|
+
}
|
|
976
1063
|
|
|
977
1064
|
const envelope = isNewVersion ? message.envelope : message.jsonEnvelope
|
|
978
1065
|
|
|
@@ -989,12 +1076,13 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
|
|
|
989
1076
|
return parseWorkerMessageFunction.apply(this, arguments)
|
|
990
1077
|
}
|
|
991
1078
|
}
|
|
1079
|
+
if (parsed[DD_EFD_RETRY_COUNT_MESSAGE]) {
|
|
1080
|
+
handleEfdRetryCountMessage(parsed[DD_EFD_RETRY_COUNT_MESSAGE])
|
|
1081
|
+
return
|
|
1082
|
+
}
|
|
992
1083
|
let pickle
|
|
993
1084
|
|
|
994
1085
|
if (parsed.testCaseStarted) {
|
|
995
|
-
if (parsed.testCaseStarted.id) {
|
|
996
|
-
testCaseStartedTimesById.set(parsed.testCaseStarted.id, performance.now())
|
|
997
|
-
}
|
|
998
1086
|
if (isNewVersion) {
|
|
999
1087
|
pickle = this.inProgress[worker.id].pickle
|
|
1000
1088
|
} else {
|
|
@@ -1016,10 +1104,6 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
|
|
|
1016
1104
|
|
|
1017
1105
|
// after calling `parseWorkerMessageFunction`, the test status can already be read
|
|
1018
1106
|
if (parsed.testCaseFinished) {
|
|
1019
|
-
const testCaseStartedId = parsed.testCaseFinished.testCaseStartedId
|
|
1020
|
-
const testCaseStartedAt = testCaseStartedTimesById.get(testCaseStartedId)
|
|
1021
|
-
testCaseStartedTimesById.delete(testCaseStartedId)
|
|
1022
|
-
|
|
1023
1107
|
let worstTestStepResult
|
|
1024
1108
|
if (isNewVersion && eventDataCollector) {
|
|
1025
1109
|
pickle = this.inProgress[worker.id].pickle
|
|
@@ -1052,21 +1136,15 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
|
|
|
1052
1136
|
}
|
|
1053
1137
|
let efdRetryCount = efdRetryCountByPickleId.get(pickle.id)
|
|
1054
1138
|
if (efdRetryCount === undefined) {
|
|
1055
|
-
const firstExecutionDurationMs = testCaseStartedAt === undefined ? 0 : performance.now() - testCaseStartedAt
|
|
1056
1139
|
efdRetryCount = status === 'skip'
|
|
1057
1140
|
? 0
|
|
1058
|
-
:
|
|
1141
|
+
: getConfiguredEfdRetryCount()
|
|
1059
1142
|
efdRetryCountByPickleId.set(pickle.id, efdRetryCount)
|
|
1060
1143
|
if (efdRetryCount === 0 && status !== 'skip') {
|
|
1061
1144
|
efdSlowAbortedPickleIds.add(pickle.id)
|
|
1062
1145
|
}
|
|
1063
1146
|
}
|
|
1064
|
-
|
|
1065
|
-
if (testStatuses.length === efdRetryCount + 1) {
|
|
1066
|
-
const newTestFinalStatus = getTestStatusFromRetries(testStatuses)
|
|
1067
|
-
// we only push to `finished` if the retries have finished
|
|
1068
|
-
finished.push(newTestFinalStatus)
|
|
1069
|
-
}
|
|
1147
|
+
maybeRecordFinalParallelEfdStatus({ pickleId: pickle.id, testFileAbsolutePath, testFullname })
|
|
1070
1148
|
} else if (
|
|
1071
1149
|
isTestManagementTestsEnabled &&
|
|
1072
1150
|
getTestProperties(getTestSuitePath(testFileAbsolutePath, process.cwd()), pickle.name).attemptToFix
|
|
@@ -1090,12 +1168,7 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
|
|
|
1090
1168
|
finished.push(status)
|
|
1091
1169
|
}
|
|
1092
1170
|
|
|
1093
|
-
|
|
1094
|
-
testSuiteFinishCh.publish({
|
|
1095
|
-
status: getSuiteStatusFromTestStatuses(finished),
|
|
1096
|
-
testSuitePath: getTestSuitePath(testFileAbsolutePath, process.cwd()),
|
|
1097
|
-
})
|
|
1098
|
-
}
|
|
1171
|
+
finishParallelSuiteIfDone(testFileAbsolutePath)
|
|
1099
1172
|
}
|
|
1100
1173
|
|
|
1101
1174
|
return parseWorkerResponse
|
|
@@ -51,9 +51,9 @@ function createWrapSelect () {
|
|
|
51
51
|
const connectCh = channel('apm:elasticsearch:query:connect')
|
|
52
52
|
return function wrapRequest (request) {
|
|
53
53
|
return function (...args) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
args[0] = shimmer.
|
|
54
|
+
const cb = args[0]
|
|
55
|
+
if (args.length === 1 && typeof cb === 'function') {
|
|
56
|
+
args[0] = shimmer.wrapCallback(cb, cb => function (err, connection) {
|
|
57
57
|
if (connectCh.hasSubscribers && connection && connection.host) {
|
|
58
58
|
connectCh.publish({ hostname: connection.host.host, port: connection.host.port })
|
|
59
59
|
}
|
|
@@ -85,7 +85,7 @@ function createWrapRequest (name) {
|
|
|
85
85
|
cb = arguments[lastIndex]
|
|
86
86
|
|
|
87
87
|
if (typeof cb === 'function') {
|
|
88
|
-
arguments[lastIndex] = shimmer.
|
|
88
|
+
arguments[lastIndex] = shimmer.wrapCallback(cb, cb => function (error) {
|
|
89
89
|
if (error) {
|
|
90
90
|
ctx.error = error
|
|
91
91
|
errorCh.publish(ctx)
|
|
@@ -343,11 +343,6 @@ addHook({ name: '@graphql-tools/executor', versions: ['>=0.0.14'] }, executor =>
|
|
|
343
343
|
return executor
|
|
344
344
|
})
|
|
345
345
|
|
|
346
|
-
addHook({ name: '@graphql-tools/executor', file: 'cjs/execution/execute.js', versions: ['>=0.0.14'] }, execute => {
|
|
347
|
-
shimmer.wrap(execute, 'execute', wrapExecute(execute))
|
|
348
|
-
return execute
|
|
349
|
-
})
|
|
350
|
-
|
|
351
346
|
addHook({ name: 'graphql', file: 'execution/execute.js', versions: ['>=0.10'] }, execute => {
|
|
352
347
|
shimmer.wrap(execute, 'execute', wrapExecute(execute))
|
|
353
348
|
return execute
|
|
@@ -14,11 +14,14 @@ const finishChannel = channel('apm:grpc:client:request:finish')
|
|
|
14
14
|
const emitChannel = channel('apm:grpc:client:request:emit')
|
|
15
15
|
|
|
16
16
|
function createWrapMakeRequest (type, hasPeer = false) {
|
|
17
|
+
const metadataIndex = type === types.client_stream || type === types.bidi ? 3 : 4
|
|
18
|
+
|
|
17
19
|
return function wrapMakeRequest (makeRequest) {
|
|
18
20
|
return function (path) {
|
|
19
|
-
|
|
21
|
+
if (!startChannel.hasSubscribers) return makeRequest.apply(this, arguments)
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
const { metadata, args } = resolveMetadata(this, arguments, metadataIndex)
|
|
24
|
+
return callMethod(this, makeRequest, args, path, metadata, type, hasPeer)
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
}
|
|
@@ -82,9 +85,13 @@ function wrapMethod (method, path, type, hasPeer) {
|
|
|
82
85
|
return method
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
const metadataIndex = type === types.client_stream || type === types.bidi ? 0 : 1
|
|
89
|
+
|
|
85
90
|
const wrapped = shimmer.wrapFunction(method, method => function () {
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
if (!startChannel.hasSubscribers) return method.apply(this, arguments)
|
|
92
|
+
|
|
93
|
+
const { metadata, args } = resolveMetadata(this, arguments, metadataIndex)
|
|
94
|
+
return callMethod(this, method, args, path, metadata, type, hasPeer)
|
|
88
95
|
})
|
|
89
96
|
|
|
90
97
|
patched.add(wrapped)
|
|
@@ -140,24 +147,25 @@ function createWrapEmit (ctx, hasPeer = false) {
|
|
|
140
147
|
}
|
|
141
148
|
|
|
142
149
|
function callMethod (client, method, args, path, metadata, type, hasPeer = false) {
|
|
143
|
-
if (!startChannel.hasSubscribers) return method.apply(client, args)
|
|
144
|
-
|
|
145
|
-
const length = args.length
|
|
146
|
-
const callback = args[length - 1]
|
|
147
|
-
|
|
148
150
|
const ctx = { metadata, path, type }
|
|
149
151
|
|
|
150
152
|
return startChannel.runStores(ctx, () => {
|
|
151
153
|
try {
|
|
154
|
+
let callArgs = args
|
|
155
|
+
|
|
152
156
|
if (type === types.unary || type === types.client_stream) {
|
|
157
|
+
if (!Array.isArray(callArgs)) callArgs = [...callArgs]
|
|
158
|
+
|
|
159
|
+
const length = callArgs.length
|
|
160
|
+
const callback = callArgs[length - 1]
|
|
153
161
|
if (typeof callback === 'function') {
|
|
154
|
-
|
|
162
|
+
callArgs[length - 1] = wrapCallback(ctx, callback)
|
|
155
163
|
} else {
|
|
156
|
-
|
|
164
|
+
callArgs[length] = wrapCallback(ctx)
|
|
157
165
|
}
|
|
158
166
|
}
|
|
159
167
|
|
|
160
|
-
const call = method.apply(client,
|
|
168
|
+
const call = method.apply(client, callArgs)
|
|
161
169
|
|
|
162
170
|
if (call && typeof call.emit === 'function') {
|
|
163
171
|
shimmer.wrap(call, 'emit', createWrapEmit(ctx, hasPeer))
|
|
@@ -167,36 +175,44 @@ function callMethod (client, method, args, path, metadata, type, hasPeer = false
|
|
|
167
175
|
} catch (e) {
|
|
168
176
|
ctx.error = e
|
|
169
177
|
errorChannel.publish(ctx)
|
|
178
|
+
throw e
|
|
170
179
|
}
|
|
171
180
|
// No end channel needed
|
|
172
181
|
})
|
|
173
182
|
}
|
|
174
183
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Returns the `Metadata` for a gRPC client invocation, splicing or replacing
|
|
186
|
+
* one at `index` when the user did not pass their own.
|
|
187
|
+
*
|
|
188
|
+
* @param {object} client
|
|
189
|
+
* @param {ArrayLike<unknown>} args
|
|
190
|
+
* @param {number} index
|
|
191
|
+
* @returns {{ metadata: object | undefined, args: ArrayLike<unknown> }}
|
|
192
|
+
*/
|
|
193
|
+
function resolveMetadata (client, args, index) {
|
|
194
|
+
const grpc = client && getGrpc(client)
|
|
195
|
+
if (!grpc) return { metadata: undefined, args }
|
|
196
|
+
|
|
197
|
+
const slot = args[index]
|
|
198
|
+
|
|
199
|
+
if (slot instanceof grpc.Metadata || slot?.constructor?.name === 'Metadata') {
|
|
200
|
+
return { metadata: slot, args }
|
|
185
201
|
}
|
|
186
202
|
|
|
187
|
-
|
|
188
|
-
normalized.push(new grpc.Metadata())
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (meta) {
|
|
192
|
-
normalized.push(meta)
|
|
193
|
-
}
|
|
203
|
+
const metadata = new grpc.Metadata()
|
|
194
204
|
|
|
195
|
-
|
|
196
|
-
|
|
205
|
+
if (slot == null) {
|
|
206
|
+
const out = [...args]
|
|
207
|
+
out[index] = metadata
|
|
208
|
+
return { metadata, args: out }
|
|
197
209
|
}
|
|
198
210
|
|
|
199
|
-
|
|
211
|
+
const out = new Array(args.length + 1)
|
|
212
|
+
for (let i = 0; i < index; i++) out[i] = args[i]
|
|
213
|
+
out[index] = metadata
|
|
214
|
+
for (let i = index; i < args.length; i++) out[i + 1] = args[i]
|
|
215
|
+
return { metadata, args: out }
|
|
200
216
|
}
|
|
201
217
|
|
|
202
218
|
function getType (definition) {
|
|
@@ -45,7 +45,7 @@ function createCallbackInstrumentor (prefix, { captureResult = false } = {}) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
return startCh.runStores(ctx, () => {
|
|
48
|
-
args[lastIndex] = shimmer.
|
|
48
|
+
args[lastIndex] = shimmer.wrapCallback(cb, cb => function (error, ...rest) {
|
|
49
49
|
if (error) {
|
|
50
50
|
ctx.error = error
|
|
51
51
|
errorCh.publish(ctx)
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
// Produce API key 0; v0–v2 use the legacy MessageSet format with no header
|
|
4
|
+
// field, so trace headers can only be carried on v3+ (Kafka >=0.11).
|
|
5
|
+
const PRODUCE_API_KEY = 0
|
|
6
|
+
const PRODUCE_VERSION_WITH_HEADERS = 3
|
|
7
|
+
|
|
3
8
|
// Side-table mapping a kafkajs producer/consumer to the cluster captured at
|
|
4
9
|
// creation time. The boundary uses it to read `cluster.brokerPool` lazily on
|
|
5
10
|
// first send/consume instead of opening a parallel admin connection. A
|
|
@@ -35,7 +40,19 @@ function cloneMessages (messages, ensureHeaders) {
|
|
|
35
40
|
return result
|
|
36
41
|
}
|
|
37
42
|
|
|
43
|
+
/**
|
|
44
|
+
* @param {{ versions?: Record<number, { minVersion: number, maxVersion: number }> } | undefined} brokerPool
|
|
45
|
+
* kafkajs's `cluster.brokerPool`. `versions` is populated once the seed
|
|
46
|
+
* broker handshakes; before that, the answer is unknown and we return
|
|
47
|
+
* `true` so the caller defaults to injection.
|
|
48
|
+
*/
|
|
49
|
+
function brokerSupportsMessageHeaders (brokerPool) {
|
|
50
|
+
const produce = brokerPool?.versions?.[PRODUCE_API_KEY]
|
|
51
|
+
return !produce || produce.maxVersion >= PRODUCE_VERSION_WITH_HEADERS
|
|
52
|
+
}
|
|
53
|
+
|
|
38
54
|
module.exports = {
|
|
55
|
+
brokerSupportsMessageHeaders,
|
|
39
56
|
clientToCluster,
|
|
40
57
|
cloneMessages,
|
|
41
58
|
}
|
|
@@ -19,9 +19,10 @@ const compiler = {
|
|
|
19
19
|
// TODO: Figure out ESBuild `createRequire` issue and remove this hack.
|
|
20
20
|
const oxc = runtimeRequire(['oxc', 'parser'].join('-'))
|
|
21
21
|
|
|
22
|
-
compiler.parse = (sourceText,
|
|
22
|
+
compiler.parse = (sourceText, { range, isModule } = {}) => {
|
|
23
23
|
const { program, errors } = oxc.parseSync('index.js', sourceText, {
|
|
24
|
-
|
|
24
|
+
range,
|
|
25
|
+
sourceType: isModule ? 'module' : 'script',
|
|
25
26
|
preserveParens: false,
|
|
26
27
|
})
|
|
27
28
|
|
|
@@ -2,15 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
const { readFileSync } = require('fs')
|
|
4
4
|
const { join } = require('path')
|
|
5
|
+
const { pathToFileURL } = require('url')
|
|
5
6
|
const log = require('../../../../dd-trace/src/log')
|
|
6
7
|
const { create } = require('../../../../../vendor/dist/@apm-js-collab/code-transformer')
|
|
7
8
|
const { traceAsyncIterator, traceIterator } = require('./transforms')
|
|
8
9
|
const instrumentations = require('./instrumentations')
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
// `dc-polyfill` is referenced from injected `require()` (CJS) and `import`
|
|
12
|
+
// (ESM) statements that the transformer splices into the rewritten module.
|
|
13
|
+
// `require()` accepts an absolute filesystem path; the ESM resolver rejects it
|
|
14
|
+
// with `ERR_INVALID_MODULE_SPECIFIER` and needs a `file://` URL instead. We
|
|
15
|
+
// pre-compute both forms here so each matcher hands the transformer a
|
|
16
|
+
// specifier that is valid for the module type it is rewriting.
|
|
17
|
+
let dcPolyfillCjs
|
|
18
|
+
let dcPolyfillEsm
|
|
11
19
|
|
|
12
20
|
try {
|
|
13
|
-
|
|
21
|
+
const resolved = require.resolve('dc-polyfill')
|
|
22
|
+
dcPolyfillCjs = resolved.replaceAll('\\', '/')
|
|
23
|
+
dcPolyfillEsm = pathToFileURL(resolved).href
|
|
14
24
|
} catch {
|
|
15
25
|
// The `dc-polyfill` module is unavailable for some reason (like bundling).
|
|
16
26
|
// Let's just keep the default of using `diagnostics-channel` as a fallback
|
|
@@ -20,10 +30,13 @@ try {
|
|
|
20
30
|
/** @type {Record<string, string>} map of module base name to version */
|
|
21
31
|
const moduleVersions = {}
|
|
22
32
|
const disabled = new Set()
|
|
23
|
-
const
|
|
33
|
+
const matcherCjs = create(instrumentations, dcPolyfillCjs)
|
|
34
|
+
const matcherEsm = create(instrumentations, dcPolyfillEsm)
|
|
24
35
|
|
|
25
|
-
matcher
|
|
26
|
-
matcher.addTransform('
|
|
36
|
+
for (const matcher of [matcherCjs, matcherEsm]) {
|
|
37
|
+
matcher.addTransform('traceIterator', traceIterator)
|
|
38
|
+
matcher.addTransform('traceAsyncIterator', traceAsyncIterator)
|
|
39
|
+
}
|
|
27
40
|
|
|
28
41
|
function rewrite (content, filename, format) {
|
|
29
42
|
if (!content) return content
|
|
@@ -41,6 +54,7 @@ function rewrite (content, filename, format) {
|
|
|
41
54
|
|
|
42
55
|
if (disabled.has(moduleName)) return content
|
|
43
56
|
|
|
57
|
+
const matcher = moduleType === 'esm' ? matcherEsm : matcherCjs
|
|
44
58
|
const transformer = matcher.getTransformer(moduleName, version, filePath)
|
|
45
59
|
|
|
46
60
|
if (!transformer) return content
|