dd-trace 6.11.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/LICENSE-3rdparty.csv +5 -0
- 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 +143 -25
- package/package.json +26 -25
- package/packages/datadog-instrumentations/src/bunyan.js +4 -2
- package/packages/datadog-instrumentations/src/cucumber.js +4 -4
- 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/mocha/utils.js +5 -2
- package/packages/datadog-instrumentations/src/pino.js +15 -4
- package/packages/datadog-instrumentations/src/playwright-reporter.js +149 -1
- package/packages/datadog-instrumentations/src/playwright.js +67 -53
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +13 -12
- 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 +13 -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/reporter.js +2 -0
- package/packages/dd-trace/src/appsec/rule_manager.js +2 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +13 -0
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +16 -0
- package/packages/dd-trace/src/appsec/telemetry/waf.js +24 -0
- package/packages/dd-trace/src/carrier.js +107 -48
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +5 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +2 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +5 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +51 -26
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +4 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +5 -11
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +6 -4
- package/packages/dd-trace/src/ci-visibility/final-flush.js +20 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +5 -3
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +196 -29
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +4 -2
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +4 -2
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +5 -5
- 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/constants.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/index.js +3 -10
- package/packages/dd-trace/src/debugger/devtools_client/send.js +4 -3
- package/packages/dd-trace/src/debugger/index.js +4 -2
- package/packages/dd-trace/src/debugger/inspect-segment.js +154 -0
- 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/evp_proxy/constants.js +8 -0
- package/packages/dd-trace/src/evp_proxy/direct.js +64 -0
- package/packages/dd-trace/src/evp_proxy/discovery.js +133 -0
- package/packages/dd-trace/src/evp_proxy/path.js +22 -0
- 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/request.js +5 -2
- 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 +10 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +301 -14
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +440 -112
- package/packages/dd-trace/src/llmobs/experiments/index.js +68 -44
- package/packages/dd-trace/src/llmobs/experiments/noop.js +103 -12
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +81 -4
- 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/constants/constants.js +0 -18
- package/packages/dd-trace/src/openfeature/index.js +7 -4
- package/packages/dd-trace/src/openfeature/writers/base.js +153 -11
- package/packages/dd-trace/src/openfeature/writers/exposures.js +70 -15
- package/packages/dd-trace/src/openfeature/writers/util.js +97 -15
- 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 +429 -352
- 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/telemetry/metrics.js +62 -8
- package/packages/dd-trace/src/telemetry/send-data.js +1 -0
- 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
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/https-proxy-agent/LICENSE +22 -0
- package/vendor/dist/https-proxy-agent/index.js +4 -0
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/proxy-from-env/LICENSE +20 -0
- package/vendor/dist/proxy-from-env/index.js +1 -0
|
@@ -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,77 +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
|
-
this._extractTags(carrier, spanContext)
|
|
547
|
-
|
|
548
|
-
if (this._config.DD_TRACE_PROPAGATION_EXTRACT_FIRST) return spanContext
|
|
549
|
-
|
|
550
|
-
const tc = this._extractTraceparentContext(carrier)
|
|
551
|
-
|
|
552
|
-
if (tc && spanContext._traceId.equals(tc._traceId)) {
|
|
553
|
-
spanContext._traceparent = tc._traceparent
|
|
554
|
-
spanContext._tracestate = tc._tracestate
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
return spanContext
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
_extractB3MultiContext (carrier) {
|
|
561
|
-
const b3 = this._extractB3MultipleHeaders(carrier)
|
|
562
|
-
if (b3 === undefined) return
|
|
563
|
-
return this._extractB3Context(b3)
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
_extractB3SingleContext (carrier) {
|
|
567
|
-
// Check the resolved value first so the regex does not run on header-less requests.
|
|
568
|
-
const header = readB3(carrier)
|
|
569
|
-
if (!header || !b3HeaderExpr.test(header)) return
|
|
570
|
-
return this._extractB3Context(this._extractB3SingleHeader(header))
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
_extractB3Context (b3) {
|
|
574
|
-
const debug = b3.flags === '1'
|
|
575
|
-
const priority = this._getPriority(b3.sampled, debug)
|
|
576
|
-
const spanContext = this._extractGenericContext(b3.traceId, b3.spanId, 16)
|
|
577
|
-
|
|
578
|
-
if (priority !== undefined) {
|
|
579
|
-
if (!spanContext) {
|
|
580
|
-
// B3 can force a sampling decision without providing IDs
|
|
581
|
-
return new DatadogSpanContext({
|
|
582
|
-
traceId: id(),
|
|
583
|
-
spanId: null,
|
|
584
|
-
sampling: { priority },
|
|
585
|
-
isRemote: true,
|
|
586
|
-
})
|
|
587
|
-
}
|
|
760
|
+
const origin = readDatadogOrigin(carrier)
|
|
761
|
+
if (typeof origin === 'string') spanContext._trace.origin = origin
|
|
588
762
|
|
|
589
|
-
|
|
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
|
|
590
767
|
}
|
|
591
768
|
|
|
592
|
-
this
|
|
769
|
+
const traceTags = this.#extractTags(carrier)
|
|
770
|
+
if (traceTags) spanContext._trace.tags = traceTags
|
|
593
771
|
|
|
594
772
|
return spanContext
|
|
595
773
|
}
|
|
596
774
|
|
|
597
|
-
|
|
775
|
+
/**
|
|
776
|
+
* @param {Record<string, unknown>} carrier
|
|
777
|
+
* @returns {DatadogSpanContext | undefined}
|
|
778
|
+
*/
|
|
779
|
+
#extractSqsdContext (carrier) {
|
|
598
780
|
const headerValue = readSqsd(carrier)
|
|
599
781
|
if (!headerValue) return
|
|
600
782
|
let parsed
|
|
@@ -603,10 +785,32 @@ class TextMapPropagator {
|
|
|
603
785
|
} catch {
|
|
604
786
|
return
|
|
605
787
|
}
|
|
606
|
-
|
|
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
|
|
607
796
|
}
|
|
608
797
|
|
|
609
|
-
|
|
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) {
|
|
610
814
|
const headerValue = readTraceparent(carrier)
|
|
611
815
|
if (!headerValue) return
|
|
612
816
|
const matches = headerValue.trim().match(traceparentExpr)
|
|
@@ -633,7 +837,7 @@ class TextMapPropagator {
|
|
|
633
837
|
tracestate,
|
|
634
838
|
})
|
|
635
839
|
|
|
636
|
-
|
|
840
|
+
extract128BitTraceId(traceId, spanContext)
|
|
637
841
|
|
|
638
842
|
tracestate.forVendor('dd', state => {
|
|
639
843
|
for (const [key, value] of state.entries()) {
|
|
@@ -682,147 +886,78 @@ class TextMapPropagator {
|
|
|
682
886
|
}
|
|
683
887
|
})
|
|
684
888
|
|
|
685
|
-
this._extractLegacyBaggageItems(carrier, spanContext)
|
|
686
889
|
return spanContext
|
|
687
890
|
}
|
|
688
891
|
}
|
|
689
892
|
|
|
690
893
|
/**
|
|
691
|
-
* @param {string
|
|
692
|
-
* @param {
|
|
693
|
-
* @
|
|
694
|
-
* @returns {DatadogSpanContext | undefined}
|
|
894
|
+
* @param {Record<string, unknown>} carrier
|
|
895
|
+
* @param {DatadogSpanContext} spanContext
|
|
896
|
+
* @returns {void}
|
|
695
897
|
*/
|
|
696
|
-
|
|
697
|
-
if (!
|
|
698
|
-
if (!spanId) return
|
|
699
|
-
|
|
700
|
-
return new DatadogSpanContext({
|
|
701
|
-
traceId: id(traceId, radix),
|
|
702
|
-
spanId: id(spanId, radix),
|
|
703
|
-
isRemote: true,
|
|
704
|
-
})
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
_extractB3MultipleHeaders (carrier) {
|
|
708
|
-
// The parent-id field is intentionally absent: this method never consults it,
|
|
709
|
-
// so a parent-id-only carrier should bail with the rest.
|
|
710
|
-
const traceId = readB3TraceId(carrier)
|
|
711
|
-
const sampled = readB3Sampled(carrier)
|
|
712
|
-
const flags = readB3Flags(carrier)
|
|
713
|
-
|
|
714
|
-
if (traceId === undefined && sampled === undefined && flags === undefined) {
|
|
715
|
-
return
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
let empty = true
|
|
719
|
-
const b3 = {}
|
|
720
|
-
const spanId = readB3SpanId(carrier)
|
|
721
|
-
|
|
722
|
-
if (traceId && spanId && b3TraceExpr.test(traceId) && b3SpanExpr.test(spanId)) {
|
|
723
|
-
b3.traceId = traceId
|
|
724
|
-
b3.spanId = spanId
|
|
725
|
-
empty = false
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
if (sampled) {
|
|
729
|
-
b3.sampled = sampled
|
|
730
|
-
empty = false
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
if (flags) {
|
|
734
|
-
b3.flags = flags
|
|
735
|
-
empty = false
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
return empty ? undefined : b3
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
/** @param {string} header */
|
|
742
|
-
_extractB3SingleHeader (header) {
|
|
743
|
-
const parts = header.split('-')
|
|
744
|
-
|
|
745
|
-
if (parts[0] === 'd') {
|
|
746
|
-
return {
|
|
747
|
-
sampled: '1',
|
|
748
|
-
flags: '1',
|
|
749
|
-
}
|
|
750
|
-
} else if (parts.length === 1) {
|
|
751
|
-
return {
|
|
752
|
-
sampled: parts[0],
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
const b3 = {
|
|
756
|
-
traceId: parts[0],
|
|
757
|
-
spanId: parts[1],
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
if (parts[2]) {
|
|
761
|
-
b3.sampled = parts[2] === '0' ? '0' : '1'
|
|
762
|
-
|
|
763
|
-
if (parts[2] === 'd') {
|
|
764
|
-
b3.flags = '1'
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
return b3
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
_extractOrigin (carrier, spanContext) {
|
|
772
|
-
const origin = readDatadogOrigin(carrier)
|
|
773
|
-
|
|
774
|
-
if (typeof origin === 'string') {
|
|
775
|
-
spanContext._trace.origin = origin
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
_extractLegacyBaggageItems (carrier, spanContext) {
|
|
780
|
-
if (!this._config.legacyBaggageEnabled) return
|
|
898
|
+
#extractLegacyBaggageItems (carrier, spanContext) {
|
|
899
|
+
if (!this.#config.legacyBaggageEnabled) return
|
|
781
900
|
readLegacyBaggage(carrier, spanContext._baggageItems)
|
|
782
901
|
}
|
|
783
902
|
|
|
784
|
-
|
|
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) {
|
|
785
910
|
removeAllBaggageItems()
|
|
786
|
-
if (!carrier || !
|
|
911
|
+
if (!carrier || !extractBaggage) return
|
|
787
912
|
const header = readBaggage(carrier)
|
|
788
913
|
if (!header) return
|
|
789
914
|
|
|
790
|
-
const baggages = header.split(',')
|
|
791
915
|
const baggageTagKeys = this.#getBaggageTagKeysSet()
|
|
792
916
|
const tagAllKeys = baggageTagKeys.has('*')
|
|
793
917
|
/** @type {Record<string, string> | undefined} */
|
|
794
918
|
let items
|
|
795
919
|
let itemCount = 0
|
|
796
920
|
let byteCount = 0
|
|
921
|
+
let start = 0
|
|
797
922
|
|
|
798
|
-
|
|
799
|
-
if (itemCount >= this.
|
|
923
|
+
while (start <= header.length) {
|
|
924
|
+
if (itemCount >= this.#config.baggageMaxItems) {
|
|
800
925
|
tracerMetrics.count('context_header.truncated', ['truncation_reason:baggage_item_count_exceeded']).inc()
|
|
801
926
|
break
|
|
802
927
|
}
|
|
928
|
+
|
|
929
|
+
const memberStart = start
|
|
930
|
+
const commaIndex = header.indexOf(',', memberStart)
|
|
931
|
+
const end = commaIndex === -1 ? header.length : commaIndex
|
|
932
|
+
|
|
803
933
|
// Charge the comma slot before the empty-entry skip so a `,,,,,foo=bar` can't iterate for free.
|
|
804
|
-
byteCount +=
|
|
805
|
-
if (byteCount > this.
|
|
934
|
+
byteCount += end - memberStart + 1
|
|
935
|
+
if (byteCount > this.#config.baggageMaxBytes) {
|
|
806
936
|
tracerMetrics.count('context_header.truncated', ['truncation_reason:baggage_byte_count_exceeded']).inc()
|
|
807
937
|
break
|
|
808
938
|
}
|
|
809
|
-
if (
|
|
939
|
+
if (memberStart === end) {
|
|
940
|
+
start = end + 1
|
|
941
|
+
continue
|
|
942
|
+
}
|
|
810
943
|
|
|
811
944
|
// Per W3C baggage, list-members can contain optional properties after `;`.
|
|
812
945
|
// Example: key=value;prop=1;prop2
|
|
813
946
|
// https://www.w3.org/TR/baggage/#header-content
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
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
|
|
820
955
|
tracerMetrics.count('context_header_style.malformed', ['header_style:baggage']).inc()
|
|
821
956
|
return
|
|
822
957
|
}
|
|
823
958
|
|
|
824
|
-
const key =
|
|
825
|
-
let value =
|
|
959
|
+
const key = header.slice(memberStart, equalsIndex).trim()
|
|
960
|
+
let value = header.slice(equalsIndex + 1, memberEnd).trim()
|
|
826
961
|
|
|
827
962
|
if (!baggageTokenExpr.test(key) || !value) {
|
|
828
963
|
tracerMetrics.count('context_header_style.malformed', ['header_style:baggage']).inc()
|
|
@@ -855,104 +990,46 @@ class TextMapPropagator {
|
|
|
855
990
|
}
|
|
856
991
|
}
|
|
857
992
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
if (Number.isInteger(priority)) {
|
|
864
|
-
spanContext._sampling.priority = priority
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
_extractTags (carrier, spanContext) {
|
|
993
|
+
/**
|
|
994
|
+
* @param {Record<string, unknown>} carrier
|
|
995
|
+
* @returns {Record<string, string> | undefined}
|
|
996
|
+
*/
|
|
997
|
+
#extractTags (carrier) {
|
|
869
998
|
const header = readDatadogTags(carrier)
|
|
870
999
|
if (!header) return
|
|
871
1000
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
if (this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) {
|
|
1001
|
+
if (this.#config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) {
|
|
875
1002
|
log.debug('Trace tag propagation is disabled, skipping extraction.')
|
|
876
|
-
} else if (header.length > this.
|
|
1003
|
+
} else if (header.length > this.#config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
|
|
877
1004
|
log.error('Trace tags from carrier are too large, skipping extraction.')
|
|
878
1005
|
} else {
|
|
879
|
-
const pairs = header.split(',')
|
|
880
1006
|
const tags = {}
|
|
1007
|
+
let start = 0
|
|
1008
|
+
let separator = header.indexOf('=')
|
|
881
1009
|
|
|
882
|
-
|
|
883
|
-
const
|
|
884
|
-
const
|
|
1010
|
+
while (start <= header.length) {
|
|
1011
|
+
const comma = header.indexOf(',', start)
|
|
1012
|
+
const end = comma === -1 ? header.length : comma
|
|
1013
|
+
const hasSeparator = separator !== -1 && separator < end
|
|
1014
|
+
const key = header.slice(start, hasSeparator ? separator : end)
|
|
1015
|
+
const value = hasSeparator ? header.slice(separator + 1, end) : ''
|
|
885
1016
|
|
|
886
|
-
if (!
|
|
1017
|
+
if (!tagKeyExpr.test(key) || !tagValueExpr.test(value)) {
|
|
887
1018
|
log.error('Trace tags from carrier are invalid, skipping extraction.')
|
|
888
1019
|
return
|
|
889
1020
|
}
|
|
890
|
-
|
|
891
|
-
if (key === '_dd.p.tid' && !(hex16.test(value))) {
|
|
1021
|
+
if (key === '_dd.p.tid' && !hex16.test(value)) {
|
|
892
1022
|
log.error('Invalid _dd.p.tid tag %s, skipping', value)
|
|
893
|
-
|
|
1023
|
+
} else {
|
|
1024
|
+
tags[key] = value
|
|
894
1025
|
}
|
|
895
|
-
tags[key] = value
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
Object.assign(trace.tags, tags)
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
_extract128BitTraceId (traceId, spanContext) {
|
|
903
|
-
if (!spanContext) return
|
|
904
|
-
|
|
905
|
-
const buffer = spanContext._traceId.toBuffer()
|
|
906
|
-
|
|
907
|
-
if (buffer.length !== 16) return
|
|
908
|
-
|
|
909
|
-
const tid = traceId.slice(0, 16)
|
|
910
|
-
|
|
911
|
-
if (tid === zeroTraceId) return
|
|
912
1026
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
_validateTagKey (key) {
|
|
917
|
-
return tagKeyExpr.test(key)
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
_validateTagValue (value) {
|
|
921
|
-
return tagValueExpr.test(value)
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
_getPriority (sampled, debug) {
|
|
925
|
-
if (debug) {
|
|
926
|
-
return USER_KEEP
|
|
927
|
-
} else if (sampled === '1') {
|
|
928
|
-
return AUTO_KEEP
|
|
929
|
-
} else if (sampled === '0') {
|
|
930
|
-
return AUTO_REJECT
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
/**
|
|
935
|
-
* @param {number} traceparentSampled
|
|
936
|
-
* @param {number|undefined} tracestateSamplingPriority
|
|
937
|
-
* @param {string|null} origin
|
|
938
|
-
* @returns {import('../../priority_sampler').SamplingPriority}
|
|
939
|
-
*/
|
|
940
|
-
static _getSamplingPriority (traceparentSampled, tracestateSamplingPriority, origin) {
|
|
941
|
-
const fromRumWithoutPriority = !tracestateSamplingPriority && origin === 'rum'
|
|
942
|
-
|
|
943
|
-
let samplingPriority =
|
|
944
|
-
/** @type {import('../../priority_sampler').SamplingPriority} */ (tracestateSamplingPriority ?? AUTO_KEEP)
|
|
945
|
-
if (!fromRumWithoutPriority) {
|
|
946
|
-
if (traceparentSampled === 0 &&
|
|
947
|
-
(!tracestateSamplingPriority || tracestateSamplingPriority >= 0)) {
|
|
948
|
-
samplingPriority = AUTO_REJECT
|
|
949
|
-
} else if (traceparentSampled === 1 &&
|
|
950
|
-
(!tracestateSamplingPriority || tracestateSamplingPriority < 0)) {
|
|
951
|
-
samplingPriority = AUTO_KEEP
|
|
1027
|
+
start = end + 1
|
|
1028
|
+
if (hasSeparator) separator = header.indexOf('=', start)
|
|
952
1029
|
}
|
|
953
|
-
}
|
|
954
1030
|
|
|
955
|
-
|
|
1031
|
+
return tags
|
|
1032
|
+
}
|
|
956
1033
|
}
|
|
957
1034
|
}
|
|
958
1035
|
|