dd-trace 5.98.0 → 5.99.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 +0 -1
- package/ext/tags.js +1 -0
- package/index.d.ts +9 -1
- package/package.json +48 -46
- 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/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-http/src/server.js +11 -11
- package/packages/datadog-plugin-jest/src/index.js +2 -2
- 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/graphql.js +6 -6
- 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/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/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 +13 -12
- package/packages/dd-trace/src/config/index.js +25 -35
- package/packages/dd-trace/src/config/parsers.js +26 -9
- package/packages/dd-trace/src/config/supported-configurations.json +32 -36
- 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/encode/0.4.js +4 -5
- 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/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/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 +2 -2
- 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 +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +3 -2
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
- 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 +17 -10
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/tracer.js +12 -5
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/test.js +126 -5
- 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 +2 -8
- 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
|
@@ -18,13 +18,14 @@ class OtlpHttpMetricExporter extends OtlpHttpExporterBase {
|
|
|
18
18
|
* Creates a new OtlpHttpMetricExporter instance.
|
|
19
19
|
*
|
|
20
20
|
* @param {string} url - OTLP endpoint URL
|
|
21
|
-
* @param {string} headers - Additional HTTP headers
|
|
21
|
+
* @param {Record<string, string>|undefined} headers - Additional HTTP headers parsed from the
|
|
22
|
+
* corresponding `OTEL_EXPORTER_OTLP_*_HEADERS` env by the MAP parser.
|
|
22
23
|
* @param {number} timeout - Request timeout in milliseconds
|
|
23
24
|
* @param {string} protocol - OTLP protocol (http/protobuf or http/json)
|
|
24
25
|
* @param {Resource} resource - Resource attributes
|
|
25
26
|
*/
|
|
26
27
|
constructor (url, headers, timeout, protocol, resource) {
|
|
27
|
-
super(url, headers, timeout, protocol, '
|
|
28
|
+
super(url, headers, timeout, protocol, 'metrics')
|
|
28
29
|
this.transformer = new OtlpTransformer(resource, protocol)
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -19,34 +19,31 @@ class OtlpHttpExporterBase {
|
|
|
19
19
|
/**
|
|
20
20
|
* Creates a new OtlpHttpExporterBase instance.
|
|
21
21
|
*
|
|
22
|
-
* @param {string} url - OTLP endpoint URL
|
|
23
|
-
* @param {string
|
|
22
|
+
* @param {string} url - OTLP endpoint URL (callers are expected to supply the full signal URL)
|
|
23
|
+
* @param {Record<string, string>|undefined} headers - Additional HTTP headers parsed from the
|
|
24
|
+
* corresponding `OTEL_EXPORTER_OTLP_*_HEADERS` env by the MAP parser.
|
|
24
25
|
* @param {number} timeout - Request timeout in milliseconds
|
|
25
26
|
* @param {string} protocol - OTLP protocol (http/protobuf or http/json)
|
|
26
|
-
* @param {string} defaultPath - Default path to use if URL has no path
|
|
27
27
|
* @param {string} signalType - Signal type for error messages (e.g., 'logs', 'metrics')
|
|
28
28
|
*/
|
|
29
|
-
constructor (url, headers, timeout, protocol,
|
|
30
|
-
const parsedUrl = new URL(url)
|
|
31
|
-
|
|
29
|
+
constructor (url, headers, timeout, protocol, signalType) {
|
|
32
30
|
this.protocol = protocol
|
|
33
31
|
this.signalType = signalType
|
|
34
32
|
|
|
35
|
-
// If no path is provided, use default path
|
|
36
|
-
const path = parsedUrl.pathname === '/' ? defaultPath : parsedUrl.pathname
|
|
37
33
|
const isJson = protocol === 'http/json'
|
|
38
34
|
|
|
35
|
+
// Initialize fields setUrl doesn't touch; it fills in hostname/port/path below.
|
|
39
36
|
this.options = {
|
|
40
|
-
hostname: parsedUrl.hostname,
|
|
41
|
-
port: parsedUrl.port,
|
|
42
|
-
path: path + parsedUrl.search,
|
|
43
37
|
method: 'POST',
|
|
44
38
|
timeout,
|
|
45
39
|
headers: {
|
|
46
40
|
'Content-Type': isJson ? 'application/json' : 'application/x-protobuf',
|
|
47
|
-
...
|
|
41
|
+
...headers,
|
|
48
42
|
},
|
|
49
43
|
}
|
|
44
|
+
|
|
45
|
+
this.setUrl(url)
|
|
46
|
+
|
|
50
47
|
this.telemetryTags = [
|
|
51
48
|
'protocol:http',
|
|
52
49
|
`encoding:${isJson ? 'json' : 'protobuf'}`,
|
|
@@ -61,6 +58,7 @@ class OtlpHttpExporterBase {
|
|
|
61
58
|
* @protected
|
|
62
59
|
*/
|
|
63
60
|
recordTelemetry (metricName, count, additionalTags) {
|
|
61
|
+
// @ts-expect-error - additionalTags is optional and can be undefined
|
|
64
62
|
if (additionalTags?.length > 0) {
|
|
65
63
|
tracerMetrics.count(metricName, [...this.telemetryTags, ...additionalTags || []]).inc(count)
|
|
66
64
|
} else {
|
|
@@ -91,6 +89,7 @@ class OtlpHttpExporterBase {
|
|
|
91
89
|
})
|
|
92
90
|
|
|
93
91
|
res.once('end', () => {
|
|
92
|
+
// @ts-expect-error - res.statusCode can be undefined
|
|
94
93
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
95
94
|
resultCallback({ code: 0 })
|
|
96
95
|
} else {
|
|
@@ -116,61 +115,15 @@ class OtlpHttpExporterBase {
|
|
|
116
115
|
}
|
|
117
116
|
|
|
118
117
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* @
|
|
118
|
+
* Updates the target URL used by this exporter. The URL is used as-is per the OTel spec: the
|
|
119
|
+
* caller is responsible for including the signal-specific path (`/v1/traces` etc.).
|
|
120
|
+
* @param {string} url - New OTLP endpoint URL
|
|
122
121
|
*/
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const result = {}
|
|
129
|
-
for (const [k, v] of Object.entries(headersString)) {
|
|
130
|
-
if (v === '' && k.includes('=')) {
|
|
131
|
-
const idx = k.indexOf('=')
|
|
132
|
-
result[k.slice(0, idx).trim()] = k.slice(idx + 1).trim()
|
|
133
|
-
} else {
|
|
134
|
-
result[k] = v
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return result
|
|
138
|
-
}
|
|
139
|
-
const headers = {}
|
|
140
|
-
let key = ''
|
|
141
|
-
let value = ''
|
|
142
|
-
let readingKey = true
|
|
143
|
-
|
|
144
|
-
for (const char of headersString) {
|
|
145
|
-
if (readingKey) {
|
|
146
|
-
if (char === '=') {
|
|
147
|
-
readingKey = false
|
|
148
|
-
key = key.trim()
|
|
149
|
-
} else {
|
|
150
|
-
key += char
|
|
151
|
-
}
|
|
152
|
-
} else if (char === ',') {
|
|
153
|
-
value = value.trim()
|
|
154
|
-
if (key && value) {
|
|
155
|
-
headers[key] = value
|
|
156
|
-
}
|
|
157
|
-
key = ''
|
|
158
|
-
value = ''
|
|
159
|
-
readingKey = true
|
|
160
|
-
} else {
|
|
161
|
-
value += char
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Add the last pair if present
|
|
166
|
-
if (!readingKey) {
|
|
167
|
-
value = value.trim()
|
|
168
|
-
if (value) {
|
|
169
|
-
headers[key] = value
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return headers
|
|
122
|
+
setUrl (url) {
|
|
123
|
+
const parsedUrl = new URL(url)
|
|
124
|
+
this.options.hostname = parsedUrl.hostname
|
|
125
|
+
this.options.port = parsedUrl.port
|
|
126
|
+
this.options.path = parsedUrl.pathname + parsedUrl.search
|
|
174
127
|
}
|
|
175
128
|
|
|
176
129
|
/**
|
|
@@ -4,7 +4,7 @@ const { VERSION } = require('../../../../../version')
|
|
|
4
4
|
const OtlpHttpTraceExporter = require('./otlp_http_trace_exporter')
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @typedef {import('../../config')} Config
|
|
7
|
+
* @typedef {import('../../config/config-base')} Config
|
|
8
8
|
* @typedef {import('../../opentracing/tracer')} DatadogTracer
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -33,21 +33,17 @@ const OtlpHttpTraceExporter = require('./otlp_http_trace_exporter')
|
|
|
33
33
|
*/
|
|
34
34
|
function buildResourceAttributes (config) {
|
|
35
35
|
const resourceAttributes = {
|
|
36
|
-
'service.name': config.service
|
|
36
|
+
'service.name': config.service,
|
|
37
37
|
'telemetry.sdk.name': 'datadog',
|
|
38
38
|
'telemetry.sdk.version': VERSION,
|
|
39
39
|
'telemetry.sdk.language': 'nodejs',
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
const version = config.version || config.tags.version
|
|
45
|
-
if (version) resourceAttributes['service.version'] = version
|
|
42
|
+
if (config.env) resourceAttributes['deployment.environment.name'] = config.env
|
|
43
|
+
if (config.version) resourceAttributes['service.version'] = config.version
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Object.assign(resourceAttributes, filteredTags)
|
|
50
|
-
}
|
|
45
|
+
const { service, version, env, ...filteredTags } = config.tags
|
|
46
|
+
Object.assign(resourceAttributes, filteredTags)
|
|
51
47
|
|
|
52
48
|
return resourceAttributes
|
|
53
49
|
}
|
|
@@ -56,15 +52,14 @@ function buildResourceAttributes (config) {
|
|
|
56
52
|
* Creates the OTLP HTTP/JSON trace exporter.
|
|
57
53
|
*
|
|
58
54
|
* @param {Config} config - Tracer configuration instance
|
|
59
|
-
* @param {import('@opentelemetry/api').Attributes} resourceAttributes - Resource attributes
|
|
60
55
|
* @returns {OtlpHttpTraceExporter} The OTLP HTTP/JSON exporter
|
|
61
56
|
*/
|
|
62
|
-
function createOtlpTraceExporter (config
|
|
57
|
+
function createOtlpTraceExporter (config) {
|
|
63
58
|
return new OtlpHttpTraceExporter(
|
|
64
|
-
config.
|
|
65
|
-
config.
|
|
66
|
-
config.
|
|
67
|
-
|
|
59
|
+
config.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
|
|
60
|
+
config.OTEL_EXPORTER_OTLP_TRACES_HEADERS,
|
|
61
|
+
config.OTEL_EXPORTER_OTLP_TRACES_TIMEOUT,
|
|
62
|
+
buildResourceAttributes(config)
|
|
68
63
|
)
|
|
69
64
|
}
|
|
70
65
|
|
|
@@ -8,13 +8,20 @@ const OtlpTraceTransformer = require('./otlp_transformer')
|
|
|
8
8
|
/**
|
|
9
9
|
* OtlpHttpTraceExporter exports DD-formatted spans via OTLP over HTTP/JSON.
|
|
10
10
|
*
|
|
11
|
-
* This implementation follows the OTLP HTTP
|
|
11
|
+
* This implementation follows the OTLP HTTP specification:
|
|
12
12
|
* https://opentelemetry.io/docs/specs/otlp/#otlphttp
|
|
13
13
|
*
|
|
14
14
|
* It receives DD-formatted spans (from span_format.js), transforms them
|
|
15
15
|
* to OTLP ExportTraceServiceRequest JSON format, and sends them to the
|
|
16
16
|
* configured OTLP endpoint via HTTP POST.
|
|
17
17
|
*
|
|
18
|
+
* TODO: Add batch handling similar to the OpenTelemetry SDK Batch Processor
|
|
19
|
+
* (https://opentelemetry.io/docs/specs/otel/trace/sdk/#batching-processor).
|
|
20
|
+
* Currently each finished trace is sent as its own HTTP request, which is
|
|
21
|
+
* unsuitable for high-traffic production environments. The config values
|
|
22
|
+
* `otelBatchTimeout`, `otelMaxExportBatchSize`, and `otelMaxQueueSize`
|
|
23
|
+
* (OTEL_BSP_*) are already defined and should drive that implementation.
|
|
24
|
+
*
|
|
18
25
|
* @class OtlpHttpTraceExporter
|
|
19
26
|
* @augments OtlpHttpExporterBase
|
|
20
27
|
*/
|
|
@@ -25,12 +32,13 @@ class OtlpHttpTraceExporter extends OtlpHttpExporterBase {
|
|
|
25
32
|
* Creates a new OtlpHttpTraceExporter instance.
|
|
26
33
|
*
|
|
27
34
|
* @param {string} url - OTLP endpoint URL
|
|
28
|
-
* @param {string} headers - Additional HTTP headers
|
|
35
|
+
* @param {Record<string, string>|undefined} headers - Additional HTTP headers parsed from the
|
|
36
|
+
* corresponding `OTEL_EXPORTER_OTLP_*_HEADERS` env by the MAP parser.
|
|
29
37
|
* @param {number} timeout - Request timeout in milliseconds
|
|
30
38
|
* @param {import('@opentelemetry/api').Attributes} resourceAttributes - Resource attributes
|
|
31
39
|
*/
|
|
32
40
|
constructor (url, headers, timeout, resourceAttributes) {
|
|
33
|
-
super(url, headers, timeout, 'http/json', '
|
|
41
|
+
super(url, headers, timeout, 'http/json', 'traces')
|
|
34
42
|
this.#transformer = new OtlpTraceTransformer(resourceAttributes)
|
|
35
43
|
}
|
|
36
44
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const OtlpTransformerBase = require('../otlp/otlp_transformer_base')
|
|
4
4
|
const { getProtobufTypes } = require('../otlp/protobuf_loader')
|
|
5
5
|
const { VERSION } = require('../../../../../version')
|
|
6
|
+
const id = require('../../id')
|
|
6
7
|
|
|
7
8
|
const { protoSpanKind } = getProtobufTypes()
|
|
8
9
|
const SPAN_KIND_UNSPECIFIED = protoSpanKind.values.SPAN_KIND_UNSPECIFIED
|
|
@@ -12,11 +13,28 @@ const SPAN_KIND_CLIENT = protoSpanKind.values.SPAN_KIND_CLIENT
|
|
|
12
13
|
const SPAN_KIND_PRODUCER = protoSpanKind.values.SPAN_KIND_PRODUCER
|
|
13
14
|
const SPAN_KIND_CONSUMER = protoSpanKind.values.SPAN_KIND_CONSUMER
|
|
14
15
|
|
|
16
|
+
// Cached zero Identifier used to detect zero IDs without re-allocating per span.
|
|
17
|
+
const ZERO_ID = id('0')
|
|
18
|
+
|
|
15
19
|
/**
|
|
20
|
+
* @typedef {import('../../id').Identifier} Identifier
|
|
21
|
+
*
|
|
22
|
+
* @typedef {object} DDSpanLink
|
|
23
|
+
* @property {string} trace_id - Hex-encoded trace ID
|
|
24
|
+
* @property {string} span_id - Hex-encoded span ID
|
|
25
|
+
* @property {Record<string, string | number | boolean>} [attributes] - Link attributes
|
|
26
|
+
* @property {number} [flags] - Trace flags
|
|
27
|
+
* @property {string} [tracestate] - W3C trace state
|
|
28
|
+
*
|
|
29
|
+
* @typedef {object} DDSpanEvent
|
|
30
|
+
* @property {string} name - Event name
|
|
31
|
+
* @property {number} time_unix_nano - Event time in nanoseconds since epoch
|
|
32
|
+
* @property {Record<string, string | number | boolean>} [attributes] - Event attributes
|
|
33
|
+
*
|
|
16
34
|
* @typedef {object} DDFormattedSpan
|
|
17
|
-
* @property {
|
|
18
|
-
* @property {
|
|
19
|
-
* @property {
|
|
35
|
+
* @property {Identifier} trace_id - DD Identifier for trace ID
|
|
36
|
+
* @property {Identifier} span_id - DD Identifier for span ID
|
|
37
|
+
* @property {Identifier} parent_id - DD Identifier for parent span ID
|
|
20
38
|
* @property {string} name - Span operation name
|
|
21
39
|
* @property {string} resource - Resource name
|
|
22
40
|
* @property {string} [service] - Service name
|
|
@@ -24,9 +42,10 @@ const SPAN_KIND_CONSUMER = protoSpanKind.values.SPAN_KIND_CONSUMER
|
|
|
24
42
|
* @property {number} error - Error flag (0 or 1)
|
|
25
43
|
* @property {{[key: string]: string}} meta - String key-value tags
|
|
26
44
|
* @property {{[key: string]: number}} metrics - Numeric key-value tags
|
|
45
|
+
* @property {{[key: string]: object}} [meta_struct] - Structured tags (JSON-serialized, bytes in protobuf)
|
|
27
46
|
* @property {number} start - Start time in nanoseconds since epoch
|
|
28
47
|
* @property {number} duration - Duration in nanoseconds
|
|
29
|
-
* @property {
|
|
48
|
+
* @property {DDSpanEvent[]} [span_events] - Span events
|
|
30
49
|
*/
|
|
31
50
|
|
|
32
51
|
// Map DD span.kind string values to OTLP SpanKind numeric values
|
|
@@ -51,7 +70,7 @@ const EXCLUDED_META_KEYS = new Set([
|
|
|
51
70
|
/**
|
|
52
71
|
* OtlpTraceTransformer transforms DD-formatted spans to OTLP trace JSON format.
|
|
53
72
|
*
|
|
54
|
-
* This implementation follows the OTLP
|
|
73
|
+
* This implementation follows the OTLP trace data model:
|
|
55
74
|
* https://opentelemetry.io/docs/specs/otlp/#trace-data-model
|
|
56
75
|
*
|
|
57
76
|
* It receives DD-formatted spans (from span_format.js) and produces
|
|
@@ -119,7 +138,7 @@ class OtlpTraceTransformer extends OtlpTransformerBase {
|
|
|
119
138
|
return {
|
|
120
139
|
traceId: this.#idToBytes(span.trace_id, 16),
|
|
121
140
|
spanId: this.#idToBytes(span.span_id, 8),
|
|
122
|
-
parentSpanId: (parentId && !
|
|
141
|
+
parentSpanId: (parentId && !parentId.equals(ZERO_ID)) ? this.#idToBytes(parentId, 8) : undefined,
|
|
123
142
|
name: span.resource,
|
|
124
143
|
kind: this.#mapSpanKind(span.meta?.['span.kind']),
|
|
125
144
|
startTimeUnixNano: span.start,
|
|
@@ -178,7 +197,10 @@ class OtlpTraceTransformer extends OtlpTransformerBase {
|
|
|
178
197
|
}
|
|
179
198
|
}
|
|
180
199
|
|
|
181
|
-
//
|
|
200
|
+
// TODO: meta_struct values are logically raw bytes. The OTLP http/json spec encodes the bytesValue
|
|
201
|
+
// field as base64, but when http/protobuf or gRPC support is added the payload should be sent as
|
|
202
|
+
// raw bytes directly (no JSON.stringify + base64). The backend decoding side will need to be
|
|
203
|
+
// updated in parallel to accept the unencoded bytes.
|
|
182
204
|
if (span.meta_struct) {
|
|
183
205
|
for (const [key, value] of Object.entries(span.meta_struct)) {
|
|
184
206
|
const bytes = Buffer.from(JSON.stringify(value))
|
|
@@ -202,33 +224,40 @@ class OtlpTraceTransformer extends OtlpTransformerBase {
|
|
|
202
224
|
|
|
203
225
|
/**
|
|
204
226
|
* Maps DD span error state to an OTLP Status object.
|
|
227
|
+
* Combines error.type and error.message when both are present so error type
|
|
228
|
+
* information is preserved on the OTel side.
|
|
205
229
|
*
|
|
206
230
|
* @param {DDFormattedSpan} span - DD-formatted span
|
|
207
231
|
* @returns {object} OTLP Status object with code and message
|
|
208
232
|
*/
|
|
209
233
|
#mapStatus (span) {
|
|
210
|
-
if (span.error
|
|
211
|
-
return {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
234
|
+
if (span.error !== 1) {
|
|
235
|
+
return { code: STATUS_CODE_UNSET, message: '' }
|
|
236
|
+
}
|
|
237
|
+
const errorType = span.meta?.['error.type']
|
|
238
|
+
const errorMessage = span.meta?.['error.message']
|
|
239
|
+
let message = ''
|
|
240
|
+
if (errorType && errorMessage) {
|
|
241
|
+
message = `${errorType}: ${errorMessage}`
|
|
242
|
+
} else if (errorType) {
|
|
243
|
+
message = errorType
|
|
244
|
+
} else if (errorMessage) {
|
|
245
|
+
message = errorMessage
|
|
215
246
|
}
|
|
216
|
-
return { code:
|
|
247
|
+
return { code: STATUS_CODE_ERROR, message }
|
|
217
248
|
}
|
|
218
249
|
|
|
219
250
|
/**
|
|
220
251
|
* Transforms a DD span event to an OTLP Event object.
|
|
221
252
|
*
|
|
222
|
-
* @param {
|
|
253
|
+
* @param {DDSpanEvent} event - DD span event
|
|
223
254
|
* @returns {object} OTLP Event object
|
|
224
255
|
*/
|
|
225
256
|
#transformEvent (event) {
|
|
226
257
|
return {
|
|
227
258
|
timeUnixNano: event.time_unix_nano,
|
|
228
259
|
name: event.name || '',
|
|
229
|
-
attributes:
|
|
230
|
-
? this.transformAttributes(event.attributes)
|
|
231
|
-
: [],
|
|
260
|
+
attributes: this.transformAttributes(event.attributes ?? {}),
|
|
232
261
|
droppedAttributesCount: 0,
|
|
233
262
|
}
|
|
234
263
|
}
|
|
@@ -257,7 +286,7 @@ class OtlpTraceTransformer extends OtlpTransformerBase {
|
|
|
257
286
|
/**
|
|
258
287
|
* Transforms a single DD span link to an OTLP Link object.
|
|
259
288
|
*
|
|
260
|
-
* @param {
|
|
289
|
+
* @param {DDSpanLink} link - DD span link
|
|
261
290
|
* @returns {object} OTLP Link object
|
|
262
291
|
*/
|
|
263
292
|
#transformLink (link) {
|
|
@@ -265,9 +294,7 @@ class OtlpTraceTransformer extends OtlpTransformerBase {
|
|
|
265
294
|
traceId: this.#hexToBytes(link.trace_id, 16),
|
|
266
295
|
spanId: this.#hexToBytes(link.span_id, 8),
|
|
267
296
|
traceState: link.tracestate || '',
|
|
268
|
-
attributes:
|
|
269
|
-
? this.transformAttributes(link.attributes)
|
|
270
|
-
: [],
|
|
297
|
+
attributes: this.transformAttributes(link.attributes ?? {}),
|
|
271
298
|
droppedAttributesCount: 0,
|
|
272
299
|
flags: link.flags,
|
|
273
300
|
}
|
|
@@ -278,7 +305,7 @@ class OtlpTraceTransformer extends OtlpTransformerBase {
|
|
|
278
305
|
* Pads with leading zeros if the identifier buffer is shorter than the target.
|
|
279
306
|
* Per the OTLP http/json spec, trace-ids and span-ids must be hex-encoded strings.
|
|
280
307
|
*
|
|
281
|
-
* @param {
|
|
308
|
+
* @param {Identifier} identifier - DD Identifier
|
|
282
309
|
* @param {number} targetLength - Target byte length (16 for trace ID, 8 for span ID)
|
|
283
310
|
* @returns {string} Hex-encoded string of the specified length
|
|
284
311
|
*/
|
|
@@ -290,29 +317,12 @@ class OtlpTraceTransformer extends OtlpTransformerBase {
|
|
|
290
317
|
if (buffer.length > targetLength) {
|
|
291
318
|
return Buffer.from(buffer.slice(buffer.length - targetLength)).toString('hex')
|
|
292
319
|
}
|
|
293
|
-
// Pad with leading zeros to reach target length
|
|
320
|
+
// Pad with leading zeros to reach target length.
|
|
294
321
|
const result = Buffer.alloc(targetLength)
|
|
295
|
-
|
|
296
|
-
for (let i = 0; i < buffer.length; i++) {
|
|
297
|
-
result[offset + i] = buffer[i]
|
|
298
|
-
}
|
|
322
|
+
Buffer.from(buffer).copy(result, targetLength - buffer.length)
|
|
299
323
|
return result.toString('hex')
|
|
300
324
|
}
|
|
301
325
|
|
|
302
|
-
/**
|
|
303
|
-
* Checks if a DD Identifier represents a zero ID (all bytes are 0).
|
|
304
|
-
*
|
|
305
|
-
* @param {object} identifier - DD Identifier object with toBuffer() method
|
|
306
|
-
* @returns {boolean} True if the identifier is all zeros
|
|
307
|
-
*/
|
|
308
|
-
#isZeroId (identifier) {
|
|
309
|
-
const buffer = identifier.toBuffer()
|
|
310
|
-
for (let i = 0; i < buffer.length; i++) {
|
|
311
|
-
if (buffer[i] !== 0) return false
|
|
312
|
-
}
|
|
313
|
-
return true
|
|
314
|
-
}
|
|
315
|
-
|
|
316
326
|
/**
|
|
317
327
|
* Normalizes a hex string to the specified byte length.
|
|
318
328
|
* Pads with leading zeros if the hex string is shorter than expected.
|
|
@@ -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
|
|
|
@@ -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
|
|
@@ -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) {
|
|
@@ -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') },
|