dd-trace 3.12.1 → 3.13.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/ci/init.js +1 -0
- package/index.d.ts +50 -0
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/fs.js +357 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/jest.js +11 -1
- package/packages/datadog-instrumentations/src/mocha.js +3 -2
- package/packages/datadog-instrumentations/src/mysql.js +7 -1
- package/packages/datadog-instrumentations/src/mysql2.js +7 -1
- package/packages/datadog-instrumentations/src/playwright.js +236 -0
- package/packages/datadog-plugin-fs/src/index.js +45 -0
- package/packages/datadog-plugin-jest/src/index.js +45 -23
- package/packages/datadog-plugin-mocha/src/index.js +34 -6
- package/packages/datadog-plugin-mysql/src/index.js +8 -7
- package/packages/datadog-plugin-playwright/src/index.js +171 -0
- 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/index.js +1 -1
- package/packages/dd-trace/src/appsec/recommended.json +247 -112
- package/packages/dd-trace/src/appsec/sdk/index.js +23 -0
- package/packages/dd-trace/src/appsec/sdk/noop.js +11 -0
- package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
- package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
- package/packages/dd-trace/src/config.js +7 -0
- 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/log/channels.js +47 -0
- package/packages/dd-trace/src/log/index.js +79 -0
- package/packages/dd-trace/src/log/writer.js +108 -0
- package/packages/dd-trace/src/noop/proxy.js +3 -0
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -21
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +27 -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/proxy.js +2 -0
- package/packages/dd-trace/src/startup-log.js +1 -1
- package/scripts/check-proposal-labels.js +71 -0
- package/packages/dd-trace/src/log.js +0 -143
|
@@ -0,0 +1,236 @@
|
|
|
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 getTestsBySuiteFromTestsById (testsById) {
|
|
29
|
+
const testsByTestSuite = {}
|
|
30
|
+
for (const { test } of testsById.values()) {
|
|
31
|
+
const { _requireFile } = test
|
|
32
|
+
if (test._type === 'beforeAll' || test._type === 'afterAll') {
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
if (testsByTestSuite[_requireFile]) {
|
|
36
|
+
testsByTestSuite[_requireFile].push(test)
|
|
37
|
+
} else {
|
|
38
|
+
testsByTestSuite[_requireFile] = [test]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return testsByTestSuite
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getPlaywrightConfig (playwrightRunner) {
|
|
45
|
+
try {
|
|
46
|
+
return playwrightRunner._configLoader.fullConfig()
|
|
47
|
+
} catch (e) {
|
|
48
|
+
try {
|
|
49
|
+
return playwrightRunner._loader.fullConfig()
|
|
50
|
+
} catch (e) {
|
|
51
|
+
return {}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getRootDir (playwrightRunner) {
|
|
57
|
+
const config = getPlaywrightConfig(playwrightRunner)
|
|
58
|
+
if (config.rootDir) {
|
|
59
|
+
return config.rootDir
|
|
60
|
+
}
|
|
61
|
+
if (playwrightRunner._configDir) {
|
|
62
|
+
return playwrightRunner._configDir
|
|
63
|
+
}
|
|
64
|
+
return process.cwd()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function testBeginHandler (test) {
|
|
68
|
+
const { title: testName, location: { file: testSuiteAbsolutePath }, _type } = test
|
|
69
|
+
|
|
70
|
+
if (_type === 'beforeAll' || _type === 'afterAll') {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const isNewTestSuite = !startedSuites.includes(testSuiteAbsolutePath)
|
|
75
|
+
|
|
76
|
+
if (isNewTestSuite) {
|
|
77
|
+
startedSuites.push(testSuiteAbsolutePath)
|
|
78
|
+
const testSuiteAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
79
|
+
testSuiteToAr.set(testSuiteAbsolutePath, testSuiteAsyncResource)
|
|
80
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
81
|
+
testSuiteStartCh.publish(testSuiteAbsolutePath)
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const testAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
86
|
+
testToAr.set(test, testAsyncResource)
|
|
87
|
+
testAsyncResource.runInAsyncScope(() => {
|
|
88
|
+
testStartCh.publish({ testName, testSuiteAbsolutePath })
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function testEndHandler (test, testStatus, error) {
|
|
93
|
+
const { location: { file: testSuiteAbsolutePath }, results, _type } = test
|
|
94
|
+
|
|
95
|
+
if (_type === 'beforeAll' || _type === 'afterAll') {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const testResult = results[results.length - 1]
|
|
100
|
+
const testAsyncResource = testToAr.get(test)
|
|
101
|
+
testAsyncResource.runInAsyncScope(() => {
|
|
102
|
+
testFinishCh.publish({ testStatus, steps: testResult.steps, error })
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
if (!testSuiteToTestStatuses.has(testSuiteAbsolutePath)) {
|
|
106
|
+
testSuiteToTestStatuses.set(testSuiteAbsolutePath, [testStatus])
|
|
107
|
+
} else {
|
|
108
|
+
testSuiteToTestStatuses.get(testSuiteAbsolutePath).push(testStatus)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
remainingTestsByFile[testSuiteAbsolutePath] = remainingTestsByFile[testSuiteAbsolutePath]
|
|
112
|
+
.filter(currentTest => currentTest !== test)
|
|
113
|
+
|
|
114
|
+
if (!remainingTestsByFile[testSuiteAbsolutePath].length) {
|
|
115
|
+
const testStatuses = testSuiteToTestStatuses.get(testSuiteAbsolutePath)
|
|
116
|
+
|
|
117
|
+
let testSuiteStatus = 'pass'
|
|
118
|
+
if (testStatuses.some(status => status === 'fail')) {
|
|
119
|
+
testSuiteStatus = 'fail'
|
|
120
|
+
} else if (testStatuses.every(status => status === 'skip')) {
|
|
121
|
+
testSuiteStatus = 'skip'
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const testSuiteAsyncResource = testSuiteToAr.get(testSuiteAbsolutePath)
|
|
125
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
126
|
+
testSuiteFinishCh.publish(testSuiteStatus)
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function dispatcherRunWrapper (run) {
|
|
132
|
+
return function () {
|
|
133
|
+
remainingTestsByFile = getTestsBySuiteFromTestsById(this._testById)
|
|
134
|
+
return run.apply(this, arguments)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function dispatcherHook (dispatcherExport) {
|
|
139
|
+
shimmer.wrap(dispatcherExport.Dispatcher.prototype, 'run', dispatcherRunWrapper)
|
|
140
|
+
shimmer.wrap(dispatcherExport.Dispatcher.prototype, '_createWorker', createWorker => function () {
|
|
141
|
+
const dispatcher = this
|
|
142
|
+
const worker = createWorker.apply(this, arguments)
|
|
143
|
+
|
|
144
|
+
worker.process.on('message', ({ method, params }) => {
|
|
145
|
+
if (method === 'testBegin') {
|
|
146
|
+
const { test } = dispatcher._testById.get(params.testId)
|
|
147
|
+
testBeginHandler(test)
|
|
148
|
+
} else if (method === 'testEnd') {
|
|
149
|
+
const { test } = dispatcher._testById.get(params.testId)
|
|
150
|
+
|
|
151
|
+
const { results } = test
|
|
152
|
+
const testResult = results[results.length - 1]
|
|
153
|
+
|
|
154
|
+
testEndHandler(test, STATUS_TO_TEST_STATUS[testResult.status], testResult.error)
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
return worker
|
|
159
|
+
})
|
|
160
|
+
return dispatcherExport
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function dispatcherHookNew (dispatcherExport) {
|
|
164
|
+
shimmer.wrap(dispatcherExport.Dispatcher.prototype, 'run', dispatcherRunWrapper)
|
|
165
|
+
shimmer.wrap(dispatcherExport.Dispatcher.prototype, '_createWorker', createWorker => function () {
|
|
166
|
+
const dispatcher = this
|
|
167
|
+
const worker = createWorker.apply(this, arguments)
|
|
168
|
+
|
|
169
|
+
worker.on('testBegin', ({ testId }) => {
|
|
170
|
+
const { test } = dispatcher._testById.get(testId)
|
|
171
|
+
testBeginHandler(test)
|
|
172
|
+
})
|
|
173
|
+
worker.on('testEnd', ({ testId, status, errors }) => {
|
|
174
|
+
const { test } = dispatcher._testById.get(testId)
|
|
175
|
+
|
|
176
|
+
testEndHandler(test, STATUS_TO_TEST_STATUS[status], errors && errors[0])
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
return worker
|
|
180
|
+
})
|
|
181
|
+
return dispatcherExport
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function runnerHook (runnerExport) {
|
|
185
|
+
shimmer.wrap(runnerExport.Runner.prototype, 'runAllTests', runAllTests => async function () {
|
|
186
|
+
const testSessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
187
|
+
const { version: frameworkVersion } = getPlaywrightConfig(this)
|
|
188
|
+
|
|
189
|
+
const rootDir = getRootDir(this)
|
|
190
|
+
|
|
191
|
+
const processArgv = process.argv.slice(2).join(' ')
|
|
192
|
+
const command = `playwright ${processArgv}`
|
|
193
|
+
testSessionAsyncResource.runInAsyncScope(() => {
|
|
194
|
+
testSessionStartCh.publish({ command, frameworkVersion, rootDir })
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
const res = await runAllTests.apply(this, arguments)
|
|
198
|
+
const sessionStatus = STATUS_TO_TEST_STATUS[res.status]
|
|
199
|
+
|
|
200
|
+
let onDone
|
|
201
|
+
|
|
202
|
+
const flushWait = new Promise(resolve => {
|
|
203
|
+
onDone = resolve
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
testSessionAsyncResource.runInAsyncScope(() => {
|
|
207
|
+
testSessionFinishCh.publish({ status: sessionStatus, onDone })
|
|
208
|
+
})
|
|
209
|
+
await flushWait
|
|
210
|
+
|
|
211
|
+
startedSuites = []
|
|
212
|
+
remainingTestsByFile = {}
|
|
213
|
+
|
|
214
|
+
return res
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
return runnerExport
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
addHook({
|
|
221
|
+
name: '@playwright/test',
|
|
222
|
+
file: 'lib/runner.js',
|
|
223
|
+
versions: ['>=1.18.0']
|
|
224
|
+
}, runnerHook)
|
|
225
|
+
|
|
226
|
+
addHook({
|
|
227
|
+
name: '@playwright/test',
|
|
228
|
+
file: 'lib/dispatcher.js',
|
|
229
|
+
versions: ['>=1.18.0 <1.30.0']
|
|
230
|
+
}, dispatcherHook)
|
|
231
|
+
|
|
232
|
+
addHook({
|
|
233
|
+
name: '@playwright/test',
|
|
234
|
+
file: 'lib/dispatcher.js',
|
|
235
|
+
versions: ['>=1.30.0']
|
|
236
|
+
}, dispatcherHookNew)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
4
|
+
|
|
5
|
+
class FsPlugin extends TracingPlugin {
|
|
6
|
+
static get name () { return 'fs' }
|
|
7
|
+
static get operation () { return 'operation' }
|
|
8
|
+
|
|
9
|
+
configure (...args) {
|
|
10
|
+
return super.configure(...args)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
start ({ operation, ...params }) {
|
|
14
|
+
if (!this.activeSpan) return this.skip()
|
|
15
|
+
|
|
16
|
+
const lowerOp = operation.toLowerCase()
|
|
17
|
+
const flag = params.flag || params.flags || (params.options && (params.options.flag || params.options.flags))
|
|
18
|
+
const defaultFlag = ((lowerOp.includes('open') || lowerOp.includes('read')) && 'r') ||
|
|
19
|
+
(lowerOp.includes('write') && 'w') ||
|
|
20
|
+
(lowerOp.includes('append') && 'a')
|
|
21
|
+
const fd = params.fd || (typeof params.file === 'number' && params.file)
|
|
22
|
+
const path = params.path || params.prefix || params.filename || (typeof params.file === 'string' && params.file)
|
|
23
|
+
const uid = typeof params.uid === 'number' && params.uid.toString()
|
|
24
|
+
const gid = typeof params.gid === 'number' && params.gid.toString()
|
|
25
|
+
const mode = typeof params.mode === 'number' ? params.mode.toString(8) : params.mode
|
|
26
|
+
|
|
27
|
+
this.startSpan('fs.operation', {
|
|
28
|
+
service: this.config.service,
|
|
29
|
+
resource: operation,
|
|
30
|
+
kind: 'internal',
|
|
31
|
+
meta: {
|
|
32
|
+
'file.descriptor': (typeof fd === 'object' || typeof fd === 'number') ? fd.toString() : '',
|
|
33
|
+
'file.dest': params.dest || params.newPath || (params.target && params.path),
|
|
34
|
+
'file.flag': String(flag || defaultFlag || ''),
|
|
35
|
+
'file.gid': gid || '',
|
|
36
|
+
'file.mode': mode,
|
|
37
|
+
'file.path': path || '',
|
|
38
|
+
'file.src': params.src || params.oldPath || params.existingPath || params.target,
|
|
39
|
+
'file.uid': uid || ''
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = FsPlugin
|
|
@@ -8,16 +8,19 @@ const {
|
|
|
8
8
|
getTestEnvironmentMetadata,
|
|
9
9
|
getTestParentSpan,
|
|
10
10
|
getTestSessionCommonTags,
|
|
11
|
+
getTestModuleCommonTags,
|
|
11
12
|
getTestSuiteCommonTags,
|
|
12
13
|
TEST_PARAMETERS,
|
|
13
14
|
getCodeOwnersFileEntries,
|
|
14
15
|
TEST_SESSION_ID,
|
|
16
|
+
TEST_MODULE_ID,
|
|
15
17
|
TEST_SUITE_ID,
|
|
16
18
|
TEST_COMMAND,
|
|
17
19
|
TEST_ITR_TESTS_SKIPPED,
|
|
18
20
|
TEST_SESSION_CODE_COVERAGE_ENABLED,
|
|
19
21
|
TEST_SESSION_ITR_SKIPPING_ENABLED,
|
|
20
|
-
TEST_CODE_COVERAGE_LINES_TOTAL
|
|
22
|
+
TEST_CODE_COVERAGE_LINES_TOTAL,
|
|
23
|
+
TEST_BUNDLE
|
|
21
24
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
22
25
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
23
26
|
|
|
@@ -49,12 +52,12 @@ class JestPlugin extends CiPlugin {
|
|
|
49
52
|
this.testEnvironmentMetadata = getTestEnvironmentMetadata('jest', this.config)
|
|
50
53
|
this.codeOwnersEntries = getCodeOwnersFileEntries()
|
|
51
54
|
|
|
52
|
-
this.addSub('ci:jest:session:start', (command) => {
|
|
53
|
-
const store = storage.getStore()
|
|
55
|
+
this.addSub('ci:jest:session:start', ({ command, testFrameworkVersion }) => {
|
|
54
56
|
const childOf = getTestParentSpan(this.tracer)
|
|
55
|
-
const testSessionSpanMetadata = getTestSessionCommonTags(command,
|
|
57
|
+
const testSessionSpanMetadata = getTestSessionCommonTags(command, testFrameworkVersion)
|
|
58
|
+
const testModuleSpanMetadata = getTestModuleCommonTags(command, testFrameworkVersion)
|
|
56
59
|
|
|
57
|
-
|
|
60
|
+
this.testSessionSpan = this.tracer.startSpan('jest.test_session', {
|
|
58
61
|
childOf,
|
|
59
62
|
tags: {
|
|
60
63
|
[COMPONENT]: this.constructor.name,
|
|
@@ -62,7 +65,14 @@ class JestPlugin extends CiPlugin {
|
|
|
62
65
|
...testSessionSpanMetadata
|
|
63
66
|
}
|
|
64
67
|
})
|
|
65
|
-
this.
|
|
68
|
+
this.testModuleSpan = this.tracer.startSpan('jest.test_module', {
|
|
69
|
+
childOf: this.testSessionSpan,
|
|
70
|
+
tags: {
|
|
71
|
+
[COMPONENT]: this.constructor.name,
|
|
72
|
+
...this.testEnvironmentMetadata,
|
|
73
|
+
...testModuleSpanMetadata
|
|
74
|
+
}
|
|
75
|
+
})
|
|
66
76
|
})
|
|
67
77
|
|
|
68
78
|
this.addSub('ci:jest:session:finish', ({
|
|
@@ -72,18 +82,18 @@ class JestPlugin extends CiPlugin {
|
|
|
72
82
|
isCodeCoverageEnabled,
|
|
73
83
|
testCodeCoverageLinesTotal
|
|
74
84
|
}) => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
testSessionSpan.setTag(
|
|
78
|
-
testSessionSpan.setTag(
|
|
79
|
-
testSessionSpan.setTag(TEST_SESSION_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false')
|
|
80
|
-
testSessionSpan.setTag(TEST_SESSION_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
|
|
85
|
+
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
86
|
+
this.testSessionSpan.setTag(TEST_ITR_TESTS_SKIPPED, isSuitesSkipped ? 'true' : 'false')
|
|
87
|
+
this.testSessionSpan.setTag(TEST_SESSION_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false')
|
|
88
|
+
this.testSessionSpan.setTag(TEST_SESSION_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
|
|
81
89
|
|
|
82
90
|
if (testCodeCoverageLinesTotal !== undefined) {
|
|
83
|
-
testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_TOTAL, testCodeCoverageLinesTotal)
|
|
91
|
+
this.testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_TOTAL, testCodeCoverageLinesTotal)
|
|
84
92
|
}
|
|
85
|
-
|
|
86
|
-
|
|
93
|
+
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
94
|
+
this.testModuleSpan.finish()
|
|
95
|
+
this.testSessionSpan.finish()
|
|
96
|
+
finishAllTraceSpans(this.testSessionSpan)
|
|
87
97
|
this.tracer._exporter.flush()
|
|
88
98
|
})
|
|
89
99
|
|
|
@@ -91,21 +101,25 @@ class JestPlugin extends CiPlugin {
|
|
|
91
101
|
// This subscriber changes the configuration objects from jest to inject the trace id
|
|
92
102
|
// of the test session to the processes that run the test suites.
|
|
93
103
|
this.addSub('ci:jest:session:configuration', configs => {
|
|
94
|
-
const testSessionSpan = storage.getStore().span
|
|
95
104
|
configs.forEach(config => {
|
|
96
|
-
config._ddTestSessionId = testSessionSpan.context().
|
|
97
|
-
config.
|
|
105
|
+
config._ddTestSessionId = this.testSessionSpan.context().toTraceId()
|
|
106
|
+
config._ddTestModuleId = this.testModuleSpan.context().toSpanId()
|
|
107
|
+
config._ddTestCommand = this.testSessionSpan.context()._tags[TEST_COMMAND]
|
|
98
108
|
})
|
|
99
109
|
})
|
|
100
110
|
|
|
101
111
|
this.addSub('ci:jest:test-suite:start', ({ testSuite, testEnvironmentOptions }) => {
|
|
102
|
-
const {
|
|
112
|
+
const {
|
|
113
|
+
_ddTestSessionId: testSessionId,
|
|
114
|
+
_ddTestCommand: testCommand,
|
|
115
|
+
_ddTestModuleId: testModuleId
|
|
116
|
+
} = testEnvironmentOptions
|
|
103
117
|
|
|
104
118
|
const store = storage.getStore()
|
|
105
119
|
|
|
106
120
|
const testSessionSpanContext = this.tracer.extract('text_map', {
|
|
107
121
|
'x-datadog-trace-id': testSessionId,
|
|
108
|
-
'x-datadog-parent-id':
|
|
122
|
+
'x-datadog-parent-id': testModuleId
|
|
109
123
|
})
|
|
110
124
|
|
|
111
125
|
const testSuiteMetadata = getTestSuiteCommonTags(testCommand, this.tracer._version, testSuite)
|
|
@@ -173,14 +187,22 @@ class JestPlugin extends CiPlugin {
|
|
|
173
187
|
}
|
|
174
188
|
|
|
175
189
|
startTestSpan (test) {
|
|
190
|
+
let childOf
|
|
176
191
|
const suiteTags = {}
|
|
177
192
|
const store = storage.getStore()
|
|
178
193
|
const testSuiteSpan = store ? store.span : undefined
|
|
179
194
|
if (testSuiteSpan) {
|
|
180
|
-
const testSuiteId = testSuiteSpan.context().
|
|
195
|
+
const testSuiteId = testSuiteSpan.context().toSpanId()
|
|
181
196
|
suiteTags[TEST_SUITE_ID] = testSuiteId
|
|
182
|
-
suiteTags[TEST_SESSION_ID] = testSuiteSpan.context().
|
|
197
|
+
suiteTags[TEST_SESSION_ID] = testSuiteSpan.context().toTraceId()
|
|
198
|
+
suiteTags[TEST_MODULE_ID] = testSuiteSpan.context()._parentId.toString(10)
|
|
183
199
|
suiteTags[TEST_COMMAND] = testSuiteSpan.context()._tags[TEST_COMMAND]
|
|
200
|
+
suiteTags[TEST_BUNDLE] = testSuiteSpan.context()._tags[TEST_COMMAND]
|
|
201
|
+
// This is a hack to get good time resolution on test events, while keeping
|
|
202
|
+
// the test event as the root span of its trace.
|
|
203
|
+
childOf = getTestParentSpan(this.tracer)
|
|
204
|
+
childOf._trace.startTime = testSuiteSpan.context()._trace.startTime
|
|
205
|
+
childOf._trace.ticks = testSuiteSpan.context()._trace.ticks
|
|
184
206
|
}
|
|
185
207
|
|
|
186
208
|
const { suite, name, runner, testParameters } = test
|
|
@@ -191,7 +213,7 @@ class JestPlugin extends CiPlugin {
|
|
|
191
213
|
...suiteTags
|
|
192
214
|
}
|
|
193
215
|
|
|
194
|
-
return super.startTestSpan(name, suite, extraTags)
|
|
216
|
+
return super.startTestSpan(name, suite, extraTags, childOf)
|
|
195
217
|
}
|
|
196
218
|
}
|
|
197
219
|
|
|
@@ -11,9 +11,12 @@ const {
|
|
|
11
11
|
getTestParentSpan,
|
|
12
12
|
getTestParametersString,
|
|
13
13
|
getTestSessionCommonTags,
|
|
14
|
+
getTestModuleCommonTags,
|
|
14
15
|
getTestSuiteCommonTags,
|
|
15
16
|
TEST_SUITE_ID,
|
|
16
17
|
TEST_SESSION_ID,
|
|
18
|
+
TEST_MODULE_ID,
|
|
19
|
+
TEST_BUNDLE,
|
|
17
20
|
TEST_COMMAND,
|
|
18
21
|
TEST_ITR_TESTS_SKIPPED,
|
|
19
22
|
TEST_SESSION_CODE_COVERAGE_ENABLED,
|
|
@@ -48,9 +51,9 @@ class MochaPlugin extends CiPlugin {
|
|
|
48
51
|
})
|
|
49
52
|
})
|
|
50
53
|
|
|
51
|
-
this.addSub('ci:mocha:session:start', (command) => {
|
|
54
|
+
this.addSub('ci:mocha:session:start', ({ command, frameworkVersion }) => {
|
|
52
55
|
const childOf = getTestParentSpan(this.tracer)
|
|
53
|
-
const testSessionSpanMetadata = getTestSessionCommonTags(command,
|
|
56
|
+
const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion)
|
|
54
57
|
|
|
55
58
|
this.command = command
|
|
56
59
|
this.testSessionSpan = this.tracer.startSpan('mocha.test_session', {
|
|
@@ -61,6 +64,16 @@ class MochaPlugin extends CiPlugin {
|
|
|
61
64
|
...testSessionSpanMetadata
|
|
62
65
|
}
|
|
63
66
|
})
|
|
67
|
+
|
|
68
|
+
const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion)
|
|
69
|
+
this.testModuleSpan = this.tracer.startSpan('mocha.test_module', {
|
|
70
|
+
childOf: this.testSessionSpan,
|
|
71
|
+
tags: {
|
|
72
|
+
[COMPONENT]: this.constructor.name,
|
|
73
|
+
...this.testEnvironmentMetadata,
|
|
74
|
+
...testModuleSpanMetadata
|
|
75
|
+
}
|
|
76
|
+
})
|
|
64
77
|
})
|
|
65
78
|
|
|
66
79
|
this.addSub('ci:mocha:test-suite:start', (suite) => {
|
|
@@ -71,7 +84,7 @@ class MochaPlugin extends CiPlugin {
|
|
|
71
84
|
getTestSuitePath(suite.file, this.sourceRoot)
|
|
72
85
|
)
|
|
73
86
|
const testSuiteSpan = this.tracer.startSpan('mocha.test_suite', {
|
|
74
|
-
childOf: this.
|
|
87
|
+
childOf: this.testModuleSpan,
|
|
75
88
|
tags: {
|
|
76
89
|
[COMPONENT]: this.constructor.name,
|
|
77
90
|
...this.testEnvironmentMetadata,
|
|
@@ -147,6 +160,8 @@ class MochaPlugin extends CiPlugin {
|
|
|
147
160
|
this.testSessionSpan.setTag(TEST_SESSION_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false')
|
|
148
161
|
this.testSessionSpan.setTag(TEST_SESSION_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
|
|
149
162
|
|
|
163
|
+
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
164
|
+
this.testModuleSpan.finish()
|
|
150
165
|
this.testSessionSpan.finish()
|
|
151
166
|
finishAllTraceSpans(this.testSessionSpan)
|
|
152
167
|
}
|
|
@@ -156,19 +171,32 @@ class MochaPlugin extends CiPlugin {
|
|
|
156
171
|
}
|
|
157
172
|
|
|
158
173
|
startTestSpan (test) {
|
|
174
|
+
const childOf = getTestParentSpan(this.tracer)
|
|
175
|
+
// This is a hack to get good time resolution on test events, while keeping
|
|
176
|
+
// the test event as the root span of its trace.
|
|
177
|
+
childOf._trace.startTime = this.testSessionSpan.context()._trace.startTime
|
|
178
|
+
childOf._trace.ticks = this.testSessionSpan.context()._trace.ticks
|
|
179
|
+
|
|
159
180
|
const testSuiteTags = {}
|
|
160
181
|
const testSuiteSpan = this._testSuites.get(test.parent.file)
|
|
161
182
|
if (testSuiteSpan) {
|
|
162
|
-
const testSuiteId = testSuiteSpan.context().
|
|
183
|
+
const testSuiteId = testSuiteSpan.context().toSpanId()
|
|
163
184
|
testSuiteTags[TEST_SUITE_ID] = testSuiteId
|
|
164
185
|
}
|
|
165
186
|
|
|
166
187
|
if (this.testSessionSpan) {
|
|
167
|
-
const testSessionId = this.testSessionSpan.context().
|
|
188
|
+
const testSessionId = this.testSessionSpan.context().toTraceId()
|
|
168
189
|
testSuiteTags[TEST_SESSION_ID] = testSessionId
|
|
169
190
|
testSuiteTags[TEST_COMMAND] = this.command
|
|
170
191
|
}
|
|
171
192
|
|
|
193
|
+
if (this.testModuleSpan) {
|
|
194
|
+
const testModuleId = this.testModuleSpan.context().toSpanId()
|
|
195
|
+
testSuiteTags[TEST_MODULE_ID] = testModuleId
|
|
196
|
+
testSuiteTags[TEST_COMMAND] = this.command
|
|
197
|
+
testSuiteTags[TEST_BUNDLE] = this.command
|
|
198
|
+
}
|
|
199
|
+
|
|
172
200
|
const { file: testSuiteAbsolutePath } = test
|
|
173
201
|
const fullTestName = test.fullTitle()
|
|
174
202
|
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.sourceRoot)
|
|
@@ -182,7 +210,7 @@ class MochaPlugin extends CiPlugin {
|
|
|
182
210
|
extraTags[TEST_PARAMETERS] = testParametersString
|
|
183
211
|
}
|
|
184
212
|
|
|
185
|
-
return super.startTestSpan(fullTestName, testSuite, extraTags)
|
|
213
|
+
return super.startTestSpan(fullTestName, testSuite, extraTags, childOf)
|
|
186
214
|
}
|
|
187
215
|
}
|
|
188
216
|
|
|
@@ -6,22 +6,23 @@ class MySQLPlugin extends DatabasePlugin {
|
|
|
6
6
|
static get name () { return 'mysql' }
|
|
7
7
|
static get system () { return 'mysql' }
|
|
8
8
|
|
|
9
|
-
start (
|
|
10
|
-
const service = getServiceName(this.config,
|
|
9
|
+
start (payload) {
|
|
10
|
+
const service = getServiceName(this.config, payload.conf)
|
|
11
11
|
|
|
12
12
|
this.startSpan(`${this.system}.query`, {
|
|
13
13
|
service,
|
|
14
|
-
resource: sql,
|
|
14
|
+
resource: payload.sql,
|
|
15
15
|
type: 'sql',
|
|
16
16
|
kind: 'client',
|
|
17
17
|
meta: {
|
|
18
18
|
'db.type': this.system,
|
|
19
|
-
'db.user':
|
|
20
|
-
'db.name':
|
|
21
|
-
'out.host':
|
|
22
|
-
'out.port':
|
|
19
|
+
'db.user': payload.conf.user,
|
|
20
|
+
'db.name': payload.conf.database,
|
|
21
|
+
'out.host': payload.conf.host,
|
|
22
|
+
'out.port': payload.conf.port
|
|
23
23
|
}
|
|
24
24
|
})
|
|
25
|
+
payload.sql = this.injectDbmQuery(payload.sql, service)
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
|