dd-trace 2.26.2 → 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 (38) 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 +4 -7
  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 +18 -67
  20. package/packages/datadog-plugin-mocha/src/index.js +35 -84
  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/opentracing/propagation/text_map.js +186 -36
  33. package/packages/dd-trace/src/opentracing/propagation/tracestate.js +99 -0
  34. package/packages/dd-trace/src/opentracing/span.js +2 -1
  35. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  36. package/packages/dd-trace/src/plugins/ci_plugin.js +69 -12
  37. package/packages/dd-trace/src/plugins/index.js +1 -0
  38. package/packages/dd-trace/src/telemetry/send-data.js +4 -1
@@ -4,6 +4,7 @@ const pick = require('lodash.pick')
4
4
  const id = require('../../id')
5
5
  const DatadogSpanContext = require('../span_context')
6
6
  const log = require('../../log')
7
+ const TraceState = require('./tracestate')
7
8
 
8
9
  const { AUTO_KEEP, AUTO_REJECT, USER_KEEP } = require('../../../../../ext/priority')
9
10
 
@@ -29,8 +30,15 @@ const tagValueExpr = /^[\x20-\x2b\x2d-\x7e]*$/ // ASCII minus commas
29
30
  const ddKeys = [traceKey, spanKey, samplingKey, originKey]
30
31
  const b3Keys = [b3TraceKey, b3SpanKey, b3ParentKey, b3SampledKey, b3FlagsKey, b3HeaderKey]
31
32
  const logKeys = ddKeys.concat(b3Keys)
32
- const traceparentExpr = /^(\d{2})-([A-Fa-f0-9]{32})-([A-Fa-f0-9]{16})-(\d{2})$/i
33
+ const traceparentExpr = /^([a-f0-9]{2})-([a-f0-9]{32})-([a-f0-9]{16})-([a-f0-9]{2})(-.*)?$/i
33
34
  const traceparentKey = 'traceparent'
35
+ // Origin value in tracestate replaces '~', ',' and ';' with '_"
36
+ const tracestateOriginFilter = /[^\x20-\x2b\x2d-\x3a\x3c-\x7d]/g
37
+ // Tag keys in tracestate replace ' ', ',' and '=' with '_'
38
+ const tracestateTagKeyFilter = /[^\x21-\x2b\x2d-\x3c\x3e-\x7e]/g
39
+ // Tag values in tracestate replace ',', '~' and ';' with '_'
40
+ const tracestateTagValueFilter = /[^\x20-\x2b\x2d-\x3a\x3c-\x7d]/g
41
+ const invalidSegment = /^0+$/
34
42
 
