dd-trace 4.40.0 → 4.42.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/ext/exporters.d.ts +1 -1
- package/index.d.ts +54 -1
- package/init.js +40 -1
- package/initialize.mjs +8 -5
- package/package.json +24 -20
- package/packages/datadog-core/src/storage/index.js +1 -10
- package/packages/datadog-esbuild/index.js +5 -1
- package/packages/datadog-instrumentations/src/aws-sdk.js +2 -1
- package/packages/datadog-instrumentations/src/cucumber.js +76 -34
- package/packages/datadog-instrumentations/src/helpers/hook.js +8 -3
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +4 -3
- package/packages/datadog-instrumentations/src/helpers/register.js +56 -5
- package/packages/datadog-instrumentations/src/http/server.js +98 -0
- package/packages/datadog-instrumentations/src/mocha/main.js +12 -1
- package/packages/datadog-instrumentations/src/mocha/utils.js +58 -14
- package/packages/datadog-instrumentations/src/mocha/worker.js +1 -0
- package/packages/datadog-instrumentations/src/playwright.js +1 -1
- package/packages/datadog-instrumentations/src/undici.js +18 -0
- package/packages/datadog-instrumentations/src/vitest.js +303 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +8 -1
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +9 -3
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +23 -5
- package/packages/datadog-plugin-child_process/src/index.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +24 -1
- package/packages/datadog-plugin-mocha/src/index.js +25 -4
- package/packages/datadog-plugin-openai/src/index.js +52 -30
- package/packages/datadog-plugin-openai/src/token-estimator.js +20 -0
- package/packages/datadog-plugin-undici/src/index.js +12 -0
- package/packages/datadog-plugin-vitest/src/index.js +156 -0
- package/packages/dd-trace/src/appsec/blocking.js +4 -0
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/iast/path-line.js +2 -19
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -0
- package/packages/dd-trace/src/appsec/index.js +45 -11
- package/packages/dd-trace/src/appsec/rasp.js +32 -5
- package/packages/dd-trace/src/appsec/recommended.json +208 -3
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +1 -0
- package/packages/dd-trace/src/appsec/remote_config/index.js +2 -0
- package/packages/dd-trace/src/appsec/reporter.js +64 -20
- package/packages/dd-trace/src/appsec/sdk/track_event.js +3 -0
- package/packages/dd-trace/src/appsec/stack_trace.js +90 -0
- package/packages/dd-trace/src/appsec/standalone.js +130 -0
- package/packages/dd-trace/src/appsec/telemetry.js +33 -1
- package/packages/dd-trace/src/appsec/waf/index.js +2 -2
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
- package/packages/dd-trace/src/config.js +110 -40
- package/packages/dd-trace/src/constants.js +3 -1
- package/packages/dd-trace/src/datastreams/processor.js +2 -1
- package/packages/dd-trace/src/exporters/agent/index.js +2 -2
- package/packages/dd-trace/src/format.js +22 -2
- package/packages/dd-trace/src/opentelemetry/span.js +33 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +12 -0
- package/packages/dd-trace/src/opentracing/span.js +42 -1
- package/packages/dd-trace/src/opentracing/tracer.js +2 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +7 -0
- package/packages/dd-trace/src/plugins/index.js +3 -0
- package/packages/dd-trace/src/plugins/util/test.js +5 -1
- package/packages/dd-trace/src/priority_sampler.js +2 -5
- package/packages/dd-trace/src/profiling/profiler.js +1 -1
- package/packages/dd-trace/src/proxy.js +3 -1
- package/packages/dd-trace/src/rate_limiter.js +2 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
- package/packages/dd-trace/src/span_stats.js +4 -3
- package/packages/dd-trace/src/tagger.js +10 -1
- package/packages/dd-trace/src/telemetry/init-telemetry.js +75 -0
- package/packages/dd-trace/src/tracer.js +2 -2
- package/packages/dd-trace/src/util.js +6 -1
- package/packages/datadog-core/src/storage/async_hooks.js +0 -49
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
2
|
+
const shimmer = require('../../datadog-shimmer')
|
|
3
|
+
|
|
4
|
+
// test hooks
|
|
5
|
+
const testStartCh = channel('ci:vitest:test:start')
|
|
6
|
+
const testFinishTimeCh = channel('ci:vitest:test:finish-time')
|
|
7
|
+
const testPassCh = channel('ci:vitest:test:pass')
|
|
8
|
+
const testErrorCh = channel('ci:vitest:test:error')
|
|
9
|
+
const testSkipCh = channel('ci:vitest:test:skip')
|
|
10
|
+
|
|
11
|
+
// test suite hooks
|
|
12
|
+
const testSuiteStartCh = channel('ci:vitest:test-suite:start')
|
|
13
|
+
const testSuiteFinishCh = channel('ci:vitest:test-suite:finish')
|
|
14
|
+
const testSuiteErrorCh = channel('ci:vitest:test-suite:error')
|
|
15
|
+
|
|
16
|
+
// test session hooks
|
|
17
|
+
const testSessionStartCh = channel('ci:vitest:session:start')
|
|
18
|
+
const testSessionFinishCh = channel('ci:vitest:session:finish')
|
|
19
|
+
|
|
20
|
+
const taskToAsync = new WeakMap()
|
|
21
|
+
|
|
22
|
+
const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
23
|
+
|
|
24
|
+
function isReporterPackage (vitestPackage) {
|
|
25
|
+
return vitestPackage.B?.name === 'BaseSequencer'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// from 2.0.0
|
|
29
|
+
function isReporterPackageNew (vitestPackage) {
|
|
30
|
+
return vitestPackage.e?.name === 'BaseSequencer'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getSessionStatus (state) {
|
|
34
|
+
if (state.getCountOfFailedTests() > 0) {
|
|
35
|
+
return 'fail'
|
|
36
|
+
}
|
|
37
|
+
if (state.pathsSet.size === 0) {
|
|
38
|
+
return 'skip'
|
|
39
|
+
}
|
|
40
|
+
return 'pass'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// eslint-disable-next-line
|
|
44
|
+
// From https://github.com/vitest-dev/vitest/blob/51c04e2f44d91322b334f8ccbcdb368facc3f8ec/packages/runner/src/run.ts#L243-L250
|
|
45
|
+
function getVitestTestStatus (test, retryCount) {
|
|
46
|
+
if (test.result.state !== 'fail') {
|
|
47
|
+
if (!test.repeats) {
|
|
48
|
+
return 'pass'
|
|
49
|
+
} else if (test.repeats && (test.retry ?? 0) === retryCount) {
|
|
50
|
+
return 'pass'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return 'fail'
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getTypeTasks (fileTasks, type = 'test') {
|
|
57
|
+
const typeTasks = []
|
|
58
|
+
|
|
59
|
+
function getTasks (tasks) {
|
|
60
|
+
for (const task of tasks) {
|
|
61
|
+
if (task.type === type) {
|
|
62
|
+
typeTasks.push(task)
|
|
63
|
+
} else if (task.tasks) {
|
|
64
|
+
getTasks(task.tasks)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
getTasks(fileTasks)
|
|
70
|
+
|
|
71
|
+
return typeTasks
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getTestName (task) {
|
|
75
|
+
let testName = task.name
|
|
76
|
+
let currentTask = task.suite
|
|
77
|
+
|
|
78
|
+
while (currentTask) {
|
|
79
|
+
if (currentTask.name) {
|
|
80
|
+
testName = `${currentTask.name} ${testName}`
|
|
81
|
+
}
|
|
82
|
+
currentTask = currentTask.suite
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return testName
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getSortWrapper (sort) {
|
|
89
|
+
return async function () {
|
|
90
|
+
if (!testSessionFinishCh.hasSubscribers) {
|
|
91
|
+
return sort.apply(this, arguments)
|
|
92
|
+
}
|
|
93
|
+
shimmer.wrap(this.ctx, 'exit', exit => async function () {
|
|
94
|
+
let onFinish
|
|
95
|
+
|
|
96
|
+
const flushPromise = new Promise(resolve => {
|
|
97
|
+
onFinish = resolve
|
|
98
|
+
})
|
|
99
|
+
const failedSuites = this.state.getFailedFilepaths()
|
|
100
|
+
let error
|
|
101
|
+
if (failedSuites.length) {
|
|
102
|
+
error = new Error(`Test suites failed: ${failedSuites.length}.`)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
sessionAsyncResource.runInAsyncScope(() => {
|
|
106
|
+
testSessionFinishCh.publish({
|
|
107
|
+
status: getSessionStatus(this.state),
|
|
108
|
+
onFinish,
|
|
109
|
+
error
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
await flushPromise
|
|
114
|
+
|
|
115
|
+
return exit.apply(this, arguments)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
return sort.apply(this, arguments)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
addHook({
|
|
123
|
+
name: 'vitest',
|
|
124
|
+
versions: ['>=1.6.0'],
|
|
125
|
+
file: 'dist/runners.js'
|
|
126
|
+
}, (vitestPackage) => {
|
|
127
|
+
const { VitestTestRunner } = vitestPackage
|
|
128
|
+
// test start (only tests that are not marked as skip or todo)
|
|
129
|
+
shimmer.wrap(VitestTestRunner.prototype, 'onBeforeTryTask', onBeforeTryTask => async function (task) {
|
|
130
|
+
if (!testStartCh.hasSubscribers) {
|
|
131
|
+
return onBeforeTryTask.apply(this, arguments)
|
|
132
|
+
}
|
|
133
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
134
|
+
taskToAsync.set(task, asyncResource)
|
|
135
|
+
|
|
136
|
+
asyncResource.runInAsyncScope(() => {
|
|
137
|
+
testStartCh.publish({ testName: getTestName(task), testSuiteAbsolutePath: task.suite.file.filepath })
|
|
138
|
+
})
|
|
139
|
+
return onBeforeTryTask.apply(this, arguments)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
// test finish (only passed tests)
|
|
143
|
+
shimmer.wrap(VitestTestRunner.prototype, 'onAfterTryTask', onAfterTryTask =>
|
|
144
|
+
async function (task, { retry: retryCount }) {
|
|
145
|
+
if (!testFinishTimeCh.hasSubscribers) {
|
|
146
|
+
return onAfterTryTask.apply(this, arguments)
|
|
147
|
+
}
|
|
148
|
+
const result = await onAfterTryTask.apply(this, arguments)
|
|
149
|
+
|
|
150
|
+
const status = getVitestTestStatus(task, retryCount)
|
|
151
|
+
const asyncResource = taskToAsync.get(task)
|
|
152
|
+
|
|
153
|
+
if (asyncResource) {
|
|
154
|
+
// We don't finish here because the test might fail in a later hook
|
|
155
|
+
asyncResource.runInAsyncScope(() => {
|
|
156
|
+
testFinishTimeCh.publish({ status, task })
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return result
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
return vitestPackage
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
addHook({
|
|
167
|
+
name: 'vitest',
|
|
168
|
+
versions: ['>=2.0.0'],
|
|
169
|
+
filePattern: 'dist/vendor/index.*'
|
|
170
|
+
}, (vitestPackage) => {
|
|
171
|
+
// there are multiple index* files so we have to check the exported values
|
|
172
|
+
if (isReporterPackageNew(vitestPackage)) {
|
|
173
|
+
shimmer.wrap(vitestPackage.e.prototype, 'sort', getSortWrapper)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return vitestPackage
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
addHook({
|
|
180
|
+
name: 'vitest',
|
|
181
|
+
versions: ['>=1.6.0'],
|
|
182
|
+
filePattern: 'dist/vendor/index.*'
|
|
183
|
+
}, (vitestPackage) => {
|
|
184
|
+
// there are multiple index* files so we have to check the exported values
|
|
185
|
+
if (isReporterPackage(vitestPackage)) {
|
|
186
|
+
shimmer.wrap(vitestPackage.B.prototype, 'sort', getSortWrapper)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return vitestPackage
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
// Can't specify file because compiled vitest includes hashes in their files
|
|
193
|
+
addHook({
|
|
194
|
+
name: 'vitest',
|
|
195
|
+
versions: ['>=1.6.0'],
|
|
196
|
+
filePattern: 'dist/vendor/cac.*'
|
|
197
|
+
}, (vitestPackage, frameworkVersion) => {
|
|
198
|
+
shimmer.wrap(vitestPackage, 'c', oldCreateCli => function () {
|
|
199
|
+
if (!testSessionStartCh.hasSubscribers) {
|
|
200
|
+
return oldCreateCli.apply(this, arguments)
|
|
201
|
+
}
|
|
202
|
+
sessionAsyncResource.runInAsyncScope(() => {
|
|
203
|
+
const processArgv = process.argv.slice(2).join(' ')
|
|
204
|
+
testSessionStartCh.publish({ command: `vitest ${processArgv}`, frameworkVersion })
|
|
205
|
+
})
|
|
206
|
+
return oldCreateCli.apply(this, arguments)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
return vitestPackage
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
// test suite start and finish
|
|
213
|
+
// only relevant for workers
|
|
214
|
+
addHook({
|
|
215
|
+
name: '@vitest/runner',
|
|
216
|
+
versions: ['>=1.6.0'],
|
|
217
|
+
file: 'dist/index.js'
|
|
218
|
+
}, vitestPackage => {
|
|
219
|
+
shimmer.wrap(vitestPackage, 'startTests', startTests => async function (testPath) {
|
|
220
|
+
let testSuiteError = null
|
|
221
|
+
if (!testSuiteStartCh.hasSubscribers) {
|
|
222
|
+
return startTests.apply(this, arguments)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const testSuiteAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
226
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
227
|
+
testSuiteStartCh.publish(testPath[0])
|
|
228
|
+
})
|
|
229
|
+
const startTestsResponse = await startTests.apply(this, arguments)
|
|
230
|
+
|
|
231
|
+
let onFinish = null
|
|
232
|
+
const onFinishPromise = new Promise(resolve => {
|
|
233
|
+
onFinish = resolve
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
const testTasks = getTypeTasks(startTestsResponse[0].tasks)
|
|
237
|
+
|
|
238
|
+
testTasks.forEach(task => {
|
|
239
|
+
const testAsyncResource = taskToAsync.get(task)
|
|
240
|
+
const { result } = task
|
|
241
|
+
|
|
242
|
+
if (result) {
|
|
243
|
+
const { state, duration, errors } = result
|
|
244
|
+
if (state === 'skip') { // programmatic skip
|
|
245
|
+
testSkipCh.publish({ testName: getTestName(task), testSuiteAbsolutePath: task.suite.file.filepath })
|
|
246
|
+
} else if (state === 'pass') {
|
|
247
|
+
if (testAsyncResource) {
|
|
248
|
+
testAsyncResource.runInAsyncScope(() => {
|
|
249
|
+
testPassCh.publish({ task })
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
} else if (state === 'fail') {
|
|
253
|
+
// If it's failing, we have no accurate finish time, so we have to use `duration`
|
|
254
|
+
let testError
|
|
255
|
+
|
|
256
|
+
if (errors?.length) {
|
|
257
|
+
testError = errors[0]
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (testAsyncResource) {
|
|
261
|
+
testAsyncResource.runInAsyncScope(() => {
|
|
262
|
+
testErrorCh.publish({ duration, error: testError })
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
if (errors?.length) {
|
|
266
|
+
testSuiteError = testError // we store the error to bubble it up to the suite
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
} else { // test.skip or test.todo
|
|
270
|
+
testSkipCh.publish({ testName: getTestName(task), testSuiteAbsolutePath: task.suite.file.filepath })
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
const testSuiteResult = startTestsResponse[0].result
|
|
275
|
+
|
|
276
|
+
if (testSuiteResult.errors?.length) { // Errors from root level hooks
|
|
277
|
+
testSuiteError = testSuiteResult.errors[0]
|
|
278
|
+
} else if (testSuiteResult.state === 'fail') { // Errors from `describe` level hooks
|
|
279
|
+
const suiteTasks = getTypeTasks(startTestsResponse[0].tasks, 'suite')
|
|
280
|
+
const failedSuites = suiteTasks.filter(task => task.result?.state === 'fail')
|
|
281
|
+
if (failedSuites.length && failedSuites[0].result?.errors?.length) {
|
|
282
|
+
testSuiteError = failedSuites[0].result.errors[0]
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (testSuiteError) {
|
|
287
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
288
|
+
testSuiteErrorCh.publish({ error: testSuiteError })
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
293
|
+
testSuiteFinishCh.publish({ status: testSuiteResult.state, onFinish })
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
// TODO: fix too frequent flushes
|
|
297
|
+
await onFinishPromise
|
|
298
|
+
|
|
299
|
+
return startTestsResponse
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
return vitestPackage
|
|
303
|
+
})
|
|
@@ -64,11 +64,17 @@ class BaseAwsSdkPlugin extends ClientPlugin {
|
|
|
64
64
|
span.setTag('region', region)
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
-
this.addSub(`apm:aws:request:complete:${this.serviceIdentifier}`, ({ response }) => {
|
|
67
|
+
this.addSub(`apm:aws:request:complete:${this.serviceIdentifier}`, ({ response, cbExists = false }) => {
|
|
68
68
|
const store = storage.getStore()
|
|
69
69
|
if (!store) return
|
|
70
70
|
const { span } = store
|
|
71
71
|
if (!span) return
|
|
72
|
+
// try to extract DSM context from response if no callback exists as extraction normally happens in CB
|
|
73
|
+
if (!cbExists && this.serviceIdentifier === 'sqs') {
|
|
74
|
+
const params = response.request.params
|
|
75
|
+
const operation = response.request.operation
|
|
76
|
+
this.responseExtractDSMContext(operation, params, response.data, span)
|
|
77
|
+
}
|
|
72
78
|
this.addResponseTags(span, response)
|
|
73
79
|
this.finish(span, response, response.error)
|
|
74
80
|
})
|
|
@@ -159,6 +165,7 @@ function normalizeConfig (config, serviceIdentifier) {
|
|
|
159
165
|
|
|
160
166
|
return Object.assign({}, config, specificConfig, {
|
|
161
167
|
splitByAwsService: config.splitByAwsService !== false,
|
|
168
|
+
batchPropagationEnabled: config.batchPropagationEnabled !== false,
|
|
162
169
|
hooks
|
|
163
170
|
})
|
|
164
171
|
}
|
|
@@ -52,7 +52,7 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
52
52
|
|
|
53
53
|
// extract DSM context after as we might not have a parent-child but may have a DSM context
|
|
54
54
|
this.responseExtractDSMContext(
|
|
55
|
-
request.operation, response, span || null, streamName
|
|
55
|
+
request.operation, request.params, response, span || null, { streamName }
|
|
56
56
|
)
|
|
57
57
|
}
|
|
58
58
|
})
|
|
@@ -100,7 +100,8 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
responseExtractDSMContext (operation, response, span,
|
|
103
|
+
responseExtractDSMContext (operation, params, response, span, kwargs = {}) {
|
|
104
|
+
const { streamName } = kwargs
|
|
104
105
|
if (!this.config.dsmEnabled) return
|
|
105
106
|
if (operation !== 'getRecords') return
|
|
106
107
|
if (!response || !response.Records || !response.Records[0]) return
|
|
@@ -151,7 +152,12 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
151
152
|
case 'putRecords':
|
|
152
153
|
stream = params.StreamArn ? params.StreamArn : (params.StreamName ? params.StreamName : '')
|
|
153
154
|
for (let i = 0; i < params.Records.length; i++) {
|
|
154
|
-
this.injectToMessage(
|
|
155
|
+
this.injectToMessage(
|
|
156
|
+
span,
|
|
157
|
+
params.Records[i],
|
|
158
|
+
stream,
|
|
159
|
+
i === 0 || (this.config.kinesis && this.config.kinesis.batchPropagationEnabled)
|
|
160
|
+
)
|
|
155
161
|
}
|
|
156
162
|
}
|
|
157
163
|
}
|
|
@@ -59,7 +59,12 @@ class Sns extends BaseAwsSdkPlugin {
|
|
|
59
59
|
break
|
|
60
60
|
case 'publishBatch':
|
|
61
61
|
for (let i = 0; i < params.PublishBatchRequestEntries.length; i++) {
|
|
62
|
-
this.injectToMessage(
|
|
62
|
+
this.injectToMessage(
|
|
63
|
+
span,
|
|
64
|
+
params.PublishBatchRequestEntries[i],
|
|
65
|
+
params.TopicArn,
|
|
66
|
+
i === 0 || (this.config.sns && this.config.sns.batchPropagationEnabled)
|
|
67
|
+
)
|
|
63
68
|
}
|
|
64
69
|
break
|
|
65
70
|
}
|
|
@@ -23,7 +23,7 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
23
23
|
const plugin = this
|
|
24
24
|
const contextExtraction = this.responseExtract(request.params, request.operation, response)
|
|
25
25
|
let span
|
|
26
|
-
let parsedMessageAttributes
|
|
26
|
+
let parsedMessageAttributes = null
|
|
27
27
|
if (contextExtraction && contextExtraction.datadogContext) {
|
|
28
28
|
obj.needsFinish = true
|
|
29
29
|
const options = {
|
|
@@ -39,8 +39,9 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
39
39
|
this.enter(span, store)
|
|
40
40
|
}
|
|
41
41
|
// extract DSM context after as we might not have a parent-child but may have a DSM context
|
|
42
|
+
|
|
42
43
|
this.responseExtractDSMContext(
|
|
43
|
-
request.operation, request.params, response, span || null, parsedMessageAttributes
|
|
44
|
+
request.operation, request.params, response, span || null, { parsedMessageAttributes }
|
|
44
45
|
)
|
|
45
46
|
})
|
|
46
47
|
|
|
@@ -165,7 +166,8 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
168
|
|
|
168
|
-
responseExtractDSMContext (operation, params, response, span,
|
|
169
|
+
responseExtractDSMContext (operation, params, response, span, kwargs = {}) {
|
|
170
|
+
let { parsedAttributes } = kwargs
|
|
169
171
|
if (!this.config.dsmEnabled) return
|
|
170
172
|
if (operation !== 'receiveMessage') return
|
|
171
173
|
if (!response || !response.Messages || !response.Messages[0]) return
|
|
@@ -188,7 +190,7 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
188
190
|
// SQS to SQS
|
|
189
191
|
}
|
|
190
192
|
}
|
|
191
|
-
if (message.MessageAttributes && message.MessageAttributes._datadog) {
|
|
193
|
+
if (!parsedAttributes && message.MessageAttributes && message.MessageAttributes._datadog) {
|
|
192
194
|
parsedAttributes = this.parseDatadogAttributes(message.MessageAttributes._datadog)
|
|
193
195
|
}
|
|
194
196
|
}
|
|
@@ -216,7 +218,23 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
216
218
|
break
|
|
217
219
|
case 'sendMessageBatch':
|
|
218
220
|
for (let i = 0; i < params.Entries.length; i++) {
|
|
219
|
-
this.injectToMessage(
|
|
221
|
+
this.injectToMessage(
|
|
222
|
+
span,
|
|
223
|
+
params.Entries[i],
|
|
224
|
+
params.QueueUrl,
|
|
225
|
+
i === 0 || (this.config.sqs && this.config.sqs.batchPropagationEnabled)
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
break
|
|
229
|
+
case 'receiveMessage':
|
|
230
|
+
if (!params.MessageAttributeNames) {
|
|
231
|
+
params.MessageAttributeNames = ['_datadog']
|
|
232
|
+
} else if (
|
|
233
|
+
!params.MessageAttributeNames.includes('_datadog') &&
|
|
234
|
+
!params.MessageAttributeNames.includes('.*') &&
|
|
235
|
+
!params.MessageAttributeNames.includes('All')
|
|
236
|
+
) {
|
|
237
|
+
params.MessageAttributeNames.push('_datadog')
|
|
220
238
|
}
|
|
221
239
|
break
|
|
222
240
|
}
|
|
@@ -54,7 +54,7 @@ class ChildProcessPlugin extends TracingPlugin {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
this.startSpan('command_execution', {
|
|
57
|
-
service: this.config.service,
|
|
57
|
+
service: this.config.service || this._tracerConfig.service,
|
|
58
58
|
resource: (shell === true) ? 'sh' : cmdFields[0],
|
|
59
59
|
type: 'system',
|
|
60
60
|
meta
|
|
@@ -195,6 +195,17 @@ class CucumberPlugin extends CiPlugin {
|
|
|
195
195
|
this.enter(testSpan, store)
|
|
196
196
|
})
|
|
197
197
|
|
|
198
|
+
this.addSub('ci:cucumber:test:retry', (isFlakyRetry) => {
|
|
199
|
+
const store = storage.getStore()
|
|
200
|
+
const span = store.span
|
|
201
|
+
if (isFlakyRetry) {
|
|
202
|
+
span.setTag(TEST_IS_RETRY, 'true')
|
|
203
|
+
}
|
|
204
|
+
span.setTag(TEST_STATUS, 'fail')
|
|
205
|
+
span.finish()
|
|
206
|
+
finishAllTraceSpans(span)
|
|
207
|
+
})
|
|
208
|
+
|
|
198
209
|
this.addSub('ci:cucumber:test-step:start', ({ resource }) => {
|
|
199
210
|
const store = storage.getStore()
|
|
200
211
|
const childOf = store ? store.span : store
|
|
@@ -239,7 +250,15 @@ class CucumberPlugin extends CiPlugin {
|
|
|
239
250
|
})
|
|
240
251
|
})
|
|
241
252
|
|
|
242
|
-
this.addSub('ci:cucumber:test:finish', ({
|
|
253
|
+
this.addSub('ci:cucumber:test:finish', ({
|
|
254
|
+
isStep,
|
|
255
|
+
status,
|
|
256
|
+
skipReason,
|
|
257
|
+
errorMessage,
|
|
258
|
+
isNew,
|
|
259
|
+
isEfdRetry,
|
|
260
|
+
isFlakyRetry
|
|
261
|
+
}) => {
|
|
243
262
|
const span = storage.getStore().span
|
|
244
263
|
const statusTag = isStep ? 'step.status' : TEST_STATUS
|
|
245
264
|
|
|
@@ -260,6 +279,10 @@ class CucumberPlugin extends CiPlugin {
|
|
|
260
279
|
span.setTag(ERROR_MESSAGE, errorMessage)
|
|
261
280
|
}
|
|
262
281
|
|
|
282
|
+
if (isFlakyRetry > 0) {
|
|
283
|
+
span.setTag(TEST_IS_RETRY, 'true')
|
|
284
|
+
}
|
|
285
|
+
|
|
263
286
|
span.finish()
|
|
264
287
|
if (!isStep) {
|
|
265
288
|
this.telemetry.ciVisEvent(
|
|
@@ -175,13 +175,15 @@ class MochaPlugin extends CiPlugin {
|
|
|
175
175
|
this.tracer._exporter.flush()
|
|
176
176
|
})
|
|
177
177
|
|
|
178
|
-
this.addSub('ci:mocha:test:finish', (status) => {
|
|
178
|
+
this.addSub('ci:mocha:test:finish', ({ status, hasBeenRetried }) => {
|
|
179
179
|
const store = storage.getStore()
|
|
180
180
|
const span = store?.span
|
|
181
181
|
|
|
182
182
|
if (span) {
|
|
183
183
|
span.setTag(TEST_STATUS, status)
|
|
184
|
-
|
|
184
|
+
if (hasBeenRetried) {
|
|
185
|
+
span.setTag(TEST_IS_RETRY, 'true')
|
|
186
|
+
}
|
|
185
187
|
span.finish()
|
|
186
188
|
this.telemetry.ciVisEvent(
|
|
187
189
|
TELEMETRY_EVENT_FINISHED,
|
|
@@ -204,8 +206,8 @@ class MochaPlugin extends CiPlugin {
|
|
|
204
206
|
|
|
205
207
|
this.addSub('ci:mocha:test:error', (err) => {
|
|
206
208
|
const store = storage.getStore()
|
|
207
|
-
|
|
208
|
-
|
|
209
|
+
const span = store?.span
|
|
210
|
+
if (err && span) {
|
|
209
211
|
if (err.constructor.name === 'Pending' && !this.forbidPending) {
|
|
210
212
|
span.setTag(TEST_STATUS, 'skip')
|
|
211
213
|
} else {
|
|
@@ -215,6 +217,25 @@ class MochaPlugin extends CiPlugin {
|
|
|
215
217
|
}
|
|
216
218
|
})
|
|
217
219
|
|
|
220
|
+
this.addSub('ci:mocha:test:retry', (isFirstAttempt) => {
|
|
221
|
+
const store = storage.getStore()
|
|
222
|
+
const span = store?.span
|
|
223
|
+
if (span) {
|
|
224
|
+
span.setTag(TEST_STATUS, 'fail')
|
|
225
|
+
if (!isFirstAttempt) {
|
|
226
|
+
span.setTag(TEST_IS_RETRY, 'true')
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
span.finish()
|
|
230
|
+
this.telemetry.ciVisEvent(
|
|
231
|
+
TELEMETRY_EVENT_FINISHED,
|
|
232
|
+
'test',
|
|
233
|
+
{ hasCodeOwners: !!span.context()._tags[TEST_CODE_OWNERS] }
|
|
234
|
+
)
|
|
235
|
+
finishAllTraceSpans(span)
|
|
236
|
+
}
|
|
237
|
+
})
|
|
238
|
+
|
|
218
239
|
this.addSub('ci:mocha:test:parameterize', ({ title, params }) => {
|
|
219
240
|
this._testTitleToParams[title] = params
|
|
220
241
|
})
|