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.
Files changed (42) hide show
  1. package/ci/init.js +2 -1
  2. package/index.d.ts +20 -0
  3. package/package.json +2 -2
  4. package/packages/datadog-instrumentations/src/aws-sdk.js +86 -0
  5. package/packages/datadog-instrumentations/src/cucumber.js +74 -15
  6. package/packages/datadog-instrumentations/src/cypress.js +1 -1
  7. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  8. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  9. package/packages/datadog-instrumentations/src/jest.js +24 -33
  10. package/packages/datadog-instrumentations/src/mocha.js +10 -8
  11. package/packages/datadog-instrumentations/src/playwright.js +2 -4
  12. package/packages/datadog-plugin-aws-sdk/src/base.js +12 -5
  13. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -2
  14. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +29 -24
  15. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +31 -16
  16. package/packages/datadog-plugin-cucumber/src/index.js +42 -11
  17. package/packages/datadog-plugin-cypress/src/plugin.js +129 -4
  18. package/packages/datadog-plugin-cypress/src/support.js +5 -0
  19. package/packages/datadog-plugin-jest/src/index.js +26 -78
  20. package/packages/datadog-plugin-mocha/src/index.js +42 -90
  21. package/packages/datadog-plugin-playwright/src/index.js +2 -61
  22. package/packages/datadog-shimmer/src/shimmer.js +28 -11
  23. package/packages/dd-trace/src/appsec/reporter.js +14 -14
  24. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +1 -5
  25. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -5
  26. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +32 -10
  27. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
  28. package/packages/dd-trace/src/config.js +55 -6
  29. package/packages/dd-trace/src/encode/0.4.js +1 -1
  30. package/packages/dd-trace/src/encode/0.5.js +1 -1
  31. package/packages/dd-trace/src/encode/tags-processors.js +3 -2
  32. package/packages/dd-trace/src/exporters/common/request.js +10 -3
  33. package/packages/dd-trace/src/log/writer.js +12 -4
  34. package/packages/dd-trace/src/opentracing/propagation/text_map.js +186 -36
  35. package/packages/dd-trace/src/opentracing/propagation/tracestate.js +99 -0
  36. package/packages/dd-trace/src/opentracing/span.js +2 -1
  37. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  38. package/packages/dd-trace/src/plugins/ci_plugin.js +69 -12
  39. package/packages/dd-trace/src/plugins/index.js +1 -0
  40. package/packages/dd-trace/src/plugins/util/test.js +26 -0
  41. package/packages/dd-trace/src/telemetry/index.js +23 -2
  42. 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.operation
22
- if (operation === 'publish' || operation === 'publishBatch') {
23
- if (!request.params) {
24
- request.params = {}
25
- }
26
- let injectPath
27
- if (request.params.PublishBatchRequestEntries && request.params.PublishBatchRequestEntries.length > 0) {
28
- injectPath = request.params.PublishBatchRequestEntries[0]
29
- } else if (request.params.Message) {
30
- injectPath = request.params
31
- }
32
- if (!injectPath.MessageAttributes) {
33
- injectPath.MessageAttributes = {}
34
- }
35
- if (Object.keys(injectPath.MessageAttributes).length >= 10) { // SNS quota
36
- log.info('Message attributes full, skipping trace context injection')
37
- return
38
- }
39
- const ddInfo = {}
40
- this.tracer.inject(span, 'text_map', ddInfo)
41
- injectPath.MessageAttributes._datadog = {
42
- DataType: 'Binary',
43
- BinaryValue: JSON.stringify(ddInfo) // BINARY types are automatically base64 encoded
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 === 'receiveMessage') {
82
- if (
83
- (!params.MaxNumberOfMessages || params.MaxNumberOfMessages === 1) &&
84
- response &&
85
- response.Messages &&
86
- response.Messages[0] &&
87
- response.Messages[0].MessageAttributes &&
88
- response.Messages[0].MessageAttributes._datadog &&
89
- response.Messages[0].MessageAttributes._datadog.StringValue
90
- ) {
91
- const textMap = response.Messages[0].MessageAttributes._datadog.StringValue
92
- try {
93
- return this.tracer.extract('text_map', JSON.parse(textMap))
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.addSub('ci:cucumber:session:finish', () => {
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:run:start', ({ testName, fullTestSuite }) => {
28
- const store = storage.getStore()
29
- const childOf = store ? store.span : store
30
- const testSuite = getTestSuitePath(fullTestSuite, process.cwd())
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
- const testSpan = this.startTestSpan(testName, testSuite, childOf)
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:run-step:start', ({ resource }) => {
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:run:finish', ({ isStep, status, skipReason, errorMessage }) => {
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, childOf) {
80
- return super.startTestSpan(testName, testSuite, {}, childOf)
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
- on('after:run', () => {
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(() => resolve(null))
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
- TEST_ITR_TESTS_SKIPPED,
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, this.tracer._version, testSuite)
91
+ const testSuiteMetadata = getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite)
126
92
 
127
- const testSuiteSpan = this.tracer.startSpan('jest.test_suite', {
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
- const testSuiteSpan = storage.getStore().span
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
- const testSuiteSpan = storage.getStore().span
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 span = storage.getStore().span
177
- span.setTag(TEST_STATUS, 'fail')
178
- span.setTag('error', error)
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
- let childOf
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
- ...suiteTags
161
+ [TEST_FRAMEWORK_VERSION]: frameworkVersion
214
162
  }
215
163
 
216
- return super.startTestSpan(name, suite, extraTags, childOf)
164
+ return super.startTestSpan(name, suite, this.testSuiteSpan, extraTags)
217
165
  }
218
166
  }
219
167