35
43
  class TextMapPropagator {
36
44
  constructor (config) {
@@ -38,15 +46,11 @@ class TextMapPropagator {
38
46
  }
39
47
 
40
48
  inject (spanContext, carrier) {
41
- carrier[traceKey] = spanContext.toTraceId()
42
- carrier[spanKey] = spanContext.toSpanId()
43
-
44
- this._injectOrigin(spanContext, carrier)
45
- this._injectSamplingPriority(spanContext, carrier)
46
49
  this._injectBaggageItems(spanContext, carrier)
47
- this._injectB3(spanContext, carrier)
50
+ this._injectDatadog(spanContext, carrier)
51
+ this._injectB3MultipleHeaders(spanContext, carrier)
52
+ this._injectB3SingleHeader(spanContext, carrier)
48
53
  this._injectTraceparent(spanContext, carrier)
49
- this._injectTags(spanContext, carrier)
50
54
 
51
55
  log.debug(() => `Inject into carrier: ${JSON.stringify(pick(carrier, logKeys))}.`)
52
56
  }
@@ -61,6 +65,17 @@ class TextMapPropagator {
61
65
  return spanContext
62
66
  }
63
67
 
68
+ _injectDatadog (spanContext, carrier) {
69
+ if (!this._hasPropagationStyle('inject', 'datadog')) return
70
+
71
+ carrier[traceKey] = spanContext.toTraceId()
72
+ carrier[spanKey] = spanContext.toSpanId()
73
+
74
+ this._injectOrigin(spanContext, carrier)
75
+ this._injectSamplingPriority(spanContext, carrier)
76
+ this._injectTags(spanContext, carrier)
77
+ }
78
+
64
79
  _injectOrigin (spanContext, carrier) {
65
80
  const origin = spanContext._trace.origin
66
81
 
@@ -112,8 +127,10 @@ class TextMapPropagator {
112
127
  }
113
128
  }
114
129
 
115
- _injectB3 (spanContext, carrier) {
116
- if (!this._config.experimental.b3) return
130
+ _injectB3MultipleHeaders (spanContext, carrier) {
131
+ const hasB3 = this._hasPropagationStyle('inject', 'b3')
132
+ const hasB3multi = this._hasPropagationStyle('inject', 'b3multi')
133
+ if (!(hasB3 || hasB3multi)) return
117
134
 
118
135
  carrier[b3TraceKey] = spanContext._traceId.toString(16)
119
136
  carrier[b3SpanKey] = spanContext._spanId.toString(16)
@@ -128,16 +145,92 @@ class TextMapPropagator {
128
145
  }
129
146
  }
130
147
 
148
+ _injectB3SingleHeader (spanContext, carrier) {
149
+ const hasB3SingleHeader = this._hasPropagationStyle('inject', 'b3 single header')
150
+ if (!hasB3SingleHeader) return null
151
+
152
+ const traceId = spanContext._traceId.toString(16)
153
+ const spanId = spanContext._spanId.toString(16)
154
+ const sampled = spanContext._sampling.priority >= AUTO_KEEP ? '1' : '0'
155
+
156
+ carrier[b3HeaderKey] = `${traceId}-${spanId}-${sampled}`
157
+ if (spanContext._parentId) {
158
+ carrier[b3HeaderKey] += '-' + spanContext._parentId.toString(16)
159
+ }
160
+ }
161
+
131
162
  _injectTraceparent (spanContext, carrier) {
132
- if (!this._config.experimental.traceparent) return
163
+ if (!this._hasPropagationStyle('inject', 'tracecontext')) return
164
+
165
+ const {
166
+ _sampling: { priority, mechanism },
167
+ _tracestate: ts = new TraceState(),
168
+ _trace: { origin, tags }
169
+ } = spanContext
170
+
133
171
  carrier[traceparentKey] = spanContext.toTraceparent()
172
+
173
+ ts.forVendor('dd', state => {
174
+ state.set('s', priority)
175
+ if (mechanism) {
176
+ state.set('t.dm', mechanism)
177
+ }
178
+
179
+ if (typeof origin === 'string') {
180
+ const originValue = origin
181
+ .replace(tracestateOriginFilter, '_')
182
+ .replace(/[\x3d]/g, '~')
183
+
184
+ state.set('o', originValue)
185
+ }
186
+
187
+ for (const key in tags) {
188
+ if (!tags[key] || !key.startsWith('_dd.p.')) continue
189
+
190
+ const tagKey = 't.' + key.slice(6)
191
+ .replace(tracestateTagKeyFilter, '_')
192
+
193
+ const tagValue = tags[key]
194
+ .toString()
195
+ .replace(tracestateTagValueFilter, '_')
196
+ .replace(/[\x3d]/g, '~')
197
+
198
+ state.set(tagKey, tagValue)
199
+ }
200
+ })
201
+
202
+ carrier.tracestate = ts.toString()
203
+ }
204
+
205
+ _hasPropagationStyle (mode, name) {
206
+ return this._config.tracePropagationStyle[mode].includes(name)
134
207
  }
135
208
 
136
209
  _extractSpanContext (carrier) {
137
- return this._extractDatadogContext(carrier) ||
138
- this._extractTraceparentContext(carrier) ||
139
- this._extractB3Context(carrier) ||
140
- this._extractSqsdContext(carrier)
210
+ for (const extractor of this._config.tracePropagationStyle.extract) {
211
+ let spanContext = null
212
+ switch (extractor) {
213
+ case 'datadog':
214
+ spanContext = this._extractDatadogContext(carrier)
215
+ break
216
+ case 'tracecontext':
217
+ spanContext = this._extractTraceparentContext(carrier)
218
+ break
219
+ case 'b3': // TODO: should match "b3 single header" in next major
220
+ case 'b3multi':
221
+ spanContext = this._extractB3MultiContext(carrier)
222
+ break
223
+ case 'b3 single header': // TODO: delete in major after singular "b3"
224
+ spanContext = this._extractB3SingleContext(carrier)
225
+ break
226
+ }
227
+
228
+ if (spanContext !== null) {
229
+ return spanContext
230
+ }
231
+ }
232
+
233
+ return this._extractSqsdContext(carrier)
141
234
  }
142
235
 
143
236
  _extractDatadogContext (carrier) {
@@ -153,10 +246,20 @@ class TextMapPropagator {
153
246
  return spanContext
154
247
  }
155
248
 
156
- _extractB3Context (carrier) {
157
- if (!this._config.experimental.b3) return null
249
+ _extractB3MultiContext (carrier) {
250
+ const b3 = this._extractB3MultipleHeaders(carrier)
251
+ if (!b3) return null
252
+ return this._extractB3Context(b3)
253
+ }
254
+
255
+ _extractB3SingleContext (carrier) {
256
+ if (!b3HeaderExpr.test(carrier[b3HeaderKey])) return null
257
+ const b3 = this._extractB3SingleHeader(carrier)
258
+ if (!b3) return null
259
+ return this._extractB3Context(b3)
260
+ }
158
261
 
159
- const b3 = this._extractB3Headers(carrier)
262
+ _extractB3Context (b3) {
160
263
  const debug = b3[b3FlagsKey] === '1'
161
264
  const priority = this._getPriority(b3[b3SampledKey], debug)
162
265
  const spanContext = this._extractGenericContext(b3, b3TraceKey, b3SpanKey, 16)
@@ -192,25 +295,73 @@ class TextMapPropagator {
192
295
  }
193
296
 
194
297
  _extractTraceparentContext (carrier) {
195
- if (!this._config.experimental.traceparent) return null
196
-
197
298
  const headerValue = carrier[traceparentKey]
198
299
  if (!headerValue) {
199
300
  return null
200
301
  }
201
- const matches = headerValue.match(traceparentExpr)
302
+ const matches = headerValue.trim().match(traceparentExpr)
202
303
  if (matches.length) {
203
- return new DatadogSpanContext({
204
- traceId: id(matches[2], 16),
205
- spanId: id(matches[3], 16),
206
- sampling: { priority: matches[4] === '01' ? 1 : 0 }
304
+ const [ version, traceId, spanId, flags, tail ] = matches.slice(1)
305
+ const tracestate = TraceState.fromString(carrier.tracestate)
306
+ if (invalidSegment.test(traceId)) return null
307
+ if (invalidSegment.test(spanId)) return null
308
+
309
+ // Version ff is considered invalid
310
+ if (version === 'ff') return null
311
+
312
+ // Version 00 should have no tail, but future versions may
313
+ if (tail && version === '00') return null
314
+
315
+ const spanContext = new DatadogSpanContext({
316
+ traceId: id(traceId, 16),
317
+ spanId: id(spanId, 16),
318
+ sampling: { priority: parseInt(flags, 10) & 1 ? 1 : 0 },
319
+ tracestate
207
320
  })
321
+
322
+ tracestate.forVendor('dd', state => {
323
+ for (const [key, value] of state.entries()) {
324
+ switch (key) {
325
+ case 's': {
326
+ const priority = parseInt(value, 10)
327
+ if (!Number.isInteger(priority)) continue
328
+ if (
329
+ (spanContext._sampling.priority === 1 && priority > 0) ||
330
+ (spanContext._sampling.priority === 0 && priority < 0)
331
+ ) {
332
+ spanContext._sampling.priority = priority
333
+ }
334
+ break
335
+ }
336
+ case 'o':
337
+ spanContext._trace.origin = value
338
+ break
339
+ case 't.dm': {
340
+ const mechanism = parseInt(value, 10)
341
+ if (Number.isInteger(mechanism)) {
342
+ spanContext._sampling.mechanism = mechanism
343
+ spanContext._trace.tags['_dd.p.dm'] = mechanism
344
+ }
345
+ break
346
+ }
347
+ default:
348
+ if (!key.startsWith('t.')) continue
349
+ spanContext._trace.tags[`_dd.p.${key.slice(2)}`] = value
350
+ .replace(/[\x7e]/gm, '=')
351
+ }
352
+ }
353
+ })
354
+
355
+ this._extractBaggageItems(carrier, spanContext)
356
+ return spanContext
208
357
  }
209
358
  return null
210
359
  }
211
360
 
212
361
  _extractGenericContext (carrier, traceKey, spanKey, radix) {
213
362
  if (carrier[traceKey] && carrier[spanKey]) {
363
+ if (invalidSegment.test(carrier[traceKey])) return null
364
+
214
365
  return new DatadogSpanContext({
215
366
  traceId: id(carrier[traceKey], radix),
216
367
  spanId: id(carrier[spanKey], radix)
@@ -220,35 +371,34 @@ class TextMapPropagator {
220
371
  return null
221
372
  }
222
373
 
223
- _extractB3Headers (carrier) {
224
- if (b3HeaderExpr.test(carrier[b3HeaderKey])) {
225
- return this._extractB3SingleHeader(carrier)
226
- } else {
227
- return this._extractB3MultipleHeaders(carrier)
228
- }
229
- }
230
-
231
374
  _extractB3MultipleHeaders (carrier) {
375
+ let empty = true
232
376
  const b3 = {}
233
377
 
234
378
  if (b3TraceExpr.test(carrier[b3TraceKey]) && b3SpanExpr.test(carrier[b3SpanKey])) {
235
379
  b3[b3TraceKey] = carrier[b3TraceKey]
236
380
  b3[b3SpanKey] = carrier[b3SpanKey]
381
+ empty = false
237
382
  }
238
383
 
239
384
  if (carrier[b3SampledKey]) {
240
385
  b3[b3SampledKey] = carrier[b3SampledKey]
386
+ empty = false
241
387
  }
242
388
 
243
389
  if (carrier[b3FlagsKey]) {
244
390
  b3[b3FlagsKey] = carrier[b3FlagsKey]
391
+ empty = false
245
392
  }
246
393
 
247
- return b3
394
+ return empty ? null : b3
248
395
  }
249
396
 
250
397
  _extractB3SingleHeader (carrier) {
251
- const parts = carrier[b3HeaderKey].split('-')
398
+ const header = carrier[b3HeaderKey]
399
+ if (!header) return null
400
+
401
+ const parts = header.split('-')
252
402
 
253
403
  if (parts[0] === 'd') {
254
404
  return {
@@ -299,7 +449,7 @@ class TextMapPropagator {
299
449
  const priority = parseInt(carrier[samplingKey], 10)
300
450
 
301
451
  if (Number.isInteger(priority)) {
302
- spanContext._sampling.priority = parseInt(carrier[samplingKey], 10)
452
+ spanContext._sampling.priority = priority
303
453
  }
304
454
  }
305
455
 
@@ -0,0 +1,99 @@
1
+ 'use strict'
2
+
3
+ const traceStateRegex = /[ \t]*([^=]+)=([ \t]*[^, \t]+)[ \t]*(,|$)/gim
4
+ const traceStateDataRegex = /([^:]+):([^;]+)(;|$)/gim
5
+
6
+ function fromString (Type, regex, value) {
7
+ if (typeof value !== 'string' || !value.length) {
8
+ return new Type()
9
+ }
10
+
11
+ const values = []
12
+ for (const row of value.matchAll(regex)) {
13
+ values.unshift(row.slice(1, 3))
14
+ }
15
+
16
+ return new Type(values)
17
+ }
18
+
19
+ function toString (map, pairSeparator, fieldSeparator) {
20
+ return Array.from(map.entries())
21
+ .reverse()
22
+ .map((pair) => pair.join(pairSeparator))
23
+ .join(fieldSeparator)
24
+ }
25
+
26
+ class TraceStateData extends Map {
27
+ constructor (...args) {
28
+ super(...args)
29
+ this.changed = false
30
+ }
31
+
32
+ set (...args) {
33
+ if (this.has(args[0]) && this.get(args[0]) === args[1]) {
34
+ return
35
+ }
36
+ this.changed = true
37
+ return super.set(...args)
38
+ }
39
+
40
+ delete (...args) {
41
+ this.changed = true
42
+ return super.delete(...args)
43
+ }
44
+
45
+ clear (...args) {
46
+ this.changed = true
47
+ return super.clear(...args)
48
+ }
49
+
50
+ static fromString (value) {
51
+ return fromString(TraceStateData, traceStateDataRegex, value)
52
+ }
53
+
54
+ toString () {
55
+ return toString(this, ':', ';')
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Pairs are stored in reverse of the serialized format to rely on set ordering
61
+ * new entries at the end to express update movement.
62
+ */
63
+ class TraceState extends Map {
64
+ // Delete entries on update to ensure they're moved to the end of the list
65
+ set (key, value) {
66
+ if (this.has(key)) {
67
+ this.delete(key)
68
+ }
69
+
70
+ return super.set(key, value)
71
+ }
72
+
73
+ forVendor (vendor, handle) {
74
+ const data = super.get(vendor)
75
+ const state = TraceStateData.fromString(data)
76
+ const result = handle(state)
77
+
78
+ if (state.changed) {
79
+ const value = state.toString()
80
+ if (value) {
81
+ this.set(vendor, state.toString())
82
+ } else {
83
+ this.delete(vendor)
84
+ }
85
+ }
86
+
87
+ return result
88
+ }
89
+
90
+ static fromString (value) {
91
+ return fromString(TraceState, traceStateRegex, value)
92
+ }
93
+
94
+ toString () {
95
+ return toString(this, '=', ',')
96
+ }
97
+ }
98
+
99
+ module.exports = TraceState
@@ -150,7 +150,8 @@ class DatadogSpan {
150
150
  parentId: parent._spanId,
151
151
  sampling: parent._sampling,
152
152
  baggageItems: Object.assign({}, parent._baggageItems),
153
- trace: parent._trace
153
+ trace: parent._trace,
154
+ tracestate: parent._tracestate
154
155
  })
155
156
  } else {
156
157
  const spanId = id()
@@ -14,6 +14,7 @@ class DatadogSpanContext {
14
14
  this._tags = props.tags || {}
15
15
  this._sampling = props.sampling || {}
16
16
  this._baggageItems = props.baggageItems || {}
17
+ this._tracestate = props.tracestate
17
18
  this._noop = props.noop || null
18
19
  this._trace = props.trace || {
19
20
  started: [],
@@ -5,11 +5,18 @@ const {
5
5
  getTestCommonTags,
6
6
  getCodeOwnersForFilename,
7
7
  TEST_CODE_OWNERS,
8
- CI_APP_ORIGIN
8
+ CI_APP_ORIGIN,
9
+ getTestSessionCommonTags,
10
+ getTestModuleCommonTags,
11
+ TEST_SUITE_ID,
12
+ TEST_MODULE_ID,
13
+ TEST_SESSION_ID,
14
+ TEST_COMMAND,
15
+ TEST_BUNDLE
9
16
  } = require('./util/test')
10
- const { COMPONENT } = require('../constants')
11
-
12
17
  const Plugin = require('./plugin')
18
+ const { COMPONENT } = require('../constants')
19
+ const log = require('../log')
13
20
 
14
21
  module.exports = class CiPlugin extends Plugin {
15
22
  constructor (...args) {
@@ -20,7 +27,9 @@ module.exports = class CiPlugin extends Plugin {
20
27
  return onDone({ err: new Error('CI Visibility was not initialized correctly') })
21
28
  }
22
29
  this.tracer._exporter.getItrConfiguration(this.testConfiguration, (err, itrConfig) => {
23
- if (!err) {
30
+ if (err) {
31
+ log.error(`Error fetching intelligent test runner configuration: ${err.message}`)
32
+ } else {
24
33
  this.itrConfig = itrConfig
25
34
  }
26
35
  onDone({ err, itrConfig })
@@ -32,9 +41,40 @@ module.exports = class CiPlugin extends Plugin {
32
41
  return onDone({ err: new Error('CI Visibility was not initialized correctly') })
33
42
  }
34
43
  this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites) => {
44
+ if (err) {
45
+ log.error(`Error fetching skippable suites: ${err.message}`)
46
+ }
35
47
  onDone({ err, skippableSuites })
36
48
  })
37
49
  })
50
+
51
+ this.addSub(`ci:${this.constructor.name}:session:start`, ({ command, frameworkVersion, rootDir }) => {
52
+ const childOf = getTestParentSpan(this.tracer)
53
+ const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion)
54
+ const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion)
55
+
56
+ this.command = command
57
+ this.frameworkVersion = frameworkVersion
58
+ // only for playwright
59
+ this.rootDir = rootDir
60
+
61
+ this.testSessionSpan = this.tracer.startSpan(`${this.constructor.name}.test_session`, {
62
+ childOf,
63
+ tags: {
64
+ [COMPONENT]: this.constructor.name,
65
+ ...this.testEnvironmentMetadata,
66
+ ...testSessionSpanMetadata
67
+ }
68
+ })
69
+ this.testModuleSpan = this.tracer.startSpan(`${this.constructor.name}.test_module`, {
70
+ childOf: this.testSessionSpan,
71
+ tags: {
72
+ [COMPONENT]: this.constructor.name,
73
+ ...this.testEnvironmentMetadata,
74
+ ...testModuleSpanMetadata
75
+ }
76
+ })
77
+ })
38
78
  }
39
79
 
40
80
  configure (config) {
@@ -65,25 +105,42 @@ module.exports = class CiPlugin extends Plugin {
65
105
  }
66
106
  }
67
107
 
68
- startTestSpan (name, suite, extraTags, childOf) {
69
- const parent = childOf || getTestParentSpan(this.tracer)
70
- const testCommonTags = getTestCommonTags(name, suite, this.tracer._version)
108
+ startTestSpan (testName, testSuite, testSuiteSpan, extraTags = {}) {
109
+ const childOf = getTestParentSpan(this.tracer)
71
110
 
72
- const testTags = {
73
- ...testCommonTags,
111
+ let testTags = {
112
+ ...getTestCommonTags(testName, testSuite, this.frameworkVersion),
74
113
  [COMPONENT]: this.constructor.name,
75
114
  ...extraTags
76
115
  }
77
116
 
78
- const codeOwners = getCodeOwnersForFilename(suite, this.codeOwnersEntries)
79
-
117
+ const codeOwners = getCodeOwnersForFilename(testSuite, this.codeOwnersEntries)
80
118
  if (codeOwners) {
81
119
  testTags[TEST_CODE_OWNERS] = codeOwners
82
120
  }
83
121
 
122
+ if (testSuiteSpan) {
123
+ // This is a hack to get good time resolution on test events, while keeping
124
+ // the test event as the root span of its trace.
125
+ childOf._trace.startTime = testSuiteSpan.context()._trace.startTime
126
+ childOf._trace.ticks = testSuiteSpan.context()._trace.ticks
127
+
128
+ const suiteTags = {
129
+ [TEST_SUITE_ID]: testSuiteSpan.context().toSpanId(),
130
+ [TEST_SESSION_ID]: testSuiteSpan.context().toTraceId(),
131
+ [TEST_MODULE_ID]: testSuiteSpan.context()._parentId.toString(10),
132
+ [TEST_COMMAND]: testSuiteSpan.context()._tags[TEST_COMMAND],
133
+ [TEST_BUNDLE]: testSuiteSpan.context()._tags[TEST_COMMAND]
134
+ }
135
+ testTags = {
136
+ ...testTags,
137
+ ...suiteTags
138
+ }
139
+ }
140
+
84
141
  const testSpan = this.tracer
85
142
  .startSpan(`${this.constructor.name}.test`, {
86
- childOf: parent,
143
+ childOf,
87
144
  tags: {
88
145
  ...this.testEnvironmentMetadata,
89
146
  ...testTags
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  module.exports = {
4
+ get '@aws-sdk/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
4
5
  get '@cucumber/cucumber' () { return require('../../../datadog-plugin-cucumber/src') },
5
6
  get '@playwright/test' () { return require('../../../datadog-plugin-playwright/src') },
6
7
  get '@elastic/elasticsearch' () { return require('../../../datadog-plugin-elasticsearch/src') },
@@ -6,6 +6,9 @@ function sendData (config, application, host, reqType, payload = {}) {
6
6
  port,
7
7
  url
8
8
  } = config
9
+
10
+ const { logger, tags, serviceMapping, ...trimmedPayload } = payload
11
+
9
12
  const options = {
10
13
  url,
11
14
  hostname,
@@ -24,7 +27,7 @@ function sendData (config, application, host, reqType, payload = {}) {
24
27
  tracer_time: Math.floor(Date.now() / 1000),
25
28
  runtime_id: config.tags['runtime-id'],
26
29
  seq_id: ++seqId,
27
- payload,
30
+ payload: trimmedPayload,
28
31
  application,
29
32
  host
30
33
  })