dd-trace 5.104.0 → 5.105.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 +90 -102
- package/index.d.ts +82 -3
- package/package.json +15 -15
- package/packages/datadog-core/src/storage.js +1 -1
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/ai.js +8 -7
- package/packages/datadog-instrumentations/src/aws-sdk.js +13 -0
- package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
- package/packages/datadog-instrumentations/src/cucumber.js +78 -5
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -62
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
- package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +37 -236
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +360 -150
- package/packages/datadog-instrumentations/src/kafkajs.js +120 -16
- package/packages/datadog-instrumentations/src/mocha/main.js +128 -17
- package/packages/datadog-instrumentations/src/nats.js +182 -0
- package/packages/datadog-instrumentations/src/nyc.js +38 -1
- package/packages/datadog-instrumentations/src/openai.js +33 -18
- package/packages/datadog-instrumentations/src/oracledb.js +6 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +515 -292
- package/packages/datadog-instrumentations/src/router.js +76 -32
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
- package/packages/datadog-plugin-bunyan/src/index.js +28 -0
- package/packages/datadog-plugin-cucumber/src/index.js +17 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +199 -28
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +2 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
- package/packages/datadog-plugin-http/src/server.js +40 -15
- package/packages/datadog-plugin-jest/src/index.js +11 -3
- package/packages/datadog-plugin-jest/src/util.js +15 -8
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -0
- package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +19 -4
- package/packages/datadog-plugin-mongodb-core/src/index.js +281 -40
- package/packages/datadog-plugin-nats/src/consumer.js +43 -0
- package/packages/datadog-plugin-nats/src/index.js +20 -0
- package/packages/datadog-plugin-nats/src/producer.js +62 -0
- package/packages/datadog-plugin-nats/src/util.js +33 -0
- package/packages/datadog-plugin-next/src/index.js +5 -3
- package/packages/datadog-plugin-openai/src/tracing.js +15 -2
- package/packages/datadog-plugin-oracledb/src/index.js +13 -2
- package/packages/datadog-plugin-pino/src/index.js +42 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -4
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +33 -44
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +5 -13
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +33 -40
- package/packages/dd-trace/src/aiguard/index.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +1 -1
- package/packages/dd-trace/src/appsec/reporter.js +5 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
- package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
- package/packages/dd-trace/src/baggage.js +7 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -2
- package/packages/dd-trace/src/config/supported-configurations.json +27 -8
- package/packages/dd-trace/src/datastreams/writer.js +2 -4
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
- package/packages/dd-trace/src/encode/0.4.js +124 -108
- package/packages/dd-trace/src/encode/0.5.js +114 -26
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +31 -23
- package/packages/dd-trace/src/encode/agentless-json.js +4 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
- package/packages/dd-trace/src/encode/span-stats.js +16 -16
- package/packages/dd-trace/src/encode/tags-processors.js +16 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +0 -16
- package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
- package/packages/dd-trace/src/llmobs/tagger.js +9 -1
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/util.js +66 -3
- package/packages/dd-trace/src/log/index.js +1 -1
- package/packages/dd-trace/src/msgpack/chunk.js +394 -10
- package/packages/dd-trace/src/msgpack/index.js +96 -2
- package/packages/dd-trace/src/openfeature/encoding.js +70 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
- package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +49 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -20
- package/packages/dd-trace/src/plugins/database.js +7 -6
- package/packages/dd-trace/src/plugins/index.js +4 -0
- package/packages/dd-trace/src/plugins/log_injection.js +56 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -48
- package/packages/dd-trace/src/plugins/outbound.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +15 -17
- package/packages/dd-trace/src/plugins/tracing.js +43 -5
- package/packages/dd-trace/src/plugins/util/test.js +236 -13
- package/packages/dd-trace/src/plugins/util/web.js +79 -65
- package/packages/dd-trace/src/priority_sampler.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
- package/packages/dd-trace/src/sampling_rule.js +7 -7
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
- package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
- package/packages/dd-trace/src/span_format.js +190 -58
- package/packages/dd-trace/src/spanleak.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -3
- package/packages/dd-trace/src/tagger.js +0 -2
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
- package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/dd-trace/src/msgpack/encoder.js +0 -308
- package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
|
@@ -109,7 +109,7 @@ function matcher (pattern, locator) {
|
|
|
109
109
|
* @returns {Locator}
|
|
110
110
|
*/
|
|
111
111
|
function makeTagLocator (tag) {
|
|
112
|
-
return (span) => span.context().
|
|
112
|
+
return (span) => span.context().getTag(tag)
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/**
|
|
@@ -129,9 +129,9 @@ function nameLocator (span) {
|
|
|
129
129
|
* @returns {string|undefined}
|
|
130
130
|
*/
|
|
131
131
|
function serviceLocator (span) {
|
|
132
|
-
const
|
|
133
|
-
return
|
|
134
|
-
|
|
132
|
+
const context = span.context()
|
|
133
|
+
return context.getTag('service') ||
|
|
134
|
+
context.getTag('service.name') ||
|
|
135
135
|
span.tracer()._service
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -142,9 +142,9 @@ function serviceLocator (span) {
|
|
|
142
142
|
* @returns {string|undefined}
|
|
143
143
|
*/
|
|
144
144
|
function resourceLocator (span) {
|
|
145
|
-
const
|
|
146
|
-
return
|
|
147
|
-
|
|
145
|
+
const context = span.context()
|
|
146
|
+
return context.getTag('resource') ||
|
|
147
|
+
context.getTag('resource.name')
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
/**
|
|
@@ -55,6 +55,11 @@ const messaging = {
|
|
|
55
55
|
serviceName: ({ tracerService }) => `${tracerService}-kafka`,
|
|
56
56
|
serviceSource: integrationSource('kafka'),
|
|
57
57
|
},
|
|
58
|
+
nats: {
|
|
59
|
+
opName: () => 'nats.publish',
|
|
60
|
+
serviceName: ({ tracerService }) => `${tracerService}-nats`,
|
|
61
|
+
serviceSource: integrationSource('nats'),
|
|
62
|
+
},
|
|
58
63
|
rhea: {
|
|
59
64
|
opName: () => 'amqp.send',
|
|
60
65
|
serviceName: ({ tracerService }) => `${tracerService}-amqp-producer`,
|
|
@@ -119,6 +124,11 @@ const messaging = {
|
|
|
119
124
|
serviceName: ({ tracerService }) => `${tracerService}-kafka`,
|
|
120
125
|
serviceSource: integrationSource('kafka'),
|
|
121
126
|
},
|
|
127
|
+
nats: {
|
|
128
|
+
opName: () => 'nats.consume',
|
|
129
|
+
serviceName: ({ tracerService }) => `${tracerService}-nats`,
|
|
130
|
+
serviceSource: integrationSource('nats'),
|
|
131
|
+
},
|
|
122
132
|
rhea: {
|
|
123
133
|
opName: () => 'amqp.receive',
|
|
124
134
|
serviceName: identityService,
|
|
@@ -44,6 +44,10 @@ const messaging = {
|
|
|
44
44
|
opName: () => 'kafka.send',
|
|
45
45
|
serviceName: identityService,
|
|
46
46
|
},
|
|
47
|
+
nats: {
|
|
48
|
+
opName: () => 'nats.send',
|
|
49
|
+
serviceName: identityService,
|
|
50
|
+
},
|
|
47
51
|
rhea: amqpOutbound,
|
|
48
52
|
sqs: {
|
|
49
53
|
opName: () => 'aws.sqs.send',
|
|
@@ -89,6 +93,10 @@ const messaging = {
|
|
|
89
93
|
opName: () => 'kafka.process',
|
|
90
94
|
serviceName: identityService,
|
|
91
95
|
},
|
|
96
|
+
nats: {
|
|
97
|
+
opName: () => 'nats.process',
|
|
98
|
+
serviceName: identityService,
|
|
99
|
+
},
|
|
92
100
|
rhea: amqpInbound,
|
|
93
101
|
sqs: {
|
|
94
102
|
opName: () => 'aws.sqs.process',
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { SVC_SRC_KEY } = require('../constants')
|
|
4
|
+
|
|
5
|
+
const INTEGRATION_SERVICE = Symbol('dd.integrationService')
|
|
6
|
+
const MANUAL = 'm'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Reconcile `_dd.svc_src` against the span's final `service.name`. Called from
|
|
10
|
+
* `Span#finish` once all writes are in.
|
|
11
|
+
*
|
|
12
|
+
* Rules:
|
|
13
|
+
* - service.name equals the tracer default → clear any svc_src
|
|
14
|
+
* - integration marker exists and equals current service.name → integration
|
|
15
|
+
* owns the value; leave the source label the integration set
|
|
16
|
+
* - otherwise → user wrote (no marker) or overrode the integration value;
|
|
17
|
+
* stamp 'm'
|
|
18
|
+
*
|
|
19
|
+
* @param {object} span Internal DatadogSpan instance.
|
|
20
|
+
* @param {string|undefined} tracerService The tracer's configured default service.
|
|
21
|
+
*/
|
|
22
|
+
function resolveServiceSource (span, tracerService) {
|
|
23
|
+
const spanContext = span._spanContext
|
|
24
|
+
const currentService = spanContext.getTag('service.name')
|
|
25
|
+
const existingSource = spanContext.getTag(SVC_SRC_KEY)
|
|
26
|
+
|
|
27
|
+
if (currentService === tracerService) {
|
|
28
|
+
if (existingSource === undefined) return
|
|
29
|
+
spanContext.deleteTag(SVC_SRC_KEY)
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const marker = span[INTEGRATION_SERVICE]
|
|
34
|
+
|
|
35
|
+
if (marker === currentService) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
spanContext.setTag(SVC_SRC_KEY, MANUAL)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = {
|
|
43
|
+
INTEGRATION_SERVICE,
|
|
44
|
+
MANUAL,
|
|
45
|
+
resolveServiceSource,
|
|
46
|
+
}
|
|
@@ -30,14 +30,6 @@ const ERROR_STACK = constants.ERROR_STACK
|
|
|
30
30
|
const ERROR_TYPE = constants.ERROR_TYPE
|
|
31
31
|
const { IGNORE_OTEL_ERROR } = constants
|
|
32
32
|
|
|
33
|
-
// TODO(BridgeAR)[31.03.2025]: Should these land in the constants file?
|
|
34
|
-
const map = {
|
|
35
|
-
'operation.name': 'name',
|
|
36
|
-
'service.name': 'service',
|
|
37
|
-
'span.type': 'type',
|
|
38
|
-
'resource.name': 'resource',
|
|
39
|
-
}
|
|
40
|
-
|
|
41
33
|
/**
|
|
42
34
|
* @typedef {object} FormattedSpan
|
|
43
35
|
* @property {import('./id').Identifier} trace_id
|
|
@@ -45,6 +37,8 @@ const map = {
|
|
|
45
37
|
* @property {import('./id').Identifier} parent_id
|
|
46
38
|
* @property {string} name
|
|
47
39
|
* @property {string} resource
|
|
40
|
+
* @property {string | undefined} service
|
|
41
|
+
* @property {string | undefined} type
|
|
48
42
|
* @property {number} error
|
|
49
43
|
* @property {Record<string, string>} meta
|
|
50
44
|
* @property {Record<string, number>} metrics
|
|
@@ -52,7 +46,12 @@ const map = {
|
|
|
52
46
|
* @property {number} start
|
|
53
47
|
* @property {number} duration
|
|
54
48
|
* @property {Array} links
|
|
55
|
-
* @property {Array<
|
|
49
|
+
* @property {Array<SpanEvent> | undefined} span_events
|
|
50
|
+
*
|
|
51
|
+
* @typedef {object} SpanEvent
|
|
52
|
+
* @property {string} name
|
|
53
|
+
* @property {number} time_unix_nano
|
|
54
|
+
* @property {Record<string, string>} [attributes]
|
|
56
55
|
*/
|
|
57
56
|
|
|
58
57
|
function format (span, isFirstSpanInChunk = false, tagForFirstSpanInChunk = false) {
|
|
@@ -61,7 +60,9 @@ function format (span, isFirstSpanInChunk = false, tagForFirstSpanInChunk = fals
|
|
|
61
60
|
extractSpanLinks(formatted, span)
|
|
62
61
|
extractSpanEvents(formatted, span)
|
|
63
62
|
extractRootTags(formatted, span)
|
|
64
|
-
|
|
63
|
+
if (isFirstSpanInChunk) {
|
|
64
|
+
extractChunkTags(formatted, span, tagForFirstSpanInChunk)
|
|
65
|
+
}
|
|
65
66
|
extractTags(formatted, span)
|
|
66
67
|
|
|
67
68
|
return formatted
|
|
@@ -69,13 +70,18 @@ function format (span, isFirstSpanInChunk = false, tagForFirstSpanInChunk = fals
|
|
|
69
70
|
|
|
70
71
|
function formatSpan (span) {
|
|
71
72
|
const spanContext = span.context()
|
|
72
|
-
|
|
73
|
+
// Pre-initialise the `service`, `type`, and `span_events` slots so every
|
|
74
|
+
// formatted span shares one V8 hidden class regardless of which optional
|
|
75
|
+
// tags fire later. Downstream encoders gate on truthy values for each,
|
|
76
|
+
// so `undefined` stays byte-identical on the msgpack wire.
|
|
73
77
|
return {
|
|
74
78
|
trace_id: spanContext._traceId,
|
|
75
79
|
span_id: spanContext._spanId,
|
|
76
80
|
parent_id: spanContext._parentId || id('0'),
|
|
77
81
|
name: String(spanContext._name),
|
|
78
82
|
resource: String(spanContext._name),
|
|
83
|
+
service: undefined,
|
|
84
|
+
type: undefined,
|
|
79
85
|
error: 0,
|
|
80
86
|
meta: {},
|
|
81
87
|
meta_struct: span.meta_struct,
|
|
@@ -83,14 +89,22 @@ function formatSpan (span) {
|
|
|
83
89
|
start: Math.round(span._startTime * 1e6),
|
|
84
90
|
duration: Math.round(span._duration * 1e6),
|
|
85
91
|
links: [],
|
|
92
|
+
span_events: undefined,
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
|
|
89
|
-
function setSingleSpanIngestionTags (
|
|
96
|
+
function setSingleSpanIngestionTags (formattedSpan, options) {
|
|
90
97
|
if (!options) return
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
const metrics = formattedSpan.metrics
|
|
99
|
+
metrics[SPAN_SAMPLING_MECHANISM] = SAMPLING_MECHANISM_SPAN
|
|
100
|
+
const sampleRate = options.sampleRate
|
|
101
|
+
if (typeof sampleRate === 'number') {
|
|
102
|
+
metrics[SPAN_SAMPLING_RULE_RATE] = sampleRate
|
|
103
|
+
}
|
|
104
|
+
const maxPerSecond = options.maxPerSecond
|
|
105
|
+
if (typeof maxPerSecond === 'number') {
|
|
106
|
+
metrics[SPAN_SAMPLING_MAX_PER_SECOND] = maxPerSecond
|
|
107
|
+
}
|
|
94
108
|
}
|
|
95
109
|
|
|
96
110
|
/**
|
|
@@ -144,12 +158,14 @@ function extractTags (formattedSpan, span) {
|
|
|
144
158
|
const origin = context._trace.origin
|
|
145
159
|
// TODO(BridgeAR)[31.03.2025]: Look into changing the way we store tags. Using
|
|
146
160
|
// a map is likely faster short term.
|
|
147
|
-
const tags = context.
|
|
161
|
+
const tags = context.getTags()
|
|
148
162
|
const hostname = context._hostname
|
|
149
163
|
const priority = context._sampling.priority
|
|
164
|
+
const meta = formattedSpan.meta
|
|
165
|
+
const metrics = formattedSpan.metrics
|
|
150
166
|
|
|
151
167
|
if (tags['span.kind'] && tags['span.kind'] !== 'internal') {
|
|
152
|
-
|
|
168
|
+
metrics[MEASURED] = 1
|
|
153
169
|
}
|
|
154
170
|
|
|
155
171
|
const tracerService = span.tracer()._service.toLowerCase()
|
|
@@ -159,27 +175,51 @@ function extractTags (formattedSpan, span) {
|
|
|
159
175
|
registerExtraService(tags['service.name'])
|
|
160
176
|
}
|
|
161
177
|
|
|
162
|
-
for (const
|
|
163
|
-
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
//
|
|
178
|
+
for (const tag of Object.keys(tags)) {
|
|
179
|
+
const value = tags[tag]
|
|
180
|
+
// The typed-helper bodies are inlined per case: V8 was not inlining
|
|
181
|
+
// `addStringTag` / `addNumberTag` / `addMixedTag` here at the call rate
|
|
182
|
+
// this loop runs in HTTP-server traces (10+ tags × 1M spans/sec), so each
|
|
183
|
+
// one paid an extra call frame the helper body was small enough to
|
|
184
|
+
// expand inline.
|
|
167
185
|
switch (tag) {
|
|
168
186
|
case 'service.name':
|
|
187
|
+
if (typeof value === 'string') {
|
|
188
|
+
formattedSpan.service = value.length > MAX_META_VALUE_LENGTH
|
|
189
|
+
? `${value.slice(0, MAX_META_VALUE_LENGTH)}...`
|
|
190
|
+
: value
|
|
191
|
+
}
|
|
192
|
+
break
|
|
169
193
|
case 'span.type':
|
|
194
|
+
if (typeof value === 'string') {
|
|
195
|
+
formattedSpan.type = value.length > MAX_META_VALUE_LENGTH
|
|
196
|
+
? `${value.slice(0, MAX_META_VALUE_LENGTH)}...`
|
|
197
|
+
: value
|
|
198
|
+
}
|
|
199
|
+
break
|
|
170
200
|
case 'resource.name':
|
|
171
|
-
|
|
201
|
+
if (typeof value === 'string') {
|
|
202
|
+
formattedSpan.resource = value.length > MAX_META_VALUE_LENGTH
|
|
203
|
+
? `${value.slice(0, MAX_META_VALUE_LENGTH)}...`
|
|
204
|
+
: value
|
|
205
|
+
}
|
|
172
206
|
break
|
|
173
207
|
// HACK: remove when Datadog supports numeric status code
|
|
174
|
-
case 'http.status_code':
|
|
175
|
-
|
|
208
|
+
case 'http.status_code': {
|
|
209
|
+
const stringValue = value && String(value)
|
|
210
|
+
if (typeof stringValue === 'string') {
|
|
211
|
+
meta[tag] = stringValue.length > MAX_META_VALUE_LENGTH
|
|
212
|
+
? `${stringValue.slice(0, MAX_META_VALUE_LENGTH)}...`
|
|
213
|
+
: stringValue
|
|
214
|
+
}
|
|
176
215
|
break
|
|
216
|
+
}
|
|
177
217
|
case 'analytics.event':
|
|
178
|
-
|
|
218
|
+
metrics[ANALYTICS] = value === undefined || value ? 1 : 0
|
|
179
219
|
break
|
|
180
220
|
case HOSTNAME_KEY:
|
|
181
221
|
case MEASURED:
|
|
182
|
-
|
|
222
|
+
metrics[tag] = value === undefined || value ? 1 : 0
|
|
183
223
|
break
|
|
184
224
|
// TODO(BridgeAR)[31.03.2025]: How come we use two different ways to pass
|
|
185
225
|
// through errors? Can we just unify the behavior to always use one way?
|
|
@@ -190,52 +230,115 @@ function extractTags (formattedSpan, span) {
|
|
|
190
230
|
break
|
|
191
231
|
case ERROR_TYPE:
|
|
192
232
|
case ERROR_MESSAGE:
|
|
193
|
-
case ERROR_STACK:
|
|
233
|
+
case ERROR_STACK: {
|
|
194
234
|
// HACK: remove when implemented in the backend
|
|
195
|
-
if (context._name === 'fs.operation')
|
|
196
|
-
break
|
|
197
|
-
}
|
|
235
|
+
if (context._name === 'fs.operation') break
|
|
198
236
|
// otel.recordException should not influence trace.error
|
|
199
237
|
if (!tags[IGNORE_OTEL_ERROR]) {
|
|
200
238
|
formattedSpan.error = 1
|
|
201
239
|
}
|
|
202
|
-
|
|
203
|
-
|
|
240
|
+
if (value != null) writeErrorMeta(meta, tag, value)
|
|
241
|
+
break
|
|
242
|
+
}
|
|
243
|
+
default: {
|
|
244
|
+
const valueType = typeof value
|
|
245
|
+
if (valueType === 'string') {
|
|
246
|
+
let writeKey = tag
|
|
247
|
+
if (writeKey.length > MAX_META_KEY_LENGTH) {
|
|
248
|
+
writeKey = `${writeKey.slice(0, MAX_META_KEY_LENGTH)}...`
|
|
249
|
+
}
|
|
250
|
+
meta[writeKey] = value.length > MAX_META_VALUE_LENGTH
|
|
251
|
+
? `${value.slice(0, MAX_META_VALUE_LENGTH)}...`
|
|
252
|
+
: value
|
|
253
|
+
} else if (valueType === 'number') {
|
|
254
|
+
if (!Number.isNaN(value)) {
|
|
255
|
+
let writeKey = tag
|
|
256
|
+
if (writeKey.length > MAX_METRIC_KEY_LENGTH) {
|
|
257
|
+
writeKey = `${writeKey.slice(0, MAX_METRIC_KEY_LENGTH)}...`
|
|
258
|
+
}
|
|
259
|
+
metrics[writeKey] = value
|
|
260
|
+
}
|
|
261
|
+
} else if (valueType === 'boolean') {
|
|
262
|
+
let writeKey = tag
|
|
263
|
+
if (writeKey.length > MAX_METRIC_KEY_LENGTH) {
|
|
264
|
+
writeKey = `${writeKey.slice(0, MAX_METRIC_KEY_LENGTH)}...`
|
|
265
|
+
}
|
|
266
|
+
metrics[writeKey] = value ? 1 : 0
|
|
267
|
+
} else {
|
|
268
|
+
addMixedTag(meta, metrics, tag, value)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
204
271
|
}
|
|
205
272
|
}
|
|
206
273
|
setSingleSpanIngestionTags(formattedSpan, context._spanSampling)
|
|
207
274
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
275
|
+
meta.language = 'javascript'
|
|
276
|
+
metrics[PROCESS_ID] = process.pid
|
|
277
|
+
if (typeof priority === 'number') {
|
|
278
|
+
metrics[SAMPLING_PRIORITY_KEY] = priority
|
|
279
|
+
}
|
|
280
|
+
if (typeof origin === 'string') {
|
|
281
|
+
meta[ORIGIN_KEY] = origin.length > MAX_META_VALUE_LENGTH
|
|
282
|
+
? `${origin.slice(0, MAX_META_VALUE_LENGTH)}...`
|
|
283
|
+
: origin
|
|
284
|
+
}
|
|
285
|
+
if (typeof hostname === 'string') {
|
|
286
|
+
meta[HOSTNAME_KEY] = hostname.length > MAX_META_VALUE_LENGTH
|
|
287
|
+
? `${hostname.slice(0, MAX_META_VALUE_LENGTH)}...`
|
|
288
|
+
: hostname
|
|
289
|
+
}
|
|
213
290
|
}
|
|
214
291
|
|
|
215
292
|
function extractRootTags (formattedSpan, span) {
|
|
216
293
|
const context = span.context()
|
|
217
|
-
const isLocalRoot = span === context._trace.started[0]
|
|
218
294
|
const parentId = context._parentId
|
|
219
295
|
|
|
220
|
-
if (
|
|
296
|
+
if (span !== context._trace.started[0] || (parentId && parentId.toString(10) !== '0')) return
|
|
221
297
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
298
|
+
const trace = context._trace
|
|
299
|
+
const metrics = formattedSpan.metrics
|
|
300
|
+
const ruleDecision = trace[SAMPLING_RULE_DECISION]
|
|
301
|
+
if (typeof ruleDecision === 'number') {
|
|
302
|
+
metrics[SAMPLING_RULE_DECISION] = ruleDecision
|
|
303
|
+
}
|
|
304
|
+
const limitDecision = trace[SAMPLING_LIMIT_DECISION]
|
|
305
|
+
if (typeof limitDecision === 'number') {
|
|
306
|
+
metrics[SAMPLING_LIMIT_DECISION] = limitDecision
|
|
307
|
+
}
|
|
308
|
+
const agentDecision = trace[SAMPLING_AGENT_DECISION]
|
|
309
|
+
if (typeof agentDecision === 'number') {
|
|
310
|
+
metrics[SAMPLING_AGENT_DECISION] = agentDecision
|
|
311
|
+
}
|
|
312
|
+
metrics[TOP_LEVEL_KEY] = 1
|
|
226
313
|
}
|
|
227
314
|
|
|
228
|
-
function extractChunkTags (formattedSpan, span,
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
addTag(formattedSpan.meta, formattedSpan.metrics, TRACING_FIELD_NAME, tagForFirstSpanInChunk)
|
|
315
|
+
function extractChunkTags (formattedSpan, span, tagForFirstSpanInChunk) {
|
|
316
|
+
const meta = formattedSpan.meta
|
|
317
|
+
if (typeof tagForFirstSpanInChunk === 'string') {
|
|
318
|
+
meta[TRACING_FIELD_NAME] = tagForFirstSpanInChunk.length > MAX_META_VALUE_LENGTH
|
|
319
|
+
? `${tagForFirstSpanInChunk.slice(0, MAX_META_VALUE_LENGTH)}...`
|
|
320
|
+
: tagForFirstSpanInChunk
|
|
235
321
|
}
|
|
236
322
|
|
|
237
|
-
|
|
238
|
-
|
|
323
|
+
// Chunk tags are always strings in production (`_dd.p.dm`, `_dd.p.tid`,
|
|
324
|
+
// `_dd.p.ts`, `baggage.*`). Inline only the string branch; non-string
|
|
325
|
+
// values fall through to `addMixedTag` so we don't carry duplicate
|
|
326
|
+
// truncation logic for branches no real chunk tag ever takes.
|
|
327
|
+
const metrics = formattedSpan.metrics
|
|
328
|
+
const traceTags = span.context()._trace.tags
|
|
329
|
+
for (const key of Object.keys(traceTags)) {
|
|
330
|
+
const value = traceTags[key]
|
|
331
|
+
if (typeof value === 'string') {
|
|
332
|
+
let writeKey = key
|
|
333
|
+
if (writeKey.length > MAX_META_KEY_LENGTH) {
|
|
334
|
+
writeKey = `${writeKey.slice(0, MAX_META_KEY_LENGTH)}...`
|
|
335
|
+
}
|
|
336
|
+
meta[writeKey] = value.length > MAX_META_VALUE_LENGTH
|
|
337
|
+
? `${value.slice(0, MAX_META_VALUE_LENGTH)}...`
|
|
338
|
+
: value
|
|
339
|
+
} else {
|
|
340
|
+
addMixedTag(meta, metrics, key, value)
|
|
341
|
+
}
|
|
239
342
|
}
|
|
240
343
|
}
|
|
241
344
|
|
|
@@ -248,13 +351,42 @@ function extractError (formattedSpan, error) {
|
|
|
248
351
|
// AggregateError only has a code and no message.
|
|
249
352
|
// TODO(BridgeAR)[31.03.2025]: An AggregateError can have a message. Should
|
|
250
353
|
// the code just generally be added, if available?
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
354
|
+
const meta = formattedSpan.meta
|
|
355
|
+
const message = error.message || error.code
|
|
356
|
+
if (message != null) writeErrorMeta(meta, ERROR_MESSAGE, message)
|
|
357
|
+
if (error.name != null) writeErrorMeta(meta, ERROR_TYPE, error.name)
|
|
358
|
+
if (error.stack != null) writeErrorMeta(meta, ERROR_STACK, error.stack)
|
|
254
359
|
}
|
|
255
360
|
}
|
|
256
361
|
|
|
257
|
-
|
|
362
|
+
/**
|
|
363
|
+
* Coerces `value` to string and truncates at `MAX_META_VALUE_LENGTH` before
|
|
364
|
+
* writing it to one of the three error meta fields.
|
|
365
|
+
*
|
|
366
|
+
* @param {Record<string, string>} meta
|
|
367
|
+
* @param {string} key
|
|
368
|
+
* @param {unknown} value
|
|
369
|
+
*/
|
|
370
|
+
function writeErrorMeta (meta, key, value) {
|
|
371
|
+
const stringValue = typeof value === 'string' ? value : String(value)
|
|
372
|
+
meta[key] = stringValue.length > MAX_META_VALUE_LENGTH
|
|
373
|
+
? `${stringValue.slice(0, MAX_META_VALUE_LENGTH)}...`
|
|
374
|
+
: stringValue
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Mixed-type dispatch retained for `extractError` and the slow-path fallback
|
|
379
|
+
* inside the inlined per-tag loops in `extractTags` / `extractChunkTags`.
|
|
380
|
+
* The scalar branches are kept here so a single `addMixedTag` call covers
|
|
381
|
+
* recursion (nested object values) without re-entering the inlined paths.
|
|
382
|
+
*
|
|
383
|
+
* @param {Record<string, string>} meta
|
|
384
|
+
* @param {Record<string, number>} metrics
|
|
385
|
+
* @param {string} key
|
|
386
|
+
* @param {unknown} value
|
|
387
|
+
* @param {boolean} [nested]
|
|
388
|
+
*/
|
|
389
|
+
function addMixedTag (meta, metrics, key, value, nested) {
|
|
258
390
|
switch (typeof value) {
|
|
259
391
|
case 'string':
|
|
260
392
|
if (key.length > MAX_META_KEY_LENGTH) {
|
|
@@ -290,7 +422,7 @@ function addTag (meta, metrics, key, value, nested) {
|
|
|
290
422
|
metrics[key] = value.toString()
|
|
291
423
|
} else if (!Array.isArray(value) && !nested) {
|
|
292
424
|
for (const [prop, val] of Object.entries(value)) {
|
|
293
|
-
|
|
425
|
+
addMixedTag(meta, metrics, `${key}.${prop}`, val, true)
|
|
294
426
|
}
|
|
295
427
|
}
|
|
296
428
|
}
|
|
@@ -66,7 +66,7 @@ module.exports.startScrubber = function () {
|
|
|
66
66
|
if (!gc) continue // everything after this point is related to manual GC
|
|
67
67
|
|
|
68
68
|
// TODO: what else can we do to alleviate memory usage
|
|
69
|
-
span.context().
|
|
69
|
+
span.context().clearTags()
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
console.log('expired spans:' +
|
|
@@ -29,12 +29,12 @@ function configure (config) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function onSpanStart ({ span, fields }) {
|
|
32
|
-
const
|
|
33
|
-
if (!
|
|
32
|
+
const context = span.context?.()
|
|
33
|
+
if (!context) return
|
|
34
34
|
|
|
35
35
|
const { parent } = fields
|
|
36
36
|
if (!parent || parent._isRemote) {
|
|
37
|
-
|
|
37
|
+
context.setTag(APM_TRACING_ENABLED_KEY, 0)
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|