dd-trace 2.26.1 → 2.27.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 +2 -1
- package/index.d.ts +20 -0
- package/package.json +2 -2
- 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/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +24 -33
- package/packages/datadog-instrumentations/src/mocha.js +10 -8
- package/packages/datadog-instrumentations/src/playwright.js +2 -4
- 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-jest/src/index.js +26 -78
- package/packages/datadog-plugin-mocha/src/index.js +42 -90
- package/packages/datadog-plugin-playwright/src/index.js +2 -61
- package/packages/datadog-shimmer/src/shimmer.js +28 -11
- package/packages/dd-trace/src/appsec/reporter.js +14 -14
- 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 +32 -10
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
- package/packages/dd-trace/src/config.js +55 -6
- 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/tags-processors.js +3 -2
- package/packages/dd-trace/src/exporters/common/request.js +10 -3
- package/packages/dd-trace/src/log/writer.js +12 -4
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +186 -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 +1 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +69 -12
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/test.js +26 -0
- package/packages/dd-trace/src/telemetry/index.js +23 -2
- package/packages/dd-trace/src/telemetry/send-data.js +4 -1
|
@@ -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
|
}
|
|
@@ -8,7 +8,12 @@ beforeEach(() => {
|
|
|
8
8
|
})
|
|
9
9
|
})
|
|
10
10
|
|
|
11
|
+
before(() => {
|
|
12
|
+
cy.task('dd:testSuiteStart', Cypress.mocha.getRootSuite().file)
|
|
13
|
+
})
|
|
14
|
+
|
|
11
15
|
after(() => {
|
|
16
|
+
cy.task('dd:testSuiteFinish', Cypress.mocha.getRunner().stats)
|
|
12
17
|
cy.window().then(win => {
|
|
13
18
|
win.dispatchEvent(new Event('beforeunload'))
|
|
14
19
|
})
|
|
@@ -6,21 +6,12 @@ const {
|
|
|
6
6
|
JEST_TEST_RUNNER,
|
|
7
7
|
finishAllTraceSpans,
|
|
8
8
|
getTestEnvironmentMetadata,
|
|
9
|
-
getTestParentSpan,
|
|
10
|
-
getTestSessionCommonTags,
|
|
11
|
-
getTestModuleCommonTags,
|
|
12
9
|
getTestSuiteCommonTags,
|
|
10
|
+
addIntelligentTestRunnerSpanTags,
|
|
13
11
|
TEST_PARAMETERS,
|
|
14
12
|
getCodeOwnersFileEntries,
|
|
15
|
-
TEST_SESSION_ID,
|
|
16
|
-
TEST_MODULE_ID,
|
|
17
|
-
TEST_SUITE_ID,
|
|
18
13
|
TEST_COMMAND,
|
|
19
|
-
|
|
20
|
-
TEST_SESSION_CODE_COVERAGE_ENABLED,
|
|
21
|
-
TEST_SESSION_ITR_SKIPPING_ENABLED,
|
|
22
|
-
TEST_CODE_COVERAGE_LINES_TOTAL,
|
|
23
|
-
TEST_BUNDLE
|
|
14
|
+
TEST_FRAMEWORK_VERSION
|
|
24
15
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
25
16
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
26
17
|
|
|
@@ -52,29 +43,6 @@ class JestPlugin extends CiPlugin {
|
|
|
52
43
|
this.testEnvironmentMetadata = getTestEnvironmentMetadata('jest', this.config)
|
|
53
44
|
this.codeOwnersEntries = getCodeOwnersFileEntries()
|
|
54
45
|
|
|
55
|
-
this.addSub('ci:jest:session:start', ({ command, testFrameworkVersion }) => {
|
|
56
|
-
const childOf = getTestParentSpan(this.tracer)
|
|
57
|
-
const testSessionSpanMetadata = getTestSessionCommonTags(command, testFrameworkVersion)
|
|
58
|
-
const testModuleSpanMetadata = getTestModuleCommonTags(command, testFrameworkVersion)
|
|
59
|
-
|
|
60
|
-
this.testSessionSpan = this.tracer.startSpan('jest.test_session', {
|
|
61
|
-
childOf,
|
|
62
|
-
tags: {
|
|
63
|
-
[COMPONENT]: this.constructor.name,
|
|
64
|
-
...this.testEnvironmentMetadata,
|
|
65
|
-
...testSessionSpanMetadata
|
|
66
|
-
}
|
|
67
|
-
})
|
|
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
|
-
})
|
|
76
|
-
})
|
|
77
|
-
|
|
78
46
|
this.addSub('ci:jest:session:finish', ({
|
|
79
47
|
status,
|
|
80
48
|
isSuitesSkipped,
|
|
@@ -83,14 +51,14 @@ class JestPlugin extends CiPlugin {
|
|
|
83
51
|
testCodeCoverageLinesTotal
|
|
84
52
|
}) => {
|
|
85
53
|
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')
|
|
89
|
-
|
|
90
|
-
if (testCodeCoverageLinesTotal !== undefined) {
|
|
91
|
-
this.testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_TOTAL, testCodeCoverageLinesTotal)
|
|
92
|
-
}
|
|
93
54
|
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
55
|
+
|
|
56
|
+
addIntelligentTestRunnerSpanTags(
|
|
57
|
+
this.testSessionSpan,
|
|
58
|
+
this.testModuleSpan,
|
|
59
|
+
{ isSuitesSkipped, isSuitesSkippingEnabled, isCodeCoverageEnabled, testCodeCoverageLinesTotal }
|
|
60
|
+
)
|
|
61
|
+
|
|
94
62
|
this.testModuleSpan.finish()
|
|
95
63
|
this.testSessionSpan.finish()
|
|
96
64
|
finishAllTraceSpans(this.testSessionSpan)
|
|
@@ -108,23 +76,21 @@ class JestPlugin extends CiPlugin {
|
|
|
108
76
|
})
|
|
109
77
|
})
|
|
110
78
|
|
|
111
|
-
this.addSub('ci:jest:test-suite:start', ({ testSuite, testEnvironmentOptions }) => {
|
|
79
|
+
this.addSub('ci:jest:test-suite:start', ({ testSuite, testEnvironmentOptions, frameworkVersion }) => {
|
|
112
80
|
const {
|
|
113
81
|
_ddTestSessionId: testSessionId,
|
|
114
82
|
_ddTestCommand: testCommand,
|
|
115
83
|
_ddTestModuleId: testModuleId
|
|
116
84
|
} = testEnvironmentOptions
|
|
117
85
|
|
|
118
|
-
const store = storage.getStore()
|
|
119
|
-
|
|
120
86
|
const testSessionSpanContext = this.tracer.extract('text_map', {
|
|
121
87
|
'x-datadog-trace-id': testSessionId,
|
|
122
88
|
'x-datadog-parent-id': testModuleId
|
|
123
89
|
})
|
|
124
90
|
|
|
125
|
-
const testSuiteMetadata = getTestSuiteCommonTags(testCommand,
|
|
91
|
+
const testSuiteMetadata = getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite)
|
|
126
92
|
|
|
127
|
-
|
|
93
|
+
this.testSuiteSpan = this.tracer.startSpan('jest.test_suite', {
|
|
128
94
|
childOf: testSessionSpanContext,
|
|
129
95
|
tags: {
|
|
130
96
|
[COMPONENT]: this.constructor.name,
|
|
@@ -132,19 +98,17 @@ class JestPlugin extends CiPlugin {
|
|
|
132
98
|
...testSuiteMetadata
|
|
133
99
|
}
|
|
134
100
|
})
|
|
135
|
-
this.enter(testSuiteSpan, store)
|
|
136
101
|
})
|
|
137
102
|
|
|
138
103
|
this.addSub('ci:jest:test-suite:finish', ({ status, errorMessage }) => {
|
|
139
|
-
|
|
140
|
-
testSuiteSpan.setTag(TEST_STATUS, status)
|
|
104
|
+
this.testSuiteSpan.setTag(TEST_STATUS, status)
|
|
141
105
|
if (errorMessage) {
|
|
142
|
-
testSuiteSpan.setTag('error', new Error(errorMessage))
|
|
106
|
+
this.testSuiteSpan.setTag('error', new Error(errorMessage))
|
|
143
107
|
}
|
|
144
|
-
testSuiteSpan.finish()
|
|
108
|
+
this.testSuiteSpan.finish()
|
|
145
109
|
// Suites potentially run in a different process than the session,
|
|
146
110
|
// so calling finishAllTraceSpans on the session span is not enough
|
|
147
|
-
finishAllTraceSpans(testSuiteSpan)
|
|
111
|
+
finishAllTraceSpans(this.testSuiteSpan)
|
|
148
112
|
})
|
|
149
113
|
|
|
150
114
|
/**
|
|
@@ -153,8 +117,7 @@ class JestPlugin extends CiPlugin {
|
|
|
153
117
|
* fetching the ITR config.
|
|
154
118
|
*/
|
|
155
119
|
this.addSub('ci:jest:test-suite:code-coverage', (coverageFiles) => {
|
|
156
|
-
|
|
157
|
-
this.tracer._exporter.exportCoverage({ span: testSuiteSpan, coverageFiles })
|
|
120
|
+
this.tracer._exporter.exportCoverage({ span: this.testSuiteSpan, coverageFiles })
|
|
158
121
|
})
|
|
159
122
|
|
|
160
123
|
this.addSub('ci:jest:test:start', (test) => {
|
|
@@ -173,9 +136,12 @@ class JestPlugin extends CiPlugin {
|
|
|
173
136
|
|
|
174
137
|
this.addSub('ci:jest:test:err', (error) => {
|
|
175
138
|
if (error) {
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
139
|
+
const store = storage.getStore()
|
|
140
|
+
if (store && store.span) {
|
|
141
|
+
const span = store.span
|
|
142
|
+
span.setTag(TEST_STATUS, 'fail')
|
|
143
|
+
span.setTag('error', error)
|
|
144
|
+
}
|
|
179
145
|
}
|
|
180
146
|
})
|
|
181
147
|
|
|
@@ -187,33 +153,15 @@ class JestPlugin extends CiPlugin {
|
|
|
187
153
|
}
|
|
188
154
|
|
|
189
155
|
startTestSpan (test) {
|
|
190
|
-
|
|
191
|
-
const suiteTags = {}
|
|
192
|
-
const store = storage.getStore()
|
|
193
|
-
const testSuiteSpan = store ? store.span : undefined
|
|
194
|
-
if (testSuiteSpan) {
|
|
195
|
-
const testSuiteId = testSuiteSpan.context().toSpanId()
|
|
196
|
-
suiteTags[TEST_SUITE_ID] = testSuiteId
|
|
197
|
-
suiteTags[TEST_SESSION_ID] = testSuiteSpan.context().toTraceId()
|
|
198
|
-
suiteTags[TEST_MODULE_ID] = testSuiteSpan.context()._parentId.toString(10)
|
|
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
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const { suite, name, runner, testParameters } = test
|
|
156
|
+
const { suite, name, runner, testParameters, frameworkVersion } = test
|
|
209
157
|
|
|
210
158
|
const extraTags = {
|
|
211
159
|
[JEST_TEST_RUNNER]: runner,
|
|
212
160
|
[TEST_PARAMETERS]: testParameters,
|
|
213
|
-
|
|
161
|
+
[TEST_FRAMEWORK_VERSION]: frameworkVersion
|
|
214
162
|
}
|
|
215
163
|
|
|
216
|
-
return super.startTestSpan(name, suite,
|
|
164
|
+
return super.startTestSpan(name, suite, this.testSuiteSpan, extraTags)
|
|
217
165
|
}
|
|
218
166
|
}
|
|
219
167
|
|