dd-trace 5.104.0 → 5.106.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 +16 -2
- 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-worker-threads.js +19 -0
- package/packages/datadog-instrumentations/src/cucumber.js +390 -157
- 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-aws-sdk/src/services/bedrockruntime/tracing.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +218 -4
- 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/id.js +15 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +92 -6
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +43 -21
- 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/opentelemetry/trace/otlp_transformer.js +22 -3
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +64 -77
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +50 -3
- 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/config.js +10 -23
- package/packages/dd-trace/src/profiling/exporters/agent.js +11 -10
- package/packages/dd-trace/src/profiling/profiler.js +21 -11
- package/packages/dd-trace/src/profiling/profilers/wall.js +12 -7
- 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
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { channel } = require('dc-polyfill')
|
|
4
|
+
const log = require('../log')
|
|
5
|
+
const { SpanEnrichmentState } = require('./span-enrichment')
|
|
6
|
+
|
|
7
|
+
const finishCh = channel('dd-trace:span:finish')
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* OpenFeature hook that enriches APM spans with feature flag evaluation data.
|
|
11
|
+
*
|
|
12
|
+
* Implements the OpenFeature `finally` hook interface to capture flag evaluations
|
|
13
|
+
* and add span tags for observability. Tags are accumulated during the span's
|
|
14
|
+
* lifetime and applied when the root span finishes.
|
|
15
|
+
*
|
|
16
|
+
* Span tags added:
|
|
17
|
+
* - `ffe_flags_enc`: Base64 delta-varint encoded serial IDs
|
|
18
|
+
* - `ffe_subjects_enc`: JSON dict of SHA256(targeting_key) → encoded serial IDs
|
|
19
|
+
* - `ffe_runtime_defaults`: JSON dict of flag_key → default value string
|
|
20
|
+
*/
|
|
21
|
+
class SpanEnrichmentHook {
|
|
22
|
+
#tracer
|
|
23
|
+
/** @type {WeakMap<object, SpanEnrichmentState>} */
|
|
24
|
+
#spanStates = new WeakMap()
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Handler for span finish channel. Applies accumulated tags to the span.
|
|
28
|
+
* Arrow function to preserve `this` binding for channel subscription.
|
|
29
|
+
*
|
|
30
|
+
* @param {object} span - The span that is finishing
|
|
31
|
+
*/
|
|
32
|
+
#onSpanFinish = (span) => {
|
|
33
|
+
const state = this.#spanStates.get(span)
|
|
34
|
+
if (!state || !state.hasData()) return
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const tags = state.toSpanTags()
|
|
38
|
+
|
|
39
|
+
for (const [key, value] of Object.entries(tags)) {
|
|
40
|
+
if (value) {
|
|
41
|
+
span.setTag(key, value)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
log.warn('SpanEnrichmentHook: error applying span tags: %s', err.message)
|
|
46
|
+
} finally {
|
|
47
|
+
this.#spanStates.delete(span)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {import('../tracer')} tracer - Datadog tracer instance
|
|
53
|
+
*/
|
|
54
|
+
constructor (tracer) {
|
|
55
|
+
this.#tracer = tracer
|
|
56
|
+
finishCh.subscribe(this.#onSpanFinish)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Called by the OpenFeature SDK after every flag evaluation (success or error).
|
|
61
|
+
*
|
|
62
|
+
* @param {object} hookContext - Hook context containing the flag key and evaluation context
|
|
63
|
+
* @param {string} hookContext.flagKey - The flag key being evaluated
|
|
64
|
+
* @param {object} [hookContext.context] - Evaluation context
|
|
65
|
+
* @param {string} [hookContext.context.targetingKey] - Targeting key
|
|
66
|
+
* @param {object} evaluationDetails - Full evaluation details including flag metadata
|
|
67
|
+
* @param {object} [evaluationDetails.flagMetadata] - Metadata from the provider
|
|
68
|
+
* @param {number} [evaluationDetails.flagMetadata.__dd_split_serial_id] - Serial ID from UFC split
|
|
69
|
+
* @param {boolean} [evaluationDetails.flagMetadata.__dd_do_log] - Whether to log subject
|
|
70
|
+
* @param {string} [evaluationDetails.variant] - Variant key if flag was found in UFC
|
|
71
|
+
* @param {boolean|string|number|object} [evaluationDetails.value] - Evaluated value
|
|
72
|
+
* @returns {void}
|
|
73
|
+
*/
|
|
74
|
+
finally (hookContext, evaluationDetails) {
|
|
75
|
+
try {
|
|
76
|
+
const rootSpan = this._getRootSpan()
|
|
77
|
+
if (!rootSpan) return
|
|
78
|
+
|
|
79
|
+
const state = this._getOrCreateState(rootSpan)
|
|
80
|
+
const { flagKey, context } = hookContext || {}
|
|
81
|
+
const { flagMetadata, variant, value } = evaluationDetails || {}
|
|
82
|
+
|
|
83
|
+
const serialId = flagMetadata?.__dd_split_serial_id
|
|
84
|
+
const doLog = flagMetadata?.__dd_do_log ?? false
|
|
85
|
+
const targetingKey = context?.targetingKey
|
|
86
|
+
|
|
87
|
+
if (serialId != null) {
|
|
88
|
+
state.addSerialId(serialId)
|
|
89
|
+
|
|
90
|
+
if (doLog && targetingKey) {
|
|
91
|
+
state.addSubject(targetingKey, serialId)
|
|
92
|
+
}
|
|
93
|
+
} else if (variant === undefined) {
|
|
94
|
+
state.addDefault(flagKey, value)
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
log.warn('SpanEnrichmentHook: error in finally hook: %s', err.message)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get the root span for the current trace context.
|
|
103
|
+
* The root span is always the first span in trace.started since spans
|
|
104
|
+
* are added in creation order and the root is created first.
|
|
105
|
+
*
|
|
106
|
+
* @returns {object|null} The root span, or null if no active span
|
|
107
|
+
* @private
|
|
108
|
+
*/
|
|
109
|
+
_getRootSpan () {
|
|
110
|
+
const span = this.#tracer.scope().active()
|
|
111
|
+
if (!span) return null
|
|
112
|
+
|
|
113
|
+
const trace = span.context()._trace
|
|
114
|
+
|
|
115
|
+
return trace?.started?.[0] ?? span
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get or create enrichment state for a span.
|
|
120
|
+
*
|
|
121
|
+
* @param {object} span - The span to get state for
|
|
122
|
+
* @returns {SpanEnrichmentState} The enrichment state
|
|
123
|
+
* @private
|
|
124
|
+
*/
|
|
125
|
+
_getOrCreateState (span) {
|
|
126
|
+
let state = this.#spanStates.get(span)
|
|
127
|
+
if (!state) {
|
|
128
|
+
state = new SpanEnrichmentState()
|
|
129
|
+
this.#spanStates.set(span, state)
|
|
130
|
+
}
|
|
131
|
+
return state
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Cleanup method to unsubscribe from channels.
|
|
136
|
+
* Should be called when the provider is shut down.
|
|
137
|
+
*/
|
|
138
|
+
destroy () {
|
|
139
|
+
finishCh.unsubscribe(this.#onSpanFinish)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = SpanEnrichmentHook
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const log = require('../log')
|
|
4
|
+
|
|
5
|
+
const { encodeDeltaVarint, hashTargetingKey } = require('./encoding')
|
|
6
|
+
|
|
7
|
+
const MAX_SERIAL_IDS = 200
|
|
8
|
+
const MAX_SUBJECTS = 10
|
|
9
|
+
const MAX_EXPERIMENTS_PER_SUBJECT = 20
|
|
10
|
+
const MAX_DEFAULTS = 5
|
|
11
|
+
const MAX_DEFAULT_VALUE_LENGTH = 64
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Manages feature flag enrichment state for a single root span.
|
|
15
|
+
* Accumulates serial IDs, subjects, and defaults throughout the span's lifetime.
|
|
16
|
+
*/
|
|
17
|
+
class SpanEnrichmentState {
|
|
18
|
+
constructor () {
|
|
19
|
+
/** @type {Set<number>} */
|
|
20
|
+
this._serialIds = new Set()
|
|
21
|
+
|
|
22
|
+
/** @type {Map<string, Set<number>>} hashed targeting key -> serial IDs */
|
|
23
|
+
this._subjects = new Map()
|
|
24
|
+
|
|
25
|
+
/** @type {Map<string, string>} flag key -> runtime default value */
|
|
26
|
+
this._defaults = new Map()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Add a serial ID from a flag evaluation.
|
|
31
|
+
*
|
|
32
|
+
* @param {number} serialId - The serial ID to add
|
|
33
|
+
* @returns {boolean} True if added, false if limit reached
|
|
34
|
+
*/
|
|
35
|
+
addSerialId (serialId) {
|
|
36
|
+
if (this._serialIds.size >= MAX_SERIAL_IDS) {
|
|
37
|
+
log.debug('SpanEnrichment: MAX_SERIAL_IDS limit (%d) reached, dropping serialId %d', MAX_SERIAL_IDS, serialId)
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
this._serialIds.add(serialId)
|
|
41
|
+
return true
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Add a subject (targeting key) with its associated serial ID.
|
|
46
|
+
* Only called when doLog=true.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} targetingKey - The targeting key (will be hashed)
|
|
49
|
+
* @param {number} serialId - The serial ID associated with this evaluation
|
|
50
|
+
* @returns {boolean} True if added, false if limit reached
|
|
51
|
+
*/
|
|
52
|
+
addSubject (targetingKey, serialId) {
|
|
53
|
+
const hashedKey = hashTargetingKey(targetingKey)
|
|
54
|
+
|
|
55
|
+
if (this._subjects.has(hashedKey)) {
|
|
56
|
+
const subjectIds = this._subjects.get(hashedKey)
|
|
57
|
+
if (subjectIds.size >= MAX_EXPERIMENTS_PER_SUBJECT) {
|
|
58
|
+
log.debug('SpanEnrichment: MAX_EXPERIMENTS_PER_SUBJECT limit (%d) reached for subject',
|
|
59
|
+
MAX_EXPERIMENTS_PER_SUBJECT)
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
subjectIds.add(serialId)
|
|
63
|
+
return true
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (this._subjects.size >= MAX_SUBJECTS) {
|
|
67
|
+
log.debug('SpanEnrichment: MAX_SUBJECTS limit (%d) reached, dropping subject', MAX_SUBJECTS)
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this._subjects.set(hashedKey, new Set([serialId]))
|
|
72
|
+
return true
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Add a default fallback for a flag not found in UFC.
|
|
77
|
+
*
|
|
78
|
+
* @param {string} flagKey - The flag key
|
|
79
|
+
* @param {boolean|string|number|object} defaultValue - The default value used
|
|
80
|
+
* @returns {boolean} True if added, false if limit reached
|
|
81
|
+
*/
|
|
82
|
+
addDefault (flagKey, defaultValue) {
|
|
83
|
+
if (this._defaults.has(flagKey)) {
|
|
84
|
+
return true
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (this._defaults.size >= MAX_DEFAULTS) {
|
|
88
|
+
log.debug('SpanEnrichment: MAX_DEFAULTS limit (%d) reached, dropping flag %s', MAX_DEFAULTS, flagKey)
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let valueStr = typeof defaultValue === 'object' && defaultValue !== null
|
|
93
|
+
? JSON.stringify(defaultValue)
|
|
94
|
+
: String(defaultValue)
|
|
95
|
+
|
|
96
|
+
if (valueStr.length > MAX_DEFAULT_VALUE_LENGTH) {
|
|
97
|
+
valueStr = valueStr.slice(0, MAX_DEFAULT_VALUE_LENGTH)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
this._defaults.set(flagKey, valueStr)
|
|
101
|
+
return true
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check if there is any enrichment data to add to the span.
|
|
106
|
+
* Note: _subjects is not checked because addSubject() is never called without first
|
|
107
|
+
* calling addSerialId(), so _subjects having data necessitates _serialIds having data.
|
|
108
|
+
*
|
|
109
|
+
* @returns {boolean} True if there is data to add
|
|
110
|
+
*/
|
|
111
|
+
hasData () {
|
|
112
|
+
return this._serialIds.size > 0 || this._defaults.size > 0
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Convert accumulated state to span tags.
|
|
117
|
+
*
|
|
118
|
+
* @returns {object} Object with ffe_flags_enc, ffe_subjects_enc, and ffe_runtime_defaults tags
|
|
119
|
+
*/
|
|
120
|
+
toSpanTags () {
|
|
121
|
+
const tags = {}
|
|
122
|
+
|
|
123
|
+
if (this._serialIds.size > 0) {
|
|
124
|
+
tags.ffe_flags_enc = encodeDeltaVarint(this._serialIds)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (this._subjects.size > 0) {
|
|
128
|
+
const subjectsObj = Object.fromEntries(
|
|
129
|
+
[...this._subjects].map(([key, ids]) => [key, encodeDeltaVarint(ids)])
|
|
130
|
+
)
|
|
131
|
+
tags.ffe_subjects_enc = JSON.stringify(subjectsObj)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (this._defaults.size > 0) {
|
|
135
|
+
tags.ffe_runtime_defaults = JSON.stringify(Object.fromEntries(this._defaults))
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return tags
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
module.exports = {
|
|
143
|
+
SpanEnrichmentState,
|
|
144
|
+
MAX_SERIAL_IDS,
|
|
145
|
+
MAX_SUBJECTS,
|
|
146
|
+
MAX_EXPERIMENTS_PER_SUBJECT,
|
|
147
|
+
MAX_DEFAULTS,
|
|
148
|
+
MAX_DEFAULT_VALUE_LENGTH,
|
|
149
|
+
}
|
|
@@ -7,6 +7,7 @@ const { timeInputToHrTime } = require('../../../../vendor/dist/@opentelemetry/co
|
|
|
7
7
|
const { ERROR_MESSAGE, ERROR_STACK, ERROR_TYPE, IGNORE_OTEL_ERROR } = require('../constants')
|
|
8
8
|
const DatadogSpanContext = require('../opentracing/span_context')
|
|
9
9
|
const TraceState = require('../opentracing/propagation/tracestate')
|
|
10
|
+
const { DD_MAJOR } = require('../../../../version')
|
|
10
11
|
|
|
11
12
|
const id = require('../id')
|
|
12
13
|
|
|
@@ -176,8 +177,8 @@ function setOtelAttributes (ddSpan, attributes) {
|
|
|
176
177
|
function addOtelLink (ddSpan, link, attrs) {
|
|
177
178
|
if (!isWritable(ddSpan) || !link) return
|
|
178
179
|
|
|
179
|
-
//
|
|
180
|
-
const { context, attributes } = isOtelLink(link)
|
|
180
|
+
// v5 still accepts the legacy `addLink(context, attrs)` shape; v6 only takes `addLink(otel.Link)`.
|
|
181
|
+
const { context, attributes } = isOtelLink(link) || DD_MAJOR >= 6
|
|
181
182
|
? link
|
|
182
183
|
: { context: link, attributes: attrs ?? {} }
|
|
183
184
|
|
|
@@ -230,7 +231,7 @@ function recordException (ddSpan, exception, timeInput) {
|
|
|
230
231
|
[ERROR_TYPE]: exception.name,
|
|
231
232
|
[ERROR_MESSAGE]: exception.message,
|
|
232
233
|
[ERROR_STACK]: exception.stack,
|
|
233
|
-
[IGNORE_OTEL_ERROR]: ddSpan.context().
|
|
234
|
+
[IGNORE_OTEL_ERROR]: ddSpan.context().getTag(IGNORE_OTEL_ERROR) ?? true,
|
|
234
235
|
})
|
|
235
236
|
|
|
236
237
|
const attributes = {}
|
|
@@ -16,6 +16,11 @@ const SPAN_KIND_CONSUMER = protoSpanKind.values.SPAN_KIND_CONSUMER
|
|
|
16
16
|
// Cached zero Identifier used to detect zero IDs without re-allocating per span.
|
|
17
17
|
const ZERO_ID = id('0')
|
|
18
18
|
|
|
19
|
+
// DD propagation tag carrying the upper 64 bits of a 128-bit trace ID as 16 hex chars.
|
|
20
|
+
// span_format.js#extractChunkTags only copies this onto the first-in-chunk span, so the
|
|
21
|
+
// transformer scans the batch to find it and applies it to every span's traceId.
|
|
22
|
+
const TRACE_ID_128 = '_dd.p.tid'
|
|
23
|
+
|
|
19
24
|
/**
|
|
20
25
|
* @typedef {import('../../id').Identifier} Identifier
|
|
21
26
|
*
|
|
@@ -65,6 +70,7 @@ const STATUS_CODE_ERROR = 2
|
|
|
65
70
|
const EXCLUDED_META_KEYS = new Set([
|
|
66
71
|
'_dd.span_links',
|
|
67
72
|
'span.kind',
|
|
73
|
+
TRACE_ID_128,
|
|
68
74
|
])
|
|
69
75
|
|
|
70
76
|
/**
|
|
@@ -113,6 +119,18 @@ class OtlpTraceTransformer extends OtlpTransformerBase {
|
|
|
113
119
|
* @returns {object[]} Array of scope span objects
|
|
114
120
|
*/
|
|
115
121
|
#transformScopeSpans (spans) {
|
|
122
|
+
let traceKey
|
|
123
|
+
let traceIdHigh
|
|
124
|
+
const otlpSpans = spans.map((span) => {
|
|
125
|
+
// `_dd.p.tid` lives only on the first-in-chunk span of each trace.
|
|
126
|
+
// Reset at each trace boundary for batching of multiple traces.
|
|
127
|
+
const key = span.trace_id.toString(16)
|
|
128
|
+
if (key !== traceKey) {
|
|
129
|
+
traceKey = key
|
|
130
|
+
traceIdHigh = span.meta?.[TRACE_ID_128]?.toLowerCase()
|
|
131
|
+
}
|
|
132
|
+
return this.#transformSpan(span, traceIdHigh)
|
|
133
|
+
})
|
|
116
134
|
return [{
|
|
117
135
|
scope: {
|
|
118
136
|
name: 'dd-trace-js',
|
|
@@ -121,7 +139,7 @@ class OtlpTraceTransformer extends OtlpTransformerBase {
|
|
|
121
139
|
droppedAttributesCount: 0,
|
|
122
140
|
},
|
|
123
141
|
schemaUrl: '',
|
|
124
|
-
spans:
|
|
142
|
+
spans: otlpSpans,
|
|
125
143
|
}]
|
|
126
144
|
}
|
|
127
145
|
|
|
@@ -129,14 +147,15 @@ class OtlpTraceTransformer extends OtlpTransformerBase {
|
|
|
129
147
|
* Transforms a single DD-formatted span to an OTLP Span object.
|
|
130
148
|
*
|
|
131
149
|
* @param {DDFormattedSpan} span - DD-formatted span to transform
|
|
150
|
+
* @param {string | undefined} traceIdHigh - 16-char hex of the upper 64 bits of the trace ID
|
|
132
151
|
* @returns {object} OTLP Span object
|
|
133
152
|
*/
|
|
134
|
-
#transformSpan (span) {
|
|
153
|
+
#transformSpan (span, traceIdHigh) {
|
|
135
154
|
const parentId = span.parent_id
|
|
136
155
|
const links = this.#extractLinks(span.meta?.['_dd.span_links'])
|
|
137
156
|
|
|
138
157
|
return {
|
|
139
|
-
traceId:
|
|
158
|
+
traceId: span.trace_id.toTraceIdHex(traceIdHigh).padStart(32, '0'),
|
|
140
159
|
spanId: this.#idToBytes(span.span_id, 8),
|
|
141
160
|
parentSpanId: (parentId && !parentId.equals(ZERO_ID)) ? this.#idToBytes(parentId, 8) : undefined,
|
|
142
161
|
name: span.resource,
|
|
@@ -11,20 +11,31 @@ class LogPropagator {
|
|
|
11
11
|
inject (spanContext, carrier) {
|
|
12
12
|
if (!carrier) return
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
const dd = {}
|
|
15
|
+
let hasField = false
|
|
15
16
|
|
|
16
17
|
if (spanContext) {
|
|
17
|
-
|
|
18
|
+
dd.trace_id = this._config.traceId128BitGenerationEnabled &&
|
|
18
19
|
this._config.traceId128BitLoggingEnabled && spanContext._trace.tags['_dd.p.tid']
|
|
19
20
|
? spanContext.toTraceId(true)
|
|
20
21
|
: spanContext.toTraceId()
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
dd.span_id = spanContext.toSpanId()
|
|
23
|
+
hasField = true
|
|
24
|
+
}
|
|
25
|
+
if (this._config.service) {
|
|
26
|
+
dd.service = this._config.service
|
|
27
|
+
hasField = true
|
|
28
|
+
}
|
|
29
|
+
if (this._config.version) {
|
|
30
|
+
dd.version = this._config.version
|
|
31
|
+
hasField = true
|
|
32
|
+
}
|
|
33
|
+
if (this._config.env) {
|
|
34
|
+
dd.env = this._config.env
|
|
35
|
+
hasField = true
|
|
23
36
|
}
|
|
24
37
|
|
|
25
|
-
if (
|
|
26
|
-
if (this._config.version) carrier.dd.version = this._config.version
|
|
27
|
-
if (this._config.env) carrier.dd.env = this._config.env
|
|
38
|
+
if (hasField) carrier.dd = dd
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
extract (carrier) {
|