dd-trace 5.116.0 → 5.118.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/ci/diagnose.js +162 -21
- package/ci/init.js +0 -1
- package/ci/runbook.md +187 -180
- package/ci/test-optimization-validation/approval-artifacts.js +3 -1
- package/ci/test-optimization-validation/approval.js +52 -15
- package/ci/test-optimization-validation/ci-command-candidate.js +26 -32
- package/ci/test-optimization-validation/ci-discovery.js +1 -1
- package/ci/test-optimization-validation/ci-package-scripts.js +141 -0
- package/ci/test-optimization-validation/ci-remediation.js +112 -39
- package/ci/test-optimization-validation/cli.js +516 -681
- package/ci/test-optimization-validation/command-blocker.js +188 -33
- package/ci/test-optimization-validation/command-output-policy.js +3 -26
- package/ci/test-optimization-validation/command-runner.js +189 -245
- package/ci/test-optimization-validation/environment.js +90 -0
- package/ci/test-optimization-validation/executable.js +159 -388
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +119 -0
- package/ci/test-optimization-validation/framework-adapters/cypress.js +107 -0
- package/ci/test-optimization-validation/framework-adapters/playwright.js +181 -0
- package/ci/test-optimization-validation/generated-files.js +75 -13
- package/ci/test-optimization-validation/generated-test-contract.js +283 -0
- package/ci/test-optimization-validation/generated-verifier.js +49 -16
- package/ci/test-optimization-validation/literal-environment.js +57 -0
- package/ci/test-optimization-validation/manifest-loader.js +2 -22
- package/ci/test-optimization-validation/manifest-scaffold.js +816 -515
- package/ci/test-optimization-validation/manifest-schema.js +494 -702
- package/ci/test-optimization-validation/offline-fixtures.js +4 -1
- package/ci/test-optimization-validation/plan-writer.js +243 -984
- package/ci/test-optimization-validation/preflight-runner.js +49 -55
- package/ci/test-optimization-validation/redaction.js +2 -1
- package/ci/test-optimization-validation/report-writer.js +391 -1357
- package/ci/test-optimization-validation/result-semantics.js +86 -0
- package/ci/test-optimization-validation/runner-command.js +249 -0
- package/ci/test-optimization-validation/runner-contract.js +664 -0
- package/ci/test-optimization-validation/scenarios/auto-test-retries.js +29 -3
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +240 -543
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +450 -670
- package/ci/test-optimization-validation/scenarios/early-flake-detection.js +4 -3
- package/ci/test-optimization-validation/scenarios/helpers.js +67 -9
- package/ci/test-optimization-validation/scenarios/test-management.js +4 -3
- package/ci/test-optimization-validation/source-text.js +87 -0
- package/ci/test-optimization-validation/test-output.js +12 -22
- package/ext/tags.d.ts +1 -0
- package/index.d.ts +7 -0
- package/package.json +3 -3
- package/packages/datadog-instrumentations/src/cucumber.js +11 -12
- package/packages/datadog-instrumentations/src/helpers/channel.js +74 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/openai-agents.js +31 -0
- package/packages/datadog-instrumentations/src/jest.js +18 -17
- package/packages/datadog-instrumentations/src/mocha/main.js +79 -30
- package/packages/datadog-instrumentations/src/openai-agents.js +159 -0
- package/packages/datadog-instrumentations/src/playwright.js +3 -24
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1 -1
- package/packages/datadog-instrumentations/src/vitest-main.js +14 -26
- package/packages/datadog-instrumentations/src/vitest-util.js +0 -7
- package/packages/datadog-instrumentations/src/vitest-worker.js +5 -8
- package/packages/datadog-plugin-cucumber/src/index.js +2 -1
- package/packages/datadog-plugin-mocha/src/index.js +2 -1
- package/packages/datadog-plugin-openai-agents/src/index.js +74 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +503 -0
- package/packages/datadog-plugin-openai-agents/src/processor.js +108 -0
- package/packages/datadog-plugin-openai-agents/src/util.js +60 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -1
- package/packages/datadog-plugin-vitest/src/index.js +5 -5
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +48 -49
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +161 -33
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +6 -4
- package/packages/dd-trace/src/config/generated-config-types.d.ts +2 -0
- package/packages/dd-trace/src/config/supported-configurations.json +7 -0
- package/packages/dd-trace/src/encode/span-stats.js +7 -1
- package/packages/dd-trace/src/exporter.js +16 -9
- package/packages/dd-trace/src/llmobs/index.js +9 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +104 -22
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +5 -9
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +20 -0
- package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +321 -0
- package/packages/dd-trace/src/llmobs/sdk.js +2 -1
- package/packages/dd-trace/src/llmobs/span_processor.js +7 -2
- package/packages/dd-trace/src/llmobs/tagger.js +23 -3
- package/packages/dd-trace/src/llmobs/util.js +56 -3
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +3 -6
- package/packages/dd-trace/src/openfeature/configuration_source.js +5 -8
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +5 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +9 -3
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/outbound.js +4 -1
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
- package/packages/dd-trace/src/span_processor.js +1 -1
- package/packages/dd-trace/src/span_stats.js +22 -4
- package/ci/test-optimization-validation/command-suitability.js +0 -471
- package/ci/test-optimization-validation/init-probe-preload.js +0 -163
- package/ci/test-optimization-validation/init-probe.js +0 -246
- package/ci/test-optimization-validation/late-initialization.js +0 -63
- package/ci/test-optimization-validation/local-command.js +0 -163
- package/ci/test-optimization-validation/setup-runner.js +0 -97
- package/ci/test-optimization-validation-manifest.schema.json +0 -1
|
@@ -51,9 +51,18 @@ const {
|
|
|
51
51
|
SAMPLING_DECISION_DROPPED,
|
|
52
52
|
PROPAGATED_SAMPLE_RATE_KEY,
|
|
53
53
|
PROPAGATED_SAMPLING_DECISION_KEY,
|
|
54
|
+
TRACE_ID,
|
|
55
|
+
PROPAGATED_TRACE_ID_KEY,
|
|
54
56
|
} = require('./constants/tags')
|
|
55
57
|
const { storage } = require('./storage')
|
|
56
|
-
const {
|
|
58
|
+
const {
|
|
59
|
+
findGenAIAncestorSpanId,
|
|
60
|
+
validateCostTags,
|
|
61
|
+
writeBridgeTags,
|
|
62
|
+
validateToolDefinitions,
|
|
63
|
+
generateLlmObsTraceId,
|
|
64
|
+
normalizeLlmObsTraceId,
|
|
65
|
+
} = require('./util')
|
|
57
66
|
|
|
58
67
|
// global registry of LLMObs spans
|
|
59
68
|
// maps LLMObs spans to their annotations
|
|
@@ -126,12 +135,20 @@ class LLMObsTagger {
|
|
|
126
135
|
|
|
127
136
|
this._register(span)
|
|
128
137
|
|
|
138
|
+
const traceTags = span.context()._trace.tags
|
|
139
|
+
|
|
140
|
+
const llmobsTraceId =
|
|
141
|
+
registry.get(parent)?.[TRACE_ID] ??
|
|
142
|
+
normalizeLlmObsTraceId(traceTags[PROPAGATED_TRACE_ID_KEY]) ??
|
|
143
|
+
generateLlmObsTraceId(span._startTime)
|
|
144
|
+
this._setTag(span, TRACE_ID, llmobsTraceId)
|
|
145
|
+
|
|
129
146
|
// When the registering span sits below an OTel `gen_ai.*` ancestor, use
|
|
130
147
|
// that ancestor as the parent_id fallback and suppress the bridge
|
|
131
148
|
// parent_id tag so the indexer doesn't invert the trace.
|
|
132
149
|
const genAIAncestorSpanId = findGenAIAncestorSpanId(span)
|
|
133
150
|
|
|
134
|
-
writeBridgeTags(span, { includeParentId: genAIAncestorSpanId === null })
|
|
151
|
+
writeBridgeTags(span, { includeParentId: genAIAncestorSpanId === null, llmobsTraceId })
|
|
135
152
|
|
|
136
153
|
this._setTag(span, ML_APP, spanMlApp)
|
|
137
154
|
|
|
@@ -141,7 +158,6 @@ class LLMObsTagger {
|
|
|
141
158
|
if (modelName) this.tagModelName(span, modelName)
|
|
142
159
|
if (modelProvider) this._setTag(span, MODEL_PROVIDER, modelProvider)
|
|
143
160
|
|
|
144
|
-
const traceTags = span.context()._trace.tags
|
|
145
161
|
sessionId = sessionId ||
|
|
146
162
|
registry.get(parent)?.[SESSION_ID] ||
|
|
147
163
|
traceTags[SESSION_ID_TRACE_DEFAULT_KEY] ||
|
|
@@ -500,6 +516,10 @@ class LLMObsTagger {
|
|
|
500
516
|
this._setTag(span, MODEL_NAME, modelName)
|
|
501
517
|
}
|
|
502
518
|
|
|
519
|
+
setName (span, name) {
|
|
520
|
+
this._setTag(span, NAME, name)
|
|
521
|
+
}
|
|
522
|
+
|
|
503
523
|
#tagText (span, data, key) {
|
|
504
524
|
if (data) {
|
|
505
525
|
if (typeof data === 'string') {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const id = require('../id')
|
|
3
4
|
const log = require('../log')
|
|
4
5
|
const {
|
|
5
6
|
LLMOBS_PARENT_ID_BRIDGE_KEY,
|
|
@@ -7,6 +8,10 @@ const {
|
|
|
7
8
|
SPAN_KINDS,
|
|
8
9
|
} = require('./constants/tags')
|
|
9
10
|
|
|
11
|
+
const DECIMAL_TRACE_ID_REGEX = /^\d+$/
|
|
12
|
+
const HEX_TRACE_ID_REGEX = /^[0-9a-f]{32}$/i
|
|
13
|
+
const MAX_UINT_64 = (1n << 64n) - 1n
|
|
14
|
+
|
|
10
15
|
// LLM I/O is overwhelmingly ASCII (English prompts and code). Walk once
|
|
11
16
|
// looking for the first non-ASCII char; if there is none, hand the input
|
|
12
17
|
// straight back. Otherwise pick up the slow path from the byte that needed
|
|
@@ -312,12 +317,12 @@ function safeJsonParse (value, fallback) {
|
|
|
312
317
|
// LLMObs root and hoists the gen_ai ancestors under it, inverting the trace.
|
|
313
318
|
/**
|
|
314
319
|
* @param {import('../opentracing/span')} span
|
|
315
|
-
* @param {{ includeParentId?: boolean }} [opts]
|
|
320
|
+
* @param {{ includeParentId?: boolean, llmobsTraceId?: string }} [opts]
|
|
316
321
|
*/
|
|
317
|
-
function writeBridgeTags (span, { includeParentId = true } = {}) {
|
|
322
|
+
function writeBridgeTags (span, { includeParentId = true, llmobsTraceId } = {}) {
|
|
318
323
|
const traceTags = span?.context?.()._trace?.tags
|
|
319
324
|
if (!traceTags || traceTags[LLMOBS_TRACE_ID_BRIDGE_KEY]) return
|
|
320
|
-
traceTags[LLMOBS_TRACE_ID_BRIDGE_KEY] = span.context().toTraceId(true)
|
|
325
|
+
traceTags[LLMOBS_TRACE_ID_BRIDGE_KEY] = llmobsTraceId ?? span.context().toTraceId(true)
|
|
321
326
|
if (includeParentId) {
|
|
322
327
|
traceTags[LLMOBS_PARENT_ID_BRIDGE_KEY] = span.context().toSpanId()
|
|
323
328
|
}
|
|
@@ -362,6 +367,51 @@ function findGenAIAncestorSpanId (span) {
|
|
|
362
367
|
return null
|
|
363
368
|
}
|
|
364
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Generate a 128-bit LLMObs trace ID with the span start time encoded in its high bits.
|
|
372
|
+
* @param {number} startTime
|
|
373
|
+
* @returns {string}
|
|
374
|
+
*/
|
|
375
|
+
function generateLlmObsTraceId (startTime) {
|
|
376
|
+
const identifier = id()
|
|
377
|
+
const traceIdHigh = Math.floor(startTime / 1000)
|
|
378
|
+
.toString(16)
|
|
379
|
+
.padStart(8, '0')
|
|
380
|
+
.padEnd(16, '0')
|
|
381
|
+
|
|
382
|
+
return identifier.toTraceIdHex(traceIdHigh).padStart(32, '0')
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Convert an internally stored hexadecimal LLMObs trace ID to its distributed wire representation.
|
|
387
|
+
* @param {string | undefined} traceId
|
|
388
|
+
* @returns {string | undefined}
|
|
389
|
+
*/
|
|
390
|
+
function llmObsTraceIdToWire (traceId) {
|
|
391
|
+
if (!traceId) return
|
|
392
|
+
if (!HEX_TRACE_ID_REGEX.test(traceId)) return traceId
|
|
393
|
+
|
|
394
|
+
return BigInt(`0x${traceId}`).toString(10)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Normalize a distributed LLMObs trace ID to the representation expected by LLMObs span events.
|
|
399
|
+
* @param {string | undefined} traceId
|
|
400
|
+
* @returns {string | undefined}
|
|
401
|
+
*/
|
|
402
|
+
function normalizeLlmObsTraceId (traceId) {
|
|
403
|
+
if (!traceId) return
|
|
404
|
+
|
|
405
|
+
if (HEX_TRACE_ID_REGEX.test(traceId) && (traceId[0] === '0' || !DECIMAL_TRACE_ID_REGEX.test(traceId))) {
|
|
406
|
+
return traceId
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (!DECIMAL_TRACE_ID_REGEX.test(traceId)) return traceId
|
|
410
|
+
|
|
411
|
+
const identifier = BigInt(traceId)
|
|
412
|
+
return identifier > MAX_UINT_64 ? identifier.toString(16).padStart(32, '0') : traceId
|
|
413
|
+
}
|
|
414
|
+
|
|
365
415
|
// Maps an audio `format` (e.g. "wav", "mp3") to a MIME type. Defaults to `audio/wav` when the
|
|
366
416
|
// format is missing. Provider-specific overrides (e.g. OpenAI's mp3 -> audio/mpeg) are passed in
|
|
367
417
|
// via `mimeTypeLookup` so this stays provider-agnostic. A non-string `format` is treated as missing
|
|
@@ -396,6 +446,9 @@ module.exports = {
|
|
|
396
446
|
audioMimeTypeFromFormat,
|
|
397
447
|
encodeUnicode,
|
|
398
448
|
findGenAIAncestorSpanId,
|
|
449
|
+
generateLlmObsTraceId,
|
|
450
|
+
llmObsTraceIdToWire,
|
|
451
|
+
normalizeLlmObsTraceId,
|
|
399
452
|
formatAudioPart,
|
|
400
453
|
validateCostTags,
|
|
401
454
|
validateKind,
|
|
@@ -20,7 +20,7 @@ const RETRY_JITTER = 0.2
|
|
|
20
20
|
* @property {URL} endpoint
|
|
21
21
|
* @property {number} pollIntervalMs
|
|
22
22
|
* @property {number} requestTimeoutMs
|
|
23
|
-
* @property {string} apiKey
|
|
23
|
+
* @property {string | undefined} apiKey
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -138,7 +138,7 @@ class AgentlessConfigurationSource {
|
|
|
138
138
|
#request (signal) {
|
|
139
139
|
const headers = getClientLibraryHeaders()
|
|
140
140
|
headers['Accept-Encoding'] = 'gzip'
|
|
141
|
-
headers['DD-API-KEY'] = this.#config.apiKey
|
|
141
|
+
if (this.#config.apiKey) headers['DD-API-KEY'] = this.#config.apiKey
|
|
142
142
|
if (this.#etag) headers['If-None-Match'] = this.#etag
|
|
143
143
|
|
|
144
144
|
/**
|
|
@@ -228,10 +228,7 @@ class AgentlessConfigurationSource {
|
|
|
228
228
|
this.#failureWarnings.add(category)
|
|
229
229
|
|
|
230
230
|
if (statusCode === 401 || statusCode === 403) {
|
|
231
|
-
log.warn(
|
|
232
|
-
'Feature Flagging agentless endpoint returned HTTP %d; verify DD_API_KEY is configured and valid',
|
|
233
|
-
statusCode
|
|
234
|
-
)
|
|
231
|
+
log.warn('Feature Flagging agentless endpoint returned HTTP %d; verify endpoint authentication', statusCode)
|
|
235
232
|
} else if (statusCode) {
|
|
236
233
|
log.warn('Feature Flagging agentless endpoint returned HTTP %d after %d attempts', statusCode, attempts)
|
|
237
234
|
} else if (attempts > 1) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { isLoopbackHost } = require('../exporters/common/url')
|
|
4
3
|
const log = require('../log')
|
|
5
4
|
|
|
6
5
|
const DEFAULT_AGENTLESS_PATH = '/api/v2/feature-flagging/config/rules-based/server'
|
|
@@ -27,9 +26,11 @@ function create (config, applyConfiguration) {
|
|
|
27
26
|
return
|
|
28
27
|
}
|
|
29
28
|
|
|
29
|
+
const hasCustomEndpoint = Boolean(baseUrl?.trim())
|
|
30
|
+
|
|
30
31
|
try {
|
|
31
|
-
if (!config.DD_API_KEY) {
|
|
32
|
-
throw new Error('DD_API_KEY is required for Feature Flagging
|
|
32
|
+
if (!hasCustomEndpoint && !config.DD_API_KEY) {
|
|
33
|
+
throw new Error('DD_API_KEY is required for the default Datadog Feature Flagging endpoint')
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
const AgentlessConfigurationSource = require('./agentless_configuration_source')
|
|
@@ -37,7 +38,7 @@ function create (config, applyConfiguration) {
|
|
|
37
38
|
endpoint: endpoint(config, baseUrl),
|
|
38
39
|
pollIntervalMs: Math.min(pollIntervalSeconds, MAX_POLL_INTERVAL_SECONDS) * 1000,
|
|
39
40
|
requestTimeoutMs: requestTimeoutSeconds * 1000,
|
|
40
|
-
apiKey: config.DD_API_KEY,
|
|
41
|
+
apiKey: hasCustomEndpoint ? undefined : config.DD_API_KEY,
|
|
41
42
|
}, applyConfiguration)
|
|
42
43
|
} catch (error) {
|
|
43
44
|
log.error('Unable to configure Feature Flagging configuration source', error)
|
|
@@ -74,10 +75,6 @@ function endpoint (config, configuredBaseUrl) {
|
|
|
74
75
|
if (url.protocol !== 'https:' && url.protocol !== 'http:') {
|
|
75
76
|
throw new Error('Feature Flagging agentless URL must use HTTP or HTTPS')
|
|
76
77
|
}
|
|
77
|
-
if (url.protocol === 'http:' && !isLoopbackHost(url.hostname)) {
|
|
78
|
-
throw new Error('Feature Flagging agentless URL must use HTTPS unless it targets loopback')
|
|
79
|
-
}
|
|
80
|
-
|
|
81
78
|
if (url.pathname === '' || url.pathname === '/') {
|
|
82
79
|
url.pathname = DEFAULT_AGENTLESS_PATH
|
|
83
80
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { LogCollapsingLowestDenseDDSketch } = require('../../../../../vendor/dist/@datadog/sketches-js')
|
|
4
4
|
const OtlpTransformerBase = require('../otlp/otlp_transformer_base')
|
|
5
5
|
const { getProtobufTypes } = require('../otlp/protobuf_loader')
|
|
6
|
+
const { GRPC_STATUS_NAMES } = require('../../constants')
|
|
6
7
|
|
|
7
8
|
const NS_PER_S = 1e9
|
|
8
9
|
|
|
@@ -152,7 +153,10 @@ class OtlpStatsTransformer extends OtlpTransformerBase {
|
|
|
152
153
|
if (aggKey.method) raw['http.request.method'] = aggKey.method
|
|
153
154
|
if (aggKey.endpoint) raw['http.route'] = aggKey.endpoint
|
|
154
155
|
if (aggKey.rpcStatusCode !== '') {
|
|
155
|
-
|
|
156
|
+
const n = Number(aggKey.rpcStatusCode)
|
|
157
|
+
raw['rpc.response.status_code'] = Number.isInteger(n) && n >= 0 && n < GRPC_STATUS_NAMES.length
|
|
158
|
+
? GRPC_STATUS_NAMES[n]
|
|
159
|
+
: String(aggKey.rpcStatusCode).toUpperCase()
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
if (!this.#otelSemanticsEnabled) {
|
|
@@ -332,8 +332,11 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
332
332
|
log.error('Known tests could not be fetched. %s', err.message)
|
|
333
333
|
this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS, err)
|
|
334
334
|
if (this.libraryConfig) {
|
|
335
|
-
this.libraryConfig
|
|
336
|
-
|
|
335
|
+
this.libraryConfig = Object.freeze({
|
|
336
|
+
...this.libraryConfig,
|
|
337
|
+
isEarlyFlakeDetectionEnabled: false,
|
|
338
|
+
isKnownTestsEnabled: false,
|
|
339
|
+
})
|
|
337
340
|
}
|
|
338
341
|
}
|
|
339
342
|
onDone({ err, knownTests, requestErrorTags: this._getCurrentRequestErrorTags() })
|
|
@@ -353,7 +356,10 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
353
356
|
log.error('Test management tests could not be fetched. %s', err.message)
|
|
354
357
|
this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS, err)
|
|
355
358
|
if (this.libraryConfig) {
|
|
356
|
-
this.libraryConfig
|
|
359
|
+
this.libraryConfig = Object.freeze({
|
|
360
|
+
...this.libraryConfig,
|
|
361
|
+
isTestManagementEnabled: false,
|
|
362
|
+
})
|
|
357
363
|
}
|
|
358
364
|
}
|
|
359
365
|
onDone({ err, testManagementTests, requestErrorTags: this._getCurrentRequestErrorTags() })
|
|
@@ -37,6 +37,7 @@ const plugins = {
|
|
|
37
37
|
get '@smithy/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
|
|
38
38
|
get '@vitest/runner' () { return require('../../../datadog-plugin-vitest/src') },
|
|
39
39
|
get '@langchain/langgraph' () { return require('../../../datadog-plugin-langgraph/src') },
|
|
40
|
+
get '@openai/agents' () { return require('../../../datadog-plugin-openai-agents/src') },
|
|
40
41
|
get aerospike () { return require('../../../datadog-plugin-aerospike/src') },
|
|
41
42
|
get ai () { return require('../../../datadog-plugin-ai/src') },
|
|
42
43
|
get amqp10 () { return require('../../../datadog-plugin-amqp10/src') },
|
|
@@ -125,7 +125,10 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
125
125
|
*/
|
|
126
126
|
tagPeerService (span) {
|
|
127
127
|
if (this._tracerConfig.spanComputePeerService) {
|
|
128
|
-
const
|
|
128
|
+
const tags = span.context().getTags()
|
|
129
|
+
if (tags[PEER_SERVICE_SOURCE_KEY] !== undefined) return
|
|
130
|
+
|
|
131
|
+
const peerData = this.getPeerService(tags)
|
|
129
132
|
if (peerData !== undefined) {
|
|
130
133
|
span.addTags(this.getPeerServiceRemap(peerData))
|
|
131
134
|
}
|
|
@@ -59,7 +59,7 @@ class NativeSpaceProfiler {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
profile (restart) {
|
|
62
|
-
const profile = this.#pprof.heap.profile(undefined, this.#mapper, getThreadLabels)
|
|
62
|
+
const profile = this.#pprof.heap.profile(undefined, this.#mapper, getThreadLabels, 'pack')
|
|
63
63
|
if (!restart) {
|
|
64
64
|
this.stop()
|
|
65
65
|
}
|
|
@@ -187,6 +187,7 @@ class NativeWallProfiler {
|
|
|
187
187
|
|
|
188
188
|
this.#pprof.time.start({
|
|
189
189
|
collectCpuTime: this.#cpuProfilingEnabled,
|
|
190
|
+
columnNumbers: 'pack',
|
|
190
191
|
durationMillis: this.#flushIntervalMillis,
|
|
191
192
|
intervalMicros: this.#samplingIntervalMicros,
|
|
192
193
|
lineNumbers: false,
|
|
@@ -62,7 +62,7 @@ class SpanProcessor {
|
|
|
62
62
|
active.push(span)
|
|
63
63
|
} else {
|
|
64
64
|
const formattedSpan = spanFormat(span, isFirstSpanInChunk, this._processTags)
|
|
65
|
-
if (
|
|
65
|
+
if (stampApmDisabled) {
|
|
66
66
|
formattedSpan.metrics[APM_TRACING_ENABLED_KEY] = 0
|
|
67
67
|
}
|
|
68
68
|
isFirstSpanInChunk = false
|
|
@@ -14,6 +14,8 @@ const {
|
|
|
14
14
|
GRPC_STATUS_CODE,
|
|
15
15
|
} = require('../../../ext/tags')
|
|
16
16
|
const { ORIGIN_KEY, TOP_LEVEL_KEY, SVC_SRC_KEY, GRPC_STATUS_NAMES } = require('./constants')
|
|
17
|
+
|
|
18
|
+
const GRPC_STATUS_CODE_MAP = Object.fromEntries(GRPC_STATUS_NAMES.map((name, i) => [name, String(i)]))
|
|
17
19
|
const { version } = require('./pkg')
|
|
18
20
|
const processTags = require('./process-tags')
|
|
19
21
|
|
|
@@ -108,10 +110,26 @@ class SpanAggKey {
|
|
|
108
110
|
this.srvSrc = span.meta[SVC_SRC_KEY] || ''
|
|
109
111
|
this.spanKind = span.meta[SPAN_KIND] || ''
|
|
110
112
|
// dd gRPC plugin sets a numeric code via setTag; OTel/manual sets a string name via meta.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
// Normalize to numeric string to match the Agent's parseGRPCStatusString convention.
|
|
114
|
+
// Also check OTel semantic aliases (rpc.grpc.status_code, rpc.response.status_code) as
|
|
115
|
+
// the OTel bridge stores attributes under their original key without remapping.
|
|
116
|
+
const grpcCode = span.meta[GRPC_STATUS_CODE] ?? span.metrics?.[GRPC_STATUS_CODE] ??
|
|
117
|
+
span.meta['rpc.grpc.status_code'] ?? span.metrics?.['rpc.grpc.status_code'] ??
|
|
118
|
+
span.meta['rpc.response.status_code'] ?? span.metrics?.['rpc.response.status_code']
|
|
119
|
+
if (typeof grpcCode === 'number') {
|
|
120
|
+
this.rpcStatusCode = String(grpcCode)
|
|
121
|
+
} else if (grpcCode) {
|
|
122
|
+
const upper = String(grpcCode).toUpperCase()
|
|
123
|
+
const numeric = GRPC_STATUS_CODE_MAP[upper]
|
|
124
|
+
if (numeric === undefined) {
|
|
125
|
+
const n = Number(grpcCode)
|
|
126
|
+
this.rpcStatusCode = Number.isInteger(n) && n >= 0 ? String(n) : ''
|
|
127
|
+
} else {
|
|
128
|
+
this.rpcStatusCode = numeric
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
this.rpcStatusCode = ''
|
|
132
|
+
}
|
|
115
133
|
}
|
|
116
134
|
|
|
117
135
|
toString () {
|