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
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const DEFAULT_MIN_SIZE =
|
|
3
|
+
const DEFAULT_MIN_SIZE = 1024 * 1024 // 1 MiB
|
|
4
|
+
// Number of consecutive `reset()` calls whose peak usage stayed under
|
|
5
|
+
// `SHRINK_USAGE_RATIO * buffer.length` before the buffer halves. Picked high
|
|
6
|
+
// enough that a one-off burst keeps the grown buffer warm.
|
|
7
|
+
const SHRINK_AFTER_FLUSHES = 32
|
|
8
|
+
// Peak fraction of the current buffer the next flush must beat to keep the
|
|
9
|
+
// shrink streak from advancing. 1/4 — a quarter — matches the doubling growth
|
|
10
|
+
// shape: after a halving step the post-shrink fill is the prior peak doubled,
|
|
11
|
+
// still under 50 %.
|
|
12
|
+
const SHRINK_USAGE_RATIO = 4
|
|
4
13
|
|
|
5
14
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
15
|
+
* Resizable msgpack write buffer. Owns the byte-layout primitives the encoder
|
|
16
|
+
* layer dispatches into; callers reach the underlying `Buffer` only when they
|
|
17
|
+
* need to assemble a fused write (pre-computed prefixes, span-id payloads).
|
|
18
|
+
*
|
|
19
|
+
* Growth doubles the capacity per `reserve`; shrink halves it after
|
|
20
|
+
* `SHRINK_AFTER_FLUSHES` consecutive `reset()` calls left the buffer barely
|
|
21
|
+
* filled. Both stop at `minSize` so callers can pin a floor (CI Visibility's
|
|
22
|
+
* payload prefix chunk uses ~2 KiB).
|
|
9
23
|
*/
|
|
10
24
|
class MsgpackChunk {
|
|
11
25
|
#minSize
|
|
26
|
+
#lowUsageStreak = 0
|
|
12
27
|
|
|
13
28
|
constructor (minSize = DEFAULT_MIN_SIZE) {
|
|
14
29
|
this.buffer = Buffer.allocUnsafe(minSize)
|
|
15
|
-
|
|
30
|
+
// `Buffer.allocUnsafe` pools small allocations, so `buffer.buffer` may be a
|
|
31
|
+
// shared slab; pass `byteOffset` / `byteLength` so the view spans only our slice.
|
|
32
|
+
this.view = new DataView(this.buffer.buffer, this.buffer.byteOffset, this.buffer.byteLength)
|
|
16
33
|
this.length = 0
|
|
17
34
|
this.#minSize = minSize
|
|
18
35
|
}
|
|
19
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Emit `value` as a msgpack string (fixstr for < 32 bytes, str32 otherwise).
|
|
39
|
+
* Returns the number of bytes written so callers can subarray the underlying
|
|
40
|
+
* buffer at the resulting position.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} value
|
|
43
|
+
* @returns {number}
|
|
44
|
+
*/
|
|
20
45
|
write (value) {
|
|
21
46
|
const length = Buffer.byteLength(value)
|
|
22
47
|
const offset = this.length
|
|
@@ -38,10 +63,24 @@ class MsgpackChunk {
|
|
|
38
63
|
return this.length - offset
|
|
39
64
|
}
|
|
40
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Copy this chunk's used bytes into `target` starting at `target[0]`. Used
|
|
68
|
+
* by `AgentEncoder.makePayload` to assemble the final wire buffer.
|
|
69
|
+
*
|
|
70
|
+
* @param {Buffer} target
|
|
71
|
+
* @param {number} sourceStart
|
|
72
|
+
* @param {number} sourceEnd
|
|
73
|
+
*/
|
|
41
74
|
copy (target, sourceStart, sourceEnd) {
|
|
42
|
-
|
|
75
|
+
this.buffer.copy(target, 0, sourceStart, sourceEnd)
|
|
43
76
|
}
|
|
44
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Append a raw byte sequence to the chunk. Caller-supplied bytes are
|
|
80
|
+
* trusted; this is the fused-prefix path.
|
|
81
|
+
*
|
|
82
|
+
* @param {Uint8Array | Buffer} array
|
|
83
|
+
*/
|
|
45
84
|
set (array) {
|
|
46
85
|
const length = this.length
|
|
47
86
|
|
|
@@ -50,20 +89,365 @@ class MsgpackChunk {
|
|
|
50
89
|
this.buffer.set(array, length)
|
|
51
90
|
}
|
|
52
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Reserve `size` more bytes after the current cursor, growing the backing
|
|
94
|
+
* buffer if needed. The cursor advances unconditionally so subsequent
|
|
95
|
+
* writes can assume the room is available.
|
|
96
|
+
*
|
|
97
|
+
* @param {number} size
|
|
98
|
+
*/
|
|
53
99
|
reserve (size) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
100
|
+
const needed = this.length + size
|
|
101
|
+
|
|
102
|
+
if (needed > this.buffer.length) {
|
|
103
|
+
let newSize = this.buffer.length
|
|
104
|
+
// `*= 2` instead of `<<= 1`: `1073741824 << 1` is negative as int32,
|
|
105
|
+
// and msgpack values can legitimately reach the multi-GiB range.
|
|
106
|
+
while (newSize < needed) newSize *= 2
|
|
107
|
+
this.#resize(newSize)
|
|
57
108
|
}
|
|
58
109
|
|
|
59
110
|
this.length += size
|
|
60
111
|
}
|
|
61
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Mark the buffer as flushed: zero the cursor and, when the previous flush
|
|
115
|
+
* barely filled the buffer for `SHRINK_AFTER_FLUSHES` consecutive resets,
|
|
116
|
+
* halve the backing buffer. A single high-watermark flush resets the
|
|
117
|
+
* streak. Long-lived encoders can therefore grow under bursts and give the
|
|
118
|
+
* memory back during quiet periods without the user having to recreate the
|
|
119
|
+
* chunk.
|
|
120
|
+
*/
|
|
121
|
+
reset () {
|
|
122
|
+
const peak = this.length
|
|
123
|
+
|
|
124
|
+
this.length = 0
|
|
125
|
+
|
|
126
|
+
if (this.buffer.length > this.#minSize && peak * SHRINK_USAGE_RATIO < this.buffer.length) {
|
|
127
|
+
if (++this.#lowUsageStreak >= SHRINK_AFTER_FLUSHES) {
|
|
128
|
+
const newSize = Math.max(this.#minSize, this.buffer.length >>> 1)
|
|
129
|
+
this.buffer = Buffer.allocUnsafe(newSize)
|
|
130
|
+
this.view = new DataView(this.buffer.buffer, this.buffer.byteOffset, this.buffer.byteLength)
|
|
131
|
+
this.#lowUsageStreak = 0
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
this.#lowUsageStreak = 0
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
writeNull () {
|
|
139
|
+
const offset = this.length
|
|
140
|
+
|
|
141
|
+
this.reserve(1)
|
|
142
|
+
this.buffer[offset] = 0xC0
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @param {boolean} value
|
|
147
|
+
*/
|
|
148
|
+
writeBoolean (value) {
|
|
149
|
+
const offset = this.length
|
|
150
|
+
|
|
151
|
+
this.reserve(1)
|
|
152
|
+
this.buffer[offset] = value ? 0xC3 : 0xC2
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {number} size 0..15.
|
|
157
|
+
*/
|
|
158
|
+
writeFixArray (size) {
|
|
159
|
+
const offset = this.length
|
|
160
|
+
|
|
161
|
+
this.reserve(1)
|
|
162
|
+
this.buffer[offset] = 0x90 + size
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Reserve a 5-byte array32 header with `value.length` slots. Used when the
|
|
167
|
+
* length is not known to fit in fixarray.
|
|
168
|
+
*
|
|
169
|
+
* @param {{ length: number }} value
|
|
170
|
+
*/
|
|
171
|
+
writeArrayPrefix (value) {
|
|
172
|
+
const length = value.length
|
|
173
|
+
const offset = this.length
|
|
174
|
+
|
|
175
|
+
this.reserve(5)
|
|
176
|
+
this.buffer[offset] = 0xDD
|
|
177
|
+
this.buffer[offset + 1] = length >> 24
|
|
178
|
+
this.buffer[offset + 2] = length >> 16
|
|
179
|
+
this.buffer[offset + 3] = length >> 8
|
|
180
|
+
this.buffer[offset + 4] = length
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Reserve a 5-byte map32 header with `keysLength` entries.
|
|
185
|
+
*
|
|
186
|
+
* @param {number} keysLength
|
|
187
|
+
*/
|
|
188
|
+
writeMapPrefix (keysLength) {
|
|
189
|
+
const offset = this.length
|
|
190
|
+
|
|
191
|
+
this.reserve(5)
|
|
192
|
+
this.buffer[offset] = 0xDF
|
|
193
|
+
this.buffer[offset + 1] = keysLength >> 24
|
|
194
|
+
this.buffer[offset + 2] = keysLength >> 16
|
|
195
|
+
this.buffer[offset + 3] = keysLength >> 8
|
|
196
|
+
this.buffer[offset + 4] = keysLength
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Write a single raw byte. Used by `0.5.js` for the fixarray-of-twelve span
|
|
201
|
+
* marker.
|
|
202
|
+
*
|
|
203
|
+
* @param {number} value
|
|
204
|
+
*/
|
|
205
|
+
writeByte (value) {
|
|
206
|
+
this.reserve(1)
|
|
207
|
+
this.buffer[this.length - 1] = value
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @param {Buffer | Uint8Array} value
|
|
212
|
+
*/
|
|
213
|
+
writeBin (value) {
|
|
214
|
+
const offset = this.length
|
|
215
|
+
|
|
216
|
+
if (value.byteLength < 256) {
|
|
217
|
+
this.reserve(2)
|
|
218
|
+
this.buffer[offset] = 0xC4
|
|
219
|
+
this.buffer[offset + 1] = value.byteLength
|
|
220
|
+
} else if (value.byteLength < 65_536) {
|
|
221
|
+
this.reserve(3)
|
|
222
|
+
this.buffer[offset] = 0xC5
|
|
223
|
+
this.buffer[offset + 1] = value.byteLength >> 8
|
|
224
|
+
this.buffer[offset + 2] = value.byteLength
|
|
225
|
+
} else {
|
|
226
|
+
this.reserve(5)
|
|
227
|
+
this.buffer[offset] = 0xC6
|
|
228
|
+
this.buffer[offset + 1] = value.byteLength >> 24
|
|
229
|
+
this.buffer[offset + 2] = value.byteLength >> 16
|
|
230
|
+
this.buffer[offset + 3] = value.byteLength >> 8
|
|
231
|
+
this.buffer[offset + 4] = value.byteLength
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
this.set(value)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Write `value` as msgpack uint32 (`0xCE` + 4 bytes), regardless of
|
|
239
|
+
* magnitude. Callers that want the shortest encoding should use `writeUint`.
|
|
240
|
+
*
|
|
241
|
+
* @param {number} value
|
|
242
|
+
*/
|
|
243
|
+
writeInteger (value) {
|
|
244
|
+
const offset = this.length
|
|
245
|
+
|
|
246
|
+
this.reserve(5)
|
|
247
|
+
this.buffer[offset] = 0xCE
|
|
248
|
+
this.buffer[offset + 1] = value >> 24
|
|
249
|
+
this.buffer[offset + 2] = value >> 16
|
|
250
|
+
this.buffer[offset + 3] = value >> 8
|
|
251
|
+
this.buffer[offset + 4] = value
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Write `value` as msgpack uint64 (`0xCF` + 8 bytes).
|
|
256
|
+
*
|
|
257
|
+
* @param {number} value
|
|
258
|
+
*/
|
|
259
|
+
writeLong (value) {
|
|
260
|
+
const offset = this.length
|
|
261
|
+
const hi = (value / 2 ** 32) >> 0
|
|
262
|
+
const lo = value >>> 0
|
|
263
|
+
|
|
264
|
+
this.reserve(9)
|
|
265
|
+
this.buffer[offset] = 0xCF
|
|
266
|
+
this.buffer[offset + 1] = hi >> 24
|
|
267
|
+
this.buffer[offset + 2] = hi >> 16
|
|
268
|
+
this.buffer[offset + 3] = hi >> 8
|
|
269
|
+
this.buffer[offset + 4] = hi
|
|
270
|
+
this.buffer[offset + 5] = lo >> 24
|
|
271
|
+
this.buffer[offset + 6] = lo >> 16
|
|
272
|
+
this.buffer[offset + 7] = lo >> 8
|
|
273
|
+
this.buffer[offset + 8] = lo
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Pick the shortest valid msgpack uint encoding for a non-negative integer.
|
|
278
|
+
*
|
|
279
|
+
* @param {number} value
|
|
280
|
+
*/
|
|
281
|
+
writeUnsigned (value) {
|
|
282
|
+
const offset = this.length
|
|
283
|
+
|
|
284
|
+
if (value <= 0x7F) {
|
|
285
|
+
this.reserve(1)
|
|
286
|
+
this.buffer[offset] = value
|
|
287
|
+
} else if (value <= 0xFF) {
|
|
288
|
+
this.reserve(2)
|
|
289
|
+
this.buffer[offset] = 0xCC
|
|
290
|
+
this.buffer[offset + 1] = value
|
|
291
|
+
} else if (value <= 0xFF_FF) {
|
|
292
|
+
this.reserve(3)
|
|
293
|
+
this.buffer[offset] = 0xCD
|
|
294
|
+
this.buffer[offset + 1] = value >> 8
|
|
295
|
+
this.buffer[offset + 2] = value
|
|
296
|
+
} else if (value <= 0xFF_FF_FF_FF) {
|
|
297
|
+
this.reserve(5)
|
|
298
|
+
this.buffer[offset] = 0xCE
|
|
299
|
+
this.buffer[offset + 1] = value >> 24
|
|
300
|
+
this.buffer[offset + 2] = value >> 16
|
|
301
|
+
this.buffer[offset + 3] = value >> 8
|
|
302
|
+
this.buffer[offset + 4] = value
|
|
303
|
+
} else {
|
|
304
|
+
const hi = (value / 2 ** 32) >> 0
|
|
305
|
+
const lo = value >>> 0
|
|
306
|
+
|
|
307
|
+
this.reserve(9)
|
|
308
|
+
this.buffer[offset] = 0xCF
|
|
309
|
+
this.buffer[offset + 1] = hi >> 24
|
|
310
|
+
this.buffer[offset + 2] = hi >> 16
|
|
311
|
+
this.buffer[offset + 3] = hi >> 8
|
|
312
|
+
this.buffer[offset + 4] = hi
|
|
313
|
+
this.buffer[offset + 5] = lo >> 24
|
|
314
|
+
this.buffer[offset + 6] = lo >> 16
|
|
315
|
+
this.buffer[offset + 7] = lo >> 8
|
|
316
|
+
this.buffer[offset + 8] = lo
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Pick the shortest valid msgpack int encoding for a negative integer.
|
|
322
|
+
*
|
|
323
|
+
* @param {number} value
|
|
324
|
+
*/
|
|
325
|
+
writeSigned (value) {
|
|
326
|
+
const offset = this.length
|
|
327
|
+
|
|
328
|
+
if (value >= -0x20) {
|
|
329
|
+
this.reserve(1)
|
|
330
|
+
this.buffer[offset] = value
|
|
331
|
+
} else if (value >= -0x80) {
|
|
332
|
+
this.reserve(2)
|
|
333
|
+
this.buffer[offset] = 0xD0
|
|
334
|
+
this.buffer[offset + 1] = value
|
|
335
|
+
} else if (value >= -0x80_00) {
|
|
336
|
+
this.reserve(3)
|
|
337
|
+
this.buffer[offset] = 0xD1
|
|
338
|
+
this.buffer[offset + 1] = value >> 8
|
|
339
|
+
this.buffer[offset + 2] = value
|
|
340
|
+
} else if (value >= -0x80_00_00_00) {
|
|
341
|
+
this.reserve(5)
|
|
342
|
+
this.buffer[offset] = 0xD2
|
|
343
|
+
this.buffer[offset + 1] = value >> 24
|
|
344
|
+
this.buffer[offset + 2] = value >> 16
|
|
345
|
+
this.buffer[offset + 3] = value >> 8
|
|
346
|
+
this.buffer[offset + 4] = value
|
|
347
|
+
} else {
|
|
348
|
+
const hi = Math.floor(value / 2 ** 32)
|
|
349
|
+
const lo = value >>> 0
|
|
350
|
+
|
|
351
|
+
this.reserve(9)
|
|
352
|
+
this.buffer[offset] = 0xD3
|
|
353
|
+
this.buffer[offset + 1] = hi >> 24
|
|
354
|
+
this.buffer[offset + 2] = hi >> 16
|
|
355
|
+
this.buffer[offset + 3] = hi >> 8
|
|
356
|
+
this.buffer[offset + 4] = hi
|
|
357
|
+
this.buffer[offset + 5] = lo >> 24
|
|
358
|
+
this.buffer[offset + 6] = lo >> 16
|
|
359
|
+
this.buffer[offset + 7] = lo >> 8
|
|
360
|
+
this.buffer[offset + 8] = lo
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// TODO: Support BigInt larger than 64bit.
|
|
365
|
+
/**
|
|
366
|
+
* @param {bigint} value
|
|
367
|
+
*/
|
|
368
|
+
writeBigInt (value) {
|
|
369
|
+
const offset = this.length
|
|
370
|
+
|
|
371
|
+
this.reserve(9)
|
|
372
|
+
|
|
373
|
+
if (value >= 0n) {
|
|
374
|
+
this.buffer[offset] = 0xCF
|
|
375
|
+
this.view.setBigUint64(offset + 1, value)
|
|
376
|
+
} else {
|
|
377
|
+
this.buffer[offset] = 0xD3
|
|
378
|
+
this.view.setBigInt64(offset + 1, value)
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* @param {number} value
|
|
384
|
+
*/
|
|
385
|
+
writeFloat (value) {
|
|
386
|
+
const offset = this.length
|
|
387
|
+
|
|
388
|
+
this.reserve(9)
|
|
389
|
+
this.buffer[offset] = 0xCB
|
|
390
|
+
this.view.setFloat64(offset + 1, value)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Pick the shortest valid msgpack number encoding for `value`. `NaN`
|
|
395
|
+
* collapses to fixint 0 — callers that need to preserve `NaN` (the tracer's
|
|
396
|
+
* span numeric path) should use `writeIntOrFloat` instead.
|
|
397
|
+
*
|
|
398
|
+
* @param {number} value
|
|
399
|
+
*/
|
|
400
|
+
writeNumber (value) {
|
|
401
|
+
if (Number.isNaN(value)) {
|
|
402
|
+
value = 0
|
|
403
|
+
}
|
|
404
|
+
if (Number.isInteger(value)) {
|
|
405
|
+
if (value >= 0) {
|
|
406
|
+
this.writeUnsigned(value)
|
|
407
|
+
} else {
|
|
408
|
+
this.writeSigned(value)
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
this.writeFloat(value)
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Emit `value` as the smallest valid msgpack number encoding: compact
|
|
417
|
+
* unsigned/signed int when integer, float64 otherwise. Unlike `writeNumber`,
|
|
418
|
+
* NaN keeps its float64 bits instead of coercing to fixint 0. Used on the
|
|
419
|
+
* tracer hot path so the agent sees the value the application produced.
|
|
420
|
+
*
|
|
421
|
+
* @param {number} value
|
|
422
|
+
*/
|
|
423
|
+
writeIntOrFloat (value) {
|
|
424
|
+
// Fast path: positive fixint (0..127). `value === (value & 0x7F)` is true
|
|
425
|
+
// iff `value` is an exact integer in that range — covers `error: 0/1`,
|
|
426
|
+
// priority flags, attribute counts, HTTP status codes mapped to numbers,
|
|
427
|
+
// and most small metrics. NaN, ±Infinity, negatives, and any non-integer
|
|
428
|
+
// float fall through.
|
|
429
|
+
if (value === (value & 0x7F)) {
|
|
430
|
+
const offset = this.length
|
|
431
|
+
this.reserve(1)
|
|
432
|
+
this.buffer[offset] = value
|
|
433
|
+
return
|
|
434
|
+
}
|
|
435
|
+
if (Number.isInteger(value)) {
|
|
436
|
+
if (value >= 0) {
|
|
437
|
+
this.writeUnsigned(value)
|
|
438
|
+
} else {
|
|
439
|
+
this.writeSigned(value)
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
this.writeFloat(value)
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
62
446
|
#resize (size) {
|
|
63
447
|
const oldBuffer = this.buffer
|
|
64
448
|
|
|
65
449
|
this.buffer = Buffer.allocUnsafe(size)
|
|
66
|
-
this.view = new DataView(this.buffer.buffer)
|
|
450
|
+
this.view = new DataView(this.buffer.buffer, this.buffer.byteOffset, this.buffer.byteLength)
|
|
67
451
|
|
|
68
452
|
oldBuffer.copy(this.buffer, 0, 0, this.length)
|
|
69
453
|
}
|
|
@@ -1,6 +1,100 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const MsgpackChunk = require('./chunk')
|
|
4
|
-
const { MsgpackEncoder } = require('./encoder')
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Encode an arbitrary JS value as a standalone msgpack buffer. Used by
|
|
7
|
+
* `DataStreamsWriter` (pipeline stats) where the payload shape is decided at
|
|
8
|
+
* runtime; encoder code that owns a `MsgpackChunk` should call
|
|
9
|
+
* `chunk.writeX(...)` directly instead.
|
|
10
|
+
*
|
|
11
|
+
* @param {unknown} value
|
|
12
|
+
* @returns {Buffer}
|
|
13
|
+
*/
|
|
14
|
+
function encode (value) {
|
|
15
|
+
const bytes = new MsgpackChunk()
|
|
16
|
+
writeValue(bytes, value)
|
|
17
|
+
|
|
18
|
+
return bytes.buffer.subarray(0, bytes.length)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {unknown} value
|
|
23
|
+
* @returns {value is Record<string, unknown>}
|
|
24
|
+
*/
|
|
25
|
+
function isPlainObject (value) {
|
|
26
|
+
return typeof value === 'object' && value !== null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {MsgpackChunk} bytes
|
|
31
|
+
* @param {unknown} value
|
|
32
|
+
*/
|
|
33
|
+
function writeValue (bytes, value) {
|
|
34
|
+
switch (typeof value) {
|
|
35
|
+
case 'string':
|
|
36
|
+
bytes.write(value)
|
|
37
|
+
break
|
|
38
|
+
case 'number':
|
|
39
|
+
bytes.writeNumber(value)
|
|
40
|
+
break
|
|
41
|
+
case 'object':
|
|
42
|
+
if (value === null) {
|
|
43
|
+
bytes.writeNull()
|
|
44
|
+
} else if (Array.isArray(value)) {
|
|
45
|
+
writeArray(bytes, value)
|
|
46
|
+
} else if (Buffer.isBuffer(value)) {
|
|
47
|
+
bytes.writeBin(value)
|
|
48
|
+
} else if (ArrayBuffer.isView(value)) {
|
|
49
|
+
bytes.writeBin(/** @type {Uint8Array} */ (value))
|
|
50
|
+
} else if (isPlainObject(value)) {
|
|
51
|
+
writeMap(bytes, value)
|
|
52
|
+
}
|
|
53
|
+
break
|
|
54
|
+
case 'boolean':
|
|
55
|
+
bytes.writeBoolean(value)
|
|
56
|
+
break
|
|
57
|
+
case 'bigint':
|
|
58
|
+
bytes.writeBigInt(value)
|
|
59
|
+
break
|
|
60
|
+
case 'symbol':
|
|
61
|
+
bytes.write(value.toString())
|
|
62
|
+
break
|
|
63
|
+
default: // function, undefined
|
|
64
|
+
bytes.writeNull()
|
|
65
|
+
break
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {MsgpackChunk} bytes
|
|
71
|
+
* @param {unknown[]} value
|
|
72
|
+
*/
|
|
73
|
+
function writeArray (bytes, value) {
|
|
74
|
+
if (value.length < 16) {
|
|
75
|
+
bytes.writeFixArray(value.length)
|
|
76
|
+
} else {
|
|
77
|
+
bytes.writeArrayPrefix(value)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for (const item of value) {
|
|
81
|
+
writeValue(bytes, item)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {MsgpackChunk} bytes
|
|
87
|
+
* @param {Record<string, unknown>} value
|
|
88
|
+
*/
|
|
89
|
+
function writeMap (bytes, value) {
|
|
90
|
+
const keys = Object.keys(value)
|
|
91
|
+
|
|
92
|
+
bytes.writeMapPrefix(keys.length)
|
|
93
|
+
|
|
94
|
+
for (const key of keys) {
|
|
95
|
+
bytes.write(key)
|
|
96
|
+
writeValue(bytes, value[key])
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = { MsgpackChunk, encode }
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Encode a single value as a ULEB128 varint (variable-length integer).
|
|
7
|
+
* Uses 7 bits per byte, with MSB as continuation flag.
|
|
8
|
+
*
|
|
9
|
+
* @param {number} value - Non-negative integer to encode
|
|
10
|
+
* @returns {number[]} Array of bytes representing the varint
|
|
11
|
+
*/
|
|
12
|
+
function encodeVarint (value) {
|
|
13
|
+
const bytes = []
|
|
14
|
+
while (value > 0x7F) {
|
|
15
|
+
bytes.push((value & 0x7F) | 0x80) // Set continuation bit
|
|
16
|
+
value >>>= 7
|
|
17
|
+
}
|
|
18
|
+
bytes.push(value & 0x7F) // Final byte without continuation bit
|
|
19
|
+
return bytes
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Encode a set of serial IDs using delta-varint encoding.
|
|
24
|
+
*
|
|
25
|
+
* Algorithm:
|
|
26
|
+
* 1. Sort serial IDs in ascending order
|
|
27
|
+
* 2. Compute deltas from previous value (first delta = first value)
|
|
28
|
+
* 3. Encode each delta as varint
|
|
29
|
+
* 4. Base64 encode the result
|
|
30
|
+
*
|
|
31
|
+
* @param {Set<number>} serialIds - Set of serial IDs to encode
|
|
32
|
+
* @returns {string} Base64-encoded delta-varint string
|
|
33
|
+
*/
|
|
34
|
+
function encodeDeltaVarint (serialIds) {
|
|
35
|
+
if (!serialIds || serialIds.size === 0) {
|
|
36
|
+
return ''
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Sort IDs in ascending order
|
|
40
|
+
const sorted = [...serialIds].sort((a, b) => a - b)
|
|
41
|
+
|
|
42
|
+
// Compute deltas and encode as varints
|
|
43
|
+
const bytes = []
|
|
44
|
+
let prev = 0
|
|
45
|
+
|
|
46
|
+
for (const id of sorted) {
|
|
47
|
+
const delta = id - prev
|
|
48
|
+
bytes.push(...encodeVarint(delta))
|
|
49
|
+
prev = id
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Base64 encode the byte array
|
|
53
|
+
return Buffer.from(bytes).toString('base64')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Hash a targeting key using SHA256.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} targetingKey - The targeting key to hash
|
|
60
|
+
* @returns {string} Lowercase hex digest of the SHA256 hash
|
|
61
|
+
*/
|
|
62
|
+
function hashTargetingKey (targetingKey) {
|
|
63
|
+
return crypto.createHash('sha256').update(targetingKey).digest('hex')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = {
|
|
67
|
+
encodeVarint,
|
|
68
|
+
encodeDeltaVarint,
|
|
69
|
+
hashTargetingKey,
|
|
70
|
+
}
|
|
@@ -5,12 +5,16 @@ const { channel } = require('dc-polyfill')
|
|
|
5
5
|
const log = require('../log')
|
|
6
6
|
const { EXPOSURE_CHANNEL } = require('./constants/constants')
|
|
7
7
|
const EvalMetricsHook = require('./eval-metrics-hook')
|
|
8
|
+
const SpanEnrichmentHook = require('./span-enrichment-hook')
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* OpenFeature provider that integrates with Datadog's feature flagging system.
|
|
11
12
|
* Extends DatadogNodeServerProvider to add tracer integration and configuration management.
|
|
12
13
|
*/
|
|
13
14
|
class FlaggingProvider extends DatadogNodeServerProvider {
|
|
15
|
+
/** @type {SpanEnrichmentHook?} */
|
|
16
|
+
#spanEnrichmentHook
|
|
17
|
+
|
|
14
18
|
/**
|
|
15
19
|
* @param {import('../tracer')} tracer - Datadog tracer instance
|
|
16
20
|
* @param {import('../config')} config - Tracer configuration object
|
|
@@ -27,10 +31,26 @@ class FlaggingProvider extends DatadogNodeServerProvider {
|
|
|
27
31
|
|
|
28
32
|
this.hooks.push(new EvalMetricsHook(config))
|
|
29
33
|
|
|
34
|
+
if (config.experimental.flaggingProvider.spanEnrichment?.enabled) {
|
|
35
|
+
this.#spanEnrichmentHook = new SpanEnrichmentHook(tracer)
|
|
36
|
+
this.hooks.push(this.#spanEnrichmentHook)
|
|
37
|
+
log.info('%s span enrichment enabled', this.constructor.name)
|
|
38
|
+
} else {
|
|
39
|
+
log.info('%s span enrichment disabled', this.constructor.name)
|
|
40
|
+
}
|
|
41
|
+
|
|
30
42
|
log.debug('%s created with timeout: %dms', this.constructor.name,
|
|
31
43
|
config.experimental.flaggingProvider.initializationTimeoutMs)
|
|
32
44
|
}
|
|
33
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Called when the provider is shut down.
|
|
48
|
+
* Cleans up resources including channel subscriptions.
|
|
49
|
+
*/
|
|
50
|
+
onClose () {
|
|
51
|
+
this.#spanEnrichmentHook?.destroy()
|
|
52
|
+
}
|
|
53
|
+
|
|
34
54
|
/**
|
|
35
55
|
* Internal method to update flag configuration from Remote Config.
|
|
36
56
|
* This method is called automatically when Remote Config delivers UFC updates.
|