dd-trace 6.14.0 → 6.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +4 -2
- package/ci/test-optimization-validation/package-check.js +4 -1
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +1 -1
- package/index.d.ts +12 -0
- package/next.d.ts +27 -0
- package/next.js +3 -0
- package/package.json +17 -13
- package/packages/datadog-esbuild/index.js +14 -1
- package/packages/datadog-esbuild/src/resolver.js +284 -0
- package/packages/datadog-esbuild/src/utils.js +163 -119
- package/packages/datadog-instrumentations/src/ai.js +39 -97
- package/packages/datadog-instrumentations/src/anthropic.js +76 -134
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +1 -1
- package/packages/datadog-instrumentations/src/azure-cosmos.js +1 -1
- package/packages/datadog-instrumentations/src/azure-durable-functions.js +23 -9
- package/packages/datadog-instrumentations/src/azure-functions.js +48 -0
- package/packages/datadog-instrumentations/src/bullmq.js +1 -1
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -1
- package/packages/datadog-instrumentations/src/dd-trace-api.js +2 -2
- package/packages/datadog-instrumentations/src/graphql.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +39 -14
- package/packages/datadog-instrumentations/src/helpers/instrument.js +25 -8
- package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +72 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -64
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +46 -14
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-durable-functions.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +1 -5
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +6 -7
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +99 -70
- package/packages/datadog-instrumentations/src/jest.js +141 -25
- package/packages/datadog-instrumentations/src/langchain.js +1 -1
- package/packages/datadog-instrumentations/src/langgraph.js +1 -1
- package/packages/datadog-instrumentations/src/mercurius.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +41 -5
- package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +1 -1
- package/packages/datadog-instrumentations/src/openai-agents.js +1 -1
- package/packages/datadog-instrumentations/src/openai.js +54 -76
- package/packages/datadog-instrumentations/src/playwright.js +4 -0
- package/packages/datadog-instrumentations/src/vitest-worker.js +7 -10
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +7 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +1 -1
- package/packages/datadog-plugin-azure-durable-functions/src/index.js +96 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -24
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -36
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-request-context.js +31 -0
- package/packages/datadog-plugin-graphql/src/resolve-error.js +33 -11
- package/packages/datadog-turbopack/index.js +212 -0
- package/packages/datadog-turbopack/src/constants.js +5 -0
- package/packages/datadog-turbopack/src/loader.js +500 -0
- package/packages/dd-trace/src/aiguard/index.js +2 -1
- package/packages/dd-trace/src/aiguard/integrations/anthropic.js +53 -25
- package/packages/dd-trace/src/aiguard/integrations/evaluate.js +49 -25
- package/packages/dd-trace/src/aiguard/integrations/index.js +3 -2
- package/packages/dd-trace/src/aiguard/integrations/openai.js +59 -30
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +116 -42
- package/packages/dd-trace/src/aiguard/messages/utils.js +29 -1
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +25 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +3 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +531 -70
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/telemetry/api_security.js +1 -3
- package/packages/dd-trace/src/appsec/telemetry/common.js +4 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +23 -5
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +1 -20
- package/packages/dd-trace/src/appsec/telemetry/user.js +1 -3
- package/packages/dd-trace/src/appsec/telemetry/waf.js +1 -20
- package/packages/dd-trace/src/ci-visibility/requests/request.js +11 -0
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +4 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +2 -0
- package/packages/dd-trace/src/config/helper.js +10 -2
- package/packages/dd-trace/src/config/index.js +20 -5
- package/packages/dd-trace/src/config/supported-configurations.json +10 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +14 -7
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +14 -1
- package/packages/dd-trace/src/debugger/devtools_client/request-options.js +1 -6
- package/packages/dd-trace/src/evp_proxy/direct.js +2 -28
- package/packages/dd-trace/src/evp_proxy/discovery.js +3 -4
- package/packages/dd-trace/src/evp_proxy/path.js +12 -3
- package/packages/dd-trace/src/exporters/agentless/writer.js +3 -1
- package/packages/dd-trace/src/exporters/common/docker.js +4 -1
- package/packages/dd-trace/src/exporters/common/proxy.js +55 -0
- package/packages/dd-trace/src/exporters/common/request.js +11 -3
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +5 -4
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +106 -25
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +12 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +8 -2
- package/packages/dd-trace/src/plugin_manager.js +9 -3
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/test.js +4 -1
- package/packages/dd-trace/src/priority_sampler.js +4 -0
- package/packages/dd-trace/src/sampling_rule.js +3 -1
- package/packages/dd-trace/src/span_processor.js +18 -3
- package/packages/dd-trace/src/telemetry/send-data.js +5 -4
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +0 -10
|
@@ -51,11 +51,12 @@ class MeterProvider {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
|
-
* @param {
|
|
54
|
+
* @param {(error: Error | null) => void} [done] Called after shutdown completes
|
|
55
|
+
* @returns {void}
|
|
55
56
|
*/
|
|
56
|
-
|
|
57
|
-
if (this.reader) this.reader.
|
|
58
|
-
else done?.()
|
|
57
|
+
shutdown (done) {
|
|
58
|
+
if (this.reader) this.reader.shutdown(done)
|
|
59
|
+
else done?.(null)
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
@@ -8,6 +8,19 @@ const {
|
|
|
8
8
|
const { ObservableInstrument } = require('./instruments')
|
|
9
9
|
const { nowUnixNano } = require('./time')
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* @param {(error: Error | null) => void} [done]
|
|
13
|
+
* @param {Error | null} [error]
|
|
14
|
+
*/
|
|
15
|
+
function callDone (done, error) {
|
|
16
|
+
if (!done) return
|
|
17
|
+
try {
|
|
18
|
+
done(error ?? null)
|
|
19
|
+
} catch (callbackError) {
|
|
20
|
+
log.error('Error completing OTLP metrics lifecycle callback:', callbackError)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
11
24
|
/**
|
|
12
25
|
* @typedef {import('@opentelemetry/api').Attributes} Attributes
|
|
13
26
|
* @typedef {import('@opentelemetry/core').InstrumentationScope} InstrumentationScope
|
|
@@ -105,6 +118,10 @@ class PeriodicMetricReader {
|
|
|
105
118
|
#exportInterval
|
|
106
119
|
#aggregator
|
|
107
120
|
#batchCallbacks = []
|
|
121
|
+
#exportQueue = []
|
|
122
|
+
#isExporting = false
|
|
123
|
+
#shutdownCallbacks = []
|
|
124
|
+
#shutdownComplete = false
|
|
108
125
|
|
|
109
126
|
/**
|
|
110
127
|
* Creates a new PeriodicMetricReader instance.
|
|
@@ -197,47 +214,36 @@ class PeriodicMetricReader {
|
|
|
197
214
|
|
|
198
215
|
/**
|
|
199
216
|
* Forces an immediate collection and export of all metrics.
|
|
200
|
-
* @param {
|
|
217
|
+
* @param {(error: Error | null) => void} [done] Called after the metric export completes
|
|
218
|
+
* @returns {void}
|
|
201
219
|
*/
|
|
202
220
|
forceFlush (done) {
|
|
203
221
|
if (this.#isShutdown) {
|
|
204
222
|
log.warn('PeriodicMetricReader is shutdown. %d measurement(s) were dropped', this.#droppedCount)
|
|
205
|
-
|
|
223
|
+
if (this.#shutdownComplete) callDone(done)
|
|
224
|
+
else if (done) this.#shutdownCallbacks.push(done)
|
|
206
225
|
return
|
|
207
226
|
}
|
|
208
|
-
|
|
209
|
-
const complete = () => {
|
|
210
|
-
if (--pending === 0) done?.()
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Snapshot requests already active before starting this flush's export.
|
|
214
|
-
try {
|
|
215
|
-
if (typeof this.exporter.flush === 'function') this.exporter.flush(complete)
|
|
216
|
-
else complete()
|
|
217
|
-
} catch (error) {
|
|
218
|
-
log.error('Error flushing OTLP metrics:', error)
|
|
219
|
-
complete()
|
|
220
|
-
}
|
|
221
|
-
try {
|
|
222
|
-
this.#collectAndExport(complete)
|
|
223
|
-
} catch (error) {
|
|
224
|
-
log.error('Error exporting OTLP metrics:', error)
|
|
225
|
-
complete()
|
|
226
|
-
}
|
|
227
|
+
this.#enqueueExport(true, done)
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
/**
|
|
230
231
|
* Shuts down the reader and stops periodic collection.
|
|
232
|
+
* @param {(error: Error | null) => void} [done] Called after the final export and exporter shutdown complete
|
|
231
233
|
* @returns {void}
|
|
232
234
|
*/
|
|
233
|
-
shutdown () {
|
|
235
|
+
shutdown (done) {
|
|
234
236
|
if (this.#isShutdown) {
|
|
235
237
|
log.warn('PeriodicMetricReader is already shutdown')
|
|
238
|
+
if (this.#shutdownComplete) callDone(done)
|
|
239
|
+
else if (done) this.#shutdownCallbacks.push(done)
|
|
236
240
|
return
|
|
237
241
|
}
|
|
242
|
+
if (done) this.#shutdownCallbacks.push(done)
|
|
243
|
+
|
|
238
244
|
this.#isShutdown = true
|
|
239
245
|
this.#clearTimer()
|
|
240
|
-
this
|
|
246
|
+
this.#enqueueExport(true, error => this.#shutdownExporter(error))
|
|
241
247
|
}
|
|
242
248
|
|
|
243
249
|
/**
|
|
@@ -248,7 +254,7 @@ class PeriodicMetricReader {
|
|
|
248
254
|
if (this.#timer) return
|
|
249
255
|
|
|
250
256
|
this.#timer = setInterval(() => {
|
|
251
|
-
this.#
|
|
257
|
+
if (!this.#isExporting && this.#exportQueue.length === 0) this.#enqueueExport(false)
|
|
252
258
|
}, this.#exportInterval)
|
|
253
259
|
this.#timer.unref?.()
|
|
254
260
|
}
|
|
@@ -264,6 +270,75 @@ class PeriodicMetricReader {
|
|
|
264
270
|
}
|
|
265
271
|
}
|
|
266
272
|
|
|
273
|
+
/**
|
|
274
|
+
* @param {boolean} flushExporter Whether to flush the exporter after export
|
|
275
|
+
* @param {(error: Error | null) => void} [done] Called when the queued export completes
|
|
276
|
+
* @returns {void}
|
|
277
|
+
*/
|
|
278
|
+
#enqueueExport (flushExporter, done) {
|
|
279
|
+
this.#exportQueue.push({ flushExporter, done })
|
|
280
|
+
this.#drainExportQueue()
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** @returns {void} */
|
|
284
|
+
#drainExportQueue () {
|
|
285
|
+
if (this.#isExporting || this.#exportQueue.length === 0) return
|
|
286
|
+
|
|
287
|
+
this.#isExporting = true
|
|
288
|
+
const { flushExporter, done } = this.#exportQueue.shift()
|
|
289
|
+
let completed = false
|
|
290
|
+
const complete = error => {
|
|
291
|
+
if (completed) return
|
|
292
|
+
completed = true
|
|
293
|
+
this.#isExporting = false
|
|
294
|
+
queueMicrotask(() => this.#drainExportQueue())
|
|
295
|
+
callDone(done, error)
|
|
296
|
+
}
|
|
297
|
+
let exportCompleted = false
|
|
298
|
+
const afterExport = error => {
|
|
299
|
+
if (exportCompleted) return
|
|
300
|
+
exportCompleted = true
|
|
301
|
+
if (!flushExporter || typeof this.exporter.flush !== 'function') return complete(error)
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
this.exporter.flush(flushError => complete(error || flushError))
|
|
305
|
+
} catch (flushError) {
|
|
306
|
+
log.error('Error flushing OTLP metrics:', flushError)
|
|
307
|
+
complete(error || flushError)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
this.#collectAndExport(afterExport)
|
|
313
|
+
} catch (error) {
|
|
314
|
+
log.error('Error exporting OTLP metrics:', error)
|
|
315
|
+
afterExport(error)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* @param {Error} [exportError] Error from the final export
|
|
321
|
+
* @returns {void}
|
|
322
|
+
*/
|
|
323
|
+
#shutdownExporter (exportError) {
|
|
324
|
+
let completed = false
|
|
325
|
+
const complete = shutdownError => {
|
|
326
|
+
if (completed) return
|
|
327
|
+
completed = true
|
|
328
|
+
this.#shutdownComplete = true
|
|
329
|
+
const callbacks = this.#shutdownCallbacks.splice(0)
|
|
330
|
+
for (const callback of callbacks) callDone(callback, exportError || shutdownError)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
if (typeof this.exporter.shutdown === 'function') this.exporter.shutdown(complete)
|
|
335
|
+
else complete()
|
|
336
|
+
} catch (error) {
|
|
337
|
+
log.error('Error shutting down OTLP metrics exporter:', error)
|
|
338
|
+
complete(error)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
267
342
|
/**
|
|
268
343
|
* Collects measurements and exports metrics.
|
|
269
344
|
*
|
|
@@ -322,7 +397,13 @@ class PeriodicMetricReader {
|
|
|
322
397
|
this.#lastExportedState
|
|
323
398
|
)
|
|
324
399
|
|
|
325
|
-
this.exporter.export(metrics,
|
|
400
|
+
this.exporter.export(metrics, result => {
|
|
401
|
+
if (result?.code === 1) {
|
|
402
|
+
callback?.(result.error || new Error('OTLP metrics export failed'))
|
|
403
|
+
} else {
|
|
404
|
+
callback?.()
|
|
405
|
+
}
|
|
406
|
+
})
|
|
326
407
|
}
|
|
327
408
|
}
|
|
328
409
|
|
|
@@ -6,7 +6,9 @@ const { URL } = require('node:url')
|
|
|
6
6
|
const { storage } = require('../../../../datadog-core')
|
|
7
7
|
const log = require('../../log')
|
|
8
8
|
const { createServerlessDeliveryTracker } = require('../../serverless')
|
|
9
|
+
const { getHttpsProxyAgent } = require('../../exporters/common/proxy')
|
|
9
10
|
const telemetryMetrics = require('../../telemetry/metrics')
|
|
11
|
+
const { version: tracerVersion } = require('../../../../../package.json')
|
|
10
12
|
|
|
11
13
|
const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
|
|
12
14
|
const legacyStorage = storage('legacy')
|
|
@@ -48,8 +50,10 @@ class OtlpHttpExporterBase {
|
|
|
48
50
|
hostname: parsedUrl.hostname,
|
|
49
51
|
port: parsedUrl.port,
|
|
50
52
|
path: parsedUrl.pathname + parsedUrl.search,
|
|
53
|
+
agent: parsedUrl.protocol === 'https:' ? getHttpsProxyAgent(parsedUrl) : undefined,
|
|
51
54
|
headers: {
|
|
52
55
|
'Content-Type': isJson ? 'application/json' : 'application/x-protobuf',
|
|
56
|
+
'User-Agent': `dd-trace-js/${tracerVersion}`,
|
|
53
57
|
...headers,
|
|
54
58
|
},
|
|
55
59
|
}
|
|
@@ -169,10 +173,17 @@ class OtlpHttpExporterBase {
|
|
|
169
173
|
this.options.hostname = parsedUrl.hostname
|
|
170
174
|
this.options.port = parsedUrl.port
|
|
171
175
|
this.options.path = parsedUrl.pathname + parsedUrl.search
|
|
176
|
+
this.options.agent = parsedUrl.protocol === 'https:' ? getHttpsProxyAgent(parsedUrl) : undefined
|
|
172
177
|
this.telemetryTags[0] = `protocol:${this.#transport === https ? 'https' : 'http'}`
|
|
173
178
|
}
|
|
174
179
|
|
|
175
|
-
|
|
180
|
+
/**
|
|
181
|
+
* @param {() => void} [done]
|
|
182
|
+
* @returns {void}
|
|
183
|
+
*/
|
|
184
|
+
shutdown (done) {
|
|
185
|
+
done?.()
|
|
186
|
+
}
|
|
176
187
|
}
|
|
177
188
|
|
|
178
189
|
module.exports = OtlpHttpExporterBase
|
|
@@ -363,6 +363,11 @@ class TextMapPropagator {
|
|
|
363
363
|
* @returns {DatadogSpanContext | null}
|
|
364
364
|
*/
|
|
365
365
|
extract (carrier) {
|
|
366
|
+
if (!carrier || typeof carrier !== 'object') {
|
|
367
|
+
if (this.#config.DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT !== 'ignore') removeAllBaggageItems()
|
|
368
|
+
return null
|
|
369
|
+
}
|
|
370
|
+
|
|
366
371
|
const spanContext = this.#extractSpanContext(carrier)
|
|
367
372
|
if (spanContext === undefined) return null
|
|
368
373
|
|
|
@@ -825,7 +830,6 @@ class TextMapPropagator {
|
|
|
825
830
|
* @returns {DatadogSpanContext | undefined}
|
|
826
831
|
*/
|
|
827
832
|
#extractDatadogContext (carrier) {
|
|
828
|
-
if (!carrier) return
|
|
829
833
|
const traceId = readDatadogTraceId(carrier)
|
|
830
834
|
if (!traceId) return
|
|
831
835
|
const spanContext = extractGenericContext(traceId, readDatadogParentId(carrier), 10)
|
|
@@ -860,6 +864,8 @@ class TextMapPropagator {
|
|
|
860
864
|
} catch {
|
|
861
865
|
return
|
|
862
866
|
}
|
|
867
|
+
if (!parsed || typeof parsed !== 'object') return
|
|
868
|
+
|
|
863
869
|
const spanContext = this.#extractDatadogContext(parsed)
|
|
864
870
|
if (!spanContext) return
|
|
865
871
|
|
|
@@ -983,7 +989,7 @@ class TextMapPropagator {
|
|
|
983
989
|
*/
|
|
984
990
|
#extractBaggageItems (carrier, spanContext, extractBaggage) {
|
|
985
991
|
removeAllBaggageItems()
|
|
986
|
-
if (!
|
|
992
|
+
if (!extractBaggage) return
|
|
987
993
|
const header = readBaggage(carrier)
|
|
988
994
|
if (!header) return
|
|
989
995
|
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
const { channel } = require('dc-polyfill')
|
|
4
4
|
|
|
5
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
getEnvironmentVariable,
|
|
7
|
+
getValueFromEnvSources,
|
|
8
|
+
isSupportedConfiguration,
|
|
9
|
+
} = require('./config/helper')
|
|
6
10
|
const { isFalse, isTrue, normalizePluginEnvName } = require('./util')
|
|
7
11
|
const plugins = require('./plugins')
|
|
8
12
|
const log = require('./log')
|
|
@@ -59,12 +63,14 @@ function maybeEnable (Plugin) {
|
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
function getEnabled (Plugin) {
|
|
62
|
-
const envName = `DD_TRACE_${Plugin.id.toUpperCase()}_ENABLED`
|
|
66
|
+
const envName = normalizePluginEnvName(`DD_TRACE_${Plugin.id.toUpperCase()}_ENABLED`)
|
|
67
|
+
if (!isSupportedConfiguration(envName)) return
|
|
68
|
+
|
|
63
69
|
// skipDefault: only an explicitly configured value should drive enablement here. A registered
|
|
64
70
|
// default of `false` (e.g. an opt-in plugin like `nats`) must not be read as an explicit
|
|
65
71
|
// "disabled via configuration option" — that path both logs a misleading line and nulls the
|
|
66
72
|
// plugin class, bypassing the opt-in handled by `loadPlugin`.
|
|
67
|
-
return getValueFromEnvSources(
|
|
73
|
+
return getValueFromEnvSources(envName, true)
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
// TODO this must always be a singleton.
|
|
@@ -19,6 +19,7 @@ const plugins = {
|
|
|
19
19
|
get '@google-cloud/pubsub' () { return require('../../../datadog-plugin-google-cloud-pubsub/src') },
|
|
20
20
|
get '@google-cloud/vertexai' () { return require('../../../datadog-plugin-google-cloud-vertexai/src') },
|
|
21
21
|
get '@google/genai' () { return require('../../../datadog-plugin-google-genai/src') },
|
|
22
|
+
get '@graphql-tools/executor' () { return require('../../../datadog-plugin-graphql/src') },
|
|
22
23
|
get '@grpc/grpc-js' () { return require('../../../datadog-plugin-grpc/src') },
|
|
23
24
|
get '@hapi/hapi' () { return require('../../../datadog-plugin-hapi/src') },
|
|
24
25
|
get '@happy-dom/jest-environment' () { return require('../../../datadog-plugin-jest/src') },
|
|
@@ -1135,7 +1135,10 @@ function getCodeOwnersPatternRegex (pattern) {
|
|
|
1135
1135
|
}
|
|
1136
1136
|
|
|
1137
1137
|
const directoryOnly = pattern.endsWith('/')
|
|
1138
|
-
|
|
1138
|
+
let normalizedPattern = pattern.replace(/^\/+/, '')
|
|
1139
|
+
let normalizedPatternEnd = normalizedPattern.length
|
|
1140
|
+
while (normalizedPatternEnd > 0 && normalizedPattern[normalizedPatternEnd - 1] === '/') normalizedPatternEnd--
|
|
1141
|
+
normalizedPattern = normalizedPattern.slice(0, normalizedPatternEnd)
|
|
1139
1142
|
const anchored = pattern.startsWith('/') || normalizedPattern.includes('/')
|
|
1140
1143
|
|
|
1141
1144
|
if (!normalizedPattern) {
|
|
@@ -263,6 +263,10 @@ class PrioritySampler {
|
|
|
263
263
|
context._sampling.mechanism = SAMPLING_MECHANISM_REMOTE_DYNAMIC
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
+
if (rule.discard) {
|
|
267
|
+
context._sampling.discard = true
|
|
268
|
+
}
|
|
269
|
+
|
|
266
270
|
return rule.sample(context) && this._isSampledByRateLimit(context)
|
|
267
271
|
? USER_KEEP
|
|
268
272
|
: USER_REJECT
|
|
@@ -185,6 +185,7 @@ function resourceLocator (span) {
|
|
|
185
185
|
* @property {number} [sampleRate=1] - Deterministic sampling rate in [0, 1].
|
|
186
186
|
* @property {string} [provenance] - Optional provenance/metadata for this rule.
|
|
187
187
|
* @property {number} [maxPerSecond] - Maximum samples per second (rate limit).
|
|
188
|
+
* @property {boolean} [discard=false] - Whether to fully drop a trace if not kept.
|
|
188
189
|
*/
|
|
189
190
|
|
|
190
191
|
/**
|
|
@@ -195,7 +196,7 @@ class SamplingRule {
|
|
|
195
196
|
/**
|
|
196
197
|
* @param {SamplingRuleConfig} [config]
|
|
197
198
|
*/
|
|
198
|
-
constructor ({ name, service, resource, tags, sampleRate = 1, provenance, maxPerSecond } = {}) {
|
|
199
|
+
constructor ({ name, service, resource, tags, sampleRate = 1, provenance, maxPerSecond, discard = false } = {}) {
|
|
199
200
|
this.matchers = []
|
|
200
201
|
|
|
201
202
|
if (name !== undefined) {
|
|
@@ -216,6 +217,7 @@ class SamplingRule {
|
|
|
216
217
|
this._sampler = new Sampler(sampleRate)
|
|
217
218
|
this._limiter = undefined
|
|
218
219
|
this.provenance = provenance
|
|
220
|
+
this.discard = !!discard
|
|
219
221
|
|
|
220
222
|
if (Number.isFinite(maxPerSecond)) {
|
|
221
223
|
this._limiter = new RateLimiter(maxPerSecond)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { AUTO_REJECT } = require('../../../ext/priority')
|
|
3
4
|
const log = require('./log')
|
|
4
5
|
const spanFormat = require('./span_format')
|
|
5
6
|
const SpanSampler = require('./span_sampler')
|
|
@@ -34,7 +35,20 @@ class SpanProcessor {
|
|
|
34
35
|
sample (span) {
|
|
35
36
|
const spanContext = span.context()
|
|
36
37
|
this._prioritySampler.sample(spanContext)
|
|
37
|
-
this
|
|
38
|
+
if (!this.#isDiscarded(spanContext)) {
|
|
39
|
+
this._spanSampler.sample(spanContext)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A rule's reject decision can later be overridden (e.g. a product force-keeping the trace via
|
|
45
|
+
* `PrioritySampler.keepTrace()`), so `discard` only applies while the priority is still a reject.
|
|
46
|
+
*
|
|
47
|
+
* @param {import('./opentracing/span_context')} spanContext
|
|
48
|
+
* @returns {boolean}
|
|
49
|
+
*/
|
|
50
|
+
#isDiscarded (spanContext) {
|
|
51
|
+
return spanContext._sampling.discard && spanContext._sampling.priority <= AUTO_REJECT
|
|
38
52
|
}
|
|
39
53
|
|
|
40
54
|
process (span) {
|
|
@@ -56,11 +70,12 @@ class SpanProcessor {
|
|
|
56
70
|
|
|
57
71
|
let isFirstSpanInChunk = true
|
|
58
72
|
const stampApmDisabled = this._config.apmTracingEnabled === false
|
|
73
|
+
const discard = this.#isDiscarded(spanContext)
|
|
59
74
|
|
|
60
75
|
for (const span of started) {
|
|
61
76
|
if (span._duration === undefined) {
|
|
62
77
|
active.push(span)
|
|
63
|
-
} else {
|
|
78
|
+
} else if (!discard) {
|
|
64
79
|
const formattedSpan = spanFormat(span, isFirstSpanInChunk, this._processTags)
|
|
65
80
|
if (stampApmDisabled) {
|
|
66
81
|
formattedSpan.metrics[APM_TRACING_ENABLED_KEY] = 0
|
|
@@ -76,7 +91,7 @@ class SpanProcessor {
|
|
|
76
91
|
}
|
|
77
92
|
}
|
|
78
93
|
|
|
79
|
-
if (formatted.length !== 0 && trace.isRecording !== false) {
|
|
94
|
+
if (!discard && formatted.length !== 0 && trace.isRecording !== false) {
|
|
80
95
|
this._exporter.export(formatted)
|
|
81
96
|
}
|
|
82
97
|
|
|
@@ -76,9 +76,10 @@ let getTestOptimizationAgent
|
|
|
76
76
|
* @param {import('../config/config-base')} config
|
|
77
77
|
* @param {TelemetryApplication} application
|
|
78
78
|
* @param {TelemetryRequestType} reqType
|
|
79
|
+
* @param {string} [apiKey]
|
|
79
80
|
* @returns {Record<string, string>}
|
|
80
81
|
*/
|
|
81
|
-
function getHeaders (config, application, reqType) {
|
|
82
|
+
function getHeaders (config, application, reqType, apiKey) {
|
|
82
83
|
const headers = {
|
|
83
84
|
'DD-Client-Library-Language': application.language_name,
|
|
84
85
|
'DD-Client-Library-Version': application.tracer_version,
|
|
@@ -94,8 +95,8 @@ function getHeaders (config, application, reqType) {
|
|
|
94
95
|
if (debug) {
|
|
95
96
|
headers['dd-telemetry-debug-enabled'] = 'true'
|
|
96
97
|
}
|
|
97
|
-
if (
|
|
98
|
-
headers['dd-api-key'] =
|
|
98
|
+
if (apiKey) {
|
|
99
|
+
headers['dd-api-key'] = apiKey
|
|
99
100
|
}
|
|
100
101
|
return headers
|
|
101
102
|
}
|
|
@@ -161,7 +162,7 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
|
|
|
161
162
|
port,
|
|
162
163
|
method: 'POST',
|
|
163
164
|
path: isAgentlessMode ? '/api/v2/apmtelemetry' : '/telemetry/proxy/api/v2/apmtelemetry',
|
|
164
|
-
headers: getHeaders(config, application, reqType),
|
|
165
|
+
headers: getHeaders(config, application, reqType, isAgentlessMode ? config.DD_API_KEY : undefined),
|
|
165
166
|
}
|
|
166
167
|
if (isCiVisibility) options.agent = getTestOptimizationAgent(url)
|
|
167
168
|
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
function splitModel (model) {
|
|
4
|
-
if (!model) return { modelName: undefined, modelProvider: 'anthropic' }
|
|
5
|
-
const idx = model.indexOf('/')
|
|
6
|
-
if (idx === -1) return { modelName: model, modelProvider: 'anthropic' }
|
|
7
|
-
return { modelName: model.slice(idx + 1), modelProvider: model.slice(0, idx) }
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
module.exports = { splitModel }
|