dd-trace 3.12.1 → 3.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +1 -0
- package/README.md +5 -5
- package/ci/init.js +3 -1
- package/index.d.ts +100 -1
- package/package.json +5 -4
- package/packages/datadog-instrumentations/src/aws-sdk.js +86 -0
- package/packages/datadog-instrumentations/src/cucumber.js +74 -15
- package/packages/datadog-instrumentations/src/cypress.js +1 -1
- package/packages/datadog-instrumentations/src/fs.js +358 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +24 -23
- package/packages/datadog-instrumentations/src/ldapjs.js +12 -2
- package/packages/datadog-instrumentations/src/mocha.js +10 -7
- package/packages/datadog-instrumentations/src/mongoose.js +1 -1
- package/packages/datadog-instrumentations/src/mysql.js +7 -1
- package/packages/datadog-instrumentations/src/mysql2.js +7 -1
- package/packages/datadog-instrumentations/src/next.js +2 -1
- package/packages/datadog-instrumentations/src/playwright.js +263 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +12 -5
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +29 -24
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +31 -16
- package/packages/datadog-plugin-cucumber/src/index.js +42 -11
- package/packages/datadog-plugin-cypress/src/plugin.js +129 -4
- package/packages/datadog-plugin-cypress/src/support.js +5 -0
- package/packages/datadog-plugin-fs/src/index.js +45 -0
- package/packages/datadog-plugin-hapi/src/index.js +5 -1
- package/packages/datadog-plugin-http/src/server.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +40 -70
- package/packages/datadog-plugin-mocha/src/index.js +44 -64
- package/packages/datadog-plugin-mysql/src/index.js +8 -7
- package/packages/datadog-plugin-playwright/src/index.js +112 -0
- package/packages/datadog-shimmer/src/shimmer.js +28 -11
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/blocking.js +35 -9
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +60 -0
- package/packages/dd-trace/src/appsec/iast/iast-context.js +6 -2
- package/packages/dd-trace/src/appsec/iast/index.js +3 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -2
- package/packages/dd-trace/src/appsec/index.js +5 -5
- package/packages/dd-trace/src/appsec/recommended.json +320 -184
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +3 -0
- package/packages/dd-trace/src/appsec/reporter.js +14 -14
- package/packages/dd-trace/src/appsec/sdk/index.js +41 -0
- package/packages/dd-trace/src/appsec/sdk/noop.js +17 -0
- package/packages/dd-trace/src/appsec/sdk/set_user.js +30 -0
- package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +73 -0
- package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +1 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -5
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +48 -11
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +7 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +4 -2
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +5 -3
- package/packages/dd-trace/src/config.js +63 -7
- package/packages/dd-trace/src/encode/0.4.js +1 -1
- package/packages/dd-trace/src/encode/0.5.js +1 -1
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -4
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +52 -37
- package/packages/dd-trace/src/encode/tags-processors.js +3 -2
- package/packages/dd-trace/src/exporters/common/request.js +10 -3
- package/packages/dd-trace/src/lambda/handler.js +5 -6
- package/packages/dd-trace/src/log/channels.js +47 -0
- package/packages/dd-trace/src/log/index.js +79 -0
- package/packages/dd-trace/src/log/writer.js +124 -0
- package/packages/dd-trace/src/metrics.js +18 -0
- package/packages/dd-trace/src/noop/proxy.js +5 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +188 -36
- package/packages/dd-trace/src/opentracing/propagation/tracestate.js +99 -0
- package/packages/dd-trace/src/opentracing/span.js +2 -1
- package/packages/dd-trace/src/opentracing/span_context.js +6 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +72 -12
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -21
- package/packages/dd-trace/src/plugins/util/exec.js +2 -2
- package/packages/dd-trace/src/plugins/util/git.js +16 -1
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +53 -10
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -7
- package/packages/dd-trace/src/plugins/util/web.js +11 -0
- package/packages/dd-trace/src/profiler.js +3 -0
- package/packages/dd-trace/src/profiling/config.js +8 -3
- package/packages/dd-trace/src/profiling/exporters/file.js +13 -2
- package/packages/dd-trace/src/profiling/profiler.js +23 -6
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
- package/packages/dd-trace/src/proxy.js +2 -0
- package/packages/dd-trace/src/span_processor.js +1 -1
- package/packages/dd-trace/src/span_sampler.js +68 -52
- package/packages/dd-trace/src/startup-log.js +3 -6
- package/packages/dd-trace/src/telemetry/index.js +23 -2
- package/packages/dd-trace/src/telemetry/send-data.js +4 -1
- package/packages/dd-trace/src/tracer.js +0 -16
- package/scripts/check-proposal-labels.js +71 -0
- package/packages/dd-trace/src/log.js +0 -143
- /package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
|
@@ -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 = /^(
|
|
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.
|
|
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
|
-
|
|
116
|
-
|
|
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.
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
157
|
-
|
|
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
|
-
|
|
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,75 @@ 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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
304
|
+
const [ version, traceId, spanId, flags, tail ] = matches.slice(1)
|
|
305
|
+
const traceparent = { version }
|
|
306
|
+
const tracestate = TraceState.fromString(carrier.tracestate)
|
|
307
|
+
if (invalidSegment.test(traceId)) return null
|
|
308
|
+
if (invalidSegment.test(spanId)) return null
|
|
309
|
+
|
|
310
|
+
// Version ff is considered invalid
|
|
311
|
+
if (version === 'ff') return null
|
|
312
|
+
|
|
313
|
+
// Version 00 should have no tail, but future versions may
|
|
314
|
+
if (tail && version === '00') return null
|
|
315
|
+
|
|
316
|
+
const spanContext = new DatadogSpanContext({
|
|
317
|
+
traceId: id(traceId, 16),
|
|
318
|
+
spanId: id(spanId, 16),
|
|
319
|
+
sampling: { priority: parseInt(flags, 10) & 1 ? 1 : 0 },
|
|
320
|
+
traceparent,
|
|
321
|
+
tracestate
|
|
207
322
|
})
|
|
323
|
+
|
|
324
|
+
tracestate.forVendor('dd', state => {
|
|
325
|
+
for (const [key, value] of state.entries()) {
|
|
326
|
+
switch (key) {
|
|
327
|
+
case 's': {
|
|
328
|
+
const priority = parseInt(value, 10)
|
|
329
|
+
if (!Number.isInteger(priority)) continue
|
|
330
|
+
if (
|
|
331
|
+
(spanContext._sampling.priority === 1 && priority > 0) ||
|
|
332
|
+
(spanContext._sampling.priority === 0 && priority < 0)
|
|
333
|
+
) {
|
|
334
|
+
spanContext._sampling.priority = priority
|
|
335
|
+
}
|
|
336
|
+
break
|
|
337
|
+
}
|
|
338
|
+
case 'o':
|
|
339
|
+
spanContext._trace.origin = value
|
|
340
|
+
break
|
|
341
|
+
case 't.dm': {
|
|
342
|
+
const mechanism = parseInt(value, 10)
|
|
343
|
+
if (Number.isInteger(mechanism)) {
|
|
344
|
+
spanContext._sampling.mechanism = mechanism
|
|
345
|
+
spanContext._trace.tags['_dd.p.dm'] = mechanism
|
|
346
|
+
}
|
|
347
|
+
break
|
|
348
|
+
}
|
|
349
|
+
default:
|
|
350
|
+
if (!key.startsWith('t.')) continue
|
|
351
|
+
spanContext._trace.tags[`_dd.p.${key.slice(2)}`] = value
|
|
352
|
+
.replace(/[\x7e]/gm, '=')
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
this._extractBaggageItems(carrier, spanContext)
|
|
358
|
+
return spanContext
|
|
208
359
|
}
|
|
209
360
|
return null
|
|
210
361
|
}
|
|
211
362
|
|
|
212
363
|
_extractGenericContext (carrier, traceKey, spanKey, radix) {
|
|
213
364
|
if (carrier[traceKey] && carrier[spanKey]) {
|
|
365
|
+
if (invalidSegment.test(carrier[traceKey])) return null
|
|
366
|
+
|
|
214
367
|
return new DatadogSpanContext({
|
|
215
368
|
traceId: id(carrier[traceKey], radix),
|
|
216
369
|
spanId: id(carrier[spanKey], radix)
|
|
@@ -220,35 +373,34 @@ class TextMapPropagator {
|
|
|
220
373
|
return null
|
|
221
374
|
}
|
|
222
375
|
|
|
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
376
|
_extractB3MultipleHeaders (carrier) {
|
|
377
|
+
let empty = true
|
|
232
378
|
const b3 = {}
|
|
233
379
|
|
|
234
380
|
if (b3TraceExpr.test(carrier[b3TraceKey]) && b3SpanExpr.test(carrier[b3SpanKey])) {
|
|
235
381
|
b3[b3TraceKey] = carrier[b3TraceKey]
|
|
236
382
|
b3[b3SpanKey] = carrier[b3SpanKey]
|
|
383
|
+
empty = false
|
|
237
384
|
}
|
|
238
385
|
|
|
239
386
|
if (carrier[b3SampledKey]) {
|
|
240
387
|
b3[b3SampledKey] = carrier[b3SampledKey]
|
|
388
|
+
empty = false
|
|
241
389
|
}
|
|
242
390
|
|
|
243
391
|
if (carrier[b3FlagsKey]) {
|
|
244
392
|
b3[b3FlagsKey] = carrier[b3FlagsKey]
|
|
393
|
+
empty = false
|
|
245
394
|
}
|
|
246
395
|
|
|
247
|
-
return b3
|
|
396
|
+
return empty ? null : b3
|
|
248
397
|
}
|
|
249
398
|
|
|
250
399
|
_extractB3SingleHeader (carrier) {
|
|
251
|
-
const
|
|
400
|
+
const header = carrier[b3HeaderKey]
|
|
401
|
+
if (!header) return null
|
|
402
|
+
|
|
403
|
+
const parts = header.split('-')
|
|
252
404
|
|
|
253
405
|
if (parts[0] === 'd') {
|
|
254
406
|
return {
|
|
@@ -299,7 +451,7 @@ class TextMapPropagator {
|
|
|
299
451
|
const priority = parseInt(carrier[samplingKey], 10)
|
|
300
452
|
|
|
301
453
|
if (Number.isInteger(priority)) {
|
|
302
|
-
spanContext._sampling.priority =
|
|
454
|
+
spanContext._sampling.priority = priority
|
|
303
455
|
}
|
|
304
456
|
}
|
|
305
457
|
|
|
@@ -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()
|
|
@@ -12,8 +12,10 @@ class DatadogSpanContext {
|
|
|
12
12
|
this._name = props.name
|
|
13
13
|
this._isFinished = props.isFinished || false
|
|
14
14
|
this._tags = props.tags || {}
|
|
15
|
-
this._sampling = props.sampling
|
|
15
|
+
this._sampling = Object.assign({}, props.sampling)
|
|
16
16
|
this._baggageItems = props.baggageItems || {}
|
|
17
|
+
this._traceparent = props.traceparent
|
|
18
|
+
this._tracestate = props.tracestate
|
|
17
19
|
this._noop = props.noop || null
|
|
18
20
|
this._trace = props.trace || {
|
|
19
21
|
started: [],
|
|
@@ -31,10 +33,11 @@ class DatadogSpanContext {
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
toTraceparent () {
|
|
34
|
-
const
|
|
36
|
+
const flags = this._sampling.priority >= AUTO_KEEP ? '01' : '00'
|
|
35
37
|
const traceId = this._traceId.toString(16).padStart(32, '0')
|
|
36
38
|
const spanId = this._spanId.toString(16).padStart(16, '0')
|
|
37
|
-
|
|
39
|
+
const version = (this._traceparent && this._traceparent.version) || '00'
|
|
40
|
+
return `${version}-${traceId}-${spanId}-${flags}`
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
43
|
|
|
@@ -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 (
|
|
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,45 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
65
105
|
}
|
|
66
106
|
}
|
|
67
107
|
|
|
68
|
-
startTestSpan (
|
|
69
|
-
const
|
|
70
|
-
const testCommonTags = getTestCommonTags(name, suite, this.tracer._version)
|
|
108
|
+
startTestSpan (testName, testSuite, testSuiteSpan, extraTags = {}) {
|
|
109
|
+
const childOf = getTestParentSpan(this.tracer)
|
|
71
110
|
|
|
72
|
-
|
|
73
|
-
...
|
|
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(
|
|
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_COMMAND]: testSuiteSpan.context()._tags[TEST_COMMAND],
|
|
132
|
+
[TEST_BUNDLE]: testSuiteSpan.context()._tags[TEST_COMMAND]
|
|
133
|
+
}
|
|
134
|
+
if (testSuiteSpan.context()._parentId) {
|
|
135
|
+
suiteTags[TEST_MODULE_ID] = testSuiteSpan.context()._parentId.toString(10)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
testTags = {
|
|
139
|
+
...testTags,
|
|
140
|
+
...suiteTags
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
84
144
|
const testSpan = this.tracer
|
|
85
145
|
.startSpan(`${this.constructor.name}.test`, {
|
|
86
|
-
childOf
|
|
146
|
+
childOf,
|
|
87
147
|
tags: {
|
|
88
148
|
...this.testEnvironmentMetadata,
|
|
89
149
|
...testTags
|
|
@@ -1,7 +1,9 @@
|
|
|
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') },
|
|
6
|
+
get '@playwright/test' () { return require('../../../datadog-plugin-playwright/src') },
|
|
5
7
|
get '@elastic/elasticsearch' () { return require('../../../datadog-plugin-elasticsearch/src') },
|
|
6
8
|
get '@elastic/transport' () { return require('../../../datadog-plugin-elasticsearch/src') },
|
|
7
9
|
get '@google-cloud/pubsub' () { return require('../../../datadog-plugin-google-cloud-pubsub/src') },
|