dd-trace 3.12.1 → 3.15.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/README.md +5 -5
- package/ci/init.js +3 -1
- package/index.d.ts +100 -1
- package/package.json +5 -4
- package/packages/datadog-instrumentations/src/aws-sdk.js +86 -0
- package/packages/datadog-instrumentations/src/cucumber.js +74 -15
- package/packages/datadog-instrumentations/src/cypress.js +1 -1
- package/packages/datadog-instrumentations/src/fs.js +358 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +24 -23
- package/packages/datadog-instrumentations/src/ldapjs.js +12 -2
- package/packages/datadog-instrumentations/src/mocha.js +10 -7
- package/packages/datadog-instrumentations/src/mongoose.js +1 -1
- package/packages/datadog-instrumentations/src/mysql.js +7 -1
- package/packages/datadog-instrumentations/src/mysql2.js +7 -1
- package/packages/datadog-instrumentations/src/next.js +2 -1
- package/packages/datadog-instrumentations/src/playwright.js +263 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +12 -5
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +29 -24
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +31 -16
- package/packages/datadog-plugin-cucumber/src/index.js +42 -11
- package/packages/datadog-plugin-cypress/src/plugin.js +129 -4
- package/packages/datadog-plugin-cypress/src/support.js +5 -0
- package/packages/datadog-plugin-fs/src/index.js +45 -0
- package/packages/datadog-plugin-hapi/src/index.js +5 -1
- package/packages/datadog-plugin-http/src/server.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +40 -70
- package/packages/datadog-plugin-mocha/src/index.js +44 -64
- package/packages/datadog-plugin-mysql/src/index.js +8 -7
- package/packages/datadog-plugin-playwright/src/index.js +112 -0
- package/packages/datadog-shimmer/src/shimmer.js +28 -11
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/blocking.js +35 -9
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +60 -0
- package/packages/dd-trace/src/appsec/iast/iast-context.js +6 -2
- package/packages/dd-trace/src/appsec/iast/index.js +3 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -2
- package/packages/dd-trace/src/appsec/index.js +5 -5
- package/packages/dd-trace/src/appsec/recommended.json +320 -184
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +3 -0
- package/packages/dd-trace/src/appsec/reporter.js +14 -14
- package/packages/dd-trace/src/appsec/sdk/index.js +41 -0
- package/packages/dd-trace/src/appsec/sdk/noop.js +17 -0
- package/packages/dd-trace/src/appsec/sdk/set_user.js +30 -0
- package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +73 -0
- package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +1 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -5
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +48 -11
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +7 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +4 -2
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +5 -3
- package/packages/dd-trace/src/config.js +63 -7
- package/packages/dd-trace/src/encode/0.4.js +1 -1
- package/packages/dd-trace/src/encode/0.5.js +1 -1
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -4
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +52 -37
- package/packages/dd-trace/src/encode/tags-processors.js +3 -2
- package/packages/dd-trace/src/exporters/common/request.js +10 -3
- package/packages/dd-trace/src/lambda/handler.js +5 -6
- package/packages/dd-trace/src/log/channels.js +47 -0
- package/packages/dd-trace/src/log/index.js +79 -0
- package/packages/dd-trace/src/log/writer.js +124 -0
- package/packages/dd-trace/src/metrics.js +18 -0
- package/packages/dd-trace/src/noop/proxy.js +5 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +188 -36
- package/packages/dd-trace/src/opentracing/propagation/tracestate.js +99 -0
- package/packages/dd-trace/src/opentracing/span.js +2 -1
- package/packages/dd-trace/src/opentracing/span_context.js +6 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +72 -12
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -21
- package/packages/dd-trace/src/plugins/util/exec.js +2 -2
- package/packages/dd-trace/src/plugins/util/git.js +16 -1
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +53 -10
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -7
- package/packages/dd-trace/src/plugins/util/web.js +11 -0
- package/packages/dd-trace/src/profiler.js +3 -0
- package/packages/dd-trace/src/profiling/config.js +8 -3
- package/packages/dd-trace/src/profiling/exporters/file.js +13 -2
- package/packages/dd-trace/src/profiling/profiler.js +23 -6
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
- package/packages/dd-trace/src/proxy.js +2 -0
- package/packages/dd-trace/src/span_processor.js +1 -1
- package/packages/dd-trace/src/span_sampler.js +68 -52
- package/packages/dd-trace/src/startup-log.js +3 -6
- package/packages/dd-trace/src/telemetry/index.js +23 -2
- package/packages/dd-trace/src/telemetry/send-data.js +4 -1
- package/packages/dd-trace/src/tracer.js +0 -16
- package/scripts/check-proposal-labels.js +71 -0
- package/packages/dd-trace/src/log.js +0 -143
- /package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
2
|
+
const shimmer = require('../../datadog-shimmer')
|
|
3
|
+
|
|
4
|
+
const testStartCh = channel('ci:playwright:test:start')
|
|
5
|
+
const testFinishCh = channel('ci:playwright:test:finish')
|
|
6
|
+
|
|
7
|
+
const testSessionStartCh = channel('ci:playwright:session:start')
|
|
8
|
+
const testSessionFinishCh = channel('ci:playwright:session:finish')
|
|
9
|
+
|
|
10
|
+
const testSuiteStartCh = channel('ci:playwright:test-suite:start')
|
|
11
|
+
const testSuiteFinishCh = channel('ci:playwright:test-suite:finish')
|
|
12
|
+
|
|
13
|
+
const testToAr = new WeakMap()
|
|
14
|
+
const testSuiteToAr = new Map()
|
|
15
|
+
const testSuiteToTestStatuses = new Map()
|
|
16
|
+
|
|
17
|
+
let startedSuites = []
|
|
18
|
+
|
|
19
|
+
const STATUS_TO_TEST_STATUS = {
|
|
20
|
+
passed: 'pass',
|
|
21
|
+
failed: 'fail',
|
|
22
|
+
timedOut: 'fail',
|
|
23
|
+
skipped: 'skip'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let remainingTestsByFile = {}
|
|
27
|
+
|
|
28
|
+
function getTestsBySuiteFromTestGroups (testGroups) {
|
|
29
|
+
return testGroups.reduce((acc, { requireFile, tests }) => {
|
|
30
|
+
if (acc[requireFile]) {
|
|
31
|
+
acc[requireFile] = acc[requireFile].concat(tests)
|
|
32
|
+
} else {
|
|
33
|
+
acc[requireFile] = tests
|
|
34
|
+
}
|
|
35
|
+
return acc
|
|
36
|
+
}, {})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getTestsBySuiteFromTestsById (testsById) {
|
|
40
|
+
const testsByTestSuite = {}
|
|
41
|
+
for (const { test } of testsById.values()) {
|
|
42
|
+
const { _requireFile } = test
|
|
43
|
+
if (test._type === 'beforeAll' || test._type === 'afterAll') {
|
|
44
|
+
continue
|
|
45
|
+
}
|
|
46
|
+
if (testsByTestSuite[_requireFile]) {
|
|
47
|
+
testsByTestSuite[_requireFile].push(test)
|
|
48
|
+
} else {
|
|
49
|
+
testsByTestSuite[_requireFile] = [test]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return testsByTestSuite
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getPlaywrightConfig (playwrightRunner) {
|
|
56
|
+
try {
|
|
57
|
+
return playwrightRunner._configLoader.fullConfig()
|
|
58
|
+
} catch (e) {
|
|
59
|
+
try {
|
|
60
|
+
return playwrightRunner._loader.fullConfig()
|
|
61
|
+
} catch (e) {
|
|
62
|
+
return playwrightRunner._config || {}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getRootDir (playwrightRunner) {
|
|
68
|
+
const config = getPlaywrightConfig(playwrightRunner)
|
|
69
|
+
if (config.rootDir) {
|
|
70
|
+
return config.rootDir
|
|
71
|
+
}
|
|
72
|
+
if (playwrightRunner._configDir) {
|
|
73
|
+
return playwrightRunner._configDir
|
|
74
|
+
}
|
|
75
|
+
return process.cwd()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function testBeginHandler (test) {
|
|
79
|
+
const { title: testName, location: { file: testSuiteAbsolutePath }, _type } = test
|
|
80
|
+
|
|
81
|
+
if (_type === 'beforeAll' || _type === 'afterAll') {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const isNewTestSuite = !startedSuites.includes(testSuiteAbsolutePath)
|
|
86
|
+
|
|
87
|
+
if (isNewTestSuite) {
|
|
88
|
+
startedSuites.push(testSuiteAbsolutePath)
|
|
89
|
+
const testSuiteAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
90
|
+
testSuiteToAr.set(testSuiteAbsolutePath, testSuiteAsyncResource)
|
|
91
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
92
|
+
testSuiteStartCh.publish(testSuiteAbsolutePath)
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const testAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
97
|
+
testToAr.set(test, testAsyncResource)
|
|
98
|
+
testAsyncResource.runInAsyncScope(() => {
|
|
99
|
+
testStartCh.publish({ testName, testSuiteAbsolutePath })
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function testEndHandler (test, testStatus, error) {
|
|
104
|
+
const { location: { file: testSuiteAbsolutePath }, results, _type } = test
|
|
105
|
+
|
|
106
|
+
if (_type === 'beforeAll' || _type === 'afterAll') {
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const testResult = results[results.length - 1]
|
|
111
|
+
const testAsyncResource = testToAr.get(test)
|
|
112
|
+
testAsyncResource.runInAsyncScope(() => {
|
|
113
|
+
testFinishCh.publish({ testStatus, steps: testResult.steps, error })
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
if (!testSuiteToTestStatuses.has(testSuiteAbsolutePath)) {
|
|
117
|
+
testSuiteToTestStatuses.set(testSuiteAbsolutePath, [testStatus])
|
|
118
|
+
} else {
|
|
119
|
+
testSuiteToTestStatuses.get(testSuiteAbsolutePath).push(testStatus)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
remainingTestsByFile[testSuiteAbsolutePath] = remainingTestsByFile[testSuiteAbsolutePath]
|
|
123
|
+
.filter(currentTest => currentTest !== test)
|
|
124
|
+
|
|
125
|
+
if (!remainingTestsByFile[testSuiteAbsolutePath].length) {
|
|
126
|
+
const testStatuses = testSuiteToTestStatuses.get(testSuiteAbsolutePath)
|
|
127
|
+
|
|
128
|
+
let testSuiteStatus = 'pass'
|
|
129
|
+
if (testStatuses.some(status => status === 'fail')) {
|
|
130
|
+
testSuiteStatus = 'fail'
|
|
131
|
+
} else if (testStatuses.every(status => status === 'skip')) {
|
|
132
|
+
testSuiteStatus = 'skip'
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const testSuiteAsyncResource = testSuiteToAr.get(testSuiteAbsolutePath)
|
|
136
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
137
|
+
testSuiteFinishCh.publish(testSuiteStatus)
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function dispatcherRunWrapper (run) {
|
|
143
|
+
return function () {
|
|
144
|
+
remainingTestsByFile = getTestsBySuiteFromTestsById(this._testById)
|
|
145
|
+
return run.apply(this, arguments)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function dispatcherRunWrapperNew (run) {
|
|
150
|
+
return function () {
|
|
151
|
+
remainingTestsByFile = getTestsBySuiteFromTestGroups(arguments[0])
|
|
152
|
+
return run.apply(this, arguments)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function dispatcherHook (dispatcherExport) {
|
|
157
|
+
shimmer.wrap(dispatcherExport.Dispatcher.prototype, 'run', dispatcherRunWrapper)
|
|
158
|
+
shimmer.wrap(dispatcherExport.Dispatcher.prototype, '_createWorker', createWorker => function () {
|
|
159
|
+
const dispatcher = this
|
|
160
|
+
const worker = createWorker.apply(this, arguments)
|
|
161
|
+
|
|
162
|
+
worker.process.on('message', ({ method, params }) => {
|
|
163
|
+
if (method === 'testBegin') {
|
|
164
|
+
const { test } = dispatcher._testById.get(params.testId)
|
|
165
|
+
testBeginHandler(test)
|
|
166
|
+
} else if (method === 'testEnd') {
|
|
167
|
+
const { test } = dispatcher._testById.get(params.testId)
|
|
168
|
+
|
|
169
|
+
const { results } = test
|
|
170
|
+
const testResult = results[results.length - 1]
|
|
171
|
+
|
|
172
|
+
testEndHandler(test, STATUS_TO_TEST_STATUS[testResult.status], testResult.error)
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
return worker
|
|
177
|
+
})
|
|
178
|
+
return dispatcherExport
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function dispatcherHookNew (dispatcherExport, runWrapper) {
|
|
182
|
+
shimmer.wrap(dispatcherExport.Dispatcher.prototype, 'run', runWrapper)
|
|
183
|
+
shimmer.wrap(dispatcherExport.Dispatcher.prototype, '_createWorker', createWorker => function () {
|
|
184
|
+
const dispatcher = this
|
|
185
|
+
const worker = createWorker.apply(this, arguments)
|
|
186
|
+
|
|
187
|
+
worker.on('testBegin', ({ testId }) => {
|
|
188
|
+
const { test } = dispatcher._testById.get(testId)
|
|
189
|
+
testBeginHandler(test)
|
|
190
|
+
})
|
|
191
|
+
worker.on('testEnd', ({ testId, status, errors }) => {
|
|
192
|
+
const { test } = dispatcher._testById.get(testId)
|
|
193
|
+
|
|
194
|
+
testEndHandler(test, STATUS_TO_TEST_STATUS[status], errors && errors[0])
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
return worker
|
|
198
|
+
})
|
|
199
|
+
return dispatcherExport
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function runnerHook (runnerExport, playwrightVersion) {
|
|
203
|
+
shimmer.wrap(runnerExport.Runner.prototype, 'runAllTests', runAllTests => async function () {
|
|
204
|
+
const testSessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
205
|
+
const rootDir = getRootDir(this)
|
|
206
|
+
|
|
207
|
+
const processArgv = process.argv.slice(2).join(' ')
|
|
208
|
+
const command = `playwright ${processArgv}`
|
|
209
|
+
testSessionAsyncResource.runInAsyncScope(() => {
|
|
210
|
+
testSessionStartCh.publish({ command, frameworkVersion: playwrightVersion, rootDir })
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
const runAllTestsReturn = await runAllTests.apply(this, arguments)
|
|
214
|
+
const sessionStatus = runAllTestsReturn.status || runAllTestsReturn
|
|
215
|
+
|
|
216
|
+
let onDone
|
|
217
|
+
|
|
218
|
+
const flushWait = new Promise(resolve => {
|
|
219
|
+
onDone = resolve
|
|
220
|
+
})
|
|
221
|
+
testSessionAsyncResource.runInAsyncScope(() => {
|
|
222
|
+
testSessionFinishCh.publish({ status: STATUS_TO_TEST_STATUS[sessionStatus], onDone })
|
|
223
|
+
})
|
|
224
|
+
await flushWait
|
|
225
|
+
|
|
226
|
+
startedSuites = []
|
|
227
|
+
remainingTestsByFile = {}
|
|
228
|
+
|
|
229
|
+
return runAllTestsReturn
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
return runnerExport
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
addHook({
|
|
236
|
+
name: '@playwright/test',
|
|
237
|
+
file: 'lib/runner.js',
|
|
238
|
+
versions: ['>=1.18.0 <1.30.0']
|
|
239
|
+
}, runnerHook)
|
|
240
|
+
|
|
241
|
+
addHook({
|
|
242
|
+
name: '@playwright/test',
|
|
243
|
+
file: 'lib/dispatcher.js',
|
|
244
|
+
versions: ['>=1.18.0 <1.30.0']
|
|
245
|
+
}, dispatcherHook)
|
|
246
|
+
|
|
247
|
+
addHook({
|
|
248
|
+
name: '@playwright/test',
|
|
249
|
+
file: 'lib/dispatcher.js',
|
|
250
|
+
versions: ['>=1.30.0 <1.31.0']
|
|
251
|
+
}, (dispatcher) => dispatcherHookNew(dispatcher, dispatcherRunWrapper))
|
|
252
|
+
|
|
253
|
+
addHook({
|
|
254
|
+
name: '@playwright/test',
|
|
255
|
+
file: 'lib/runner/dispatcher.js',
|
|
256
|
+
versions: ['>=1.31.0']
|
|
257
|
+
}, (dispatcher) => dispatcherHookNew(dispatcher, dispatcherRunWrapperNew))
|
|
258
|
+
|
|
259
|
+
addHook({
|
|
260
|
+
name: '@playwright/test',
|
|
261
|
+
file: 'lib/runner/runner.js',
|
|
262
|
+
versions: ['>=1.31.0']
|
|
263
|
+
}, runnerHook)
|
|
@@ -23,13 +23,12 @@ class BaseAwsSdkPlugin extends Plugin {
|
|
|
23
23
|
request,
|
|
24
24
|
operation,
|
|
25
25
|
awsRegion,
|
|
26
|
-
awsService
|
|
27
|
-
serviceIdentifier
|
|
26
|
+
awsService
|
|
28
27
|
}) => {
|
|
29
28
|
if (!this.isEnabled(request)) {
|
|
30
29
|
return
|
|
31
30
|
}
|
|
32
|
-
const serviceName = this.getServiceName(
|
|
31
|
+
const serviceName = this.getServiceName()
|
|
33
32
|
const childOf = this.tracer.scope().active()
|
|
34
33
|
const tags = {
|
|
35
34
|
'span.kind': 'client',
|
|
@@ -52,6 +51,14 @@ class BaseAwsSdkPlugin extends Plugin {
|
|
|
52
51
|
this.enter(span, store)
|
|
53
52
|
})
|
|
54
53
|
|
|
54
|
+
this.addSub(`apm:aws:request:region:${this.serviceIdentifier}`, region => {
|
|
55
|
+
const store = storage.getStore()
|
|
56
|
+
if (!store) return
|
|
57
|
+
const { span } = store
|
|
58
|
+
if (!span) return
|
|
59
|
+
span.setTag('aws.region', region)
|
|
60
|
+
})
|
|
61
|
+
|
|
55
62
|
this.addSub(`apm:aws:request:complete:${this.serviceIdentifier}`, ({ response }) => {
|
|
56
63
|
const store = storage.getStore()
|
|
57
64
|
if (!store) return
|
|
@@ -109,10 +116,10 @@ class BaseAwsSdkPlugin extends Plugin {
|
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
// TODO: test splitByAwsService when the test suite is fixed
|
|
112
|
-
getServiceName (
|
|
119
|
+
getServiceName () {
|
|
113
120
|
return this.config.service
|
|
114
121
|
? this.config.service
|
|
115
|
-
: `${this.tracer._service}-aws-${serviceIdentifier}`
|
|
122
|
+
: `${this.tracer._service}-aws-${this.serviceIdentifier}`
|
|
116
123
|
}
|
|
117
124
|
}
|
|
118
125
|
|
|
@@ -48,8 +48,8 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
48
48
|
const parsedData = this._tryParse(injectPath.Data)
|
|
49
49
|
if (parsedData) {
|
|
50
50
|
parsedData._datadog = traceData
|
|
51
|
-
const finalData = JSON.stringify(parsedData)
|
|
52
|
-
const byteSize =
|
|
51
|
+
const finalData = Buffer.from(JSON.stringify(parsedData))
|
|
52
|
+
const byteSize = finalData.length
|
|
53
53
|
// Kinesis max payload size is 1MB
|
|
54
54
|
// So we must ensure adding DD context won't go over that (512b is an estimate)
|
|
55
55
|
if (byteSize >= 1048576) {
|
|
@@ -18,30 +18,35 @@ class Sns extends BaseAwsSdkPlugin {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
requestInject (span, request) {
|
|
21
|
-
const operation = request
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
21
|
+
const { operation, params } = request
|
|
22
|
+
|
|
23
|
+
if (!params) return
|
|
24
|
+
|
|
25
|
+
switch (operation) {
|
|
26
|
+
case 'publish':
|
|
27
|
+
this._injectMessageAttributes(span, params)
|
|
28
|
+
break
|
|
29
|
+
case 'publishBatch':
|
|
30
|
+
if (params.PublishBatchRequestEntries && params.PublishBatchRequestEntries.length > 0) {
|
|
31
|
+
this._injectMessageAttributes(span, params.PublishBatchRequestEntries[0])
|
|
32
|
+
}
|
|
33
|
+
break
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
_injectMessageAttributes (span, params) {
|
|
38
|
+
if (!params.MessageAttributes) {
|
|
39
|
+
params.MessageAttributes = {}
|
|
40
|
+
}
|
|
41
|
+
if (Object.keys(params.MessageAttributes).length >= 10) { // SNS quota
|
|
42
|
+
log.info('Message attributes full, skipping trace context injection')
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
const ddInfo = {}
|
|
46
|
+
this.tracer.inject(span, 'text_map', ddInfo)
|
|
47
|
+
params.MessageAttributes._datadog = {
|
|
48
|
+
DataType: 'Binary',
|
|
49
|
+
BinaryValue: Buffer.from(JSON.stringify(ddInfo)) // BINARY types are automatically base64 encoded
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
}
|
|
@@ -78,24 +78,39 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
responseExtract (params, operation, response) {
|
|
81
|
-
if (operation
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
} catch (err) {
|
|
95
|
-
log.error(err)
|
|
96
|
-
return undefined
|
|
81
|
+
if (operation !== 'receiveMessage') return
|
|
82
|
+
if (params.MaxNumberOfMessages && params.MaxNumberOfMessages !== 1) return
|
|
83
|
+
if (!response || !response.Messages || !response.Messages[0]) return
|
|
84
|
+
|
|
85
|
+
let message = response.Messages[0]
|
|
86
|
+
|
|
87
|
+
if (message.Body) {
|
|
88
|
+
try {
|
|
89
|
+
const body = JSON.parse(message.Body)
|
|
90
|
+
|
|
91
|
+
// SNS to SQS
|
|
92
|
+
if (body.Type === 'Notification') {
|
|
93
|
+
message = body
|
|
97
94
|
}
|
|
95
|
+
} catch (e) {
|
|
96
|
+
// SQS to SQS
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!message.MessageAttributes || !message.MessageAttributes._datadog) return
|
|
101
|
+
|
|
102
|
+
const datadogAttribute = message.MessageAttributes._datadog
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
if (datadogAttribute.StringValue) {
|
|
106
|
+
const textMap = datadogAttribute.StringValue
|
|
107
|
+
return this.tracer.extract('text_map', JSON.parse(textMap))
|
|
108
|
+
} else if (datadogAttribute.Type === 'Binary') {
|
|
109
|
+
const buffer = Buffer.from(datadogAttribute.Value, 'base64')
|
|
110
|
+
return this.tracer.extract('text_map', JSON.parse(buffer))
|
|
98
111
|
}
|
|
112
|
+
} catch (e) {
|
|
113
|
+
log.error(e)
|
|
99
114
|
}
|
|
100
115
|
}
|
|
101
116
|
|
|
@@ -7,7 +7,8 @@ const {
|
|
|
7
7
|
TEST_SKIP_REASON,
|
|
8
8
|
TEST_STATUS,
|
|
9
9
|
finishAllTraceSpans,
|
|
10
|
-
getTestSuitePath
|
|
10
|
+
getTestSuitePath,
|
|
11
|
+
getTestSuiteCommonTags
|
|
11
12
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
12
13
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
13
14
|
const { COMPONENT, ERROR_MESSAGE } = require('../../dd-trace/src/constants')
|
|
@@ -20,21 +21,47 @@ class CucumberPlugin extends CiPlugin {
|
|
|
20
21
|
constructor (...args) {
|
|
21
22
|
super(...args)
|
|
22
23
|
|
|
23
|
-
this.
|
|
24
|
+
this.sourceRoot = process.cwd()
|
|
25
|
+
|
|
26
|
+
this.addSub('ci:cucumber:session:finish', (status) => {
|
|
27
|
+
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
28
|
+
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
29
|
+
this.testModuleSpan.finish()
|
|
30
|
+
this.testSessionSpan.finish()
|
|
31
|
+
finishAllTraceSpans(this.testSessionSpan)
|
|
24
32
|
this.tracer._exporter.flush()
|
|
25
33
|
})
|
|
26
34
|
|
|
27
|
-
this.addSub('ci:cucumber:
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
this.addSub('ci:cucumber:test-suite:start', (testSuiteFullPath) => {
|
|
36
|
+
const testSuiteMetadata = getTestSuiteCommonTags(
|
|
37
|
+
this.command,
|
|
38
|
+
this.frameworkVersion,
|
|
39
|
+
getTestSuitePath(testSuiteFullPath, this.sourceRoot)
|
|
40
|
+
)
|
|
41
|
+
this.testSuiteSpan = this.tracer.startSpan('cucumber.test_suite', {
|
|
42
|
+
childOf: this.testModuleSpan,
|
|
43
|
+
tags: {
|
|
44
|
+
[COMPONENT]: this.constructor.name,
|
|
45
|
+
...this.testEnvironmentMetadata,
|
|
46
|
+
...testSuiteMetadata
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
})
|
|
31
50
|
|
|
32
|
-
|
|
51
|
+
this.addSub('ci:cucumber:test-suite:finish', status => {
|
|
52
|
+
this.testSuiteSpan.setTag(TEST_STATUS, status)
|
|
53
|
+
this.testSuiteSpan.finish()
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
this.addSub('ci:cucumber:test:start', ({ testName, fullTestSuite }) => {
|
|
57
|
+
const store = storage.getStore()
|
|
58
|
+
const testSuite = getTestSuitePath(fullTestSuite, this.sourceRoot)
|
|
59
|
+
const testSpan = this.startTestSpan(testName, testSuite)
|
|
33
60
|
|
|
34
61
|
this.enter(testSpan, store)
|
|
35
62
|
})
|
|
36
63
|
|
|
37
|
-
this.addSub('ci:cucumber:
|
|
64
|
+
this.addSub('ci:cucumber:test-step:start', ({ resource }) => {
|
|
38
65
|
const store = storage.getStore()
|
|
39
66
|
const childOf = store ? store.span : store
|
|
40
67
|
const span = this.tracer.startSpan('cucumber.step', {
|
|
@@ -48,7 +75,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
48
75
|
this.enter(span, store)
|
|
49
76
|
})
|
|
50
77
|
|
|
51
|
-
this.addSub('ci:cucumber:
|
|
78
|
+
this.addSub('ci:cucumber:test:finish', ({ isStep, status, skipReason, errorMessage }) => {
|
|
52
79
|
const span = storage.getStore().span
|
|
53
80
|
const statusTag = isStep ? 'step.status' : TEST_STATUS
|
|
54
81
|
|
|
@@ -76,8 +103,12 @@ class CucumberPlugin extends CiPlugin {
|
|
|
76
103
|
})
|
|
77
104
|
}
|
|
78
105
|
|
|
79
|
-
startTestSpan (testName, testSuite
|
|
80
|
-
return super.startTestSpan(
|
|
106
|
+
startTestSpan (testName, testSuite) {
|
|
107
|
+
return super.startTestSpan(
|
|
108
|
+
testName,
|
|
109
|
+
testSuite,
|
|
110
|
+
this.testSuiteSpan
|
|
111
|
+
)
|
|
81
112
|
}
|
|
82
113
|
}
|
|
83
114
|
|
|
@@ -7,7 +7,16 @@ const {
|
|
|
7
7
|
getTestParentSpan,
|
|
8
8
|
getCodeOwnersFileEntries,
|
|
9
9
|
getCodeOwnersForFilename,
|
|
10
|
-
getTestCommonTags
|
|
10
|
+
getTestCommonTags,
|
|
11
|
+
getTestSessionCommonTags,
|
|
12
|
+
getTestModuleCommonTags,
|
|
13
|
+
getTestSuiteCommonTags,
|
|
14
|
+
TEST_SUITE_ID,
|
|
15
|
+
TEST_MODULE_ID,
|
|
16
|
+
TEST_SESSION_ID,
|
|
17
|
+
TEST_COMMAND,
|
|
18
|
+
TEST_BUNDLE,
|
|
19
|
+
finishAllTraceSpans
|
|
11
20
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
12
21
|
|
|
13
22
|
const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
|
|
@@ -30,6 +39,43 @@ function getTestSpanMetadata (tracer, testName, testSuite, cypressConfig) {
|
|
|
30
39
|
}
|
|
31
40
|
}
|
|
32
41
|
|
|
42
|
+
function getCypressVersion (details) {
|
|
43
|
+
if (details && details.cypressVersion) {
|
|
44
|
+
return details.cypressVersion
|
|
45
|
+
}
|
|
46
|
+
if (details && details.config && details.config.version) {
|
|
47
|
+
return details.config.version
|
|
48
|
+
}
|
|
49
|
+
return ''
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getCypressCommand (details) {
|
|
53
|
+
if (!details) {
|
|
54
|
+
return 'cypress'
|
|
55
|
+
}
|
|
56
|
+
return `cypress ${details.specPattern || ''}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getSessionStatus (summary) {
|
|
60
|
+
if (summary.totalFailed !== undefined && summary.totalFailed > 0) {
|
|
61
|
+
return 'fail'
|
|
62
|
+
}
|
|
63
|
+
if (summary.totalSkipped !== undefined && summary.totalSkipped === summary.totalTests) {
|
|
64
|
+
return 'skip'
|
|
65
|
+
}
|
|
66
|
+
return 'pass'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getSuiteStatus (suiteStats) {
|
|
70
|
+
if (suiteStats.failures !== undefined && suiteStats.failures > 0) {
|
|
71
|
+
return 'fail'
|
|
72
|
+
}
|
|
73
|
+
if (suiteStats.tests !== undefined && suiteStats.tests === suiteStats.pending) {
|
|
74
|
+
return 'skip'
|
|
75
|
+
}
|
|
76
|
+
return 'pass'
|
|
77
|
+
}
|
|
78
|
+
|
|
33
79
|
module.exports = (on, config) => {
|
|
34
80
|
const tracer = require('../../dd-trace')
|
|
35
81
|
const testEnvironmentMetadata = getTestEnvironmentMetadata('cypress')
|
|
@@ -37,14 +83,92 @@ module.exports = (on, config) => {
|
|
|
37
83
|
const codeOwnersEntries = getCodeOwnersFileEntries()
|
|
38
84
|
|
|
39
85
|
let activeSpan = null
|
|
40
|
-
|
|
86
|
+
let testSessionSpan = null
|
|
87
|
+
let testModuleSpan = null
|
|
88
|
+
let testSuiteSpan = null
|
|
89
|
+
let command = null
|
|
90
|
+
let frameworkVersion
|
|
91
|
+
|
|
92
|
+
on('before:run', (details) => {
|
|
93
|
+
const childOf = getTestParentSpan(tracer)
|
|
94
|
+
|
|
95
|
+
command = getCypressCommand(details)
|
|
96
|
+
frameworkVersion = getCypressVersion(details)
|
|
97
|
+
|
|
98
|
+
const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion)
|
|
99
|
+
const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion)
|
|
100
|
+
|
|
101
|
+
testSessionSpan = tracer.startSpan('cypress.test_session', {
|
|
102
|
+
childOf,
|
|
103
|
+
tags: {
|
|
104
|
+
[COMPONENT]: 'cypress',
|
|
105
|
+
...testEnvironmentMetadata,
|
|
106
|
+
...testSessionSpanMetadata
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
testModuleSpan = tracer.startSpan('cypress.test_module', {
|
|
110
|
+
childOf: testSessionSpan,
|
|
111
|
+
tags: {
|
|
112
|
+
[COMPONENT]: 'cypress',
|
|
113
|
+
...testEnvironmentMetadata,
|
|
114
|
+
...testModuleSpanMetadata
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
on('after:run', (suiteStats) => {
|
|
120
|
+
const testStatus = getSessionStatus(suiteStats)
|
|
121
|
+
testModuleSpan.setTag(TEST_STATUS, testStatus)
|
|
122
|
+
testSessionSpan.setTag(TEST_STATUS, testStatus)
|
|
123
|
+
|
|
124
|
+
testModuleSpan.finish()
|
|
125
|
+
testSessionSpan.finish()
|
|
126
|
+
|
|
127
|
+
finishAllTraceSpans(testSessionSpan)
|
|
128
|
+
|
|
41
129
|
return new Promise(resolve => {
|
|
42
|
-
tracer._tracer._exporter._writer.flush(() =>
|
|
130
|
+
tracer._tracer._exporter._writer.flush(() => {
|
|
131
|
+
resolve(null)
|
|
132
|
+
})
|
|
43
133
|
})
|
|
44
134
|
})
|
|
45
135
|
on('task', {
|
|
136
|
+
'dd:testSuiteStart': (suite) => {
|
|
137
|
+
if (testSuiteSpan) {
|
|
138
|
+
return null
|
|
139
|
+
}
|
|
140
|
+
const testSuiteSpanMetadata = getTestSuiteCommonTags(command, frameworkVersion, suite)
|
|
141
|
+
testSuiteSpan = tracer.startSpan('cypress.test_suite', {
|
|
142
|
+
childOf: testModuleSpan,
|
|
143
|
+
tags: {
|
|
144
|
+
[COMPONENT]: 'cypress',
|
|
145
|
+
...testEnvironmentMetadata,
|
|
146
|
+
...testSuiteSpanMetadata
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
return null
|
|
150
|
+
},
|
|
151
|
+
'dd:testSuiteFinish': (suiteStats) => {
|
|
152
|
+
const status = getSuiteStatus(suiteStats)
|
|
153
|
+
testSuiteSpan.setTag(TEST_STATUS, status)
|
|
154
|
+
testSuiteSpan.finish()
|
|
155
|
+
testSuiteSpan = null
|
|
156
|
+
return null
|
|
157
|
+
},
|
|
46
158
|
'dd:beforeEach': (test) => {
|
|
47
159
|
const { testName, testSuite } = test
|
|
160
|
+
const testSuiteId = testSuiteSpan.context().toSpanId()
|
|
161
|
+
const testSessionId = testSessionSpan.context().toTraceId()
|
|
162
|
+
const testModuleId = testModuleSpan.context().toSpanId()
|
|
163
|
+
|
|
164
|
+
const testSuiteTags = {
|
|
165
|
+
[TEST_SUITE_ID]: testSuiteId,
|
|
166
|
+
[TEST_SESSION_ID]: testSessionId,
|
|
167
|
+
[TEST_COMMAND]: command,
|
|
168
|
+
[TEST_MODULE_ID]: testModuleId,
|
|
169
|
+
[TEST_COMMAND]: command,
|
|
170
|
+
[TEST_BUNDLE]: command
|
|
171
|
+
}
|
|
48
172
|
|
|
49
173
|
const {
|
|
50
174
|
childOf,
|
|
@@ -65,7 +189,8 @@ module.exports = (on, config) => {
|
|
|
65
189
|
[COMPONENT]: 'cypress',
|
|
66
190
|
[ORIGIN_KEY]: CI_APP_ORIGIN,
|
|
67
191
|
...testSpanMetadata,
|
|
68
|
-
...testEnvironmentMetadata
|
|
192
|
+
...testEnvironmentMetadata,
|
|
193
|
+
...testSuiteTags
|
|
69
194
|
}
|
|
70
195
|
})
|
|
71
196
|
}
|