dd-trace 6.2.0 → 6.3.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/README.md +1 -1
- package/package.json +3 -4
- package/packages/datadog-instrumentations/src/cookie.js +7 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/modelcontextprotocol-sdk.js +30 -54
- package/packages/datadog-instrumentations/src/http/server.js +27 -0
- package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +248 -1
- package/packages/datadog-instrumentations/src/playwright.js +40 -3
- package/packages/datadog-plugin-azure-functions/src/index.js +2 -1
- package/packages/datadog-plugin-graphql/src/request.js +1 -1
- package/packages/datadog-plugin-modelcontextprotocol-sdk/src/tracing.js +144 -26
- package/packages/datadog-plugin-modelcontextprotocol-sdk/src/utils.js +30 -0
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-shimmer/src/shimmer.js +9 -2
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +6 -3
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +23 -16
- package/packages/dd-trace/src/config/config-types.d.ts +8 -0
- package/packages/dd-trace/src/config/defaults.js +20 -15
- package/packages/dd-trace/src/config/index.js +13 -3
- package/packages/dd-trace/src/config/parsers.js +79 -0
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
- package/packages/dd-trace/src/llmobs/tagger.js +15 -1
- package/packages/dd-trace/src/opentelemetry/span_processor.js +7 -5
- package/packages/dd-trace/src/opentelemetry/tracer_provider.js +32 -16
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +20 -11
|
@@ -35,6 +35,7 @@ const {
|
|
|
35
35
|
INTEGRATION,
|
|
36
36
|
DECORATOR,
|
|
37
37
|
PROPAGATED_ML_APP_KEY,
|
|
38
|
+
PROPAGATED_SESSION_ID_KEY,
|
|
38
39
|
DEFAULT_PROMPT_NAME,
|
|
39
40
|
INTERNAL_CONTEXT_VARIABLE_KEYS,
|
|
40
41
|
INTERNAL_QUERY_VARIABLE_KEYS,
|
|
@@ -139,7 +140,8 @@ class LLMObsTagger {
|
|
|
139
140
|
if (modelName) this.tagModelName(span, modelName)
|
|
140
141
|
if (modelProvider) this._setTag(span, MODEL_PROVIDER, modelProvider)
|
|
141
142
|
|
|
142
|
-
|
|
143
|
+
const traceTags = span.context()._trace.tags
|
|
144
|
+
sessionId = sessionId || registry.get(parent)?.[SESSION_ID] || traceTags[PROPAGATED_SESSION_ID_KEY]
|
|
143
145
|
if (sessionId) this._setTag(span, SESSION_ID, sessionId)
|
|
144
146
|
if (integration) this._setTag(span, INTEGRATION, integration)
|
|
145
147
|
if (_decorator) this._setTag(span, DECORATOR, _decorator)
|
|
@@ -752,6 +754,18 @@ class LLMObsTagger {
|
|
|
752
754
|
|
|
753
755
|
const tagsCarrier = registry.get(span)
|
|
754
756
|
tagsCarrier[key] = value
|
|
757
|
+
|
|
758
|
+
// The first session set in a trace becomes the trace-level default, stored on the trace-shared
|
|
759
|
+
// propagating tags so later spans (incl. those under a session-less parent) inherit it and it
|
|
760
|
+
// rides `x-datadog-tags` across service boundaries. Established here, the single choke point for
|
|
761
|
+
// session writes, so sessions post-populated by integrations after span start also seed it.
|
|
762
|
+
// First-writer wins, so an explicit session still overrides locally.
|
|
763
|
+
if (key === SESSION_ID && value) {
|
|
764
|
+
const traceTags = span.context()._trace.tags
|
|
765
|
+
if (traceTags[PROPAGATED_SESSION_ID_KEY] === undefined) {
|
|
766
|
+
traceTags[PROPAGATED_SESSION_ID_KEY] = value
|
|
767
|
+
}
|
|
768
|
+
}
|
|
755
769
|
}
|
|
756
770
|
}
|
|
757
771
|
|
|
@@ -14,32 +14,34 @@ class NoopSpanProcessor {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
class MultiSpanProcessor extends NoopSpanProcessor {
|
|
17
|
+
#processors
|
|
18
|
+
|
|
17
19
|
constructor (spanProcessors) {
|
|
18
20
|
super()
|
|
19
|
-
this
|
|
21
|
+
this.#processors = spanProcessors
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
forceFlush () {
|
|
23
25
|
return Promise.all(
|
|
24
|
-
this.
|
|
26
|
+
this.#processors.map(p => p.forceFlush())
|
|
25
27
|
)
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
onStart (span, context) {
|
|
29
|
-
for (const processor of this
|
|
31
|
+
for (const processor of this.#processors) {
|
|
30
32
|
processor.onStart(span, context)
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
onEnd (span) {
|
|
35
|
-
for (const processor of this
|
|
37
|
+
for (const processor of this.#processors) {
|
|
36
38
|
processor.onEnd(span)
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
shutdown () {
|
|
41
43
|
return Promise.all(
|
|
42
|
-
this.
|
|
44
|
+
this.#processors.map(p => p.shutdown())
|
|
43
45
|
)
|
|
44
46
|
}
|
|
45
47
|
}
|
|
@@ -10,46 +10,62 @@ const { MultiSpanProcessor, NoopSpanProcessor } = require('./span_processor')
|
|
|
10
10
|
const Tracer = require('./tracer')
|
|
11
11
|
|
|
12
12
|
class TracerProvider {
|
|
13
|
+
#activeProcessor = new NoopSpanProcessor()
|
|
14
|
+
#contextManager = new ContextManager()
|
|
15
|
+
#processors = []
|
|
16
|
+
#tracers = new Map()
|
|
17
|
+
|
|
13
18
|
constructor (config = {}) {
|
|
14
19
|
this.config = config
|
|
15
20
|
this.resource = config.resource
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
// @opentelemetry/sdk-trace 2.x (used by @opentelemetry/sdk-node 0.220+)
|
|
23
|
+
// dropped `addSpanProcessor` and hands the processors to the provider
|
|
24
|
+
// constructor instead. Wire them the same way the 1.x `addSpanProcessor`
|
|
25
|
+
// path does, so a NodeSDK configured with a trace exporter or custom
|
|
26
|
+
// processors still delivers onStart/onEnd to them.
|
|
27
|
+
if (Array.isArray(config.spanProcessors)) {
|
|
28
|
+
for (const spanProcessor of config.spanProcessors) {
|
|
29
|
+
this.addSpanProcessor(spanProcessor)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
21
32
|
}
|
|
22
33
|
|
|
23
34
|
getTracer (name = 'opentelemetry', version = '0.0.0', options) {
|
|
24
35
|
const key = `${name}@${version}`
|
|
25
|
-
if (!this.
|
|
26
|
-
this.
|
|
36
|
+
if (!this.#tracers.has(key)) {
|
|
37
|
+
this.#tracers.set(key, new Tracer(
|
|
27
38
|
{ ...options, name, version },
|
|
28
39
|
this.config,
|
|
29
40
|
this
|
|
30
41
|
))
|
|
31
42
|
}
|
|
32
|
-
return this.
|
|
43
|
+
return this.#tracers.get(key)
|
|
33
44
|
}
|
|
34
45
|
|
|
46
|
+
/**
|
|
47
|
+
* @param {NoopSpanProcessor} spanProcessor
|
|
48
|
+
*/
|
|
35
49
|
addSpanProcessor (spanProcessor) {
|
|
36
|
-
if (
|
|
37
|
-
|
|
50
|
+
if (this.#processors.includes(spanProcessor)) return
|
|
51
|
+
|
|
52
|
+
if (!this.#processors.length) {
|
|
53
|
+
this.#activeProcessor.shutdown()
|
|
38
54
|
}
|
|
39
|
-
this.
|
|
40
|
-
this
|
|
41
|
-
this
|
|
55
|
+
this.#processors.push(spanProcessor)
|
|
56
|
+
this.#activeProcessor = new MultiSpanProcessor(
|
|
57
|
+
this.#processors
|
|
42
58
|
)
|
|
43
59
|
}
|
|
44
60
|
|
|
45
61
|
getActiveSpanProcessor () {
|
|
46
|
-
return this
|
|
62
|
+
return this.#activeProcessor
|
|
47
63
|
}
|
|
48
64
|
|
|
49
65
|
// Not actually required by the SDK spec, but the official Node.js SDK does
|
|
50
66
|
// this and the docs reflect that so we should do this too for familiarity.
|
|
51
67
|
register (config = {}) {
|
|
52
|
-
context.setGlobalContextManager(this
|
|
68
|
+
context.setGlobalContextManager(this.#contextManager)
|
|
53
69
|
if (!trace.setGlobalTracerProvider(this)) {
|
|
54
70
|
trace.getTracerProvider().setDelegate(this)
|
|
55
71
|
}
|
|
@@ -69,11 +85,11 @@ class TracerProvider {
|
|
|
69
85
|
}
|
|
70
86
|
|
|
71
87
|
exporter._writer?.flush()
|
|
72
|
-
return this.
|
|
88
|
+
return this.#activeProcessor.forceFlush()
|
|
73
89
|
}
|
|
74
90
|
|
|
75
91
|
shutdown () {
|
|
76
|
-
return this.
|
|
92
|
+
return this.#activeProcessor.shutdown()
|
|
77
93
|
}
|
|
78
94
|
}
|
|
79
95
|
|
|
@@ -7,10 +7,16 @@ const os = require('os')
|
|
|
7
7
|
const process = require('process')
|
|
8
8
|
const { performance, PerformanceObserver, monitorEventLoopDelay } = require('perf_hooks')
|
|
9
9
|
const log = require('../log')
|
|
10
|
-
const { NODE_MAJOR } = require('../../../../version')
|
|
10
|
+
const { NODE_MAJOR, NODE_MINOR } = require('../../../../version')
|
|
11
11
|
const { createMetricsClient } = require('./client')
|
|
12
12
|
|
|
13
13
|
const eventLoopDelayResolution = 4
|
|
14
|
+
const EVENT_LOOP_SAMPLE_PER_ITERATION_AVAILABLE = NODE_MAJOR > 26 || (NODE_MAJOR === 26 && NODE_MINOR >= 5)
|
|
15
|
+
|
|
16
|
+
// @datadog/native-metrics is only needed on Node versions where
|
|
17
|
+
// monitorEventLoopDelay's samplePerIteration option is unavailable.
|
|
18
|
+
// TODO: remove @datadog/native-metrics and this branch once Node < 26.5 is no longer supported.
|
|
19
|
+
const NATIVE_METRICS_REQUIRED = !EVENT_LOOP_SAMPLE_PER_ITERATION_AVAILABLE
|
|
14
20
|
|
|
15
21
|
let nativeMetrics = null
|
|
16
22
|
let gcObserver = null
|
|
@@ -45,7 +51,10 @@ module.exports = {
|
|
|
45
51
|
startGCObserver()
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
// When per-iteration sampling is available we prefer it over the native
|
|
55
|
+
// addon: it provides accurate event loop delay measurements and lets us
|
|
56
|
+
// collect CPU/GC/heap metrics entirely from JS APIs.
|
|
57
|
+
const useNative = NATIVE_METRICS_REQUIRED && config.runtimeMetrics.native !== false
|
|
49
58
|
|
|
50
59
|
if (useNative) {
|
|
51
60
|
// Using no-gc prevents the native gc metrics from being tracked. Not
|
|
@@ -74,7 +83,10 @@ module.exports = {
|
|
|
74
83
|
lastCpuUsage = process.cpuUsage()
|
|
75
84
|
|
|
76
85
|
if (trackEventLoop) {
|
|
77
|
-
eventLoopDelayObserver = monitorEventLoopDelay({
|
|
86
|
+
eventLoopDelayObserver = monitorEventLoopDelay({
|
|
87
|
+
resolution: eventLoopDelayResolution,
|
|
88
|
+
samplePerIteration: EVENT_LOOP_SAMPLE_PER_ITERATION_AVAILABLE,
|
|
89
|
+
})
|
|
78
90
|
eventLoopDelayObserver.enable()
|
|
79
91
|
}
|
|
80
92
|
|
|
@@ -83,11 +95,6 @@ module.exports = {
|
|
|
83
95
|
captureCommonMetrics(trackEventLoop)
|
|
84
96
|
captureHeapSpace()
|
|
85
97
|
if (trackEventLoop) {
|
|
86
|
-
// Experimental: The Node.js implementation deviates from the native metrics.
|
|
87
|
-
// We normalize the metrics to the same format but the Node.js values
|
|
88
|
-
// are that way lower than they should be, while they are still nearer
|
|
89
|
-
// to the native ones that way.
|
|
90
|
-
// We use these only as fallback values.
|
|
91
98
|
captureEventLoopDelay()
|
|
92
99
|
}
|
|
93
100
|
client.flush()
|
|
@@ -195,12 +202,14 @@ function captureEventLoopDelay () {
|
|
|
195
202
|
eventLoopDelayObserver.disable()
|
|
196
203
|
|
|
197
204
|
if (eventLoopDelayObserver.count !== 0) {
|
|
198
|
-
|
|
205
|
+
// Node.js versions without iteration-based metrics use the default sampling method,
|
|
206
|
+
// which is interval-based and requires normalization because its values are much smaller
|
|
207
|
+
// than those from the original native implementation and iteration-based metrics.
|
|
208
|
+
const minimum = EVENT_LOOP_SAMPLE_PER_ITERATION_AVAILABLE ? 0 : eventLoopDelayResolution * 1e6
|
|
199
209
|
const avg = Math.max(eventLoopDelayObserver.mean - minimum, 0)
|
|
200
210
|
const sum = Math.round(avg * eventLoopDelayObserver.count)
|
|
201
211
|
|
|
202
212
|
if (sum !== 0) {
|
|
203
|
-
// Normalize the metrics to the same format as the native metrics.
|
|
204
213
|
const stats = {
|
|
205
214
|
min: Math.max(eventLoopDelayObserver.min - minimum, 0),
|
|
206
215
|
max: Math.max(eventLoopDelayObserver.max - minimum, 0),
|
|
@@ -214,7 +223,7 @@ function captureEventLoopDelay () {
|
|
|
214
223
|
histogram('runtime.node.event_loop.delay', stats)
|
|
215
224
|
}
|
|
216
225
|
}
|
|
217
|
-
eventLoopDelayObserver
|
|
226
|
+
eventLoopDelayObserver.reset()
|
|
218
227
|
eventLoopDelayObserver.enable()
|
|
219
228
|
}
|
|
220
229
|
|