dd-trace 5.124.0 → 5.126.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 +3 -1
- package/ci/init.js +8 -3
- package/ci/test-optimization-validation/ci-package-scripts.js +2 -2
- package/ci/test-optimization-validation/ci-remediation.js +6 -6
- package/ci/test-optimization-validation/command-blocker.js +7 -5
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +1 -1
- package/ci/test-optimization-validation/framework-adapters/vitest.js +3 -3
- package/ci/test-optimization-validation/package-check.js +1 -1
- package/ci/test-optimization-validation/report-writer.js +7 -5
- package/ci/vitest-no-worker-init-runner-setup.mjs +8 -0
- package/ci/vitest-no-worker-init-setup.mjs +13 -13
- package/ci/vitest-no-worker-init-v5-setup.mjs +4 -0
- package/index.d.ts +8 -0
- package/package.json +13 -10
- package/packages/datadog-esbuild/index.js +3 -1
- package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
- package/packages/datadog-instrumentations/src/fs.js +24 -20
- package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
- package/packages/datadog-instrumentations/src/graphql.js +16 -16
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +265 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +14 -5
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +251 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +11 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
- package/packages/datadog-instrumentations/src/jest.js +166 -45
- package/packages/datadog-instrumentations/src/knex.js +76 -0
- package/packages/datadog-instrumentations/src/mariadb.js +6 -0
- package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
- package/packages/datadog-instrumentations/src/mocha/main.js +66 -20
- package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
- package/packages/datadog-instrumentations/src/net.js +14 -17
- package/packages/datadog-instrumentations/src/next.js +212 -62
- package/packages/datadog-instrumentations/src/openai.js +42 -40
- package/packages/datadog-instrumentations/src/pg.js +15 -0
- package/packages/datadog-instrumentations/src/playwright.js +113 -13
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
- package/packages/datadog-instrumentations/src/sequelize.js +94 -2
- package/packages/datadog-instrumentations/src/undici.js +53 -4
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +37 -3
- package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
- package/packages/datadog-instrumentations/src/vitest-worker.js +71 -14
- package/packages/datadog-instrumentations/src/webdriverio.js +965 -6
- package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
- package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
- package/packages/datadog-plugin-amqp10/src/util.js +2 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
- package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
- package/packages/datadog-plugin-cucumber/src/index.js +0 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
- package/packages/datadog-plugin-graphql/src/execute.js +998 -196
- package/packages/datadog-plugin-graphql/src/index.js +27 -7
- package/packages/datadog-plugin-graphql/src/jit.js +136 -0
- package/packages/datadog-plugin-graphql/src/request.js +18 -27
- package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
- package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
- package/packages/datadog-plugin-graphql/src/utils.js +208 -120
- package/packages/datadog-plugin-graphql/src/validate.js +10 -23
- package/packages/datadog-plugin-jest/src/index.js +0 -6
- package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
- package/packages/datadog-plugin-mocha/src/index.js +403 -75
- package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
- package/packages/datadog-plugin-mysql/src/index.js +41 -15
- package/packages/datadog-plugin-net/src/tcp.js +3 -1
- package/packages/datadog-plugin-next/src/index.js +63 -29
- package/packages/datadog-plugin-playwright/src/index.js +167 -27
- package/packages/datadog-plugin-undici/src/index.js +27 -41
- package/packages/datadog-plugin-vitest/src/index.js +6 -12
- package/packages/dd-trace/src/aiguard/evaluation.js +2 -1
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +8 -1
- package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
- package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
- package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
- package/packages/dd-trace/src/appsec/graphql.js +6 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +3 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +531 -95
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/lambda.js +44 -26
- package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +5 -173
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +394 -225
- package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
- package/packages/dd-trace/src/ci-visibility/final-flush.js +2 -1
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
- package/packages/dd-trace/src/ci-visibility/requests/request.js +11 -0
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +180 -0
- package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
- package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -0
- package/packages/dd-trace/src/config/index.js +73 -13
- package/packages/dd-trace/src/config/parsers.js +11 -1
- package/packages/dd-trace/src/config/stable.js +3 -3
- package/packages/dd-trace/src/config/supported-configurations.json +22 -2
- package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
- package/packages/dd-trace/src/debugger/config.js +12 -1
- package/packages/dd-trace/src/debugger/constants.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/request-options.js +28 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -40
- package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
- package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
- package/packages/dd-trace/src/debugger/index.js +23 -3
- package/packages/dd-trace/src/dogstatsd.js +510 -76
- package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
- package/packages/dd-trace/src/encode/0.4.js +5 -5
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
- package/packages/dd-trace/src/evp_proxy/direct.js +3 -25
- package/packages/dd-trace/src/exporters/agent/index.js +2 -1
- package/packages/dd-trace/src/exporters/agent/writer.js +24 -7
- package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
- package/packages/dd-trace/src/exporters/agentless/writer.js +103 -119
- package/packages/dd-trace/src/exporters/common/agents.js +28 -6
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
- package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
- package/packages/dd-trace/src/exporters/common/proxy.js +52 -0
- package/packages/dd-trace/src/exporters/common/request.js +42 -14
- package/packages/dd-trace/src/exporters/common/url.js +40 -1
- package/packages/dd-trace/src/exporters/common/writer.js +9 -7
- package/packages/dd-trace/src/flush.js +6 -3
- package/packages/dd-trace/src/id.js +14 -0
- package/packages/dd-trace/src/index.js +5 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +2 -1
- package/packages/dd-trace/src/llmobs/index.js +32 -32
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
- package/packages/dd-trace/src/llmobs/util.js +0 -33
- package/packages/dd-trace/src/llmobs/writers/base.js +49 -32
- package/packages/dd-trace/src/log/index.js +7 -1
- package/packages/dd-trace/src/{ci-visibility/log-submission → log-submission}/log-submission-plugin.js +48 -19
- package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/index.js +5 -24
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +15 -22
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +14 -4
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +10 -0
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +5 -0
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
- package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +101 -20
- package/packages/dd-trace/src/payload-tagging/index.js +2 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
- package/packages/dd-trace/src/plugins/tracing.js +12 -10
- package/packages/dd-trace/src/plugins/util/ci.js +3 -1
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
- package/packages/dd-trace/src/plugins/util/test.js +83 -20
- package/packages/dd-trace/src/plugins/util/url.js +2 -2
- package/packages/dd-trace/src/plugins/util/web.js +4 -9
- package/packages/dd-trace/src/priority_sampler.js +4 -0
- package/packages/dd-trace/src/profiling/config.js +1 -0
- package/packages/dd-trace/src/profiling/oom.js +7 -2
- package/packages/dd-trace/src/profiling/profiler.js +23 -13
- package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
- package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
- package/packages/dd-trace/src/proxy.js +75 -5
- package/packages/dd-trace/src/remote_config/index.js +319 -101
- package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
- package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +5 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -1
- package/packages/dd-trace/src/sampling_rule.js +39 -10
- package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +4 -8
- package/packages/dd-trace/src/serverless/vercel.js +53 -20
- package/packages/dd-trace/src/serverless.js +10 -3
- package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
- package/packages/dd-trace/src/span_processor.js +18 -3
- package/packages/dd-trace/src/span_stats.js +24 -28
- package/packages/dd-trace/src/startup-log.js +3 -2
- package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
- package/packages/dd-trace/src/telemetry/send-data.js +23 -20
- package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
- package/packages/dd-trace/src/tracer.js +4 -5
- package/packages/dd-trace/src/tracer_metadata.js +11 -3
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +0 -27
- package/packages/dd-trace/src/encode/agentless-json.js +0 -210
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const { channel } = require('dc-polyfill')
|
|
4
4
|
|
|
5
|
-
const { readDatadogTags, writeDatadogTags } = require('../carrier')
|
|
6
5
|
const { registerTelemetryFlusher } = require('../flush')
|
|
7
6
|
const log = require('../log')
|
|
8
7
|
const { createServerlessDeliveryTracker } = require('../serverless')
|
|
@@ -25,7 +24,7 @@ const {
|
|
|
25
24
|
PROPAGATED_TRACE_ID_KEY,
|
|
26
25
|
} = require('./constants/tags')
|
|
27
26
|
const { storage } = require('./storage')
|
|
28
|
-
const { agentNameWireSafe,
|
|
27
|
+
const { agentNameWireSafe, resolveAgentAttribution } = require('./util')
|
|
29
28
|
const telemetry = require('./telemetry')
|
|
30
29
|
const LLMObsSpanProcessor = require('./span_processor')
|
|
31
30
|
const LLMObsEvalMetricsWriter = require('./writers/evaluations')
|
|
@@ -64,6 +63,13 @@ let unregisterTelemetryFlusher
|
|
|
64
63
|
/** @type {import('../config/config-base')} */
|
|
65
64
|
let globalTracerConfig
|
|
66
65
|
|
|
66
|
+
/**
|
|
67
|
+
* @typedef {object} TraceTagInjection
|
|
68
|
+
* @property {import('../opentracing/span_context')} spanContext
|
|
69
|
+
* @property {Array<string | undefined>} [traceTagReplacements]
|
|
70
|
+
* @property {number} [optionalTraceTagCount]
|
|
71
|
+
*/
|
|
72
|
+
|
|
67
73
|
/**
|
|
68
74
|
* @param {@type import('../config/config-base')} config
|
|
69
75
|
*/
|
|
@@ -163,7 +169,8 @@ function retireWriters (retiredSpanWriter, retiredEvalWriter) {
|
|
|
163
169
|
|
|
164
170
|
// since LLMObs traces can extend between services and be the same trace,
|
|
165
171
|
// we need to propagate the parent id, mlApp, session id, and sampling rate/decision.
|
|
166
|
-
|
|
172
|
+
/** @param {TraceTagInjection} injection */
|
|
173
|
+
function handleLLMObsInjection (injection) {
|
|
167
174
|
// Respect the standard propagator's gate: when trace tag propagation is
|
|
168
175
|
// disabled, don't write `x-datadog-tags` for LLMObs either.
|
|
169
176
|
if (globalTracerConfig.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) return
|
|
@@ -201,37 +208,30 @@ function handleLLMObsInjection ({ carrier }) {
|
|
|
201
208
|
mlObsSpanTags, parent
|
|
202
209
|
)
|
|
203
210
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (
|
|
209
|
-
if (
|
|
210
|
-
|
|
211
|
-
if (sampleRate != null) tags += `${tags ? ',' : ''}${PROPAGATED_SAMPLE_RATE_KEY}=${sampleRate}`
|
|
212
|
-
if (samplingDecision != null) tags += `${tags ? ',' : ''}${PROPAGATED_SAMPLING_DECISION_KEY}=${samplingDecision}`
|
|
213
|
-
if (propagatedTraceId != null) tags += `${tags ? ',' : ''}${PROPAGATED_TRACE_ID_KEY}=${propagatedTraceId}`
|
|
214
|
-
// When a local agent attribution is resolved, strip any stale upstream pagent entries that
|
|
215
|
-
// `_injectTags` may have already written into the carrier (it propagates all `_dd.p.*` from
|
|
216
|
-
// `_trace.tags`). This ensures the downstream sees a consistent id-only or id+name pair
|
|
217
|
-
// rather than a mix from different hops. The id is always digit-safe; an unsafe name is wiped.
|
|
218
|
-
if (parentAgentSpanId) {
|
|
219
|
-
tags = stripTagsetEntry(tags, PROPAGATED_PARENT_AGENT_ID_KEY)
|
|
220
|
-
tags = stripTagsetEntry(tags, PROPAGATED_PARENT_AGENT_NAME_KEY)
|
|
211
|
+
const traceTagReplacements = []
|
|
212
|
+
if (parentId) traceTagReplacements.push(PROPAGATED_PARENT_ID_KEY, parentId)
|
|
213
|
+
if (mlApp) traceTagReplacements.push(PROPAGATED_ML_APP_KEY, mlApp)
|
|
214
|
+
if (sessionId) traceTagReplacements.push(PROPAGATED_SESSION_ID_KEY, sessionId)
|
|
215
|
+
if (sampleRate != null) traceTagReplacements.push(PROPAGATED_SAMPLE_RATE_KEY, sampleRate.toString())
|
|
216
|
+
if (samplingDecision != null) {
|
|
217
|
+
traceTagReplacements.push(PROPAGATED_SAMPLING_DECISION_KEY, samplingDecision.toString())
|
|
221
218
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
219
|
+
if (propagatedTraceId != null) traceTagReplacements.push(PROPAGATED_TRACE_ID_KEY, propagatedTraceId)
|
|
220
|
+
|
|
221
|
+
let optionalTraceTagCount = 0
|
|
222
|
+
if (parentAgentSpanId) {
|
|
223
|
+
traceTagReplacements.push(PROPAGATED_PARENT_AGENT_ID_KEY, parentAgentSpanId)
|
|
224
|
+
optionalTraceTagCount++
|
|
225
|
+
if (parentAgentName && agentNameWireSafe(parentAgentName)) {
|
|
226
|
+
traceTagReplacements.push(PROPAGATED_PARENT_AGENT_NAME_KEY, parentAgentName)
|
|
227
|
+
} else {
|
|
228
|
+
traceTagReplacements.push(PROPAGATED_PARENT_AGENT_NAME_KEY, undefined)
|
|
229
|
+
}
|
|
230
|
+
optionalTraceTagCount++
|
|
233
231
|
}
|
|
234
|
-
|
|
232
|
+
|
|
233
|
+
injection.traceTagReplacements = traceTagReplacements
|
|
234
|
+
injection.optionalTraceTagCount = optionalTraceTagCount
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
/**
|
|
@@ -4,7 +4,6 @@ const { channel } = require('dc-polyfill')
|
|
|
4
4
|
const BaseLLMObsPlugin = require('../base')
|
|
5
5
|
const { getModelProvider } = require('../../../../../datadog-plugin-ai/src/utils')
|
|
6
6
|
|
|
7
|
-
const toolCreationCh = channel('tracing:orchestrion:ai:tool:start')
|
|
8
7
|
const setAttributesCh = channel('dd-trace:vercel-ai:span:setAttributes')
|
|
9
8
|
|
|
10
9
|
const { MODEL_NAME, MODEL_PROVIDER, NAME } = require('../../constants/tags')
|
|
@@ -21,16 +20,10 @@ const {
|
|
|
21
20
|
getTelemetryMetadata,
|
|
22
21
|
} = require('./util')
|
|
23
22
|
|
|
24
|
-
/**
|
|
25
|
-
* @typedef {Record<string, unknown> & { description?: string, id?: string }} AvailableToolArgs
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
23
|
/**
|
|
29
24
|
* @typedef {string | number | boolean | null | undefined | string[] | number[] | boolean[]} TagValue
|
|
30
25
|
* @typedef {Record<string, TagValue>} SpanTags
|
|
31
26
|
*
|
|
32
|
-
* @typedef {{ name?: string, description?: string }} ToolForModel
|
|
33
|
-
*
|
|
34
27
|
* @typedef {{ type: 'text' | 'reasoning' | 'redacted-reasoning', text?: string, data?: string }} TextPart
|
|
35
28
|
* @typedef {{ type: 'tool-call', toolName: string, toolCallId: string, args?: unknown, input?: unknown }} ToolCallPart
|
|
36
29
|
* @typedef {(
|
|
@@ -76,58 +69,14 @@ class DdTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
76
69
|
static integration = 'ai'
|
|
77
70
|
static prefix = 'tracing:dd-trace:vercel-ai'
|
|
78
71
|
|
|
79
|
-
/**
|
|
80
|
-
* The available tools within the runtime scope of this integration.
|
|
81
|
-
* This essentially acts as a global registry for all tools made through the Vercel AI SDK.
|
|
82
|
-
* @type {Set<AvailableToolArgs>}
|
|
83
|
-
*/
|
|
84
|
-
#availableTools
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* A mapping of tool call IDs to tool names.
|
|
88
|
-
* This is used to map the tool call ID to the tool name for the output message.
|
|
89
|
-
* @type {Record<string, string>}
|
|
90
|
-
*/
|
|
91
|
-
#toolCallIdsToName
|
|
92
|
-
|
|
93
72
|
constructor (...args) {
|
|
94
73
|
super(...args)
|
|
95
74
|
|
|
96
|
-
this.#toolCallIdsToName = {}
|
|
97
|
-
this.#availableTools = new Set()
|
|
98
|
-
toolCreationCh.subscribe(ctx => {
|
|
99
|
-
const toolArgs = ctx.arguments
|
|
100
|
-
const tool = toolArgs[0] ?? {}
|
|
101
|
-
this.#availableTools.add(tool)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
75
|
setAttributesCh.subscribe(({ ctx, attributes }) => {
|
|
105
76
|
Object.assign(ctx.attributes, attributes)
|
|
106
77
|
})
|
|
107
78
|
}
|
|
108
79
|
|
|
109
|
-
/**
|
|
110
|
-
* Does a best-effort attempt to find the right tool name for the given tool description.
|
|
111
|
-
* This is because the Vercel AI SDK does not tag tools by name properly, but
|
|
112
|
-
* rather by the index they were passed in. Tool names appear nowhere in the span tags.
|
|
113
|
-
*
|
|
114
|
-
* We use the tool description as the next best identifier for a tool.
|
|
115
|
-
*
|
|
116
|
-
* @param {string} toolName
|
|
117
|
-
* @param {string | undefined} toolDescription
|
|
118
|
-
* @returns {string | undefined}
|
|
119
|
-
*/
|
|
120
|
-
findToolName (toolName, toolDescription) {
|
|
121
|
-
if (Number.isNaN(Number.parseInt(toolName, 10))) return toolName
|
|
122
|
-
|
|
123
|
-
for (const availableTool of this.#availableTools) {
|
|
124
|
-
const description = availableTool.description
|
|
125
|
-
if (description === toolDescription && availableTool.id) {
|
|
126
|
-
return availableTool.id
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
80
|
/**
|
|
132
81
|
* @override
|
|
133
82
|
*/
|
|
@@ -232,7 +181,13 @@ class DdTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
232
181
|
const lastUserPrompt =
|
|
233
182
|
promptInfo.prompt ??
|
|
234
183
|
promptInfo.messages.reverse().find(message => message.role === 'user')?.content
|
|
235
|
-
|
|
184
|
+
let prompt = lastUserPrompt
|
|
185
|
+
if (Array.isArray(lastUserPrompt)) {
|
|
186
|
+
prompt = ''
|
|
187
|
+
for (const part of lastUserPrompt) {
|
|
188
|
+
if (typeof part.text === 'string') prompt += part.text
|
|
189
|
+
}
|
|
190
|
+
}
|
|
236
191
|
|
|
237
192
|
const output = tags['ai.response.object']
|
|
238
193
|
|
|
@@ -248,7 +203,13 @@ class DdTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
248
203
|
const lastUserPrompt =
|
|
249
204
|
promptInfo.prompt ??
|
|
250
205
|
promptInfo.messages.reverse().find(message => message.role === 'user')?.content
|
|
251
|
-
|
|
206
|
+
let prompt = lastUserPrompt
|
|
207
|
+
if (Array.isArray(lastUserPrompt)) {
|
|
208
|
+
prompt = ''
|
|
209
|
+
for (const part of lastUserPrompt) {
|
|
210
|
+
if (typeof part.text === 'string') prompt += part.text
|
|
211
|
+
}
|
|
212
|
+
}
|
|
252
213
|
|
|
253
214
|
const output = tags['ai.response.text']
|
|
254
215
|
|
|
@@ -263,16 +224,14 @@ class DdTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
263
224
|
* @param {SpanTags} tags
|
|
264
225
|
*/
|
|
265
226
|
setLLMOperationTags (span, tags) {
|
|
266
|
-
const toolsForModel = tags['ai.prompt.tools']?.map(getJsonStringValue)
|
|
267
|
-
|
|
268
227
|
const inputMessages = getJsonStringValue(tags['ai.prompt.messages'], [])
|
|
269
228
|
const parsedInputMessages = []
|
|
270
229
|
for (const message of inputMessages) {
|
|
271
|
-
const formattedMessages = this.formatMessage(message
|
|
230
|
+
const formattedMessages = this.formatMessage(message)
|
|
272
231
|
parsedInputMessages.push(...formattedMessages)
|
|
273
232
|
}
|
|
274
233
|
|
|
275
|
-
const outputMessage = this.formatOutputMessage(tags
|
|
234
|
+
const outputMessage = this.formatOutputMessage(tags)
|
|
276
235
|
|
|
277
236
|
this._tagger.tagLLMIO(span, parsedInputMessages, outputMessage)
|
|
278
237
|
|
|
@@ -284,8 +243,8 @@ class DdTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
284
243
|
}
|
|
285
244
|
|
|
286
245
|
setToolTags (span, tags) {
|
|
287
|
-
const
|
|
288
|
-
|
|
246
|
+
const name = getToolNameFromTags(tags)
|
|
247
|
+
|
|
289
248
|
if (name) this._tagger._setTag(span, NAME, name)
|
|
290
249
|
|
|
291
250
|
const input = tags['ai.toolCall.args']
|
|
@@ -294,7 +253,7 @@ class DdTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
294
253
|
this._tagger.tagTextIO(span, input, output)
|
|
295
254
|
}
|
|
296
255
|
|
|
297
|
-
formatOutputMessage (tags
|
|
256
|
+
formatOutputMessage (tags) {
|
|
298
257
|
const outputMessageText = tags['ai.response.text'] ?? tags['ai.response.object']
|
|
299
258
|
const outputMessageToolCalls = getJsonStringValue(tags['ai.response.toolCalls'], [])
|
|
300
259
|
|
|
@@ -302,13 +261,9 @@ class DdTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
302
261
|
for (const toolCall of outputMessageToolCalls) {
|
|
303
262
|
const toolArgs = toolCall.args ?? toolCall.input
|
|
304
263
|
const toolCallArgs = typeof toolArgs === 'string' ? getJsonStringValue(toolArgs, {}) : toolArgs
|
|
305
|
-
const toolDescription = toolsForModel?.find(tool => toolCall.toolName === tool.name)?.description
|
|
306
|
-
const name = this.findToolName(toolCall.toolName, toolDescription)
|
|
307
|
-
this.#toolCallIdsToName[toolCall.toolCallId] = name
|
|
308
|
-
|
|
309
264
|
formattedToolCalls.push({
|
|
310
265
|
arguments: toolCallArgs,
|
|
311
|
-
name,
|
|
266
|
+
name: toolCall.toolName,
|
|
312
267
|
toolId: toolCall.toolCallId,
|
|
313
268
|
type: toolCall.toolCallType ?? 'function',
|
|
314
269
|
})
|
|
@@ -328,11 +283,10 @@ class DdTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
328
283
|
* need to split into multiple messages.
|
|
329
284
|
*
|
|
330
285
|
* @param {AiSdkMessage} message
|
|
331
|
-
* @param {ToolForModel[] | null | undefined} toolsForModel
|
|
332
286
|
* @returns {Array<{role: string, content: string, toolId?: string,
|
|
333
287
|
* toolCalls?: Array<{arguments: string, name: string, toolId: string, type: string}>}>}
|
|
334
288
|
*/
|
|
335
|
-
formatMessage (message
|
|
289
|
+
formatMessage (message) {
|
|
336
290
|
const { role, content } = message
|
|
337
291
|
|
|
338
292
|
if (role === 'system') {
|
|
@@ -357,12 +311,9 @@ class DdTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
357
311
|
if (['text', 'reasoning', 'redacted-reasoning'].includes(type)) {
|
|
358
312
|
finalContent += part.text ?? part.data
|
|
359
313
|
} else if (type === 'tool-call') {
|
|
360
|
-
const toolDescription = toolsForModel?.find(tool => part.toolName === tool.name)?.description
|
|
361
|
-
const name = this.findToolName(part.toolName, toolDescription)
|
|
362
|
-
|
|
363
314
|
toolCalls.push({
|
|
364
315
|
arguments: part.args ?? part.input,
|
|
365
|
-
name,
|
|
316
|
+
name: part.toolName,
|
|
366
317
|
toolId: part.toolCallId,
|
|
367
318
|
type: 'function',
|
|
368
319
|
})
|
|
@@ -38,11 +38,15 @@ function formatLanguageModelInputMessages (instructions, messages) {
|
|
|
38
38
|
const inputMessages = []
|
|
39
39
|
|
|
40
40
|
if (instructions) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
let systemPrompt = instructions
|
|
42
|
+
if (typeof instructions !== 'string') {
|
|
43
|
+
if (Array.isArray(instructions)) {
|
|
44
|
+
systemPrompt = ''
|
|
45
|
+
for (const instruction of instructions) systemPrompt += instruction.content
|
|
46
|
+
} else {
|
|
47
|
+
systemPrompt = instructions.content
|
|
48
|
+
}
|
|
49
|
+
}
|
|
46
50
|
|
|
47
51
|
inputMessages.push({ role: 'system', content: systemPrompt })
|
|
48
52
|
}
|
|
@@ -53,13 +57,13 @@ function formatLanguageModelInputMessages (instructions, messages) {
|
|
|
53
57
|
if (role === 'system') {
|
|
54
58
|
inputMessages.push({ role, content })
|
|
55
59
|
} else if (role === 'user') {
|
|
56
|
-
|
|
57
|
-
typeof content
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
let userMessageContent = content
|
|
61
|
+
if (typeof content !== 'string') {
|
|
62
|
+
userMessageContent = ''
|
|
63
|
+
for (const part of content) {
|
|
64
|
+
if (part.type === 'text') userMessageContent += part.text
|
|
65
|
+
}
|
|
66
|
+
}
|
|
63
67
|
|
|
64
68
|
inputMessages.push({ role, content: userMessageContent })
|
|
65
69
|
} else if (role === 'assistant') {
|
|
@@ -292,7 +296,13 @@ class VercelAiTelemetryPlugin extends BaseLLMObsPlugin {
|
|
|
292
296
|
const { event, result } = ctx
|
|
293
297
|
|
|
294
298
|
const lastUserPrompt = event.messages.findLast(message => message.role === 'user')?.content
|
|
295
|
-
|
|
299
|
+
let input = lastUserPrompt
|
|
300
|
+
if (Array.isArray(lastUserPrompt)) {
|
|
301
|
+
input = ''
|
|
302
|
+
for (const part of lastUserPrompt) {
|
|
303
|
+
if (part.type === 'text') input += part.text
|
|
304
|
+
}
|
|
305
|
+
}
|
|
296
306
|
|
|
297
307
|
const output =
|
|
298
308
|
ctx.isStream
|
|
@@ -46,6 +46,13 @@ class BaseLangChainLLMObsPlugin extends LLMObsPlugin {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
error (ctx) {
|
|
50
|
+
// NodeInterrupt or GraphInterrupt "errors" for control flow, do not mark as real errors
|
|
51
|
+
if (ctx.error?.is_bubble_up) return
|
|
52
|
+
|
|
53
|
+
super.error(ctx)
|
|
54
|
+
}
|
|
55
|
+
|
|
49
56
|
getLLMObsSpanRegisterOptions (ctx) {
|
|
50
57
|
const span = ctx.currentStore?.span
|
|
51
58
|
const spanContext = span?.context()
|
|
@@ -337,37 +337,6 @@ function resolveAgentAttribution (tags, span) {
|
|
|
337
337
|
return { name: tags[PARENT_AGENT_NAME], spanId: tags[PARENT_AGENT_SPAN_ID] }
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
/**
|
|
341
|
-
* Removes all `key=value` entries for the given key from a comma-separated tagset string.
|
|
342
|
-
*
|
|
343
|
-
* @param {string} tags - Existing tagset string (may be empty).
|
|
344
|
-
* @param {string} key
|
|
345
|
-
* @returns {string}
|
|
346
|
-
*/
|
|
347
|
-
function stripTagsetEntry (tags, key) {
|
|
348
|
-
if (!tags.includes(key)) return tags
|
|
349
|
-
return tags.split(',').filter(entry => !entry.startsWith(`${key}=`)).join(',')
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Appends `key=value` to the tagset string with a comma separator, but only when `value` is
|
|
354
|
-
* truthy, passes the optional `safeguard` predicate, and fits within `maxTagSetLength`. Returns
|
|
355
|
-
* the original `tags` unchanged when the value is absent, unsafe, or would overflow the budget.
|
|
356
|
-
*
|
|
357
|
-
* @param {string} tags - Existing tagset string (may be empty).
|
|
358
|
-
* @param {string} key
|
|
359
|
-
* @param {string | undefined} value
|
|
360
|
-
* @param {((v: string) => boolean) | null} [safeguard]
|
|
361
|
-
* @param {number} [maxTagSetLength]
|
|
362
|
-
* @returns {string}
|
|
363
|
-
*/
|
|
364
|
-
function appendOptionalPropagatedTag (tags, key, value, safeguard, maxTagSetLength) {
|
|
365
|
-
if (!value || (safeguard && !safeguard(value))) return tags
|
|
366
|
-
const entry = `${tags ? ',' : ''}${key}=${value}`
|
|
367
|
-
if (maxTagSetLength != null && tags.length + entry.length > maxTagSetLength) return tags
|
|
368
|
-
return `${tags}${entry}`
|
|
369
|
-
}
|
|
370
|
-
|
|
371
340
|
function spanHasError (span) {
|
|
372
341
|
const spanContext = span.context()
|
|
373
342
|
return !!(spanContext.getTag('error') || spanContext.getTag('error.type'))
|
|
@@ -518,7 +487,6 @@ function formatAudioPart (data, mimeType) {
|
|
|
518
487
|
|
|
519
488
|
module.exports = {
|
|
520
489
|
agentNameWireSafe,
|
|
521
|
-
appendOptionalPropagatedTag,
|
|
522
490
|
audioMimeTypeFromFormat,
|
|
523
491
|
encodeUnicode,
|
|
524
492
|
findGenAIAncestorSpanId,
|
|
@@ -527,7 +495,6 @@ module.exports = {
|
|
|
527
495
|
normalizeLlmObsTraceId,
|
|
528
496
|
formatAudioPart,
|
|
529
497
|
resolveAgentAttribution,
|
|
530
|
-
stripTagsetEntry,
|
|
531
498
|
validateCostTags,
|
|
532
499
|
validateKind,
|
|
533
500
|
getFunctionArguments,
|
|
@@ -17,13 +17,20 @@ const {
|
|
|
17
17
|
} = require('../constants/writers')
|
|
18
18
|
const { parseResponseAndLog } = require('./util')
|
|
19
19
|
|
|
20
|
+
const MAX_BUFFER_EVENTS = 1000
|
|
21
|
+
|
|
20
22
|
class LLMObsBuffer {
|
|
21
|
-
|
|
23
|
+
/**
|
|
24
|
+
* @param {{
|
|
25
|
+
* events: Record<string, unknown>[],
|
|
26
|
+
* size: number,
|
|
27
|
+
* routing?: { apiKey?: string, site?: string }
|
|
28
|
+
* }} options
|
|
29
|
+
*/
|
|
30
|
+
constructor ({ events, size, routing = {} }) {
|
|
22
31
|
this.events = events
|
|
23
32
|
this.size = size
|
|
24
33
|
this.routing = routing
|
|
25
|
-
this.isDefault = isDefault
|
|
26
|
-
this.limit = limit
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
clear () {
|
|
@@ -46,7 +53,7 @@ class BaseLLMObsWriter {
|
|
|
46
53
|
this._eventType = eventType
|
|
47
54
|
|
|
48
55
|
/** @type {LLMObsBuffer} */
|
|
49
|
-
this._buffer = new LLMObsBuffer({ events: [], size: 0
|
|
56
|
+
this._buffer = new LLMObsBuffer({ events: [], size: 0 })
|
|
50
57
|
|
|
51
58
|
/** @type {import('../../config/config-base')} */
|
|
52
59
|
this._config = config
|
|
@@ -102,8 +109,8 @@ class BaseLLMObsWriter {
|
|
|
102
109
|
append (event, routing, byteLength) {
|
|
103
110
|
const buffer = this._getBuffer(routing)
|
|
104
111
|
|
|
105
|
-
if (buffer.events.length >=
|
|
106
|
-
logger.warn(`${this.constructor.name} event buffer full (limit is ${
|
|
112
|
+
if (buffer.events.length >= MAX_BUFFER_EVENTS) {
|
|
113
|
+
logger.warn(`${this.constructor.name} event buffer full (limit is ${MAX_BUFFER_EVENTS}), dropping event`)
|
|
107
114
|
telemetry.recordDroppedPayload(1, this._eventType, 'buffer_full')
|
|
108
115
|
return false
|
|
109
116
|
}
|
|
@@ -158,30 +165,48 @@ class BaseLLMObsWriter {
|
|
|
158
165
|
}
|
|
159
166
|
|
|
160
167
|
for (const [apiKey, buffer] of this.#multiTenantBuffers) {
|
|
161
|
-
if (buffer.events.length === 0)
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
if (buffer.events.length === 0) {
|
|
169
|
+
this.#multiTenantBuffers.delete(apiKey)
|
|
170
|
+
continue
|
|
171
|
+
}
|
|
164
172
|
const site = buffer.routing.site || this._config.site
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
173
|
+
const maskedApiKey = `****${apiKey.slice(-4)}`
|
|
174
|
+
let options
|
|
175
|
+
let url
|
|
176
|
+
try {
|
|
177
|
+
options = {
|
|
178
|
+
headers: {
|
|
179
|
+
'Content-Type': 'application/json',
|
|
180
|
+
'DD-API-KEY': apiKey,
|
|
181
|
+
},
|
|
182
|
+
method: 'POST',
|
|
183
|
+
timeout: this._timeout,
|
|
184
|
+
url: new URL(format({
|
|
185
|
+
protocol: 'https:',
|
|
186
|
+
hostname: `${this._intake}.${site}`,
|
|
187
|
+
})),
|
|
188
|
+
path: this._baseEndpoint,
|
|
189
|
+
}
|
|
190
|
+
url = this.#buildUrl(options.url.href, options.path)
|
|
191
|
+
} catch (error) {
|
|
192
|
+
buffer.clear()
|
|
193
|
+
this.#multiTenantBuffers.delete(apiKey)
|
|
194
|
+
logger.error(
|
|
195
|
+
'Failed to route LLMObs %s events for API key %s: %s',
|
|
196
|
+
this._eventType,
|
|
197
|
+
maskedApiKey,
|
|
198
|
+
error.message
|
|
199
|
+
)
|
|
200
|
+
continue
|
|
177
201
|
}
|
|
178
|
-
|
|
179
|
-
const
|
|
202
|
+
|
|
203
|
+
const events = buffer.events
|
|
204
|
+
buffer.clear()
|
|
205
|
+
this.#multiTenantBuffers.delete(apiKey)
|
|
180
206
|
log.debug('Encoding and flushing multi-tenant buffer for %s', maskedApiKey)
|
|
181
207
|
requests.push({ events, options, url })
|
|
182
208
|
}
|
|
183
209
|
|
|
184
|
-
this.#cleanupEmptyBuffers()
|
|
185
210
|
return requests
|
|
186
211
|
}
|
|
187
212
|
|
|
@@ -194,14 +219,6 @@ class BaseLLMObsWriter {
|
|
|
194
219
|
})
|
|
195
220
|
}
|
|
196
221
|
|
|
197
|
-
#cleanupEmptyBuffers () {
|
|
198
|
-
for (const [key, buffer] of this.#multiTenantBuffers) {
|
|
199
|
-
if (buffer.events.length === 0) {
|
|
200
|
-
this.#multiTenantBuffers.delete(key)
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
222
|
makePayload (events) {}
|
|
206
223
|
|
|
207
224
|
/**
|
|
@@ -29,7 +29,13 @@ const log = {
|
|
|
29
29
|
const stack = logRecord.stack.split('\n')
|
|
30
30
|
const fn = stack[1].replace(/^\s+at ([^\s]+) .+/, '$1')
|
|
31
31
|
const options = { depth: 2, breakLength: Infinity, compact: true, maxArrayLength: Infinity }
|
|
32
|
-
|
|
32
|
+
let params = ''
|
|
33
|
+
let isFirstParameter = true
|
|
34
|
+
for (const argument of args) {
|
|
35
|
+
if (!isFirstParameter) params += ', '
|
|
36
|
+
params += inspect(argument, options)
|
|
37
|
+
isFirstParameter = false
|
|
38
|
+
}
|
|
33
39
|
|
|
34
40
|
stack[0] = `Trace: ${fn}(${params})`
|
|
35
41
|
|