dd-trace 5.98.0 → 5.99.1
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 +0 -1
- package/ext/tags.js +1 -0
- package/index.d.ts +9 -1
- package/package.json +68 -47
- package/packages/datadog-instrumentations/src/crypto.js +45 -0
- package/packages/datadog-instrumentations/src/cypress-config.js +122 -16
- package/packages/datadog-instrumentations/src/dns.js +24 -56
- package/packages/datadog-instrumentations/src/graphql.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +74 -0
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +4 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +10 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/modelcontextprotocol-sdk.js +59 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +11 -2
- package/packages/datadog-instrumentations/src/jest.js +5 -5
- package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +7 -0
- package/packages/datadog-instrumentations/src/pino.js +4 -28
- package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +27 -0
- package/packages/datadog-instrumentations/src/playwright.js +5 -17
- package/packages/datadog-instrumentations/src/stripe.js +38 -24
- package/packages/datadog-instrumentations/src/vitest.js +32 -4
- package/packages/datadog-instrumentations/src/zlib.js +29 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +1 -2
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +8 -15
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +4 -9
- package/packages/datadog-plugin-cucumber/src/index.js +2 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +5 -5
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +48 -1
- package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -1
- package/packages/datadog-plugin-graphql/src/utils.js +2 -2
- package/packages/datadog-plugin-http/src/server.js +11 -11
- package/packages/datadog-plugin-jest/src/index.js +2 -2
- package/packages/datadog-plugin-memcached/src/index.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +1 -2
- package/packages/datadog-plugin-modelcontextprotocol-sdk/src/index.js +24 -0
- package/packages/datadog-plugin-modelcontextprotocol-sdk/src/tracing.js +55 -0
- package/packages/datadog-plugin-mongodb-core/src/index.js +1 -6
- package/packages/datadog-plugin-playwright/src/index.js +2 -3
- package/packages/datadog-plugin-vitest/src/index.js +14 -6
- package/packages/datadog-plugin-ws/src/close.js +2 -0
- package/packages/datadog-plugin-ws/src/producer.js +2 -0
- package/packages/datadog-plugin-ws/src/receiver.js +1 -0
- package/packages/dd-trace/src/aiguard/channels.js +8 -0
- package/packages/dd-trace/src/aiguard/index.js +7 -3
- package/packages/dd-trace/src/aiguard/sdk.js +44 -0
- package/packages/dd-trace/src/aiguard/tags.js +1 -0
- package/packages/dd-trace/src/appsec/blocking.js +18 -6
- package/packages/dd-trace/src/appsec/graphql.js +7 -7
- package/packages/dd-trace/src/appsec/index.js +9 -11
- package/packages/dd-trace/src/appsec/rasp/command_injection.js +4 -5
- package/packages/dd-trace/src/appsec/rasp/lfi.js +8 -4
- package/packages/dd-trace/src/appsec/rasp/sql_injection.js +5 -10
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +5 -6
- package/packages/dd-trace/src/appsec/recommended.json +2438 -13
- package/packages/dd-trace/src/appsec/reporter.js +6 -5
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -8
- package/packages/dd-trace/src/appsec/store.js +50 -0
- package/packages/dd-trace/src/appsec/waf/index.js +3 -5
- package/packages/dd-trace/src/baggage.js +16 -13
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +3 -4
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -2
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -5
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +3 -4
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +6 -6
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +2 -2
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -2
- package/packages/dd-trace/src/config/config-types.d.ts +0 -4
- package/packages/dd-trace/src/config/defaults.js +10 -10
- package/packages/dd-trace/src/config/generated-config-types.d.ts +39 -38
- package/packages/dd-trace/src/config/index.js +29 -39
- package/packages/dd-trace/src/config/parsers.js +26 -9
- package/packages/dd-trace/src/config/supported-configurations.json +46 -78
- package/packages/dd-trace/src/debugger/config.js +2 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +25 -5
- package/packages/dd-trace/src/dogstatsd.js +5 -8
- package/packages/dd-trace/src/encode/0.4.js +4 -5
- package/packages/dd-trace/src/exporter.js +1 -1
- package/packages/dd-trace/src/exporters/agent/index.js +0 -1
- package/packages/dd-trace/src/exporters/agent/writer.js +1 -2
- package/packages/dd-trace/src/exporters/agentless/writer.js +3 -3
- package/packages/dd-trace/src/exporters/common/util.js +2 -2
- package/packages/dd-trace/src/git_metadata_tagger.js +1 -1
- package/packages/dd-trace/src/id.js +2 -0
- package/packages/dd-trace/src/index.js +2 -5
- package/packages/dd-trace/src/lambda/handler.js +1 -3
- package/packages/dd-trace/src/llmobs/constants/tags.js +3 -0
- package/packages/dd-trace/src/llmobs/plugins/{anthropic.js → anthropic/index.js} +5 -63
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +106 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +3 -2
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +3 -2
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +2 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +0 -49
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/vectorstore.js +2 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/messages.js +76 -0
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -26
- package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/index.js +68 -0
- package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +57 -0
- package/packages/dd-trace/src/llmobs/sdk.js +23 -3
- package/packages/dd-trace/src/llmobs/span_processor.js +14 -1
- package/packages/dd-trace/src/llmobs/writers/base.js +7 -1
- package/packages/dd-trace/src/llmobs/writers/spans.js +1 -1
- package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +103 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -0
- package/packages/dd-trace/src/opentelemetry/logs/index.js +6 -6
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +3 -2
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +7 -7
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +3 -2
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +19 -66
- package/packages/dd-trace/src/opentelemetry/trace/index.js +11 -16
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +11 -3
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +51 -41
- package/packages/dd-trace/src/opentelemetry/tracer.js +9 -11
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +30 -23
- package/packages/dd-trace/src/opentracing/span.js +2 -2
- package/packages/dd-trace/src/opentracing/tracer.js +12 -5
- package/packages/dd-trace/src/plugin_manager.js +6 -6
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +128 -7
- package/packages/dd-trace/src/plugins/util/url.js +2 -1
- package/packages/dd-trace/src/profiling/profilers/event_plugins/crypto.js +32 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/zlib.js +19 -0
- package/packages/dd-trace/src/profiling/profilers/events.js +35 -0
- package/packages/dd-trace/src/proxy.js +8 -14
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +2 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
- package/packages/dd-trace/src/span_processor.js +1 -2
- package/packages/dd-trace/src/tagger.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +5 -7
- package/packages/dd-trace/src/tracer.js +2 -2
- package/vendor/dist/ignore/LICENSE +0 -21
- package/vendor/dist/ignore/index.js +0 -1
|
@@ -81,10 +81,10 @@ class Tracer {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
_convertOtelContextToDatadog (traceId, spanId, traceFlag, ts, meta = {}) {
|
|
84
|
-
|
|
84
|
+
let origin = null
|
|
85
85
|
let samplingPriority = traceFlag
|
|
86
86
|
|
|
87
|
-
ts = ts?.traceparent
|
|
87
|
+
ts = ts?.traceparent
|
|
88
88
|
|
|
89
89
|
if (ts) {
|
|
90
90
|
// Use TraceState.fromString to parse the tracestate header
|
|
@@ -101,19 +101,17 @@ class Tracer {
|
|
|
101
101
|
// Assuming ddTraceStateData is now a Map or similar structure containing Datadog trace state data
|
|
102
102
|
// Extract values as needed, similar to the original logic
|
|
103
103
|
const samplingPriorityTs = ddTraceStateData.get('s')
|
|
104
|
-
|
|
104
|
+
origin = ddTraceStateData.get('o') ?? null
|
|
105
105
|
// Convert Map to object for meta
|
|
106
106
|
const otherPropagatedTags = Object.fromEntries(ddTraceStateData.entries())
|
|
107
107
|
|
|
108
108
|
// Update meta and samplingPriority based on extracted values
|
|
109
109
|
Object.assign(meta, otherPropagatedTags)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
origin
|
|
114
|
-
)
|
|
110
|
+
// Guard against an undefined/empty `s:` field that would result in NaN.
|
|
111
|
+
const tracestateSamplingPriority = samplingPriorityTs ? Math.trunc(samplingPriorityTs) : undefined
|
|
112
|
+
samplingPriority = TextMapPropagator._getSamplingPriority(traceFlag, tracestateSamplingPriority, origin)
|
|
115
113
|
} else {
|
|
116
|
-
log.debug('
|
|
114
|
+
log.debug('No dd list member in tracestate from incoming request:', ts)
|
|
117
115
|
}
|
|
118
116
|
}
|
|
119
117
|
|
|
@@ -121,8 +119,8 @@ class Tracer {
|
|
|
121
119
|
traceId: id(traceId, 16), spanId: id(), tags: meta, parentId: id(spanId, 16),
|
|
122
120
|
})
|
|
123
121
|
|
|
124
|
-
spanContext._sampling = { priority: samplingPriority }
|
|
125
|
-
spanContext._trace = { origin }
|
|
122
|
+
spanContext._ddContext._sampling = { priority: samplingPriority }
|
|
123
|
+
spanContext._ddContext._trace = { ...spanContext._ddContext._trace, origin }
|
|
126
124
|
return spanContext
|
|
127
125
|
}
|
|
128
126
|
|
|
@@ -64,6 +64,7 @@ const tracestateTagValueFilter = /[^\x20-\x2B\x2D-\x3A\x3C-\x7D]/g
|
|
|
64
64
|
const invalidSegment = /^0+$/
|
|
65
65
|
const zeroTraceId = '0000000000000000'
|
|
66
66
|
const hex16 = /^[0-9A-Fa-f]{16}$/
|
|
67
|
+
const percentByte = /%([0-9A-Fa-f]{2})/g
|
|
67
68
|
|
|
68
69
|
class TextMapPropagator {
|
|
69
70
|
#extractB3Context
|
|
@@ -173,15 +174,15 @@ class TextMapPropagator {
|
|
|
173
174
|
const baggageItems = getAllBaggageItems()
|
|
174
175
|
if (!baggageItems) return
|
|
175
176
|
for (const [key, value] of Object.entries(baggageItems)) {
|
|
176
|
-
const baggageKey =
|
|
177
|
-
if (!
|
|
177
|
+
const baggageKey = key.trim()
|
|
178
|
+
if (!baggageTokenExpr.test(baggageKey)) continue
|
|
178
179
|
|
|
179
180
|
// Do not trim values. If callers include leading/trailing whitespace, it must be percent-encoded.
|
|
180
181
|
// W3C list-member allows optional properties after ';'.
|
|
181
182
|
// https://www.w3.org/TR/baggage/#header-content
|
|
182
|
-
const item = `${baggageKey}=${encodeURIComponent(
|
|
183
|
+
const item = `${baggageKey}=${encodeURIComponent(value)},`
|
|
183
184
|
itemCounter += 1
|
|
184
|
-
byteCounter +=
|
|
185
|
+
byteCounter += item.length
|
|
185
186
|
|
|
186
187
|
// Check for item count limit exceeded
|
|
187
188
|
if (itemCounter > this._config.baggageMaxItems) {
|
|
@@ -209,7 +210,7 @@ class TextMapPropagator {
|
|
|
209
210
|
_injectTags (spanContext, carrier) {
|
|
210
211
|
const trace = spanContext._trace
|
|
211
212
|
|
|
212
|
-
if (this._config.
|
|
213
|
+
if (this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) {
|
|
213
214
|
log.debug('Trace tag propagation is disabled, skipping injection.')
|
|
214
215
|
return
|
|
215
216
|
}
|
|
@@ -228,7 +229,7 @@ class TextMapPropagator {
|
|
|
228
229
|
|
|
229
230
|
const header = tags.join(',')
|
|
230
231
|
|
|
231
|
-
if (header.length > this._config.
|
|
232
|
+
if (header.length > this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
|
|
232
233
|
log.error('Trace tags from span are too large, skipping injection.')
|
|
233
234
|
} else if (header) {
|
|
234
235
|
carrier[tagsKey] = header
|
|
@@ -387,7 +388,7 @@ class TextMapPropagator {
|
|
|
387
388
|
if (context === null) {
|
|
388
389
|
context = extractedContext
|
|
389
390
|
style = extractor
|
|
390
|
-
if (this._config.
|
|
391
|
+
if (this._config.DD_TRACE_PROPAGATION_EXTRACT_FIRST) {
|
|
391
392
|
break
|
|
392
393
|
}
|
|
393
394
|
} else {
|
|
@@ -436,7 +437,7 @@ class TextMapPropagator {
|
|
|
436
437
|
this._extractSamplingPriority(carrier, spanContext)
|
|
437
438
|
this._extractTags(carrier, spanContext)
|
|
438
439
|
|
|
439
|
-
if (this._config.
|
|
440
|
+
if (this._config.DD_TRACE_PROPAGATION_EXTRACT_FIRST) return spanContext
|
|
440
441
|
|
|
441
442
|
const tc = this._extractTraceparentContext(carrier)
|
|
442
443
|
|
|
@@ -706,9 +707,8 @@ class TextMapPropagator {
|
|
|
706
707
|
try {
|
|
707
708
|
value = decodeURIComponent(value)
|
|
708
709
|
} catch {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
return
|
|
710
|
+
const bytes = value.replaceAll(percentByte, (_, hex) => String.fromCharCode(Number.parseInt(hex, 16)))
|
|
711
|
+
value = Buffer.from(bytes, 'binary').toString('utf8')
|
|
712
712
|
}
|
|
713
713
|
|
|
714
714
|
if (spanContext && (tagAllKeys || baggageTagKeys.has(key))) {
|
|
@@ -734,9 +734,9 @@ class TextMapPropagator {
|
|
|
734
734
|
|
|
735
735
|
const trace = spanContext._trace
|
|
736
736
|
|
|
737
|
-
if (this._config.
|
|
737
|
+
if (this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) {
|
|
738
738
|
log.debug('Trace tag propagation is disabled, skipping extraction.')
|
|
739
|
-
} else if (carrier[tagsKey].length > this._config.
|
|
739
|
+
} else if (carrier[tagsKey].length > this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
|
|
740
740
|
log.error('Trace tags from carrier are too large, skipping extraction.')
|
|
741
741
|
} else {
|
|
742
742
|
const pairs = carrier[tagsKey].split(',')
|
|
@@ -802,18 +802,25 @@ class TextMapPropagator {
|
|
|
802
802
|
return spanContext._traceId.toString(16)
|
|
803
803
|
}
|
|
804
804
|
|
|
805
|
-
|
|
805
|
+
/**
|
|
806
|
+
* @param {number} traceparentSampled
|
|
807
|
+
* @param {number|undefined} tracestateSamplingPriority
|
|
808
|
+
* @param {string|null} origin
|
|
809
|
+
* @returns {import('../../priority_sampler').SamplingPriority}
|
|
810
|
+
*/
|
|
811
|
+
static _getSamplingPriority (traceparentSampled, tracestateSamplingPriority, origin) {
|
|
806
812
|
const fromRumWithoutPriority = !tracestateSamplingPriority && origin === 'rum'
|
|
807
813
|
|
|
808
|
-
let samplingPriority
|
|
809
|
-
|
|
810
|
-
(!
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
814
|
+
let samplingPriority =
|
|
815
|
+
/** @type {import('../../priority_sampler').SamplingPriority} */ (tracestateSamplingPriority ?? AUTO_KEEP)
|
|
816
|
+
if (!fromRumWithoutPriority) {
|
|
817
|
+
if (traceparentSampled === 0 &&
|
|
818
|
+
(!tracestateSamplingPriority || tracestateSamplingPriority >= 0)) {
|
|
819
|
+
samplingPriority = AUTO_REJECT
|
|
820
|
+
} else if (traceparentSampled === 1 &&
|
|
821
|
+
(!tracestateSamplingPriority || tracestateSamplingPriority < 0)) {
|
|
822
|
+
samplingPriority = AUTO_KEEP
|
|
823
|
+
}
|
|
817
824
|
}
|
|
818
825
|
|
|
819
826
|
return samplingPriority
|
|
@@ -112,7 +112,7 @@ class DatadogSpan {
|
|
|
112
112
|
// even `Span` itself in this case.
|
|
113
113
|
//
|
|
114
114
|
// TODO: Refactor Tracer/Span + tests to avoid having to do nullish checks.
|
|
115
|
-
if (tracer?._config?.
|
|
115
|
+
if (tracer?._config?.DD_TRACE_SPAN_LEAK_DEBUG > 0) {
|
|
116
116
|
require('../spanleak').addSpan(this, operationName)
|
|
117
117
|
}
|
|
118
118
|
|
|
@@ -149,7 +149,7 @@ class DatadogSpan {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
|
-
* @returns {import('
|
|
152
|
+
* @returns {import('./span_context')}
|
|
153
153
|
*/
|
|
154
154
|
context () {
|
|
155
155
|
return this._spanContext
|
|
@@ -20,7 +20,7 @@ const REFERENCE_CHILD_OF = 'child_of'
|
|
|
20
20
|
const REFERENCE_FOLLOWS_FROM = 'follows_from'
|
|
21
21
|
|
|
22
22
|
class DatadogTracer {
|
|
23
|
-
constructor (config, prioritySampler
|
|
23
|
+
constructor (config, prioritySampler) {
|
|
24
24
|
this._config = config
|
|
25
25
|
this._service = config.service
|
|
26
26
|
this._version = config.version
|
|
@@ -29,8 +29,15 @@ class DatadogTracer {
|
|
|
29
29
|
this._debug = config.debug
|
|
30
30
|
this._prioritySampler = prioritySampler ?? new PrioritySampler(config.env, config.sampler)
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
// OTEL_TRACES_EXPORTER=otlp should not replace the Test Optimization
|
|
33
|
+
// exporter when the tracer is running in Test Optimization mode. Test spans
|
|
34
|
+
// (test_session/test_module/ test_suite/test) belong on the citestcycle
|
|
35
|
+
// endpoint, not on an OTLP traces endpoint — otherwise users with OTEL_*
|
|
36
|
+
// vars set in their environment (e.g. for a separate telemetry integration)
|
|
37
|
+
// silently lose all test spans.
|
|
38
|
+
if (config.OTEL_TRACES_EXPORTER === 'otlp' && !config.isCiVisibility) {
|
|
39
|
+
const { createOtlpTraceExporter } = require('../opentelemetry/trace')
|
|
40
|
+
this._exporter = createOtlpTraceExporter(config)
|
|
34
41
|
} else {
|
|
35
42
|
const Exporter = getExporter(config.experimental.exporter)
|
|
36
43
|
this._exporter = new Exporter(config, this._prioritySampler)
|
|
@@ -43,7 +50,7 @@ class DatadogTracer {
|
|
|
43
50
|
this._propagators = {
|
|
44
51
|
[formats.TEXT_MAP]: new TextMapPropagator(config),
|
|
45
52
|
[formats.HTTP_HEADERS]: new HttpPropagator(config),
|
|
46
|
-
[formats.BINARY]: new BinaryPropagator(
|
|
53
|
+
[formats.BINARY]: new BinaryPropagator(),
|
|
47
54
|
[formats.LOG]: new LogPropagator(config),
|
|
48
55
|
[formats.TEXT_MAP_DSM]: new DSMTextMapPropagator(config),
|
|
49
56
|
}
|
|
@@ -116,7 +123,7 @@ class DatadogTracer {
|
|
|
116
123
|
* Get the span context from a span or a span context.
|
|
117
124
|
*
|
|
118
125
|
* @param {Span|SpanContext} spanContext
|
|
119
|
-
* @returns {SpanContext}
|
|
126
|
+
* @returns {SpanContext|null}
|
|
120
127
|
*/
|
|
121
128
|
function getContext (spanContext) {
|
|
122
129
|
if (spanContext instanceof Span) {
|
|
@@ -163,9 +163,9 @@ module.exports = class PluginManager {
|
|
|
163
163
|
dsmEnabled,
|
|
164
164
|
clientIpEnabled,
|
|
165
165
|
clientIpHeader,
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
DD_TRACE_MEMCACHED_COMMAND_ENABLED,
|
|
167
|
+
DD_TEST_SESSION_NAME,
|
|
168
|
+
DD_AGENTLESS_LOG_SUBMISSION_ENABLED,
|
|
169
169
|
isTestDynamicInstrumentationEnabled,
|
|
170
170
|
isServiceUserProvided,
|
|
171
171
|
middlewareTracingEnabled,
|
|
@@ -180,13 +180,13 @@ module.exports = class PluginManager {
|
|
|
180
180
|
codeOriginForSpans,
|
|
181
181
|
dbmPropagationMode,
|
|
182
182
|
dsmEnabled,
|
|
183
|
-
|
|
183
|
+
DD_TRACE_MEMCACHED_COMMAND_ENABLED,
|
|
184
184
|
site,
|
|
185
185
|
url,
|
|
186
186
|
headers: headerTags || [],
|
|
187
187
|
clientIpHeader,
|
|
188
|
-
|
|
189
|
-
|
|
188
|
+
DD_TEST_SESSION_NAME,
|
|
189
|
+
DD_AGENTLESS_LOG_SUBMISSION_ENABLED,
|
|
190
190
|
isTestDynamicInstrumentationEnabled,
|
|
191
191
|
isServiceUserProvided,
|
|
192
192
|
traceWebsocketMessagesEnabled,
|
|
@@ -6,6 +6,7 @@ const plugins = {
|
|
|
6
6
|
get '@aws-sdk/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
|
|
7
7
|
get '@azure/event-hubs' () { return require('../../../datadog-plugin-azure-event-hubs/src') },
|
|
8
8
|
get '@azure/functions' () { return require('../../../datadog-plugin-azure-functions/src') },
|
|
9
|
+
get '@modelcontextprotocol/sdk' () { return require('../../../datadog-plugin-modelcontextprotocol-sdk/src') },
|
|
9
10
|
get 'durable-functions' () { return require('../../../datadog-plugin-azure-durable-functions/src') },
|
|
10
11
|
get '@azure/service-bus' () { return require('../../../datadog-plugin-azure-service-bus/src') },
|
|
11
12
|
get '@cucumber/cucumber' () { return require('../../../datadog-plugin-cucumber/src') },
|
|
@@ -51,7 +51,7 @@ module.exports = class LogPlugin extends Plugin {
|
|
|
51
51
|
configure (config) {
|
|
52
52
|
return super.configure({
|
|
53
53
|
...config,
|
|
54
|
-
enabled: config.enabled && (config.logInjection || config.
|
|
54
|
+
enabled: config.enabled && (config.logInjection || config.DD_AGENTLESS_LOG_SUBMISSION_ENABLED),
|
|
55
55
|
})
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -9,7 +9,6 @@ const { getEnvironmentVariable } = require('../../config/helper')
|
|
|
9
9
|
const satisfies = require('../../../../../vendor/dist/semifies')
|
|
10
10
|
|
|
11
11
|
const istanbul = require('../../../../../vendor/dist/istanbul-lib-coverage')
|
|
12
|
-
const ignore = require('../../../../../vendor/dist/ignore')
|
|
13
12
|
|
|
14
13
|
const id = require('../../id')
|
|
15
14
|
const {
|
|
@@ -671,24 +670,146 @@ function getCodeOwnersFileEntries (rootDir) {
|
|
|
671
670
|
const trimmed = content.trim()
|
|
672
671
|
if (trimmed === '') continue
|
|
673
672
|
const [pattern, ...owners] = trimmed.split(/\s+/)
|
|
674
|
-
entries.push({ pattern, owners })
|
|
673
|
+
entries.push(setCodeOwnersPatternRegex({ pattern, owners }))
|
|
675
674
|
}
|
|
676
675
|
// Reverse because rules defined last take precedence
|
|
677
676
|
return entries.reverse()
|
|
678
677
|
}
|
|
679
678
|
|
|
680
|
-
const
|
|
679
|
+
const codeOwnersPerEntries = new WeakMap()
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* @param {string} character
|
|
683
|
+
* @returns {string}
|
|
684
|
+
*/
|
|
685
|
+
function escapeRegexCharacter (character) {
|
|
686
|
+
return character.replaceAll(/[|\\{}()[\]^$+*?.]/g, String.raw`\$&`)
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* @param {string} pattern
|
|
691
|
+
* @returns {boolean}
|
|
692
|
+
*/
|
|
693
|
+
function hasUnescapedWildcard (pattern) {
|
|
694
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
695
|
+
const character = pattern[i]
|
|
696
|
+
if (character === '\\') {
|
|
697
|
+
i++
|
|
698
|
+
} else if (character === '*' || character === '?') {
|
|
699
|
+
return true
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return false
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* @param {string} pattern
|
|
707
|
+
* @returns {string}
|
|
708
|
+
*/
|
|
709
|
+
function codeOwnersPatternToRegexSource (pattern) {
|
|
710
|
+
let source = ''
|
|
711
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
712
|
+
const character = pattern[i]
|
|
713
|
+
|
|
714
|
+
if (character === '\\') {
|
|
715
|
+
const escapedCharacter = pattern[i + 1]
|
|
716
|
+
source += escapedCharacter === undefined
|
|
717
|
+
? escapeRegexCharacter(character)
|
|
718
|
+
: escapeRegexCharacter(escapedCharacter)
|
|
719
|
+
i++
|
|
720
|
+
} else if (character === '*') {
|
|
721
|
+
if (pattern[i + 1] === '*') {
|
|
722
|
+
if (pattern[i + 2] === '/') {
|
|
723
|
+
source += '(?:.*/)?'
|
|
724
|
+
i += 2
|
|
725
|
+
} else {
|
|
726
|
+
source += '.*'
|
|
727
|
+
i++
|
|
728
|
+
}
|
|
729
|
+
} else {
|
|
730
|
+
source += '[^/]*'
|
|
731
|
+
}
|
|
732
|
+
} else if (character === '?') {
|
|
733
|
+
source += '[^/]'
|
|
734
|
+
} else {
|
|
735
|
+
source += escapeRegexCharacter(character)
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
return source
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* @param {string} pattern
|
|
743
|
+
* @returns {RegExp|null}
|
|
744
|
+
*/
|
|
745
|
+
function getCodeOwnersPatternRegex (pattern) {
|
|
746
|
+
if (!pattern || pattern[0] === '!') {
|
|
747
|
+
return null
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const directoryOnly = pattern.endsWith('/')
|
|
751
|
+
const normalizedPattern = pattern.replace(/^\/+/, '').replace(/\/+$/, '')
|
|
752
|
+
const anchored = pattern.startsWith('/') || normalizedPattern.includes('/')
|
|
753
|
+
|
|
754
|
+
if (!normalizedPattern) {
|
|
755
|
+
return null
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const lastSlashIndex = normalizedPattern.lastIndexOf('/')
|
|
759
|
+
const lastSegment = lastSlashIndex === -1 ? normalizedPattern : normalizedPattern.slice(lastSlashIndex + 1)
|
|
760
|
+
const descendantSuffix = directoryOnly || !hasUnescapedWildcard(lastSegment) ? '(?:/.*)?' : ''
|
|
761
|
+
const patternSource = codeOwnersPatternToRegexSource(normalizedPattern)
|
|
762
|
+
const regexSource = anchored
|
|
763
|
+
? `^${patternSource}${descendantSuffix}$`
|
|
764
|
+
: `(?:^|/)${patternSource}${descendantSuffix}$`
|
|
765
|
+
|
|
766
|
+
return new RegExp(regexSource)
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
function setCodeOwnersPatternRegex (entry) {
|
|
770
|
+
Object.defineProperty(entry, 'regex', {
|
|
771
|
+
configurable: true,
|
|
772
|
+
value: getCodeOwnersPatternRegex(entry.pattern),
|
|
773
|
+
writable: true,
|
|
774
|
+
})
|
|
775
|
+
return entry
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Match a repository-relative filename against a CODEOWNERS pattern.
|
|
780
|
+
* See GitHub's CODEOWNERS pattern rules:
|
|
781
|
+
* https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
|
782
|
+
*
|
|
783
|
+
* @param {RegExp|null} regex
|
|
784
|
+
* @param {string} filename
|
|
785
|
+
* @returns {boolean}
|
|
786
|
+
*/
|
|
787
|
+
function isCodeOwnersPatternMatch (regex, filename) {
|
|
788
|
+
if (!regex || !filename) {
|
|
789
|
+
return false
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
const normalizedFilename = filename.replaceAll('\\', '/').replace(/^\/+/, '')
|
|
793
|
+
return regex.test(normalizedFilename)
|
|
794
|
+
}
|
|
681
795
|
|
|
682
796
|
function getCodeOwnersForFilename (filename, entries) {
|
|
683
797
|
if (!entries) {
|
|
684
798
|
return null
|
|
685
799
|
}
|
|
686
|
-
|
|
800
|
+
let codeOwnersPerFileName = codeOwnersPerEntries.get(entries)
|
|
801
|
+
|
|
802
|
+
if (!codeOwnersPerFileName) {
|
|
803
|
+
codeOwnersPerFileName = new Map()
|
|
804
|
+
codeOwnersPerEntries.set(entries, codeOwnersPerFileName)
|
|
805
|
+
} else if (codeOwnersPerFileName.has(filename)) {
|
|
687
806
|
return codeOwnersPerFileName.get(filename)
|
|
688
807
|
}
|
|
808
|
+
|
|
689
809
|
for (const entry of entries) {
|
|
690
810
|
try {
|
|
691
|
-
const
|
|
811
|
+
const regex = entry.regex === undefined ? setCodeOwnersPatternRegex(entry).regex : entry.regex
|
|
812
|
+
const isResponsible = isCodeOwnersPatternMatch(regex, filename)
|
|
692
813
|
if (isResponsible) {
|
|
693
814
|
const codeOwners = JSON.stringify(entry.owners)
|
|
694
815
|
codeOwnersPerFileName.set(filename, codeOwners)
|
|
@@ -934,8 +1055,8 @@ function getIsFaultyEarlyFlakeDetection (projectSuites, testsBySuiteName, faulty
|
|
|
934
1055
|
}
|
|
935
1056
|
|
|
936
1057
|
function getTestSessionName (config, trimmedCommand, envTags) {
|
|
937
|
-
if (config.
|
|
938
|
-
return config.
|
|
1058
|
+
if (config.DD_TEST_SESSION_NAME) {
|
|
1059
|
+
return config.DD_TEST_SESSION_NAME
|
|
939
1060
|
}
|
|
940
1061
|
const lageTestSessionName = getLageTestSessionName()
|
|
941
1062
|
if (lageTestSessionName) {
|
|
@@ -31,7 +31,8 @@ function extractURL (req) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function getProtocol (req) {
|
|
34
|
-
|
|
34
|
+
// Do not check deprecated `req.connection` property.
|
|
35
|
+
return req.socket?.encrypted ? 'https' : 'http'
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/**
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const EventPlugin = require('./event')
|
|
4
|
+
|
|
5
|
+
// Params captured on the instrumentation context that are safe to forward as pprof labels. Must be
|
|
6
|
+
// a subset of the names declared in asyncParamsByMethod in datadog-instrumentations/src/crypto.js.
|
|
7
|
+
const allowedParams = new Set([
|
|
8
|
+
'algorithm', 'digest', 'iterations', 'keylen', 'offset', 'operation', 'size', 'type',
|
|
9
|
+
])
|
|
10
|
+
|
|
11
|
+
class CryptoPlugin extends EventPlugin {
|
|
12
|
+
static id = 'crypto'
|
|
13
|
+
|
|
14
|
+
static operation = 'operation'
|
|
15
|
+
|
|
16
|
+
static entryType = 'crypto'
|
|
17
|
+
|
|
18
|
+
extendEvent (event, ctx) {
|
|
19
|
+
const detail = {}
|
|
20
|
+
for (const name of allowedParams) {
|
|
21
|
+
const value = ctx[name]
|
|
22
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
23
|
+
detail[name] = value
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
event.detail = detail
|
|
27
|
+
|
|
28
|
+
return event
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = CryptoPlugin
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const EventPlugin = require('./event')
|
|
4
|
+
|
|
5
|
+
class ZlibPlugin extends EventPlugin {
|
|
6
|
+
static id = 'zlib'
|
|
7
|
+
|
|
8
|
+
static operation = 'operation'
|
|
9
|
+
|
|
10
|
+
static entryType = 'zlib'
|
|
11
|
+
|
|
12
|
+
extendEvent (event, ctx) {
|
|
13
|
+
event.detail = { operation: ctx.operation }
|
|
14
|
+
|
|
15
|
+
return event
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = ZlibPlugin
|
|
@@ -194,13 +194,46 @@ class FilesystemDecorator {
|
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
class ZlibDecorator {
|
|
198
|
+
constructor (stringTable) {
|
|
199
|
+
this.stringTable = stringTable
|
|
200
|
+
this.operationNameLabelKey = stringTable.dedup('operation')
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
decorateSample (sampleInput, item) {
|
|
204
|
+
sampleInput.label.push(labelFromStr(this.stringTable, this.operationNameLabelKey, item.detail.operation))
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
class CryptoDecorator {
|
|
209
|
+
constructor (stringTable) {
|
|
210
|
+
this.stringTable = stringTable
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
decorateSample (sampleInput, item) {
|
|
214
|
+
const labels = sampleInput.label
|
|
215
|
+
const stringTable = this.stringTable
|
|
216
|
+
for (const [key, value] of Object.entries(item.detail)) {
|
|
217
|
+
switch (typeof value) {
|
|
218
|
+
case 'string':
|
|
219
|
+
labels.push(labelFromStrStr(stringTable, key, value))
|
|
220
|
+
break
|
|
221
|
+
case 'number':
|
|
222
|
+
labels.push(new Label({ key: stringTable.dedup(key), num: value }))
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
197
228
|
// Keys correspond to PerformanceEntry.entryType, values are constructor
|
|
198
229
|
// functions for type-specific decorators.
|
|
199
230
|
const decoratorTypes = {
|
|
231
|
+
crypto: CryptoDecorator,
|
|
200
232
|
fs: FilesystemDecorator,
|
|
201
233
|
dns: DNSDecorator,
|
|
202
234
|
gc: GCDecorator,
|
|
203
235
|
net: NetDecorator,
|
|
236
|
+
zlib: ZlibDecorator,
|
|
204
237
|
}
|
|
205
238
|
|
|
206
239
|
// Translates performance entries into pprof samples.
|
|
@@ -348,12 +381,14 @@ class DatadogInstrumentationEventSource {
|
|
|
348
381
|
constructor (eventHandler, eventFilter) {
|
|
349
382
|
// List all entries explicitly for bundlers to pick up the require calls correctly.
|
|
350
383
|
const plugins = [
|
|
384
|
+
require('./event_plugins/crypto'),
|
|
351
385
|
require('./event_plugins/dns_lookup'),
|
|
352
386
|
require('./event_plugins/dns_lookupservice'),
|
|
353
387
|
require('./event_plugins/dns_resolve'),
|
|
354
388
|
require('./event_plugins/dns_reverse'),
|
|
355
389
|
require('./event_plugins/fs'),
|
|
356
390
|
require('./event_plugins/net'),
|
|
391
|
+
require('./event_plugins/zlib'),
|
|
357
392
|
]
|
|
358
393
|
this.plugins = plugins.map((Plugin) => {
|
|
359
394
|
return new Plugin(eventHandler, eventFilter)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { getValueFromEnvSources } = require('./config/helper')
|
|
4
3
|
const NoopProxy = require('./noop/proxy')
|
|
5
4
|
const DatadogTracer = require('./tracer')
|
|
6
5
|
const getConfig = require('./config')
|
|
@@ -129,11 +128,11 @@ class Tracer extends NoopProxy {
|
|
|
129
128
|
lazyProxy(this, 'dogstatsd', () => require('./dogstatsd').CustomMetrics, config)
|
|
130
129
|
}
|
|
131
130
|
|
|
132
|
-
if (config.
|
|
131
|
+
if (config.DD_TRACE_SPAN_LEAK_DEBUG > 0) {
|
|
133
132
|
const spanleak = require('./spanleak')
|
|
134
|
-
if (config.
|
|
133
|
+
if (config.DD_TRACE_SPAN_LEAK_DEBUG === spanleak.MODES.LOG) {
|
|
135
134
|
spanleak.enableLogging()
|
|
136
|
-
} else if (config.
|
|
135
|
+
} else if (config.DD_TRACE_SPAN_LEAK_DEBUG === spanleak.MODES.GC_AND_LOG) {
|
|
137
136
|
spanleak.enableGarbageCollection()
|
|
138
137
|
}
|
|
139
138
|
spanleak.startScrubber()
|
|
@@ -204,7 +203,7 @@ class Tracer extends NoopProxy {
|
|
|
204
203
|
|
|
205
204
|
this._modules.rewriter.enable(config)
|
|
206
205
|
|
|
207
|
-
if (config.tracing && config.
|
|
206
|
+
if (config.tracing && config.DD_CIVISIBILITY_MANUAL_API_ENABLED) {
|
|
208
207
|
const TestApiManualPlugin = require('./ci-visibility/test-api-manual/test-api-manual-plugin')
|
|
209
208
|
this._testApiManualPlugin = new TestApiManualPlugin(this)
|
|
210
209
|
// `shouldGetEnvironmentData` is passed as false so that we only lazily calculate it
|
|
@@ -212,8 +211,8 @@ class Tracer extends NoopProxy {
|
|
|
212
211
|
// are lazily configured when the library is imported.
|
|
213
212
|
this._testApiManualPlugin.configure({ ...config, enabled: true }, false)
|
|
214
213
|
}
|
|
215
|
-
if (config.
|
|
216
|
-
if (
|
|
214
|
+
if (config.DD_AGENTLESS_LOG_SUBMISSION_ENABLED) {
|
|
215
|
+
if (config.apiKey) {
|
|
217
216
|
const LogSubmissionPlugin = require('./ci-visibility/log-submission/log-submission-plugin')
|
|
218
217
|
const automaticLogPlugin = new LogSubmissionPlugin(this)
|
|
219
218
|
automaticLogPlugin.configure({ ...config, enabled: true })
|
|
@@ -225,7 +224,7 @@ class Tracer extends NoopProxy {
|
|
|
225
224
|
}
|
|
226
225
|
}
|
|
227
226
|
|
|
228
|
-
if (config.
|
|
227
|
+
if (config.DD_LOGS_OTEL_ENABLED) {
|
|
229
228
|
const { initializeOpenTelemetryLogs } = require('./opentelemetry/logs')
|
|
230
229
|
initializeOpenTelemetryLogs(config)
|
|
231
230
|
}
|
|
@@ -279,12 +278,7 @@ class Tracer extends NoopProxy {
|
|
|
279
278
|
const prioritySampler = config.apmTracingEnabled === false
|
|
280
279
|
? require('./standalone').configure(config)
|
|
281
280
|
: undefined
|
|
282
|
-
|
|
283
|
-
if (config.otelTracesEnabled) {
|
|
284
|
-
const { buildResourceAttributes, createOtlpTraceExporter } = require('./opentelemetry/trace')
|
|
285
|
-
otlpExporter = createOtlpTraceExporter(config, buildResourceAttributes(config))
|
|
286
|
-
}
|
|
287
|
-
this._tracer = new DatadogTracer(config, prioritySampler, otlpExporter)
|
|
281
|
+
this._tracer = new DatadogTracer(config, prioritySampler)
|
|
288
282
|
this.dataStreamsCheckpointer = this._tracer.dataStreamsCheckpointer
|
|
289
283
|
lazyProxy(this, 'appsec', () => require('./appsec/sdk'), this._tracer, config)
|
|
290
284
|
lazyProxy(this, 'llmobs', () => require('./llmobs/sdk'), this._tracer, this._modules.llmobs, config)
|
|
@@ -51,6 +51,8 @@ module.exports = {
|
|
|
51
51
|
const trackEventLoop = config.runtimeMetrics.eventLoop !== false
|
|
52
52
|
const trackGc = config.runtimeMetrics.gc !== false
|
|
53
53
|
|
|
54
|
+
client = new MetricsAggregationClient(new DogStatsDClient(clientConfig))
|
|
55
|
+
|
|
54
56
|
if (trackGc) {
|
|
55
57
|
startGCObserver()
|
|
56
58
|
}
|
|
@@ -72,8 +74,6 @@ module.exports = {
|
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
client = new MetricsAggregationClient(new DogStatsDClient(clientConfig))
|
|
76
|
-
|
|
77
77
|
lastTime = performance.now()
|
|
78
78
|
|
|
79
79
|
if (nativeMetrics) {
|