dd-trace 6.12.0 → 6.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ci/test-optimization-validation/framework-adapters/cypress.js +9 -11
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +5 -4
- package/index.d.ts +127 -26
- package/package.json +10 -10
- package/packages/datadog-instrumentations/src/bunyan.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/bunyan.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +28 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
- package/packages/datadog-instrumentations/src/jest.js +140 -18
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +1597 -0
- package/packages/datadog-instrumentations/src/mariadb.js +7 -0
- package/packages/datadog-instrumentations/src/pino.js +15 -4
- package/packages/datadog-instrumentations/src/playwright.js +34 -20
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +7 -4
- package/packages/datadog-instrumentations/src/vitest-worker.js +11 -0
- package/packages/datadog-instrumentations/src/webdriverio.js +26 -0
- package/packages/datadog-instrumentations/src/winston.js +6 -3
- package/packages/datadog-plugin-cypress/src/support.js +1 -0
- package/packages/datadog-plugin-http/src/client.js +2 -15
- package/packages/datadog-plugin-http2/src/client.js +2 -15
- package/packages/datadog-plugin-openai-agents/src/integration.js +15 -11
- package/packages/datadog-plugin-playwright/src/index.js +9 -1
- package/packages/datadog-plugin-undici/src/index.js +2 -15
- package/packages/dd-trace/src/aiguard/evaluation.js +94 -20
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -3
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +21 -9
- package/packages/dd-trace/src/aiguard/noop.js +9 -1
- package/packages/dd-trace/src/aiguard/redaction.js +183 -0
- package/packages/dd-trace/src/aiguard/sdk.js +7 -2
- package/packages/dd-trace/src/aiguard/tags.js +2 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +10 -9
- package/packages/dd-trace/src/appsec/rule_manager.js +2 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +51 -26
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +5 -11
- package/packages/dd-trace/src/ci-visibility/final-flush.js +20 -0
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +196 -29
- package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -0
- package/packages/dd-trace/src/config/index.js +2 -1
- package/packages/dd-trace/src/config/supported-configurations.json +27 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +4 -3
- package/packages/dd-trace/src/dogstatsd.js +45 -18
- package/packages/dd-trace/src/encode/agentless-json.js +5 -4
- package/packages/dd-trace/src/exporters/agent/index.js +22 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +4 -4
- package/packages/dd-trace/src/exporters/common/writer.js +24 -2
- package/packages/dd-trace/src/exporters/span-stats/index.js +23 -4
- package/packages/dd-trace/src/external-logger/src/index.js +4 -3
- package/packages/dd-trace/src/flush.js +102 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -0
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +51 -2
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +420 -105
- package/packages/dd-trace/src/llmobs/experiments/index.js +54 -42
- package/packages/dd-trace/src/llmobs/experiments/noop.js +39 -8
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +21 -0
- package/packages/dd-trace/src/llmobs/index.js +80 -17
- package/packages/dd-trace/src/llmobs/noop.js +2 -1
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +8 -4
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +6 -3
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +13 -6
- package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +5 -7
- package/packages/dd-trace/src/llmobs/writers/base.js +60 -24
- package/packages/dd-trace/src/noop/span.js +5 -0
- package/packages/dd-trace/src/openfeature/writers/exposures.js +8 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +45 -3
- package/packages/dd-trace/src/opentelemetry/logs/index.js +4 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +7 -4
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +3 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +8 -0
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +4 -2
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +4 -2
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +25 -5
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +61 -25
- package/packages/dd-trace/src/opentelemetry/tracer.js +26 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +410 -342
- package/packages/dd-trace/src/opentracing/span.js +28 -0
- package/packages/dd-trace/src/otel-thread-ctx.js +23 -5
- package/packages/dd-trace/src/plugin_manager.js +2 -0
- package/packages/dd-trace/src/plugins/util/status-validator.js +98 -0
- package/packages/dd-trace/src/plugins/util/test.js +74 -21
- package/packages/dd-trace/src/plugins/util/web.js +2 -65
- package/packages/dd-trace/src/profiling/oom.js +4 -3
- package/packages/dd-trace/src/profiling/profiler.js +7 -0
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +14 -14
- package/packages/dd-trace/src/proxy.js +36 -8
- package/packages/dd-trace/src/runtime_metrics/index.js +5 -0
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +5 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +17 -6
- package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +55 -0
- package/packages/dd-trace/src/serverless/vercel.js +122 -0
- package/packages/dd-trace/src/serverless.js +37 -20
- package/packages/dd-trace/src/span_stats.js +40 -3
- package/packages/dd-trace/src/tracer.js +22 -0
- package/packages/dd-trace/src/web-tags-cache.js +67 -13
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
|
@@ -66,15 +66,6 @@ const tagValueExpr = /^[\x20-\x2B\x2D-\x7E]*$/ // ASCII minus commas
|
|
|
66
66
|
// https://github.com/nodejs/node/blob/main/lib/_http_common.js
|
|
67
67
|
const invalidHeaderValueCharExpr = /[^\t\x20-\x7E\x80-\xFF]/
|
|
68
68
|
const traceparentExpr = /^([a-f0-9]{2})-([a-f0-9]{32})-([a-f0-9]{16})-([a-f0-9]{2})(-.*)?$/i
|
|
69
|
-
// Dispatch table for `_extractSpanContext`. `'b3'` resolves to the matching
|
|
70
|
-
// single/multi extractor per instance — see `#b3MethodName` — so it is not in
|
|
71
|
-
// this table. `'baggage'` is consumed by `_extractBaggageItems`, not the loop.
|
|
72
|
-
const EXTRACT_STYLE_METHODS = new Map([
|
|
73
|
-
['datadog', '_extractDatadogContext'],
|
|
74
|
-
['tracecontext', '_extractTraceparentContext'],
|
|
75
|
-
['b3 single header', '_extractB3SingleContext'],
|
|
76
|
-
['b3multi', '_extractB3MultiContext'],
|
|
77
|
-
])
|
|
78
69
|
// Origin value in tracestate replaces '~', ',' and ';' with '_"
|
|
79
70
|
const tracestateOriginFilter = /[^\x20-\x2B\x2D-\x3A\x3C-\x7D]/g
|
|
80
71
|
// Tag keys in tracestate replace ' ', ',' and '=' with '_'
|
|
@@ -86,35 +77,216 @@ const zeroTraceId = '0000000000000000'
|
|
|
86
77
|
const hex16 = /^[0-9A-Fa-f]{16}$/
|
|
87
78
|
const percentByte = /%([0-9A-Fa-f]{2})/g
|
|
88
79
|
|
|
80
|
+
/**
|
|
81
|
+
* @typedef {object} B3Context
|
|
82
|
+
* @property {string} [flags]
|
|
83
|
+
* @property {string} [sampled]
|
|
84
|
+
* @property {string} [spanId]
|
|
85
|
+
* @property {string} [traceId]
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @param {string | undefined} traceId
|
|
90
|
+
* @param {string | undefined} spanId
|
|
91
|
+
* @param {number} radix
|
|
92
|
+
* @returns {DatadogSpanContext | undefined}
|
|
93
|
+
*/
|
|
94
|
+
function extractGenericContext (traceId, spanId, radix) {
|
|
95
|
+
if (!traceId || invalidSegment.test(traceId)) return
|
|
96
|
+
if (!spanId) return
|
|
97
|
+
|
|
98
|
+
return new DatadogSpanContext({
|
|
99
|
+
traceId: id(traceId, radix),
|
|
100
|
+
spanId: id(spanId, radix),
|
|
101
|
+
isRemote: true,
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @param {string} traceId
|
|
107
|
+
* @param {DatadogSpanContext} spanContext
|
|
108
|
+
* @returns {void}
|
|
109
|
+
*/
|
|
110
|
+
function extract128BitTraceId (traceId, spanContext) {
|
|
111
|
+
const buffer = spanContext._traceId.toBuffer()
|
|
112
|
+
|
|
113
|
+
if (buffer.length !== 16) return
|
|
114
|
+
|
|
115
|
+
const tid = traceId.slice(0, 16)
|
|
116
|
+
|
|
117
|
+
if (tid === zeroTraceId) return
|
|
118
|
+
|
|
119
|
+
spanContext._trace.tags['_dd.p.tid'] = tid
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {string | undefined} sampled
|
|
124
|
+
* @param {boolean} debug
|
|
125
|
+
* @returns {import('../../priority_sampler').SamplingPriority | undefined}
|
|
126
|
+
*/
|
|
127
|
+
function getB3Priority (sampled, debug) {
|
|
128
|
+
if (debug) {
|
|
129
|
+
return USER_KEEP
|
|
130
|
+
} else if (sampled === '1') {
|
|
131
|
+
return AUTO_KEEP
|
|
132
|
+
} else if (sampled === '0') {
|
|
133
|
+
return AUTO_REJECT
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @param {B3Context} b3
|
|
139
|
+
* @returns {DatadogSpanContext | undefined}
|
|
140
|
+
*/
|
|
141
|
+
function extractB3Context (b3) {
|
|
142
|
+
const priority = getB3Priority(b3.sampled, b3.flags === '1')
|
|
143
|
+
const spanContext = extractGenericContext(b3.traceId, b3.spanId, 16)
|
|
144
|
+
|
|
145
|
+
if (priority !== undefined) {
|
|
146
|
+
if (!spanContext) {
|
|
147
|
+
return new DatadogSpanContext({
|
|
148
|
+
traceId: id(),
|
|
149
|
+
spanId: null,
|
|
150
|
+
sampling: { priority },
|
|
151
|
+
isRemote: true,
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
spanContext._sampling.priority = priority
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (spanContext && b3.traceId) extract128BitTraceId(b3.traceId, spanContext)
|
|
159
|
+
|
|
160
|
+
return spanContext
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @param {Record<string, unknown>} carrier
|
|
165
|
+
* @returns {B3Context | undefined}
|
|
166
|
+
*/
|
|
167
|
+
function extractB3MultipleHeaders (carrier) {
|
|
168
|
+
// Parent ID is intentionally not a standalone signal for B3 extraction.
|
|
169
|
+
const traceId = readB3TraceId(carrier)
|
|
170
|
+
const sampled = readB3Sampled(carrier)
|
|
171
|
+
const flags = readB3Flags(carrier)
|
|
172
|
+
|
|
173
|
+
if (traceId === undefined && sampled === undefined && flags === undefined) return
|
|
174
|
+
|
|
175
|
+
let empty = true
|
|
176
|
+
const b3 = {}
|
|
177
|
+
const spanId = readB3SpanId(carrier)
|
|
178
|
+
|
|
179
|
+
if (traceId && spanId && b3TraceExpr.test(traceId) && b3SpanExpr.test(spanId)) {
|
|
180
|
+
b3.traceId = traceId
|
|
181
|
+
b3.spanId = spanId
|
|
182
|
+
empty = false
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (sampled) {
|
|
186
|
+
b3.sampled = sampled
|
|
187
|
+
empty = false
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (flags) {
|
|
191
|
+
b3.flags = flags
|
|
192
|
+
empty = false
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return empty ? undefined : b3
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @param {string} header
|
|
200
|
+
* @returns {B3Context}
|
|
201
|
+
*/
|
|
202
|
+
function extractB3SingleHeader (header) {
|
|
203
|
+
const traceIdEnd = header.indexOf('-')
|
|
204
|
+
|
|
205
|
+
if (traceIdEnd === -1) {
|
|
206
|
+
if (header === 'd') {
|
|
207
|
+
return {
|
|
208
|
+
sampled: '1',
|
|
209
|
+
flags: '1',
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
sampled: header,
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const spanIdStart = traceIdEnd + 1
|
|
218
|
+
const spanIdEnd = spanIdStart + 16
|
|
219
|
+
const b3 = {
|
|
220
|
+
traceId: header.slice(0, traceIdEnd),
|
|
221
|
+
spanId: header.slice(spanIdStart, spanIdEnd),
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (header.length > spanIdEnd) {
|
|
225
|
+
const sampled = header[spanIdEnd + 1]
|
|
226
|
+
b3.sampled = sampled === '0' ? '0' : '1'
|
|
227
|
+
|
|
228
|
+
if (sampled === 'd') {
|
|
229
|
+
b3.flags = '1'
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return b3
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @param {Record<string, unknown>} carrier
|
|
238
|
+
* @returns {DatadogSpanContext | undefined}
|
|
239
|
+
*/
|
|
240
|
+
function extractB3MultiContext (carrier) {
|
|
241
|
+
const b3 = extractB3MultipleHeaders(carrier)
|
|
242
|
+
if (b3 === undefined) return
|
|
243
|
+
return extractB3Context(b3)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @param {Record<string, unknown>} carrier
|
|
248
|
+
* @returns {DatadogSpanContext | undefined}
|
|
249
|
+
*/
|
|
250
|
+
function extractB3SingleContext (carrier) {
|
|
251
|
+
// Resolve the value before running the regex on the common header-less path.
|
|
252
|
+
const header = readB3(carrier)
|
|
253
|
+
if (!header || !b3HeaderExpr.test(header)) return
|
|
254
|
+
return extractB3Context(extractB3SingleHeader(header))
|
|
255
|
+
}
|
|
256
|
+
|
|
89
257
|
class TextMapPropagator {
|
|
90
|
-
/** @type {Set<string> | undefined} Cached `Set` view of
|
|
258
|
+
/** @type {Set<string> | undefined} Cached `Set` view of `#config.baggageTagKeys`. */
|
|
91
259
|
#baggageTagKeysSet
|
|
92
260
|
|
|
93
261
|
/** @type {string[] | undefined} Source array that `#baggageTagKeysSet` was built from. */
|
|
94
262
|
#baggageTagKeysSetSource
|
|
95
263
|
|
|
96
|
-
/** @type {'
|
|
97
|
-
#
|
|
264
|
+
/** @type {import('../../config')} */
|
|
265
|
+
#config
|
|
266
|
+
|
|
267
|
+
/** @type {typeof extractB3SingleContext | typeof extractB3MultiContext} */
|
|
268
|
+
#extractB3Context
|
|
98
269
|
|
|
270
|
+
/** @param {import('../../config')} config */
|
|
99
271
|
constructor (config) {
|
|
100
|
-
this
|
|
272
|
+
this.#config = config
|
|
101
273
|
|
|
102
|
-
// v6
|
|
274
|
+
// v6+: `'b3'` is always single-header. v5: `OTEL_PROPAGATORS` callers
|
|
103
275
|
// expect single, legacy `DD_TRACE_PROPAGATION_STYLE` callers expect multi.
|
|
104
|
-
/* istanbul ignore else: v5 fallback
|
|
276
|
+
/* istanbul ignore else: v5 fallback */
|
|
105
277
|
if (DD_MAJOR >= 6) {
|
|
106
|
-
this.#
|
|
278
|
+
this.#extractB3Context = extractB3SingleContext
|
|
107
279
|
} else {
|
|
108
280
|
const envName = getConfiguredEnvName('DD_TRACE_PROPAGATION_STYLE')
|
|
109
281
|
// eslint-disable-next-line eslint-rules/eslint-env-aliases
|
|
110
|
-
this.#
|
|
111
|
-
?
|
|
112
|
-
:
|
|
282
|
+
this.#extractB3Context = envName === 'OTEL_PROPAGATORS'
|
|
283
|
+
? extractB3SingleContext
|
|
284
|
+
: extractB3MultiContext
|
|
113
285
|
}
|
|
114
286
|
}
|
|
115
287
|
|
|
116
288
|
/**
|
|
117
|
-
* Returns a `Set` view of
|
|
289
|
+
* Returns a `Set` view of `#config.baggageTagKeys` that is rebuilt only
|
|
118
290
|
* when the source array reference changes. Avoids an `O(n)` `Set` alloc
|
|
119
291
|
* per baggage extract (which is per-request when baggage propagation is
|
|
120
292
|
* enabled).
|
|
@@ -122,7 +294,7 @@ class TextMapPropagator {
|
|
|
122
294
|
* @returns {Set<string>}
|
|
123
295
|
*/
|
|
124
296
|
#getBaggageTagKeysSet () {
|
|
125
|
-
const source = this.
|
|
297
|
+
const source = this.#config.baggageTagKeys
|
|
126
298
|
if (this.#baggageTagKeysSetSource !== source) {
|
|
127
299
|
this.#baggageTagKeysSet = new Set(source)
|
|
128
300
|
this.#baggageTagKeysSetSource = source
|
|
@@ -137,18 +309,18 @@ class TextMapPropagator {
|
|
|
137
309
|
*/
|
|
138
310
|
inject (spanContext, carrier) {
|
|
139
311
|
if (carrier === null) return
|
|
140
|
-
let injectedCarrier = this
|
|
312
|
+
let injectedCarrier = this.#injectBaggageItems(spanContext, carrier)
|
|
141
313
|
if (!spanContext) return injectedCarrier
|
|
142
314
|
|
|
143
|
-
const injectTraceContext = this.
|
|
315
|
+
const injectTraceContext = this.#config.apmTracingEnabled !== false ||
|
|
144
316
|
hasTraceSourcePropagationTag(spanContext._trace.tags)
|
|
145
317
|
if (injectTraceContext) {
|
|
146
|
-
injectedCarrier = this
|
|
147
|
-
injectedCarrier = this
|
|
148
|
-
injectedCarrier = this
|
|
318
|
+
injectedCarrier = this.#injectDatadog(spanContext, injectedCarrier ?? carrier) ?? injectedCarrier
|
|
319
|
+
injectedCarrier = this.#injectB3MultipleHeaders(spanContext, injectedCarrier ?? carrier) ?? injectedCarrier
|
|
320
|
+
injectedCarrier = this.#injectB3SingleHeader(spanContext, injectedCarrier ?? carrier) ?? injectedCarrier
|
|
149
321
|
}
|
|
150
322
|
injectedCarrier = this
|
|
151
|
-
|
|
323
|
+
.#injectTraceparent(spanContext, injectedCarrier ?? carrier, injectTraceContext) ?? injectedCarrier
|
|
152
324
|
|
|
153
325
|
if (injectedCarrier === undefined) return
|
|
154
326
|
|
|
@@ -161,8 +333,12 @@ class TextMapPropagator {
|
|
|
161
333
|
return carrier
|
|
162
334
|
}
|
|
163
335
|
|
|
336
|
+
/**
|
|
337
|
+
* @param {Record<string, unknown>} carrier
|
|
338
|
+
* @returns {DatadogSpanContext | null}
|
|
339
|
+
*/
|
|
164
340
|
extract (carrier) {
|
|
165
|
-
const spanContext = this
|
|
341
|
+
const spanContext = this.#extractSpanContext(carrier)
|
|
166
342
|
if (spanContext === undefined) return null
|
|
167
343
|
|
|
168
344
|
if (extractCh.hasSubscribers) {
|
|
@@ -172,7 +348,7 @@ class TextMapPropagator {
|
|
|
172
348
|
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
173
349
|
log.debug(() => {
|
|
174
350
|
const keys = JSON.stringify(pickTextMap(carrier))
|
|
175
|
-
const styles = this.
|
|
351
|
+
const styles = this.#config.tracePropagationStyle.extract.join(', ')
|
|
176
352
|
|
|
177
353
|
return `Extract from carrier (${styles}): ${keys}.`
|
|
178
354
|
})
|
|
@@ -185,34 +361,22 @@ class TextMapPropagator {
|
|
|
185
361
|
* @param {Record<string, string>} [carrier]
|
|
186
362
|
* @returns {Record<string, string> | undefined}
|
|
187
363
|
*/
|
|
188
|
-
|
|
189
|
-
if (!this
|
|
364
|
+
#injectDatadog (spanContext, carrier) {
|
|
365
|
+
if (!this.#hasPropagationStyle('inject', 'datadog')) return
|
|
190
366
|
|
|
191
367
|
carrier ??= {}
|
|
192
368
|
writeDatadogTraceId(carrier, spanContext.toTraceId())
|
|
193
369
|
writeDatadogParentId(carrier, spanContext.toSpanId())
|
|
194
370
|
|
|
195
|
-
this._injectOrigin(spanContext, carrier)
|
|
196
|
-
this._injectSamplingPriority(spanContext, carrier)
|
|
197
|
-
this._injectTags(spanContext, carrier)
|
|
198
|
-
|
|
199
|
-
return carrier
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
_injectOrigin (spanContext, carrier) {
|
|
203
371
|
const origin = spanContext._trace.origin
|
|
372
|
+
if (origin) writeDatadogOrigin(carrier, origin)
|
|
204
373
|
|
|
205
|
-
if (origin) {
|
|
206
|
-
writeDatadogOrigin(carrier, origin)
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
_injectSamplingPriority (spanContext, carrier) {
|
|
211
374
|
const priority = spanContext._sampling.priority
|
|
375
|
+
if (Number.isInteger(priority)) writeDatadogSamplingPriority(carrier, priority.toString())
|
|
212
376
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
377
|
+
this.#injectTags(spanContext, carrier)
|
|
378
|
+
|
|
379
|
+
return carrier
|
|
216
380
|
}
|
|
217
381
|
|
|
218
382
|
/**
|
|
@@ -220,9 +384,9 @@ class TextMapPropagator {
|
|
|
220
384
|
* @param {Record<string, string>} [carrier]
|
|
221
385
|
* @returns {Record<string, string> | undefined}
|
|
222
386
|
*/
|
|
223
|
-
|
|
387
|
+
#injectBaggageItems (spanContext, carrier) {
|
|
224
388
|
let injectedCarrier
|
|
225
|
-
if (this.
|
|
389
|
+
if (this.#config.legacyBaggageEnabled) {
|
|
226
390
|
const baggageItems = spanContext?._baggageItems
|
|
227
391
|
if (baggageItems) {
|
|
228
392
|
for (const key of Object.keys(baggageItems)) {
|
|
@@ -241,7 +405,7 @@ class TextMapPropagator {
|
|
|
241
405
|
}
|
|
242
406
|
}
|
|
243
407
|
|
|
244
|
-
if (this
|
|
408
|
+
if (this.#hasPropagationStyle('inject', 'baggage')) {
|
|
245
409
|
let baggage = ''
|
|
246
410
|
let itemCounter = 0
|
|
247
411
|
let byteCounter = 0
|
|
@@ -259,13 +423,13 @@ class TextMapPropagator {
|
|
|
259
423
|
byteCounter += item.length
|
|
260
424
|
|
|
261
425
|
// Check for item count limit exceeded
|
|
262
|
-
if (itemCounter > this.
|
|
426
|
+
if (itemCounter > this.#config.baggageMaxItems) {
|
|
263
427
|
tracerMetrics.count('context_header.truncated', ['truncation_reason:baggage_item_count_exceeded']).inc()
|
|
264
428
|
break
|
|
265
429
|
}
|
|
266
430
|
|
|
267
431
|
// Check for byte count limit exceeded
|
|
268
|
-
if (byteCounter > this.
|
|
432
|
+
if (byteCounter > this.#config.baggageMaxBytes) {
|
|
269
433
|
tracerMetrics.count('context_header.truncated', ['truncation_reason:baggage_byte_count_exceeded']).inc()
|
|
270
434
|
break
|
|
271
435
|
}
|
|
@@ -284,30 +448,34 @@ class TextMapPropagator {
|
|
|
284
448
|
return injectedCarrier
|
|
285
449
|
}
|
|
286
450
|
|
|
287
|
-
|
|
451
|
+
/**
|
|
452
|
+
* @param {DatadogSpanContext} spanContext
|
|
453
|
+
* @param {Record<string, string>} carrier
|
|
454
|
+
* @returns {void}
|
|
455
|
+
*/
|
|
456
|
+
#injectTags (spanContext, carrier) {
|
|
288
457
|
const trace = spanContext._trace
|
|
289
458
|
|
|
290
|
-
if (this.
|
|
459
|
+
if (this.#config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) {
|
|
291
460
|
log.debug('Trace tag propagation is disabled, skipping injection.')
|
|
292
461
|
return
|
|
293
462
|
}
|
|
294
463
|
|
|
295
|
-
|
|
464
|
+
let header = ''
|
|
296
465
|
|
|
297
466
|
for (const key of Object.keys(trace.tags)) {
|
|
298
467
|
const value = trace.tags[key]
|
|
299
468
|
if (!value || !key.startsWith('_dd.p.')) continue
|
|
300
|
-
if (!
|
|
469
|
+
if (!tagKeyExpr.test(key) || !tagValueExpr.test(value)) {
|
|
301
470
|
log.error('Trace tags from span are invalid, skipping injection.')
|
|
302
471
|
return
|
|
303
472
|
}
|
|
304
473
|
|
|
305
|
-
|
|
474
|
+
if (header) header += ','
|
|
475
|
+
header += `${key}=${value}`
|
|
306
476
|
}
|
|
307
477
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (header.length > this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
|
|
478
|
+
if (header.length > this.#config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
|
|
311
479
|
log.error('Trace tags from span are too large, skipping injection.')
|
|
312
480
|
} else if (header) {
|
|
313
481
|
writeDatadogTags(carrier, header)
|
|
@@ -319,10 +487,10 @@ class TextMapPropagator {
|
|
|
319
487
|
* @param {Record<string, string>} [carrier]
|
|
320
488
|
* @returns {Record<string, string> | undefined}
|
|
321
489
|
*/
|
|
322
|
-
|
|
323
|
-
// v5 also accepts the legacy `'b3'` spelling for multi; v6 routes `'b3'` to single-header.
|
|
324
|
-
const hasB3multi = this
|
|
325
|
-
(DD_MAJOR < 6 && this
|
|
490
|
+
#injectB3MultipleHeaders (spanContext, carrier) {
|
|
491
|
+
// v5 also accepts the legacy `'b3'` spelling for multi; v6+ routes `'b3'` to single-header.
|
|
492
|
+
const hasB3multi = this.#hasPropagationStyle('inject', 'b3multi') ||
|
|
493
|
+
(DD_MAJOR < 6 && this.#hasPropagationStyle('inject', 'b3'))
|
|
326
494
|
if (!hasB3multi) return
|
|
327
495
|
|
|
328
496
|
carrier ??= {}
|
|
@@ -346,10 +514,10 @@ class TextMapPropagator {
|
|
|
346
514
|
* @param {Record<string, string>} [carrier]
|
|
347
515
|
* @returns {Record<string, string> | undefined}
|
|
348
516
|
*/
|
|
349
|
-
|
|
350
|
-
// v6 keeps `'b3 single header'` as a back-compat alias for callers that bypass parser normalisation.
|
|
351
|
-
const hasB3SingleHeader = this
|
|
352
|
-
(DD_MAJOR >= 6 && this
|
|
517
|
+
#injectB3SingleHeader (spanContext, carrier) {
|
|
518
|
+
// v6+ keeps `'b3 single header'` as a back-compat alias for callers that bypass parser normalisation.
|
|
519
|
+
const hasB3SingleHeader = this.#hasPropagationStyle('inject', 'b3 single header') ||
|
|
520
|
+
(DD_MAJOR >= 6 && this.#hasPropagationStyle('inject', 'b3'))
|
|
353
521
|
if (!hasB3SingleHeader) return
|
|
354
522
|
|
|
355
523
|
carrier ??= {}
|
|
@@ -372,8 +540,8 @@ class TextMapPropagator {
|
|
|
372
540
|
* @param {boolean} injectTraceContext
|
|
373
541
|
* @returns {Record<string, string> | undefined}
|
|
374
542
|
*/
|
|
375
|
-
|
|
376
|
-
if (!this
|
|
543
|
+
#injectTraceparent (spanContext, carrier, injectTraceContext) {
|
|
544
|
+
if (!this.#hasPropagationStyle('inject', 'tracecontext')) return
|
|
377
545
|
|
|
378
546
|
if (!injectTraceContext) {
|
|
379
547
|
const tracestate = TraceState.fromString(spanContext._tracestate?.toString())
|
|
@@ -437,53 +605,93 @@ class TextMapPropagator {
|
|
|
437
605
|
return carrier
|
|
438
606
|
}
|
|
439
607
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
firstSpanContext.toSpanId() !== w3cSpanContext.toSpanId()
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
_hasParentIdInTags (spanContext) {
|
|
451
|
-
return tags.DD_PARENT_ID in spanContext._trace.tags
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
_updateParentIdFromDdHeaders (carrier, firstSpanContext) {
|
|
455
|
-
const ddCtx = this._extractDatadogContext(carrier)
|
|
456
|
-
if (ddCtx !== undefined) {
|
|
457
|
-
firstSpanContext._trace.tags[tags.DD_PARENT_ID] = ddCtx._spanId.toString().padStart(16, '0')
|
|
458
|
-
}
|
|
608
|
+
/**
|
|
609
|
+
* @param {'inject' | 'extract'} mode
|
|
610
|
+
* @param {string} name
|
|
611
|
+
* @returns {boolean}
|
|
612
|
+
*/
|
|
613
|
+
#hasPropagationStyle (mode, name) {
|
|
614
|
+
return this.#config.tracePropagationStyle[mode].includes(name)
|
|
459
615
|
}
|
|
460
616
|
|
|
461
|
-
|
|
462
|
-
|
|
617
|
+
/**
|
|
618
|
+
* @param {DatadogSpanContext | undefined} w3cSpanContext
|
|
619
|
+
* @param {DatadogSpanContext} firstSpanContext
|
|
620
|
+
* @param {Record<string, unknown>} carrier
|
|
621
|
+
* @param {DatadogSpanContext | undefined} datadogContext
|
|
622
|
+
* @returns {DatadogSpanContext}
|
|
623
|
+
*/
|
|
624
|
+
#resolveTraceContextConflicts (w3cSpanContext, firstSpanContext, carrier, datadogContext) {
|
|
625
|
+
if (w3cSpanContext === undefined ||
|
|
626
|
+
firstSpanContext.toTraceId(true) !== w3cSpanContext.toTraceId(true) ||
|
|
627
|
+
firstSpanContext.toSpanId() === w3cSpanContext.toSpanId()) {
|
|
463
628
|
return firstSpanContext
|
|
464
629
|
}
|
|
465
|
-
if (
|
|
630
|
+
if (tags.DD_PARENT_ID in w3cSpanContext._trace.tags) {
|
|
466
631
|
// tracecontext headers contain a p value, ensure this value is sent to backend
|
|
467
632
|
firstSpanContext._trace.tags[tags.DD_PARENT_ID] = w3cSpanContext._trace.tags[tags.DD_PARENT_ID]
|
|
468
633
|
} else {
|
|
469
634
|
// if p value is not present in tracestate, use the parent id from the datadog headers
|
|
470
|
-
|
|
635
|
+
datadogContext ||= extractGenericContext(readDatadogTraceId(carrier), readDatadogParentId(carrier), 10)
|
|
636
|
+
if (datadogContext) {
|
|
637
|
+
firstSpanContext._trace.tags[tags.DD_PARENT_ID] = datadogContext._spanId.toString().padStart(16, '0')
|
|
638
|
+
}
|
|
471
639
|
}
|
|
472
640
|
// the span_id in tracecontext takes precedence over the first extracted propagation style
|
|
473
641
|
firstSpanContext._spanId = w3cSpanContext._spanId
|
|
474
642
|
return firstSpanContext
|
|
475
643
|
}
|
|
476
644
|
|
|
477
|
-
|
|
645
|
+
/**
|
|
646
|
+
* @param {Record<string, unknown>} carrier
|
|
647
|
+
* @returns {DatadogSpanContext | undefined}
|
|
648
|
+
*/
|
|
649
|
+
#extractSpanContext (carrier) {
|
|
478
650
|
let context
|
|
651
|
+
let datadogContext
|
|
479
652
|
let style = ''
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
653
|
+
let extractBaggage = false
|
|
654
|
+
let traceContext
|
|
655
|
+
let traceContextExtracted = false
|
|
656
|
+
for (const extractor of this.#config.tracePropagationStyle.extract) {
|
|
657
|
+
let extractedContext
|
|
658
|
+
switch (extractor) {
|
|
659
|
+
case 'datadog':
|
|
660
|
+
datadogContext = this.#extractDatadogContext(carrier)
|
|
661
|
+
extractedContext = datadogContext
|
|
662
|
+
if (extractedContext !== undefined && !this.#config.DD_TRACE_PROPAGATION_EXTRACT_FIRST) {
|
|
663
|
+
if (!traceContextExtracted) {
|
|
664
|
+
traceContext = this.#extractTraceparentContext(carrier)
|
|
665
|
+
traceContextExtracted = true
|
|
666
|
+
}
|
|
667
|
+
this.#addTraceContextState(extractedContext, traceContext)
|
|
668
|
+
}
|
|
669
|
+
break
|
|
670
|
+
case 'tracecontext':
|
|
671
|
+
if (!traceContextExtracted) {
|
|
672
|
+
traceContext = this.#extractTraceparentContext(carrier)
|
|
673
|
+
traceContextExtracted = true
|
|
674
|
+
}
|
|
675
|
+
extractedContext = traceContext
|
|
676
|
+
break
|
|
677
|
+
case 'b3':
|
|
678
|
+
extractedContext = this.#extractB3Context(carrier)
|
|
679
|
+
break
|
|
680
|
+
case 'b3 single header':
|
|
681
|
+
extractedContext = extractB3SingleContext(carrier)
|
|
682
|
+
break
|
|
683
|
+
case 'b3multi':
|
|
684
|
+
extractedContext = extractB3MultiContext(carrier)
|
|
685
|
+
break
|
|
686
|
+
case 'baggage':
|
|
687
|
+
extractBaggage = true
|
|
688
|
+
continue
|
|
689
|
+
case 'none':
|
|
690
|
+
continue
|
|
691
|
+
default:
|
|
692
|
+
log.warn('Unknown propagation style:', extractor)
|
|
693
|
+
continue
|
|
485
694
|
}
|
|
486
|
-
const extractedContext = this[method](carrier)
|
|
487
695
|
if (extractedContext === undefined) {
|
|
488
696
|
continue
|
|
489
697
|
}
|
|
@@ -491,14 +699,14 @@ class TextMapPropagator {
|
|
|
491
699
|
if (context === undefined) {
|
|
492
700
|
context = extractedContext
|
|
493
701
|
style = extractor
|
|
494
|
-
if (this.
|
|
702
|
+
if (this.#config.DD_TRACE_PROPAGATION_EXTRACT_FIRST) {
|
|
495
703
|
break
|
|
496
704
|
}
|
|
497
705
|
} else {
|
|
498
706
|
// If extractor is tracecontext, add tracecontext specific information to the context
|
|
499
707
|
if (extractor === 'tracecontext') {
|
|
500
|
-
context = this
|
|
501
|
-
|
|
708
|
+
context = this.#resolveTraceContextConflicts(
|
|
709
|
+
extractedContext, context, carrier, datadogContext)
|
|
502
710
|
}
|
|
503
711
|
if (extractedContext._traceId && extractedContext._spanId &&
|
|
504
712
|
extractedContext.toTraceId(true) !== context.toTraceId(true)) {
|
|
@@ -511,10 +719,14 @@ class TextMapPropagator {
|
|
|
511
719
|
}
|
|
512
720
|
}
|
|
513
721
|
|
|
514
|
-
if (
|
|
722
|
+
if (context && (style === 'datadog' || style === 'tracecontext')) {
|
|
723
|
+
this.#extractLegacyBaggageItems(carrier, context)
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
if (this.#config.DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT === 'ignore') {
|
|
515
727
|
if (context !== undefined) context._links = []
|
|
516
728
|
} else {
|
|
517
|
-
if (this.
|
|
729
|
+
if (this.#config.DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT === 'restart' && context) {
|
|
518
730
|
context._links = []
|
|
519
731
|
context._links.push({
|
|
520
732
|
context,
|
|
@@ -524,78 +736,47 @@ class TextMapPropagator {
|
|
|
524
736
|
},
|
|
525
737
|
})
|
|
526
738
|
}
|
|
527
|
-
this.
|
|
739
|
+
if (!extractBaggage && this.#config.DD_TRACE_PROPAGATION_EXTRACT_FIRST) {
|
|
740
|
+
extractBaggage = this.#hasPropagationStyle('extract', 'baggage')
|
|
741
|
+
}
|
|
742
|
+
this.#extractBaggageItems(carrier, context, extractBaggage)
|
|
528
743
|
}
|
|
529
744
|
|
|
530
|
-
return context || this
|
|
745
|
+
return context || this.#extractSqsdContext(carrier)
|
|
531
746
|
}
|
|
532
747
|
|
|
533
|
-
|
|
748
|
+
/**
|
|
749
|
+
* @param {Record<string, unknown>} carrier
|
|
750
|
+
* @returns {DatadogSpanContext | undefined}
|
|
751
|
+
*/
|
|
752
|
+
#extractDatadogContext (carrier) {
|
|
534
753
|
if (!carrier) return
|
|
535
|
-
const
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
10
|
|
539
|
-
)
|
|
754
|
+
const traceId = readDatadogTraceId(carrier)
|
|
755
|
+
if (!traceId) return
|
|
756
|
+
const spanContext = extractGenericContext(traceId, readDatadogParentId(carrier), 10)
|
|
540
757
|
|
|
541
758
|
if (!spanContext) return spanContext
|
|
542
759
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
this._extractSamplingPriority(carrier, spanContext)
|
|
546
|
-
const traceTags = this._extractTags(carrier)
|
|
547
|
-
if (traceTags) spanContext._trace.tags = traceTags
|
|
548
|
-
|
|
549
|
-
if (this._config.DD_TRACE_PROPAGATION_EXTRACT_FIRST) return spanContext
|
|
550
|
-
|
|
551
|
-
const tc = this._extractTraceparentContext(carrier)
|
|
552
|
-
|
|
553
|
-
if (tc && spanContext._traceId.equals(tc._traceId)) {
|
|
554
|
-
spanContext._traceparent = tc._traceparent
|
|
555
|
-
spanContext._tracestate = tc._tracestate
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
return spanContext
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
_extractB3MultiContext (carrier) {
|
|
562
|
-
const b3 = this._extractB3MultipleHeaders(carrier)
|
|
563
|
-
if (b3 === undefined) return
|
|
564
|
-
return this._extractB3Context(b3)
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
_extractB3SingleContext (carrier) {
|
|
568
|
-
// Check the resolved value first so the regex does not run on header-less requests.
|
|
569
|
-
const header = readB3(carrier)
|
|
570
|
-
if (!header || !b3HeaderExpr.test(header)) return
|
|
571
|
-
return this._extractB3Context(this._extractB3SingleHeader(header))
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
_extractB3Context (b3) {
|
|
575
|
-
const debug = b3.flags === '1'
|
|
576
|
-
const priority = this._getPriority(b3.sampled, debug)
|
|
577
|
-
const spanContext = this._extractGenericContext(b3.traceId, b3.spanId, 16)
|
|
578
|
-
|
|
579
|
-
if (priority !== undefined) {
|
|
580
|
-
if (!spanContext) {
|
|
581
|
-
// B3 can force a sampling decision without providing IDs
|
|
582
|
-
return new DatadogSpanContext({
|
|
583
|
-
traceId: id(),
|
|
584
|
-
spanId: null,
|
|
585
|
-
sampling: { priority },
|
|
586
|
-
isRemote: true,
|
|
587
|
-
})
|
|
588
|
-
}
|
|
760
|
+
const origin = readDatadogOrigin(carrier)
|
|
761
|
+
if (typeof origin === 'string') spanContext._trace.origin = origin
|
|
589
762
|
|
|
590
|
-
|
|
763
|
+
const header = readDatadogSamplingPriority(carrier)
|
|
764
|
+
if (header !== undefined) {
|
|
765
|
+
const priority = Number.parseInt(header, 10)
|
|
766
|
+
if (Number.isInteger(priority)) spanContext._sampling.priority = priority
|
|
591
767
|
}
|
|
592
768
|
|
|
593
|
-
this
|
|
769
|
+
const traceTags = this.#extractTags(carrier)
|
|
770
|
+
if (traceTags) spanContext._trace.tags = traceTags
|
|
594
771
|
|
|
595
772
|
return spanContext
|
|
596
773
|
}
|
|
597
774
|
|
|
598
|
-
|
|
775
|
+
/**
|
|
776
|
+
* @param {Record<string, unknown>} carrier
|
|
777
|
+
* @returns {DatadogSpanContext | undefined}
|
|
778
|
+
*/
|
|
779
|
+
#extractSqsdContext (carrier) {
|
|
599
780
|
const headerValue = readSqsd(carrier)
|
|
600
781
|
if (!headerValue) return
|
|
601
782
|
let parsed
|
|
@@ -604,10 +785,32 @@ class TextMapPropagator {
|
|
|
604
785
|
} catch {
|
|
605
786
|
return
|
|
606
787
|
}
|
|
607
|
-
|
|
788
|
+
const spanContext = this.#extractDatadogContext(parsed)
|
|
789
|
+
if (!spanContext) return
|
|
790
|
+
|
|
791
|
+
this.#extractLegacyBaggageItems(parsed, spanContext)
|
|
792
|
+
if (this.#config.DD_TRACE_PROPAGATION_EXTRACT_FIRST) return spanContext
|
|
793
|
+
|
|
794
|
+
this.#addTraceContextState(spanContext, this.#extractTraceparentContext(parsed))
|
|
795
|
+
return spanContext
|
|
608
796
|
}
|
|
609
797
|
|
|
610
|
-
|
|
798
|
+
/**
|
|
799
|
+
* @param {DatadogSpanContext} datadogContext
|
|
800
|
+
* @param {DatadogSpanContext | undefined} traceContext
|
|
801
|
+
*/
|
|
802
|
+
#addTraceContextState (datadogContext, traceContext) {
|
|
803
|
+
if (traceContext && datadogContext._traceId.equals(traceContext._traceId)) {
|
|
804
|
+
datadogContext._traceparent = traceContext._traceparent
|
|
805
|
+
datadogContext._tracestate = traceContext._tracestate
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* @param {Record<string, unknown>} carrier
|
|
811
|
+
* @returns {DatadogSpanContext | undefined}
|
|
812
|
+
*/
|
|
813
|
+
#extractTraceparentContext (carrier) {
|
|
611
814
|
const headerValue = readTraceparent(carrier)
|
|
612
815
|
if (!headerValue) return
|
|
613
816
|
const matches = headerValue.trim().match(traceparentExpr)
|
|
@@ -634,7 +837,7 @@ class TextMapPropagator {
|
|
|
634
837
|
tracestate,
|
|
635
838
|
})
|
|
636
839
|
|
|
637
|
-
|
|
840
|
+
extract128BitTraceId(traceId, spanContext)
|
|
638
841
|
|
|
639
842
|
tracestate.forVendor('dd', state => {
|
|
640
843
|
for (const [key, value] of state.entries()) {
|
|
@@ -683,147 +886,78 @@ class TextMapPropagator {
|
|
|
683
886
|
}
|
|
684
887
|
})
|
|
685
888
|
|
|
686
|
-
this._extractLegacyBaggageItems(carrier, spanContext)
|
|
687
889
|
return spanContext
|
|
688
890
|
}
|
|
689
891
|
}
|
|
690
892
|
|
|
691
893
|
/**
|
|
692
|
-
* @param {string
|
|
693
|
-
* @param {
|
|
694
|
-
* @
|
|
695
|
-
* @returns {DatadogSpanContext | undefined}
|
|
894
|
+
* @param {Record<string, unknown>} carrier
|
|
895
|
+
* @param {DatadogSpanContext} spanContext
|
|
896
|
+
* @returns {void}
|
|
696
897
|
*/
|
|
697
|
-
|
|
698
|
-
if (!
|
|
699
|
-
if (!spanId) return
|
|
700
|
-
|
|
701
|
-
return new DatadogSpanContext({
|
|
702
|
-
traceId: id(traceId, radix),
|
|
703
|
-
spanId: id(spanId, radix),
|
|
704
|
-
isRemote: true,
|
|
705
|
-
})
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
_extractB3MultipleHeaders (carrier) {
|
|
709
|
-
// The parent-id field is intentionally absent: this method never consults it,
|
|
710
|
-
// so a parent-id-only carrier should bail with the rest.
|
|
711
|
-
const traceId = readB3TraceId(carrier)
|
|
712
|
-
const sampled = readB3Sampled(carrier)
|
|
713
|
-
const flags = readB3Flags(carrier)
|
|
714
|
-
|
|
715
|
-
if (traceId === undefined && sampled === undefined && flags === undefined) {
|
|
716
|
-
return
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
let empty = true
|
|
720
|
-
const b3 = {}
|
|
721
|
-
const spanId = readB3SpanId(carrier)
|
|
722
|
-
|
|
723
|
-
if (traceId && spanId && b3TraceExpr.test(traceId) && b3SpanExpr.test(spanId)) {
|
|
724
|
-
b3.traceId = traceId
|
|
725
|
-
b3.spanId = spanId
|
|
726
|
-
empty = false
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
if (sampled) {
|
|
730
|
-
b3.sampled = sampled
|
|
731
|
-
empty = false
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
if (flags) {
|
|
735
|
-
b3.flags = flags
|
|
736
|
-
empty = false
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
return empty ? undefined : b3
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
/** @param {string} header */
|
|
743
|
-
_extractB3SingleHeader (header) {
|
|
744
|
-
const parts = header.split('-')
|
|
745
|
-
|
|
746
|
-
if (parts[0] === 'd') {
|
|
747
|
-
return {
|
|
748
|
-
sampled: '1',
|
|
749
|
-
flags: '1',
|
|
750
|
-
}
|
|
751
|
-
} else if (parts.length === 1) {
|
|
752
|
-
return {
|
|
753
|
-
sampled: parts[0],
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
const b3 = {
|
|
757
|
-
traceId: parts[0],
|
|
758
|
-
spanId: parts[1],
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
if (parts[2]) {
|
|
762
|
-
b3.sampled = parts[2] === '0' ? '0' : '1'
|
|
763
|
-
|
|
764
|
-
if (parts[2] === 'd') {
|
|
765
|
-
b3.flags = '1'
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
return b3
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
_extractOrigin (carrier, spanContext) {
|
|
773
|
-
const origin = readDatadogOrigin(carrier)
|
|
774
|
-
|
|
775
|
-
if (typeof origin === 'string') {
|
|
776
|
-
spanContext._trace.origin = origin
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
_extractLegacyBaggageItems (carrier, spanContext) {
|
|
781
|
-
if (!this._config.legacyBaggageEnabled) return
|
|
898
|
+
#extractLegacyBaggageItems (carrier, spanContext) {
|
|
899
|
+
if (!this.#config.legacyBaggageEnabled) return
|
|
782
900
|
readLegacyBaggage(carrier, spanContext._baggageItems)
|
|
783
901
|
}
|
|
784
902
|
|
|
785
|
-
|
|
903
|
+
/**
|
|
904
|
+
* @param {Record<string, unknown> | undefined} carrier
|
|
905
|
+
* @param {DatadogSpanContext | undefined} spanContext
|
|
906
|
+
* @param {boolean} extractBaggage
|
|
907
|
+
* @returns {void}
|
|
908
|
+
*/
|
|
909
|
+
#extractBaggageItems (carrier, spanContext, extractBaggage) {
|
|
786
910
|
removeAllBaggageItems()
|
|
787
|
-
if (!carrier || !
|
|
911
|
+
if (!carrier || !extractBaggage) return
|
|
788
912
|
const header = readBaggage(carrier)
|
|
789
913
|
if (!header) return
|
|
790
914
|
|
|
791
|
-
const baggages = header.split(',')
|
|
792
915
|
const baggageTagKeys = this.#getBaggageTagKeysSet()
|
|
793
916
|
const tagAllKeys = baggageTagKeys.has('*')
|
|
794
917
|
/** @type {Record<string, string> | undefined} */
|
|
795
918
|
let items
|
|
796
919
|
let itemCount = 0
|
|
797
920
|
let byteCount = 0
|
|
921
|
+
let start = 0
|
|
798
922
|
|
|
799
|
-
|
|
800
|
-
if (itemCount >= this.
|
|
923
|
+
while (start <= header.length) {
|
|
924
|
+
if (itemCount >= this.#config.baggageMaxItems) {
|
|
801
925
|
tracerMetrics.count('context_header.truncated', ['truncation_reason:baggage_item_count_exceeded']).inc()
|
|
802
926
|
break
|
|
803
927
|
}
|
|
928
|
+
|
|
929
|
+
const memberStart = start
|
|
930
|
+
const commaIndex = header.indexOf(',', memberStart)
|
|
931
|
+
const end = commaIndex === -1 ? header.length : commaIndex
|
|
932
|
+
|
|
804
933
|
// Charge the comma slot before the empty-entry skip so a `,,,,,foo=bar` can't iterate for free.
|
|
805
|
-
byteCount +=
|
|
806
|
-
if (byteCount > this.
|
|
934
|
+
byteCount += end - memberStart + 1
|
|
935
|
+
if (byteCount > this.#config.baggageMaxBytes) {
|
|
807
936
|
tracerMetrics.count('context_header.truncated', ['truncation_reason:baggage_byte_count_exceeded']).inc()
|
|
808
937
|
break
|
|
809
938
|
}
|
|
810
|
-
if (
|
|
939
|
+
if (memberStart === end) {
|
|
940
|
+
start = end + 1
|
|
941
|
+
continue
|
|
942
|
+
}
|
|
811
943
|
|
|
812
944
|
// Per W3C baggage, list-members can contain optional properties after `;`.
|
|
813
945
|
// Example: key=value;prop=1;prop2
|
|
814
946
|
// https://www.w3.org/TR/baggage/#header-content
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
if (
|
|
947
|
+
let memberEnd = header.indexOf(';', memberStart)
|
|
948
|
+
if (memberEnd === -1 || memberEnd > end) memberEnd = end
|
|
949
|
+
const equalsIndex = header.indexOf('=', memberStart)
|
|
950
|
+
start = end + 1
|
|
951
|
+
|
|
952
|
+
if (equalsIndex === -1 || equalsIndex >= memberEnd) {
|
|
953
|
+
const member = header.slice(memberStart, memberEnd).trim()
|
|
954
|
+
if (!member) continue
|
|
821
955
|
tracerMetrics.count('context_header_style.malformed', ['header_style:baggage']).inc()
|
|
822
956
|
return
|
|
823
957
|
}
|
|
824
958
|
|
|
825
|
-
const key =
|
|
826
|
-
let value =
|
|
959
|
+
const key = header.slice(memberStart, equalsIndex).trim()
|
|
960
|
+
let value = header.slice(equalsIndex + 1, memberEnd).trim()
|
|
827
961
|
|
|
828
962
|
if (!baggageTokenExpr.test(key) || !value) {
|
|
829
963
|
tracerMetrics.count('context_header_style.malformed', ['header_style:baggage']).inc()
|
|
@@ -856,27 +990,17 @@ class TextMapPropagator {
|
|
|
856
990
|
}
|
|
857
991
|
}
|
|
858
992
|
|
|
859
|
-
_extractSamplingPriority (carrier, spanContext) {
|
|
860
|
-
const header = readDatadogSamplingPriority(carrier)
|
|
861
|
-
if (header === undefined) return
|
|
862
|
-
const priority = Number.parseInt(header, 10)
|
|
863
|
-
|
|
864
|
-
if (Number.isInteger(priority)) {
|
|
865
|
-
spanContext._sampling.priority = priority
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
|
|
869
993
|
/**
|
|
870
994
|
* @param {Record<string, unknown>} carrier
|
|
871
995
|
* @returns {Record<string, string> | undefined}
|
|
872
996
|
*/
|
|
873
|
-
|
|
997
|
+
#extractTags (carrier) {
|
|
874
998
|
const header = readDatadogTags(carrier)
|
|
875
999
|
if (!header) return
|
|
876
1000
|
|
|
877
|
-
if (this.
|
|
1001
|
+
if (this.#config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) {
|
|
878
1002
|
log.debug('Trace tag propagation is disabled, skipping extraction.')
|
|
879
|
-
} else if (header.length > this.
|
|
1003
|
+
} else if (header.length > this.#config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
|
|
880
1004
|
log.error('Trace tags from carrier are too large, skipping extraction.')
|
|
881
1005
|
} else {
|
|
882
1006
|
const tags = {}
|
|
@@ -890,7 +1014,7 @@ class TextMapPropagator {
|
|
|
890
1014
|
const key = header.slice(start, hasSeparator ? separator : end)
|
|
891
1015
|
const value = hasSeparator ? header.slice(separator + 1, end) : ''
|
|
892
1016
|
|
|
893
|
-
if (!
|
|
1017
|
+
if (!tagKeyExpr.test(key) || !tagValueExpr.test(value)) {
|
|
894
1018
|
log.error('Trace tags from carrier are invalid, skipping extraction.')
|
|
895
1019
|
return
|
|
896
1020
|
}
|
|
@@ -907,62 +1031,6 @@ class TextMapPropagator {
|
|
|
907
1031
|
return tags
|
|
908
1032
|
}
|
|
909
1033
|
}
|
|
910
|
-
|
|
911
|
-
_extract128BitTraceId (traceId, spanContext) {
|
|
912
|
-
if (!spanContext) return
|
|
913
|
-
|
|
914
|
-
const buffer = spanContext._traceId.toBuffer()
|
|
915
|
-
|
|
916
|
-
if (buffer.length !== 16) return
|
|
917
|
-
|
|
918
|
-
const tid = traceId.slice(0, 16)
|
|
919
|
-
|
|
920
|
-
if (tid === zeroTraceId) return
|
|
921
|
-
|
|
922
|
-
spanContext._trace.tags['_dd.p.tid'] = tid
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
_validateTagKey (key) {
|
|
926
|
-
return tagKeyExpr.test(key)
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
_validateTagValue (value) {
|
|
930
|
-
return tagValueExpr.test(value)
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
_getPriority (sampled, debug) {
|
|
934
|
-
if (debug) {
|
|
935
|
-
return USER_KEEP
|
|
936
|
-
} else if (sampled === '1') {
|
|
937
|
-
return AUTO_KEEP
|
|
938
|
-
} else if (sampled === '0') {
|
|
939
|
-
return AUTO_REJECT
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
/**
|
|
944
|
-
* @param {number} traceparentSampled
|
|
945
|
-
* @param {number|undefined} tracestateSamplingPriority
|
|
946
|
-
* @param {string|null} origin
|
|
947
|
-
* @returns {import('../../priority_sampler').SamplingPriority}
|
|
948
|
-
*/
|
|
949
|
-
static _getSamplingPriority (traceparentSampled, tracestateSamplingPriority, origin) {
|
|
950
|
-
const fromRumWithoutPriority = !tracestateSamplingPriority && origin === 'rum'
|
|
951
|
-
|
|
952
|
-
let samplingPriority =
|
|
953
|
-
/** @type {import('../../priority_sampler').SamplingPriority} */ (tracestateSamplingPriority ?? AUTO_KEEP)
|
|
954
|
-
if (!fromRumWithoutPriority) {
|
|
955
|
-
if (traceparentSampled === 0 &&
|
|
956
|
-
(!tracestateSamplingPriority || tracestateSamplingPriority >= 0)) {
|
|
957
|
-
samplingPriority = AUTO_REJECT
|
|
958
|
-
} else if (traceparentSampled === 1 &&
|
|
959
|
-
(!tracestateSamplingPriority || tracestateSamplingPriority < 0)) {
|
|
960
|
-
samplingPriority = AUTO_KEEP
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
return samplingPriority
|
|
965
|
-
}
|
|
966
1034
|
}
|
|
967
1035
|
|
|
968
1036
|
module.exports = TextMapPropagator
|