dd-trace 6.19.0 → 6.20.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/index.d.ts +163 -22
- package/package.json +2 -2
- package/packages/datadog-esbuild/index.js +9 -6
- package/packages/datadog-instrumentations/src/ai.js +26 -0
- package/packages/datadog-instrumentations/src/aws-sdk.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +0 -7
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +25 -0
- package/packages/datadog-plugin-openai/src/stream-helpers.js +50 -1
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -0
- package/packages/dd-trace/src/config/remote_config.js +12 -0
- package/packages/dd-trace/src/config/supported-configurations.json +21 -0
- package/packages/dd-trace/src/debugger/constants.js +13 -4
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +14 -1
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +109 -6
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +65 -6
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +22 -10
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +12 -8
- package/packages/dd-trace/src/debugger/devtools_client/send.js +14 -0
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +43 -5
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +3 -8
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +2 -122
- package/packages/dd-trace/src/debugger/guardrail-metrics.js +0 -2
- package/packages/dd-trace/src/debugger/index.js +60 -28
- package/packages/dd-trace/src/debugger/inspect-segment.js +92 -23
- package/packages/dd-trace/src/debugger/pause-duration-histogram.js +74 -0
- package/packages/dd-trace/src/debugger/probe_sampler.js +192 -52
- package/packages/dd-trace/src/debugger/redaction.js +139 -0
- package/packages/dd-trace/src/knuth-hash.js +17 -0
- package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +66 -2
- package/packages/dd-trace/src/llmobs/experiments/evaluator.js +138 -0
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +213 -90
- package/packages/dd-trace/src/llmobs/experiments/index.js +40 -1
- package/packages/dd-trace/src/llmobs/experiments/noop.js +53 -2
- package/packages/dd-trace/src/llmobs/experiments/remote-evaluator.js +110 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +34 -6
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +2 -2
- package/packages/dd-trace/src/llmobs/sdk.js +19 -3
- package/packages/dd-trace/src/llmobs/span_processor.js +42 -26
- package/packages/dd-trace/src/llmobs/tagger.js +35 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +1 -6
- package/packages/dd-trace/src/openfeature/constants/constants.js +10 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +14 -1
- package/packages/dd-trace/src/openfeature/writers/base.js +39 -18
- package/packages/dd-trace/src/openfeature/writers/flag-eval-evp-hook.js +105 -0
- package/packages/dd-trace/src/openfeature/writers/flag-evaluation-aggregation.js +190 -0
- package/packages/dd-trace/src/openfeature/writers/flag-evaluation-consumer.js +233 -0
- package/packages/dd-trace/src/openfeature/writers/flag-evaluation-context.js +262 -0
- package/packages/dd-trace/src/openfeature/writers/flag-evaluation-payload.js +181 -0
- package/packages/dd-trace/src/openfeature/writers/flag-evaluation-pii.js +108 -0
- package/packages/dd-trace/src/openfeature/writers/flag-evaluation-telemetry.js +154 -0
- package/packages/dd-trace/src/openfeature/writers/flag-evaluation-worker.js +77 -0
- package/packages/dd-trace/src/openfeature/writers/flag-evaluations.js +398 -0
- package/packages/dd-trace/src/openfeature/writers/util.js +5 -4
- package/packages/dd-trace/src/opentelemetry/context_manager.js +3 -0
- package/packages/dd-trace/src/opentelemetry/span_context.js +6 -2
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +6 -0
- package/packages/dd-trace/src/opentelemetry/tracer.js +16 -18
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +116 -25
- package/packages/dd-trace/src/opentracing/propagation/tracestate.js +80 -16
- package/packages/dd-trace/src/opentracing/span.js +14 -9
- package/packages/dd-trace/src/opentracing/tracer.js +10 -3
- package/packages/dd-trace/src/otel-sampling.js +171 -0
- package/packages/dd-trace/src/plugins/index.js +0 -1
- package/packages/dd-trace/src/priority_sampler.js +155 -33
- package/packages/dd-trace/src/remote_config/capabilities.js +9 -0
- package/packages/dd-trace/src/sampler.js +2 -5
- package/packages/dd-trace/src/sampling_rule.js +4 -8
- package/packages/dd-trace/src/span_format.js +6 -0
- package/packages/dd-trace/src/span_processor.js +26 -2
- package/packages/dd-trace/src/standalone/index.js +5 -4
- package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +25 -5
- package/packages/dd-trace/src/telemetry/metrics.js +4 -3
- package/packages/datadog-instrumentations/src/postgres.js +0 -7
- package/packages/datadog-instrumentations/src/supabase.js +0 -15
|
@@ -77,6 +77,8 @@ const zeroTraceId = '0000000000000000'
|
|
|
77
77
|
const hex16 = /^[0-9A-Fa-f]{16}$/
|
|
78
78
|
const percentByte = /%([0-9A-Fa-f]{2})/g
|
|
79
79
|
|
|
80
|
+
let otelSampling
|
|
81
|
+
|
|
80
82
|
/**
|
|
81
83
|
* @typedef {object} B3Context
|
|
82
84
|
* @property {string} [flags]
|
|
@@ -85,6 +87,13 @@ const percentByte = /%([0-9A-Fa-f]{2})/g
|
|
|
85
87
|
* @property {string} [traceId]
|
|
86
88
|
*/
|
|
87
89
|
|
|
90
|
+
/**
|
|
91
|
+
* @typedef {object} TraceTagInjection
|
|
92
|
+
* @property {DatadogSpanContext} spanContext
|
|
93
|
+
* @property {Array<string | undefined>} [traceTagReplacements]
|
|
94
|
+
* @property {number} [optionalTraceTagCount]
|
|
95
|
+
*/
|
|
96
|
+
|
|
88
97
|
/**
|
|
89
98
|
* @param {Array<string | undefined>} traceTagReplacements
|
|
90
99
|
* @param {string} key
|
|
@@ -96,6 +105,28 @@ function hasTraceTagReplacement (traceTagReplacements, key) {
|
|
|
96
105
|
return false
|
|
97
106
|
}
|
|
98
107
|
|
|
108
|
+
/** @param {string} key */
|
|
109
|
+
function toTraceStateTagKey (key) {
|
|
110
|
+
return 't.' + key.slice(6).replaceAll(tracestateTagKeyFilter, '_')
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @param {string} key
|
|
115
|
+
* @param {TraceTagInjection | undefined} injection
|
|
116
|
+
*/
|
|
117
|
+
function isOptionalDatadogTraceStateField (key, injection) {
|
|
118
|
+
if (!key.startsWith('t.') || key === 't.dm' || key === 't.ts') return false
|
|
119
|
+
|
|
120
|
+
const traceTagReplacements = injection?.traceTagReplacements
|
|
121
|
+
if (!traceTagReplacements) return true
|
|
122
|
+
const firstOptionalTraceTagIndex = traceTagReplacements.length - (injection.optionalTraceTagCount ?? 0) * 2
|
|
123
|
+
for (let index = 0; index < firstOptionalTraceTagIndex; index += 2) {
|
|
124
|
+
const traceTagKey = traceTagReplacements[index]
|
|
125
|
+
if (traceTagKey.startsWith('_dd.p.') && toTraceStateTagKey(traceTagKey) === key) return false
|
|
126
|
+
}
|
|
127
|
+
return true
|
|
128
|
+
}
|
|
129
|
+
|
|
99
130
|
/**
|
|
100
131
|
* @param {string | undefined} traceId
|
|
101
132
|
* @param {string | undefined} spanId
|
|
@@ -149,12 +180,15 @@ function getB3Priority (sampled, debug) {
|
|
|
149
180
|
* @returns {DatadogSpanContext | undefined}
|
|
150
181
|
*/
|
|
151
182
|
function extractB3Context (b3) {
|
|
152
|
-
const
|
|
153
|
-
const
|
|
183
|
+
const debug = b3.flags === '1'
|
|
184
|
+
const priority = getB3Priority(b3.sampled, debug)
|
|
185
|
+
let spanContext = extractGenericContext(b3.traceId, b3.spanId, 16)
|
|
154
186
|
|
|
155
187
|
if (priority !== undefined) {
|
|
156
|
-
if (
|
|
157
|
-
|
|
188
|
+
if (spanContext) {
|
|
189
|
+
spanContext._sampling.priority = priority
|
|
190
|
+
} else {
|
|
191
|
+
spanContext = new DatadogSpanContext({
|
|
158
192
|
traceId: id(),
|
|
159
193
|
spanId: null,
|
|
160
194
|
sampling: { priority },
|
|
@@ -162,7 +196,7 @@ function extractB3Context (b3) {
|
|
|
162
196
|
})
|
|
163
197
|
}
|
|
164
198
|
|
|
165
|
-
spanContext._sampling.
|
|
199
|
+
if (debug) spanContext._sampling.isProbabilityDecision = false
|
|
166
200
|
}
|
|
167
201
|
|
|
168
202
|
if (spanContext && b3.traceId) extract128BitTraceId(b3.traceId, spanContext)
|
|
@@ -326,13 +360,15 @@ class TextMapPropagator {
|
|
|
326
360
|
hasTraceSourcePropagationTag(spanContext._trace.tags)
|
|
327
361
|
let traceTagReplacements
|
|
328
362
|
let optionalTraceTagCount = 0
|
|
363
|
+
/** @type {TraceTagInjection | undefined} */
|
|
364
|
+
let traceTagInjection
|
|
329
365
|
if (injectTraceContext && injectCh.hasSubscribers && (
|
|
330
366
|
this.#hasPropagationStyle('inject', 'datadog') || this.#hasPropagationStyle('inject', 'tracecontext')
|
|
331
367
|
)) {
|
|
332
|
-
|
|
333
|
-
injectCh.publish(
|
|
334
|
-
traceTagReplacements =
|
|
335
|
-
optionalTraceTagCount =
|
|
368
|
+
traceTagInjection = { spanContext }
|
|
369
|
+
injectCh.publish(traceTagInjection)
|
|
370
|
+
traceTagReplacements = traceTagInjection.traceTagReplacements
|
|
371
|
+
optionalTraceTagCount = traceTagInjection.optionalTraceTagCount ?? 0
|
|
336
372
|
}
|
|
337
373
|
if (injectTraceContext) {
|
|
338
374
|
injectedCarrier = this.#injectDatadog(
|
|
@@ -343,7 +379,7 @@ class TextMapPropagator {
|
|
|
343
379
|
}
|
|
344
380
|
injectedCarrier = this
|
|
345
381
|
.#injectTraceparent(
|
|
346
|
-
spanContext, injectedCarrier ?? carrier, injectTraceContext, traceTagReplacements
|
|
382
|
+
spanContext, injectedCarrier ?? carrier, injectTraceContext, traceTagReplacements, traceTagInjection
|
|
347
383
|
) ?? injectedCarrier
|
|
348
384
|
|
|
349
385
|
if (injectedCarrier === undefined) return
|
|
@@ -509,7 +545,7 @@ class TextMapPropagator {
|
|
|
509
545
|
}
|
|
510
546
|
|
|
511
547
|
if (traceTagReplacements) {
|
|
512
|
-
const
|
|
548
|
+
const firstOptionalTraceTagIndex = traceTagReplacements.length - optionalTraceTagCount * 2
|
|
513
549
|
for (let index = 0; index < traceTagReplacements.length; index += 2) {
|
|
514
550
|
const key = traceTagReplacements[index]
|
|
515
551
|
const value = traceTagReplacements[index + 1]
|
|
@@ -520,7 +556,7 @@ class TextMapPropagator {
|
|
|
520
556
|
}
|
|
521
557
|
|
|
522
558
|
const entry = `${header ? ',' : ''}${key}=${value}`
|
|
523
|
-
if (index >=
|
|
559
|
+
if (index >= firstOptionalTraceTagIndex && header.length + entry.length > maxLength) break
|
|
524
560
|
header += entry
|
|
525
561
|
}
|
|
526
562
|
}
|
|
@@ -589,13 +625,14 @@ class TextMapPropagator {
|
|
|
589
625
|
* @param {Record<string, string> | undefined} carrier
|
|
590
626
|
* @param {boolean} injectTraceContext
|
|
591
627
|
* @param {Array<string | undefined>} [traceTagReplacements]
|
|
628
|
+
* @param {TraceTagInjection} [traceTagInjection]
|
|
592
629
|
* @returns {Record<string, string> | undefined}
|
|
593
630
|
*/
|
|
594
|
-
#injectTraceparent (spanContext, carrier, injectTraceContext, traceTagReplacements) {
|
|
631
|
+
#injectTraceparent (spanContext, carrier, injectTraceContext, traceTagReplacements, traceTagInjection) {
|
|
595
632
|
if (!this.#hasPropagationStyle('inject', 'tracecontext')) return
|
|
596
633
|
|
|
597
634
|
if (!injectTraceContext) {
|
|
598
|
-
const tracestate =
|
|
635
|
+
const tracestate = spanContext._tracestate?.clone() ?? new TraceState()
|
|
599
636
|
tracestate.delete('dd')
|
|
600
637
|
const header = tracestate.toString()
|
|
601
638
|
if (!header) return
|
|
@@ -611,11 +648,14 @@ class TextMapPropagator {
|
|
|
611
648
|
_trace: { origin },
|
|
612
649
|
} = spanContext
|
|
613
650
|
const ts = traceTagReplacements
|
|
614
|
-
?
|
|
651
|
+
? _tracestate?.clone() ?? new TraceState()
|
|
615
652
|
: _tracestate ?? new TraceState()
|
|
616
653
|
|
|
617
654
|
writeTraceparent(carrier, spanContext.toTraceparent())
|
|
618
655
|
|
|
656
|
+
otelSampling ??= require('../../otel-sampling')
|
|
657
|
+
otelSampling.updateOtelTraceState(spanContext, ts)
|
|
658
|
+
|
|
619
659
|
ts.forVendor('dd', state => {
|
|
620
660
|
if (!spanContext._isRemote) {
|
|
621
661
|
// SpanContext was created by a ddtrace span.
|
|
@@ -643,8 +683,7 @@ class TextMapPropagator {
|
|
|
643
683
|
const tagValueRaw = spanContext._trace.tags[key]
|
|
644
684
|
if (!tagValueRaw || !key.startsWith('_dd.p.')) continue
|
|
645
685
|
|
|
646
|
-
const tagKey =
|
|
647
|
-
.replaceAll(tracestateTagKeyFilter, '_')
|
|
686
|
+
const tagKey = toTraceStateTagKey(key)
|
|
648
687
|
|
|
649
688
|
const tagValue = tagValueRaw
|
|
650
689
|
.toString()
|
|
@@ -659,8 +698,7 @@ class TextMapPropagator {
|
|
|
659
698
|
const key = traceTagReplacements[index]
|
|
660
699
|
if (!key.startsWith('_dd.p.')) continue
|
|
661
700
|
|
|
662
|
-
const tagKey =
|
|
663
|
-
.replaceAll(tracestateTagKeyFilter, '_')
|
|
701
|
+
const tagKey = toTraceStateTagKey(key)
|
|
664
702
|
const tagValueRaw = traceTagReplacements[index + 1]
|
|
665
703
|
if (!tagValueRaw) {
|
|
666
704
|
state.delete(tagKey)
|
|
@@ -675,7 +713,7 @@ class TextMapPropagator {
|
|
|
675
713
|
state.set(tagKey, tagValue)
|
|
676
714
|
}
|
|
677
715
|
}
|
|
678
|
-
})
|
|
716
|
+
}, isOptionalDatadogTraceStateField, traceTagInjection)
|
|
679
717
|
|
|
680
718
|
writeTracestate(carrier, ts.toString())
|
|
681
719
|
|
|
@@ -690,6 +728,32 @@ class TextMapPropagator {
|
|
|
690
728
|
return this.#config.tracePropagationStyle[mode].includes(name)
|
|
691
729
|
}
|
|
692
730
|
|
|
731
|
+
/**
|
|
732
|
+
* Merges W3C sampling state into the context selected by propagation-style precedence.
|
|
733
|
+
*
|
|
734
|
+
* @param {DatadogSpanContext} w3cSpanContext
|
|
735
|
+
* @param {DatadogSpanContext} selectedSpanContext
|
|
736
|
+
*/
|
|
737
|
+
#mergeTraceContextState (w3cSpanContext, selectedSpanContext) {
|
|
738
|
+
const selectedPriority = selectedSpanContext._sampling.priority
|
|
739
|
+
if (selectedPriority === undefined) {
|
|
740
|
+
selectedSpanContext._sampling.priority = w3cSpanContext._sampling.priority
|
|
741
|
+
selectedSpanContext._sampling.mechanism = w3cSpanContext._sampling.mechanism
|
|
742
|
+
selectedSpanContext._trace.tags['_dd.p.dm'] = w3cSpanContext._trace.tags['_dd.p.dm']
|
|
743
|
+
} else if (
|
|
744
|
+
selectedSpanContext._sampling.isProbabilityDecision === false ||
|
|
745
|
+
(selectedPriority >= AUTO_KEEP) !== (w3cSpanContext._sampling.priority >= AUTO_KEEP)
|
|
746
|
+
) {
|
|
747
|
+
// Copied sampling metadata must not describe a conflicting or non-probabilistic selected decision.
|
|
748
|
+
selectedSpanContext._sampling.isProbabilityDecision = false
|
|
749
|
+
w3cSpanContext._tracestate.forVendor('dd', state => {
|
|
750
|
+
if (state.get('t.dm') !== undefined) state.delete('t.dm')
|
|
751
|
+
})
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
selectedSpanContext._tracestate = w3cSpanContext._tracestate
|
|
755
|
+
}
|
|
756
|
+
|
|
693
757
|
/**
|
|
694
758
|
* @param {DatadogSpanContext | undefined} w3cSpanContext
|
|
695
759
|
* @param {DatadogSpanContext} firstSpanContext
|
|
@@ -699,10 +763,13 @@ class TextMapPropagator {
|
|
|
699
763
|
*/
|
|
700
764
|
#resolveTraceContextConflicts (w3cSpanContext, firstSpanContext, carrier, datadogContext) {
|
|
701
765
|
if (w3cSpanContext === undefined ||
|
|
702
|
-
firstSpanContext.toTraceId(true) !== w3cSpanContext.toTraceId(true)
|
|
703
|
-
firstSpanContext.toSpanId() === w3cSpanContext.toSpanId()) {
|
|
766
|
+
firstSpanContext.toTraceId(true) !== w3cSpanContext.toTraceId(true)) {
|
|
704
767
|
return firstSpanContext
|
|
705
768
|
}
|
|
769
|
+
|
|
770
|
+
this.#mergeTraceContextState(w3cSpanContext, firstSpanContext)
|
|
771
|
+
if (firstSpanContext.toSpanId() === w3cSpanContext.toSpanId()) return firstSpanContext
|
|
772
|
+
|
|
706
773
|
if (tags.DD_PARENT_ID in w3cSpanContext._trace.tags) {
|
|
707
774
|
// tracecontext headers contain a p value, ensure this value is sent to backend
|
|
708
775
|
firstSpanContext._trace.tags[tags.DD_PARENT_ID] = w3cSpanContext._trace.tags[tags.DD_PARENT_ID]
|
|
@@ -740,7 +807,8 @@ class TextMapPropagator {
|
|
|
740
807
|
traceContext = this.#extractTraceparentContext(carrier)
|
|
741
808
|
traceContextExtracted = true
|
|
742
809
|
}
|
|
743
|
-
|
|
810
|
+
const selectedContext = context && context !== traceContext ? context : extractedContext
|
|
811
|
+
this.#addTraceContextState(selectedContext, traceContext)
|
|
744
812
|
}
|
|
745
813
|
break
|
|
746
814
|
case 'tracecontext':
|
|
@@ -842,7 +910,25 @@ class TextMapPropagator {
|
|
|
842
910
|
}
|
|
843
911
|
|
|
844
912
|
const traceTags = this.#extractTags(carrier)
|
|
845
|
-
if (traceTags)
|
|
913
|
+
if (traceTags) {
|
|
914
|
+
spanContext._trace.tags = traceTags
|
|
915
|
+
const decisionMaker = traceTags['_dd.p.dm']
|
|
916
|
+
if (decisionMaker !== undefined) {
|
|
917
|
+
// Avoid general integer parsing for the common single-digit mechanisms.
|
|
918
|
+
const digit = decisionMaker.length === 2 && decisionMaker[0] === '-'
|
|
919
|
+
? decisionMaker.charCodeAt(1) - 48
|
|
920
|
+
: -1
|
|
921
|
+
if (digit >= 0 && digit <= 9) {
|
|
922
|
+
spanContext._sampling.mechanism = digit
|
|
923
|
+
} else {
|
|
924
|
+
// Preserve integer-prefix parsing; Number() also turns empty values into zero.
|
|
925
|
+
const mechanism = Math.abs(Number.parseInt(decisionMaker, 10))
|
|
926
|
+
if (Number.isInteger(mechanism) && mechanism >= 0) {
|
|
927
|
+
spanContext._sampling.mechanism = mechanism
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
846
932
|
|
|
847
933
|
return spanContext
|
|
848
934
|
}
|
|
@@ -879,7 +965,7 @@ class TextMapPropagator {
|
|
|
879
965
|
#addTraceContextState (datadogContext, traceContext) {
|
|
880
966
|
if (traceContext && datadogContext._traceId.equals(traceContext._traceId)) {
|
|
881
967
|
datadogContext._traceparent = traceContext._traceparent
|
|
882
|
-
datadogContext
|
|
968
|
+
this.#mergeTraceContextState(traceContext, datadogContext)
|
|
883
969
|
}
|
|
884
970
|
}
|
|
885
971
|
|
|
@@ -905,6 +991,11 @@ class TextMapPropagator {
|
|
|
905
991
|
// Version 00 should have no tail, but future versions may
|
|
906
992
|
if (tail && version === '00') return
|
|
907
993
|
|
|
994
|
+
if (tracestate.get('ot') !== undefined) {
|
|
995
|
+
otelSampling ??= require('../../otel-sampling')
|
|
996
|
+
otelSampling.normalizeOtelTraceState(tracestate)
|
|
997
|
+
}
|
|
998
|
+
|
|
908
999
|
const spanContext = new DatadogSpanContext({
|
|
909
1000
|
traceId: id(traceId, 16),
|
|
910
1001
|
spanId: id(spanId, 16),
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// W3C Trace Context §3.3.1.2: max 32 list-members.
|
|
4
4
|
// https://www.w3.org/TR/trace-context/#tracestate-header-field-values
|
|
5
5
|
const MAX_LIST_MEMBERS = 32
|
|
6
|
+
const MAX_VALUE_LENGTH = 256
|
|
6
7
|
const WHITESPACE = /[ \t]/
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -12,10 +13,12 @@ const WHITESPACE = /[ \t]/
|
|
|
12
13
|
* @param {string} fieldSeparator Between entries.
|
|
13
14
|
* @param {string} pairSeparator Between key and value within an entry.
|
|
14
15
|
* @param {boolean} rejectValueTabs Drop entries whose value contains an internal tab.
|
|
16
|
+
* @param {number} [maxEntries] Maximum number of entries to parse.
|
|
17
|
+
* @param {number} [maxValueLength] Maximum length of an entry value.
|
|
15
18
|
* @returns {[string, string][]} Entries in reverse of wire order.
|
|
16
19
|
*/
|
|
17
|
-
function parseEntries (value, fieldSeparator, pairSeparator, rejectValueTabs) {
|
|
18
|
-
const segments = value.split(fieldSeparator,
|
|
20
|
+
function parseEntries (value, fieldSeparator, pairSeparator, rejectValueTabs, maxEntries, maxValueLength) {
|
|
21
|
+
const segments = value.split(fieldSeparator, maxEntries)
|
|
19
22
|
|
|
20
23
|
// TODO: We should extract dd no matter at what position and move it to the front of the list.
|
|
21
24
|
// Extract up 31 additional entries.
|
|
@@ -29,7 +32,9 @@ function parseEntries (value, fieldSeparator, pairSeparator, rejectValueTabs) {
|
|
|
29
32
|
// W3C §3.3.1.3.2: value = 0*255(chr) nblk-chr; chr = %x20 / nblk-chr (no tab).
|
|
30
33
|
// Leading 0x20 is part of value; trailing whitespace is OWS.
|
|
31
34
|
const entryValue = segment.slice(splitIndex + 1).trimEnd()
|
|
32
|
-
if (!entryValue ||
|
|
35
|
+
if (!entryValue ||
|
|
36
|
+
maxValueLength !== undefined && entryValue.length > maxValueLength ||
|
|
37
|
+
rejectValueTabs && entryValue.includes('\t')) continue
|
|
33
38
|
entries.push([key, entryValue])
|
|
34
39
|
}
|
|
35
40
|
// Reverse so the Map's insertion order is reverse of wire order. `toString`
|
|
@@ -38,11 +43,21 @@ function parseEntries (value, fieldSeparator, pairSeparator, rejectValueTabs) {
|
|
|
38
43
|
return entries
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
/**
|
|
47
|
+
* @param {typeof TraceState | typeof TraceStateData} Type
|
|
48
|
+
* @param {string | undefined} value
|
|
49
|
+
* @param {string} fieldSeparator
|
|
50
|
+
* @param {string} pairSeparator
|
|
51
|
+
* @param {boolean} rejectValueTabs
|
|
52
|
+
* @param {number} [maxEntries]
|
|
53
|
+
* @param {number} [maxValueLength]
|
|
54
|
+
* @returns {TraceState | TraceStateData}
|
|
55
|
+
*/
|
|
56
|
+
function fromString (Type, value, fieldSeparator, pairSeparator, rejectValueTabs, maxEntries, maxValueLength) {
|
|
42
57
|
if (typeof value !== 'string' || !value.length) {
|
|
43
58
|
return new Type()
|
|
44
59
|
}
|
|
45
|
-
return new Type(parseEntries(value, fieldSeparator, pairSeparator, rejectValueTabs))
|
|
60
|
+
return new Type(parseEntries(value, fieldSeparator, pairSeparator, rejectValueTabs, maxEntries, maxValueLength))
|
|
46
61
|
}
|
|
47
62
|
|
|
48
63
|
function toString (map, pairSeparator, fieldSeparator) {
|
|
@@ -76,8 +91,9 @@ class TraceStateData {
|
|
|
76
91
|
}
|
|
77
92
|
|
|
78
93
|
delete (key) {
|
|
94
|
+
if (!this.#map.delete(key)) return false
|
|
79
95
|
this.changed = true
|
|
80
|
-
return
|
|
96
|
+
return true
|
|
81
97
|
}
|
|
82
98
|
|
|
83
99
|
clear () {
|
|
@@ -97,6 +113,24 @@ class TraceStateData {
|
|
|
97
113
|
return this.#map.size
|
|
98
114
|
}
|
|
99
115
|
|
|
116
|
+
/**
|
|
117
|
+
* @template Context
|
|
118
|
+
* @param {number} valueLength
|
|
119
|
+
* @param {(key: string, context: Context) => boolean} isOptional
|
|
120
|
+
* @param {Context} context
|
|
121
|
+
*/
|
|
122
|
+
trimOptionalFields (valueLength, isOptional, context) {
|
|
123
|
+
const fields = [...this.#map]
|
|
124
|
+
for (let index = fields.length - 1; index >= 0 && valueLength > MAX_VALUE_LENGTH; index--) {
|
|
125
|
+
const [key, value] = fields[index]
|
|
126
|
+
if (!isOptional(key, context)) continue
|
|
127
|
+
|
|
128
|
+
valueLength -= key.length + String(value).length + (this.#map.size > 1 ? 2 : 1)
|
|
129
|
+
this.delete(key)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** @param {string | undefined} value */
|
|
100
134
|
static fromString (value) {
|
|
101
135
|
return fromString(TraceStateData, value, ';', ':', false)
|
|
102
136
|
}
|
|
@@ -115,11 +149,22 @@ class TraceState {
|
|
|
115
149
|
|
|
116
150
|
constructor (entries) {
|
|
117
151
|
this.#map = entries ? new Map(entries) : new Map()
|
|
152
|
+
while (this.#map.size > MAX_LIST_MEMBERS) {
|
|
153
|
+
this.#map.delete(this.#map.keys().next().value)
|
|
154
|
+
}
|
|
118
155
|
}
|
|
119
156
|
|
|
120
157
|
// Delete entries on update to ensure they're moved to the end of the list
|
|
158
|
+
/**
|
|
159
|
+
* @param {string} key
|
|
160
|
+
* @param {string} value
|
|
161
|
+
*/
|
|
121
162
|
set (key, value) {
|
|
122
|
-
if (
|
|
163
|
+
if (value.length > MAX_VALUE_LENGTH) return this
|
|
164
|
+
const updated = this.#map.delete(key)
|
|
165
|
+
if (!updated && this.#map.size === MAX_LIST_MEMBERS) {
|
|
166
|
+
this.#map.delete(this.#map.keys().next().value)
|
|
167
|
+
}
|
|
123
168
|
this.#map.set(key, value)
|
|
124
169
|
return this
|
|
125
170
|
}
|
|
@@ -140,25 +185,44 @@ class TraceState {
|
|
|
140
185
|
return this.#map.size
|
|
141
186
|
}
|
|
142
187
|
|
|
143
|
-
|
|
188
|
+
/** @returns {TraceState} A shallow copy with independent member storage. */
|
|
189
|
+
clone () {
|
|
190
|
+
return new TraceState(this.#map)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @template Context
|
|
195
|
+
* @param {string} vendor
|
|
196
|
+
* @param {(state: TraceStateData) => unknown} handle
|
|
197
|
+
* @param {(key: string, context: Context) => boolean} [isOptional]
|
|
198
|
+
* @param {Context} [context]
|
|
199
|
+
* @returns {unknown}
|
|
200
|
+
*/
|
|
201
|
+
forVendor (vendor, handle, isOptional, context) {
|
|
144
202
|
const data = this.#map.get(vendor)
|
|
145
203
|
const state = TraceStateData.fromString(data)
|
|
146
204
|
const result = handle(state)
|
|
147
205
|
|
|
148
|
-
if (state.changed)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
206
|
+
if (!state.changed) return result
|
|
207
|
+
|
|
208
|
+
let value = state.toString()
|
|
209
|
+
if (value.length > MAX_VALUE_LENGTH && isOptional) {
|
|
210
|
+
state.trimOptionalFields(value.length, isOptional, context)
|
|
211
|
+
value = state.toString()
|
|
212
|
+
}
|
|
213
|
+
if (value.length > MAX_VALUE_LENGTH) {
|
|
214
|
+
if (isOptional) this.delete(vendor)
|
|
215
|
+
return result
|
|
155
216
|
}
|
|
217
|
+
if (value === data) return result
|
|
218
|
+
if (value) this.set(vendor, value)
|
|
219
|
+
else this.delete(vendor)
|
|
156
220
|
|
|
157
221
|
return result
|
|
158
222
|
}
|
|
159
223
|
|
|
160
224
|
static fromString (value) {
|
|
161
|
-
return fromString(TraceState, value, ',', '=', true)
|
|
225
|
+
return fromString(TraceState, value, ',', '=', true, MAX_LIST_MEMBERS, MAX_VALUE_LENGTH)
|
|
162
226
|
}
|
|
163
227
|
|
|
164
228
|
toString () {
|
|
@@ -213,8 +213,8 @@ class DatadogSpan {
|
|
|
213
213
|
setTag (key, value) {
|
|
214
214
|
this._spanContext.setTag(key, value)
|
|
215
215
|
|
|
216
|
-
if (isSamplingPriorityTag(key)
|
|
217
|
-
this._prioritySampler.
|
|
216
|
+
if (isSamplingPriorityTag(key)) {
|
|
217
|
+
this._prioritySampler.setPriorityFromTags(this, this._spanContext.getTags())
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
if (tagsUpdateCh.hasSubscribers) {
|
|
@@ -236,21 +236,26 @@ class DatadogSpan {
|
|
|
236
236
|
if (keyValueMap !== null && typeof keyValueMap === 'object' && !Array.isArray(keyValueMap)) {
|
|
237
237
|
Object.assign(tags, keyValueMap)
|
|
238
238
|
mayChangeSamplingPriority =
|
|
239
|
-
MANUAL_KEEP
|
|
240
|
-
MANUAL_DROP
|
|
241
|
-
SAMPLING_PRIORITY
|
|
239
|
+
keyValueMap[MANUAL_KEEP] !== undefined ||
|
|
240
|
+
keyValueMap[MANUAL_DROP] !== undefined ||
|
|
241
|
+
keyValueMap[SAMPLING_PRIORITY] !== undefined
|
|
242
242
|
} else {
|
|
243
243
|
/* istanbul ignore if: v5 fallback, master ships 6.0.0-pre */
|
|
244
244
|
if (DD_MAJOR < 6 && (typeof keyValueMap === 'string' || Array.isArray(keyValueMap))) {
|
|
245
|
-
|
|
246
|
-
|
|
245
|
+
const samplingTags = {}
|
|
246
|
+
tagger.add(samplingTags, keyValueMap)
|
|
247
|
+
Object.assign(tags, samplingTags)
|
|
248
|
+
mayChangeSamplingPriority =
|
|
249
|
+
samplingTags[MANUAL_KEEP] !== undefined ||
|
|
250
|
+
samplingTags[MANUAL_DROP] !== undefined ||
|
|
251
|
+
samplingTags[SAMPLING_PRIORITY] !== undefined
|
|
247
252
|
} else {
|
|
248
253
|
return this
|
|
249
254
|
}
|
|
250
255
|
}
|
|
251
256
|
|
|
252
|
-
if (mayChangeSamplingPriority
|
|
253
|
-
this._prioritySampler.
|
|
257
|
+
if (mayChangeSamplingPriority) {
|
|
258
|
+
this._prioritySampler.setPriorityFromTags(this, tags)
|
|
254
259
|
}
|
|
255
260
|
|
|
256
261
|
if (tagsUpdateCh.hasSubscribers) {
|
|
@@ -39,8 +39,9 @@ class DatadogTracer {
|
|
|
39
39
|
// silently lose all test spans. The same applies to the Electron exporter:
|
|
40
40
|
// spans must reach the Electron SDK's IPC bridge, not an OTLP endpoint,
|
|
41
41
|
// even when OTEL_* vars are set for unrelated telemetry.
|
|
42
|
-
|
|
43
|
-
config.tracing.DD_TRACE_EXPERIMENTAL_EXPORTER !== 'electron'
|
|
42
|
+
const exportOtlpTraces = config.OTEL_TRACES_EXPORTER === 'otlp' && !config.isCiVisibility &&
|
|
43
|
+
config.tracing.DD_TRACE_EXPERIMENTAL_EXPORTER !== 'electron'
|
|
44
|
+
if (exportOtlpTraces) {
|
|
44
45
|
const { createOtlpTraceExporter } = require('../opentelemetry/trace')
|
|
45
46
|
this._exporter = createOtlpTraceExporter(config)
|
|
46
47
|
} else {
|
|
@@ -53,7 +54,13 @@ class DatadogTracer {
|
|
|
53
54
|
const { createOtlpSpanStatsExporter } = require('../opentelemetry/metrics')
|
|
54
55
|
otlpStatsExporter = createOtlpSpanStatsExporter(config)
|
|
55
56
|
}
|
|
56
|
-
this._processor = new SpanProcessor(
|
|
57
|
+
this._processor = new SpanProcessor(
|
|
58
|
+
this._exporter,
|
|
59
|
+
this._prioritySampler,
|
|
60
|
+
config,
|
|
61
|
+
otlpStatsExporter,
|
|
62
|
+
exportOtlpTraces
|
|
63
|
+
)
|
|
57
64
|
this._url = this._exporter._url
|
|
58
65
|
this._enableGetRumData = config.rum.DD_TRACE_EXPERIMENTAL_GET_RUM_DATA_ENABLED
|
|
59
66
|
this._traceId128BitGenerationEnabled = config.traceId128BitGenerationEnabled
|