@mastra/datadog 1.0.8-alpha.0 → 1.0.8
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/CHANGELOG.md +28 -0
- package/dist/index.cjs +29 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +29 -19
- package/dist/index.js.map +1 -1
- package/dist/tracing.d.ts.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @mastra/datadog
|
|
2
2
|
|
|
3
|
+
## 1.0.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fix cache token extraction in multi-step agent runs. Prefer AI SDK aggregated `inputTokenDetails` over `providerMetadata` (which only reflects the last step). Also fix truthiness checks to correctly handle zero values for cache and reasoning tokens. ([#14492](https://github.com/mastra-ai/mastra/pull/14492))
|
|
8
|
+
|
|
9
|
+
Fix Datadog metric keys to match dd-trace expected format: `cacheReadTokens`, `cacheWriteTokens`, `reasoningOutputTokens`.
|
|
10
|
+
|
|
11
|
+
- Fixed span duration accuracy in Datadog LLM Observability traces. Previously, all spans in a trace appeared to have the same end time because dd-trace's `llmobs.trace()` does not honor `endTime` in span options. Now uses `ddSpan.finish()` to explicitly set each span's correct end time, so tools, LLM calls, and agent runs show their actual durations in Datadog. ([#14490](https://github.com/mastra-ai/mastra/pull/14490))
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [[`cb611a1`](https://github.com/mastra-ai/mastra/commit/cb611a1e89a4f4cf74c97b57e0c27bb56f2eceb5), [`da93115`](https://github.com/mastra-ai/mastra/commit/da931155c1a9bc63d455d3d86b4ec984db5991fe), [`62d1d3c`](https://github.com/mastra-ai/mastra/commit/62d1d3cc08fe8182e7080237fd975de862ec8c91), [`9e1a3ed`](https://github.com/mastra-ai/mastra/commit/9e1a3ed07cfafb5e8e19a796ce0bee817002d7c0), [`5ac24c4`](https://github.com/mastra-ai/mastra/commit/5ac24c4fa5275b9c837641d98ed1d988f6b7c327), [`8681ecb`](https://github.com/mastra-ai/mastra/commit/8681ecb86184d5907267000e4576cc442a9a83fc), [`4e699e0`](https://github.com/mastra-ai/mastra/commit/4e699e0c97a3991f9bbf793c78284149944f646a), [`28d0249`](https://github.com/mastra-ai/mastra/commit/28d0249295782277040ad1e0d243e695b7ab1ce4), [`681ee1c`](https://github.com/mastra-ai/mastra/commit/681ee1c811359efd1b8bebc4bce35b9bb7b14bec), [`bb0f09d`](https://github.com/mastra-ai/mastra/commit/bb0f09dbac58401b36069f483acf5673202db5b5), [`a579f7a`](https://github.com/mastra-ai/mastra/commit/a579f7a31e582674862b5679bc79af7ccf7429b8), [`5f7e9d0`](https://github.com/mastra-ai/mastra/commit/5f7e9d0db664020e1f3d97d7d18c6b0b9d4843d0), [`d7f14c3`](https://github.com/mastra-ai/mastra/commit/d7f14c3285cd253ecdd5f58139b7b6cbdf3678b5), [`0efe12a`](https://github.com/mastra-ai/mastra/commit/0efe12a5f008a939a1aac71699486ba40138054e)]:
|
|
14
|
+
- @mastra/core@1.15.0
|
|
15
|
+
- @mastra/observability@1.5.1
|
|
16
|
+
|
|
17
|
+
## 1.0.8-alpha.1
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Fix cache token extraction in multi-step agent runs. Prefer AI SDK aggregated `inputTokenDetails` over `providerMetadata` (which only reflects the last step). Also fix truthiness checks to correctly handle zero values for cache and reasoning tokens. ([#14492](https://github.com/mastra-ai/mastra/pull/14492))
|
|
22
|
+
|
|
23
|
+
Fix Datadog metric keys to match dd-trace expected format: `cacheReadTokens`, `cacheWriteTokens`, `reasoningOutputTokens`.
|
|
24
|
+
|
|
25
|
+
- Fixed span duration accuracy in Datadog LLM Observability traces. Previously, all spans in a trace appeared to have the same end time because dd-trace's `llmobs.trace()` does not honor `endTime` in span options. Now uses `ddSpan.finish()` to explicitly set each span's correct end time, so tools, LLM calls, and agent runs show their actual durations in Datadog. ([#14490](https://github.com/mastra-ai/mastra/pull/14490))
|
|
26
|
+
|
|
27
|
+
- Updated dependencies [[`9e1a3ed`](https://github.com/mastra-ai/mastra/commit/9e1a3ed07cfafb5e8e19a796ce0bee817002d7c0), [`5ac24c4`](https://github.com/mastra-ai/mastra/commit/5ac24c4fa5275b9c837641d98ed1d988f6b7c327), [`a579f7a`](https://github.com/mastra-ai/mastra/commit/a579f7a31e582674862b5679bc79af7ccf7429b8)]:
|
|
28
|
+
- @mastra/core@1.15.0-alpha.2
|
|
29
|
+
- @mastra/observability@1.5.1-alpha.1
|
|
30
|
+
|
|
3
31
|
## 1.0.8-alpha.0
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -23,15 +23,15 @@ function formatUsageMetrics(usage) {
|
|
|
23
23
|
result.totalTokens = inputTokens + outputTokens;
|
|
24
24
|
}
|
|
25
25
|
if (usage?.outputDetails?.reasoning !== void 0) {
|
|
26
|
-
result.
|
|
26
|
+
result.reasoningOutputTokens = usage.outputDetails.reasoning;
|
|
27
27
|
}
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
30
|
-
result.
|
|
28
|
+
const cacheReadTokens = usage?.inputDetails?.cacheRead;
|
|
29
|
+
if (cacheReadTokens !== void 0) {
|
|
30
|
+
result.cacheReadTokens = cacheReadTokens;
|
|
31
31
|
}
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
34
|
-
result.
|
|
32
|
+
const cacheWriteTokens = usage?.inputDetails?.cacheWrite;
|
|
33
|
+
if (cacheWriteTokens !== void 0) {
|
|
34
|
+
result.cacheWriteTokens = cacheWriteTokens;
|
|
35
35
|
}
|
|
36
36
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
37
37
|
}
|
|
@@ -475,14 +475,18 @@ var DatadogExporter = class extends observability.BaseExporter {
|
|
|
475
475
|
const startTime = toDate(span.startTime);
|
|
476
476
|
const endTime = span.endTime ? toDate(span.endTime) : span.isEvent ? startTime : /* @__PURE__ */ new Date();
|
|
477
477
|
return {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
478
|
+
traceOptions: {
|
|
479
|
+
kind,
|
|
480
|
+
name: span.name,
|
|
481
|
+
sessionId: traceCtx.sessionId,
|
|
482
|
+
userId: traceCtx.userId,
|
|
483
|
+
startTime,
|
|
484
|
+
...kind === "llm" && attrs?.model ? { modelName: attrs.model } : {},
|
|
485
|
+
...kind === "llm" && attrs?.provider ? { modelProvider: attrs.provider } : {}
|
|
486
|
+
},
|
|
487
|
+
// endTime as milliseconds for ddSpan.finish() — dd-trace's llmobs.trace() does not
|
|
488
|
+
// honor endTime in options, so we must call finish(ms) explicitly on the span.
|
|
489
|
+
endTimeMs: endTime.getTime()
|
|
486
490
|
};
|
|
487
491
|
}
|
|
488
492
|
/**
|
|
@@ -492,8 +496,8 @@ var DatadogExporter = class extends observability.BaseExporter {
|
|
|
492
496
|
*/
|
|
493
497
|
emitSpanTree(node, state) {
|
|
494
498
|
const span = node.span;
|
|
495
|
-
const
|
|
496
|
-
tracer2__default.default.llmobs.trace(
|
|
499
|
+
const { traceOptions, endTimeMs } = this.buildSpanOptions(span);
|
|
500
|
+
tracer2__default.default.llmobs.trace(traceOptions, (ddSpan) => {
|
|
497
501
|
const annotations = this.buildAnnotations(span);
|
|
498
502
|
if (Object.keys(annotations).length > 0) {
|
|
499
503
|
tracer2__default.default.llmobs.annotate(ddSpan, annotations);
|
|
@@ -506,6 +510,9 @@ var DatadogExporter = class extends observability.BaseExporter {
|
|
|
506
510
|
for (const child of node.children) {
|
|
507
511
|
this.emitSpanTree(child, state);
|
|
508
512
|
}
|
|
513
|
+
if (typeof ddSpan.finish === "function") {
|
|
514
|
+
ddSpan.finish(endTimeMs);
|
|
515
|
+
}
|
|
509
516
|
});
|
|
510
517
|
}
|
|
511
518
|
/**
|
|
@@ -513,8 +520,8 @@ var DatadogExporter = class extends observability.BaseExporter {
|
|
|
513
520
|
* Used for late-arriving spans after the main tree has been emitted.
|
|
514
521
|
*/
|
|
515
522
|
emitSingleSpan(span, state, parent) {
|
|
516
|
-
const
|
|
517
|
-
const runTrace = () => tracer2__default.default.llmobs.trace(
|
|
523
|
+
const { traceOptions, endTimeMs } = this.buildSpanOptions(span);
|
|
524
|
+
const runTrace = () => tracer2__default.default.llmobs.trace(traceOptions, (ddSpan) => {
|
|
518
525
|
const annotations = this.buildAnnotations(span);
|
|
519
526
|
if (Object.keys(annotations).length > 0) {
|
|
520
527
|
tracer2__default.default.llmobs.annotate(ddSpan, annotations);
|
|
@@ -524,6 +531,9 @@ var DatadogExporter = class extends observability.BaseExporter {
|
|
|
524
531
|
}
|
|
525
532
|
const exported = tracer2__default.default.llmobs.exportSpan ? tracer2__default.default.llmobs.exportSpan(ddSpan) : void 0;
|
|
526
533
|
state.contexts.set(span.id, { ddSpan, exported });
|
|
534
|
+
if (typeof ddSpan.finish === "function") {
|
|
535
|
+
ddSpan.finish(endTimeMs);
|
|
536
|
+
}
|
|
527
537
|
});
|
|
528
538
|
if (parent) {
|
|
529
539
|
tracer2__default.default.scope().activate(parent, runTrace);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/metrics.ts","../src/utils.ts","../src/tracing.ts"],"names":["SpanType","tracer","BaseExporter","omitKeys"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\nimport type tracer from 'dd-trace';\n\ntype DatadogAnnotationMetrics = tracer.llmobs.AnnotationOptions['metrics'];\n\nexport function formatUsageMetrics(usage?: UsageStats): DatadogAnnotationMetrics | undefined {\n if (!usage) return undefined;\n\n const result: DatadogAnnotationMetrics = {};\n\n const inputTokens = usage.inputTokens;\n if (inputTokens !== undefined) result.inputTokens = inputTokens;\n\n const outputTokens = usage.outputTokens;\n if (outputTokens !== undefined) result.outputTokens = outputTokens;\n\n if (inputTokens !== undefined && outputTokens !== undefined) {\n result.totalTokens = inputTokens + outputTokens;\n }\n\n if (usage?.outputDetails?.reasoning !== undefined) {\n result.reasoningTokens = usage.outputDetails.reasoning;\n }\n\n const cachedTokens = usage?.inputDetails?.cacheRead;\n if (cachedTokens !== undefined) {\n result.cachedInputTokens = cachedTokens;\n }\n\n const cachedOutputTokens = usage?.inputDetails?.cacheWrite;\n if (cachedOutputTokens !== undefined) {\n result.cachedOutputTokens = cachedOutputTokens;\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n","/**\n * Utility functions for Datadog LLM Observability Exporter\n */\n\nimport { SpanType } from '@mastra/core/observability';\nimport tracer from 'dd-trace';\n\n/**\n * Datadog LLM Observability span kinds.\n */\nexport type DatadogSpanKind = 'llm' | 'agent' | 'workflow' | 'tool' | 'task' | 'retrieval' | 'embedding';\n\n/**\n * Maps Mastra SpanTypes to Datadog LLMObs span kinds.\n * Only non-task mappings are defined; unmapped types fall back to 'task'.\n */\nexport const SPAN_TYPE_TO_KIND: Partial<Record<SpanType, DatadogSpanKind>> = {\n [SpanType.AGENT_RUN]: 'agent',\n [SpanType.MODEL_GENERATION]: 'workflow',\n [SpanType.MODEL_STEP]: 'llm',\n [SpanType.TOOL_CALL]: 'tool',\n [SpanType.MCP_TOOL_CALL]: 'tool',\n [SpanType.WORKFLOW_RUN]: 'workflow',\n};\n\n/**\n * Singleton flag to prevent multiple tracer initializations.\n * dd-trace should only be initialized once per process.\n */\nconst tracerInitFlag = { done: false };\n\n/**\n * Ensures dd-trace is initialized exactly once.\n * Respects any existing tracer initialization by the application.\n */\nexport function ensureTracer(config: {\n mlApp: string;\n site: string;\n apiKey?: string;\n agentless: boolean;\n service?: string;\n env?: string;\n integrationsEnabled?: boolean;\n}): void {\n if (tracerInitFlag.done) return;\n\n // Set environment variables for dd-trace to pick up\n // (LLMObsEnableOptions only accepts mlApp and agentlessEnabled)\n // Always set when config is provided to ensure explicit config takes precedence\n // over any stale env vars that may already be set in the process\n if (config.site) {\n process.env.DD_SITE = config.site;\n }\n if (config.apiKey) {\n process.env.DD_API_KEY = config.apiKey;\n }\n\n // Check if tracer was already started by the application\n const alreadyStarted = (tracer as any)._tracer?.started;\n\n if (!alreadyStarted) {\n tracer.init({\n service: config.service || config.mlApp,\n env: config.env || process.env.DD_ENV,\n // Disable automatic integrations by default to avoid surprise instrumentation\n plugins: config.integrationsEnabled ?? false,\n });\n }\n\n // Enable LLM Observability with the resolved configuration\n tracer.llmobs.enable({\n mlApp: config.mlApp,\n agentlessEnabled: config.agentless,\n });\n\n tracerInitFlag.done = true;\n}\n\n/**\n * Returns the Datadog kind for a Mastra span type.\n */\nexport function kindFor(spanType: SpanType): DatadogSpanKind {\n return SPAN_TYPE_TO_KIND[spanType] || 'task';\n}\n\n/**\n * Converts a value to a Date object.\n */\nexport function toDate(value: Date | string | number): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\n/**\n * Safely stringifies data, handling circular references.\n */\nexport function safeStringify(data: unknown): string {\n try {\n return JSON.stringify(data);\n } catch {\n if (typeof data === 'object' && data !== null) {\n return `[Non-serializable ${data.constructor?.name || 'Object'}]`;\n }\n return String(data);\n }\n}\n\n/**\n * Checks if data is already in message array format ({role, content}[]).\n */\nfunction isMessageArray(data: any): data is Array<{ role: string; content: any }> {\n return Array.isArray(data) && data.every(m => m?.role && m?.content !== undefined);\n}\n\n/**\n * Formats input data for Datadog annotations.\n * LLM spans use message array format; others use raw or stringified data.\n */\nexport function formatInput(input: any, spanType: SpanType): any {\n // LLM spans expect {role, content}[] format\n if (spanType === SpanType.MODEL_GENERATION || spanType === SpanType.MODEL_STEP) {\n // Already in message format\n if (isMessageArray(input)) {\n return input.map(m => ({\n role: m.role,\n content: typeof m.content === 'string' ? m.content : safeStringify(m.content),\n }));\n }\n // String input becomes user message\n if (typeof input === 'string') {\n return [{ role: 'user', content: input }];\n }\n // Object input gets stringified as user message\n return [{ role: 'user', content: safeStringify(input) }];\n }\n\n // Non-LLM spans: pass through strings/arrays, stringify objects\n if (typeof input === 'string' || Array.isArray(input)) return input;\n return safeStringify(input);\n}\n\n/**\n * Formats output data for Datadog annotations.\n * LLM spans use message array format; others use raw or stringified data.\n */\nexport function formatOutput(output: any, spanType: SpanType): any {\n // LLM spans expect {role, content}[] format\n if (spanType === SpanType.MODEL_GENERATION || spanType === SpanType.MODEL_STEP) {\n // Already in message format\n if (isMessageArray(output)) {\n return output.map(m => ({\n role: m.role,\n content: typeof m.content === 'string' ? m.content : safeStringify(m.content),\n }));\n }\n // String output becomes assistant message\n if (typeof output === 'string') {\n return [{ role: 'assistant', content: output }];\n }\n // Object with text property (common AI SDK format)\n if (output?.text) {\n return [{ role: 'assistant', content: output.text }];\n }\n // Other objects get stringified as assistant message\n return [{ role: 'assistant', content: safeStringify(output) }];\n }\n\n // Non-LLM spans: pass through strings, stringify objects\n if (typeof output === 'string') return output;\n return safeStringify(output);\n}\n","/**\n * Datadog LLM Observability Exporter for Mastra\n *\n * Exports Mastra observability data to Datadog's LLM Observability product.\n * Uses a completion-only pattern where spans are emitted on span_ended events.\n *\n * Key features:\n * - Maps Mastra span types to Datadog span kinds\n * - Normalizes AI SDK v4/v5 token usage formats\n * - Formats LLM inputs/outputs as message arrays\n * - Flattens metadata into searchable tags\n * - Supports both agent and agentless modes\n */\n\nimport type {\n TracingEvent,\n AnyExportedSpan,\n ModelGenerationAttributes,\n ModelStepAttributes,\n} from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { BaseExporter } from '@mastra/observability';\nimport type { BaseExporterConfig } from '@mastra/observability';\nimport tracer from 'dd-trace';\nimport { formatUsageMetrics } from './metrics';\nimport { ensureTracer, kindFor, toDate, formatInput, formatOutput } from './utils';\nimport type { DatadogSpanKind } from './utils';\n\n/**\n * LLMObs span options with required name and kind properties.\n */\ninterface LLMObsSpanOptions {\n kind: DatadogSpanKind;\n name: string;\n sessionId?: string;\n userId?: string;\n mlApp?: string;\n modelName?: string;\n modelProvider?: string;\n startTime?: Date;\n endTime?: Date;\n}\n\n/**\n * Minimal per-trace context for user/session tagging.\n */\ninterface TraceContext {\n userId?: string;\n sessionId?: string;\n}\n\ntype TraceState = {\n buffer: Map<string, AnyExportedSpan>;\n contexts: Map<string, { ddSpan: any; exported?: { traceId: string; spanId: string } }>;\n rootEnded: boolean;\n treeEmitted: boolean; // Whether the initial span tree has been emitted\n createdAt: number;\n cleanupTimer?: ReturnType<typeof setTimeout>;\n maxLifetimeTimer?: ReturnType<typeof setTimeout>;\n};\n\n/**\n * Tree node representing a span and its children for recursive emission.\n */\ninterface SpanNode {\n span: AnyExportedSpan;\n children: SpanNode[];\n}\n\n/**\n * Maximum lifetime for a trace state entry (30 minutes).\n * This is a fallback cleanup mechanism for traces that never receive a root span\n * or have all spans marked as non-root, preventing unbounded memory growth.\n */\nconst MAX_TRACE_LIFETIME_MS = 30 * 60 * 1000;\n\n/**\n * Regular cleanup interval for trace state entries (1 minute).\n */\nconst REGULAR_CLEANUP_INTERVAL_MS = 1 * 60 * 1000;\n\n/**\n * Configuration options for the Datadog LLM Observability exporter.\n */\nexport interface DatadogExporterConfig extends BaseExporterConfig {\n /**\n * Datadog API key. Required (agentless mode is the default).\n * Falls back to DD_API_KEY environment variable.\n */\n apiKey?: string;\n\n /**\n * ML application name for grouping traces.\n * Required - falls back to DD_LLMOBS_ML_APP environment variable.\n */\n mlApp?: string;\n\n /**\n * Datadog site (e.g., 'datadoghq.com', 'datadoghq.eu').\n * Falls back to DD_SITE environment variable, defaults to 'datadoghq.com'.\n */\n site?: string;\n\n /**\n * Service name for the application.\n * Falls back to mlApp if not specified.\n */\n service?: string;\n\n /**\n * Environment name (e.g., 'production', 'staging').\n * Falls back to DD_ENV environment variable.\n */\n env?: string;\n\n /**\n * Use agentless mode (direct HTTPS intake without local Datadog Agent).\n * Defaults to true for consistency with other Mastra exporters.\n * Set to false to use a local Datadog Agent instead.\n * Falls back to DD_LLMOBS_AGENTLESS_ENABLED environment variable.\n */\n agentless?: boolean;\n\n /**\n * Enable dd-trace automatic integrations.\n * Defaults to false to avoid unexpected instrumentation.\n */\n integrationsEnabled?: boolean;\n}\n\n/**\n * Datadog LLM Observability Exporter for Mastra.\n *\n * Exports observability data to Datadog's LLM Observability product using\n * a completion-only pattern where spans are emitted on span_ended events.\n */\nexport class DatadogExporter extends BaseExporter {\n name = 'datadog';\n\n private config: Required<Pick<DatadogExporterConfig, 'mlApp' | 'site'>> & DatadogExporterConfig;\n private traceContext = new Map<string, TraceContext>();\n private traceState = new Map<string, TraceState>();\n\n constructor(config: DatadogExporterConfig = {}) {\n super(config);\n\n // Resolve configuration from config object and environment variables\n const mlApp = config.mlApp ?? process.env.DD_LLMOBS_ML_APP;\n const apiKey = config.apiKey ?? process.env.DD_API_KEY;\n const site = config.site ?? process.env.DD_SITE ?? 'datadoghq.com';\n const env = config.env ?? process.env.DD_ENV;\n\n // Default to agentless mode (true) for consistency with other Mastra exporters\n // Only disable if explicitly set to false via config or env var\n const envAgentless = process.env.DD_LLMOBS_AGENTLESS_ENABLED?.toLowerCase();\n const agentless = config.agentless ?? (envAgentless === 'false' || envAgentless === '0' ? false : true);\n\n // Validate required configuration\n if (!mlApp) {\n this.setDisabled(`Missing required mlApp. Set DD_LLMOBS_ML_APP environment variable or pass mlApp in config.`);\n this.config = config as any;\n return;\n }\n\n if (agentless && !apiKey) {\n this.setDisabled(\n `Missing required apiKey for agentless mode. Set DD_API_KEY environment variable or pass apiKey in config.`,\n );\n this.config = config as any;\n return;\n }\n\n this.config = { ...config, mlApp, site, apiKey, agentless, env };\n\n // Initialize tracer and enable LLM Observability\n ensureTracer({\n mlApp,\n site,\n apiKey,\n agentless,\n service: config.service,\n env,\n integrationsEnabled: config.integrationsEnabled,\n });\n\n this.logger.info('Datadog exporter initialized', { mlApp, site, agentless });\n }\n\n /**\n * Main entry point for tracing events from Mastra.\n */\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (this.isDisabled || !(tracer as any).llmobs) return;\n\n try {\n const span = event.exportedSpan;\n\n // Handle event spans (zero-duration spans) - buffer like regular spans for parent-first emission\n if (span.isEvent) {\n if (event.type === 'span_started') {\n this.captureTraceContext(span);\n this.enqueueSpan(span); // Route through buffer for proper parent context\n }\n return; // Skip span_updated and span_ended for events\n }\n\n // Handle regular spans based on event type\n switch (event.type) {\n case 'span_started':\n this.captureTraceContext(span);\n return;\n\n case 'span_updated':\n // No-op: completion-only pattern ignores mid-span updates\n return;\n\n case 'span_ended':\n this.enqueueSpan(span);\n return;\n }\n } catch (error) {\n this.logger.error('Datadog exporter error', {\n error,\n eventType: event.type,\n spanId: event.exportedSpan?.id,\n spanName: event.exportedSpan?.name,\n });\n }\n }\n\n /**\n * Captures user/session context from root spans for tagging all spans in the trace.\n */\n private captureTraceContext(span: AnyExportedSpan): void {\n if (span.isRootSpan && !this.traceContext.has(span.traceId)) {\n this.traceContext.set(span.traceId, {\n userId: span.metadata?.userId,\n sessionId: span.metadata?.sessionId,\n });\n }\n }\n\n /**\n * Queue span until its parent context is available, then emit spans parent-first.\n */\n private enqueueSpan(span: AnyExportedSpan): void {\n const state = this.getOrCreateTraceState(span.traceId);\n if (span.isRootSpan) {\n state.rootEnded = true;\n }\n\n state.buffer.set(span.id, span);\n this.tryEmitReadySpans(span.traceId);\n }\n\n /**\n * Builds annotations object for llmobs.annotate().\n * Uses dd-trace's expected property names: inputData, outputData, metadata, tags, metrics.\n */\n private buildAnnotations(span: AnyExportedSpan): Record<string, any> {\n const annotations: Record<string, any> = {};\n\n // Format and add input (dd-trace expects 'inputData')\n if (span.input !== undefined) {\n annotations.inputData = formatInput(span.input, span.type);\n }\n\n // Format and add output (dd-trace expects 'outputData')\n if (span.output !== undefined) {\n annotations.outputData = formatOutput(span.output, span.type);\n }\n\n // Add token usage metrics (only on MODEL_GENERATION or MODEL_STEP spans)\n if (span.type === SpanType.MODEL_GENERATION || span.type === SpanType.MODEL_STEP) {\n const usage = (span.attributes as ModelGenerationAttributes | ModelStepAttributes)?.usage;\n const metrics = formatUsageMetrics(usage);\n if (metrics) {\n annotations.metrics = metrics;\n }\n }\n\n // Forward span.attributes to metadata (minus known fields handled separately)\n // This ensures tool/workflow spans preserve custom attributes like other exporters\n const knownFields = ['usage', 'model', 'provider', 'parameters'];\n const otherAttributes = omitKeys((span.attributes ?? {}) as Record<string, any>, knownFields);\n\n // Merge span.metadata + remaining attributes into metadata\n const combinedMetadata = {\n ...span.metadata,\n ...otherAttributes,\n };\n if (Object.keys(combinedMetadata).length > 0) {\n annotations.metadata = combinedMetadata;\n }\n\n // Build tags from span.tags (user-provided string[] converted to object) and error info\n // Datadog annotation tags accept Record<string, any>, so we use proper types\n // The native span error status is also set via ddSpan.setTag('error', true) in emitSpan()\n const tags: Record<string, any> = {};\n\n // Convert span.tags (string[]) to object format\n // Tags in \"key:value\" format (e.g. \"instance_name:career-scout-api\") are split into { key: \"value\" }\n // Tags without a colon (e.g. \"production\") are set as { tag: true } (preserving existing behavior)\n if (span.tags?.length) {\n for (const tag of span.tags) {\n const colonIndex = tag.indexOf(':');\n if (colonIndex > 0) {\n tags[tag.substring(0, colonIndex)] = tag.substring(colonIndex + 1);\n } else {\n tags[tag] = true;\n }\n }\n }\n\n // Add error info as consolidated tags\n if (span.errorInfo) {\n tags.error = true;\n tags.errorInfo = {\n message: span.errorInfo.message,\n ...(span.errorInfo.id ? { id: span.errorInfo.id } : {}),\n ...(span.errorInfo.domain ? { domain: span.errorInfo.domain } : {}),\n ...(span.errorInfo.category ? { category: span.errorInfo.category } : {}),\n };\n }\n\n if (Object.keys(tags).length > 0) {\n annotations.tags = tags;\n }\n\n return annotations;\n }\n\n /**\n * Force flush any buffered spans without shutting down the exporter.\n * This is useful in serverless environments where you need to ensure spans\n * are exported before the runtime instance is terminated.\n */\n async flush(): Promise<void> {\n if (this.isDisabled || !(tracer as any).llmobs) return;\n\n // Flush any pending data to Datadog\n if (tracer.llmobs?.flush) {\n try {\n await tracer.llmobs.flush();\n this.logger.debug('Datadog llmobs flushed');\n } catch (e) {\n this.logger.error('Error flushing llmobs', { error: e });\n }\n } else if ((tracer as any).flush) {\n try {\n await (tracer as any).flush();\n this.logger.debug('Datadog tracer flushed');\n } catch (e) {\n this.logger.error('Error flushing tracer', { error: e });\n }\n }\n }\n\n /**\n * Gracefully shuts down the exporter.\n */\n async shutdown(): Promise<void> {\n // Cancel all pending cleanup timers and clear state FIRST\n for (const [traceId, state] of this.traceState) {\n if (state.cleanupTimer) {\n clearTimeout(state.cleanupTimer);\n }\n if (state.maxLifetimeTimer) {\n clearTimeout(state.maxLifetimeTimer);\n }\n if (state.buffer.size > 0) {\n this.logger.warn('Shutdown with pending spans', {\n traceId,\n pendingCount: state.buffer.size,\n spanIds: Array.from(state.buffer.keys()),\n });\n }\n }\n this.traceState.clear();\n\n // Flush any pending data\n await this.flush();\n\n // Disable LLM Observability\n if (tracer.llmobs?.disable) {\n try {\n tracer.llmobs.disable();\n } catch (e) {\n this.logger.error('Error disabling llmobs', { error: e });\n }\n }\n\n // Clear local state\n this.traceContext.clear();\n\n await super.shutdown();\n }\n\n /**\n * Retrieve or initialize trace state for buffering and parent tracking.\n */\n private getOrCreateTraceState(traceId: string): TraceState {\n const existing = this.traceState.get(traceId);\n if (existing) {\n if (existing.cleanupTimer) {\n clearTimeout(existing.cleanupTimer);\n existing.cleanupTimer = undefined;\n }\n return existing;\n }\n\n const created: TraceState = {\n buffer: new Map<string, AnyExportedSpan>(),\n contexts: new Map<string, { ddSpan: any; exported?: { traceId: string; spanId: string } }>(),\n rootEnded: false,\n treeEmitted: false,\n createdAt: Date.now(),\n cleanupTimer: undefined,\n maxLifetimeTimer: undefined,\n };\n\n // Schedule fallback cleanup after max lifetime to prevent memory leaks\n // when traces never receive a root span or all spans are non-root\n const maxLifetimeTimer = setTimeout(() => {\n const state = this.traceState.get(traceId);\n if (state) {\n if (state.buffer.size > 0 || state.contexts.size > 0) {\n this.logger.warn('Discarding trace due to max lifetime exceeded', {\n traceId,\n bufferedSpans: state.buffer.size,\n emittedSpans: state.contexts.size,\n lifetimeMs: Date.now() - state.createdAt,\n });\n }\n if (state.cleanupTimer) {\n clearTimeout(state.cleanupTimer);\n }\n this.traceState.delete(traceId);\n this.traceContext.delete(traceId);\n }\n }, MAX_TRACE_LIFETIME_MS);\n // Prevent the timer from keeping the process alive\n (maxLifetimeTimer as any).unref?.();\n created.maxLifetimeTimer = maxLifetimeTimer;\n\n this.traceState.set(traceId, created);\n return created;\n }\n\n /**\n * Attempt to emit spans from the buffer.\n *\n * Two modes of operation:\n * 1. Initial tree emission: When root span ends and tree hasn't been emitted yet,\n * build a tree from all buffered spans and emit recursively using nested\n * llmobs.trace() calls. This ensures proper parent-child relationships in Datadog.\n * 2. Late-arriving spans: After the tree has been emitted, emit individual spans\n * with their parent context for proper linking.\n */\n private tryEmitReadySpans(traceId: string): void {\n const state = this.traceState.get(traceId);\n if (!state) return;\n\n // If tree hasn't been emitted yet, wait for root and emit as tree\n if (!state.treeEmitted) {\n // Wait until the root span has ended before emitting any spans\n if (!state.rootEnded) return;\n\n // Build tree and emit recursively\n const tree = this.buildSpanTree(state.buffer);\n if (tree) {\n this.emitSpanTree(tree, state);\n }\n\n // Clear the buffer and mark tree as emitted\n state.buffer.clear();\n state.treeEmitted = true;\n } else {\n // Tree already emitted - handle late-arriving spans individually\n // Use the old parent-first emission pattern for these\n let emitted = false;\n do {\n emitted = false;\n for (const [spanId, span] of state.buffer) {\n const parentCtx = span.parentSpanId ? state.contexts.get(span.parentSpanId) : undefined;\n if (span.parentSpanId && !parentCtx) {\n continue;\n }\n\n this.emitSingleSpan(span, state, parentCtx?.ddSpan);\n state.buffer.delete(spanId);\n emitted = true;\n }\n } while (emitted);\n }\n\n // Schedule cleanup if root has ended and buffer is empty\n if (state.rootEnded && state.buffer.size === 0 && !state.cleanupTimer) {\n const timer = setTimeout(() => {\n const currentState = this.traceState.get(traceId);\n if (currentState) {\n if (currentState.buffer.size > 0) {\n this.logger.warn('Discarding orphaned spans during cleanup', {\n traceId,\n orphanedCount: currentState.buffer.size,\n spanIds: Array.from(currentState.buffer.keys()),\n });\n }\n // Clear the max lifetime timer since normal cleanup is handling this\n if (currentState.maxLifetimeTimer) {\n clearTimeout(currentState.maxLifetimeTimer);\n }\n }\n this.traceState.delete(traceId);\n this.traceContext.delete(traceId);\n }, REGULAR_CLEANUP_INTERVAL_MS);\n // Prevent the timer from keeping the process alive\n (timer as any).unref?.();\n state.cleanupTimer = timer;\n }\n }\n\n /**\n * Builds a tree structure from buffered spans based on parentSpanId relationships.\n * Returns the root node of the tree, or undefined if no root span is found.\n */\n private buildSpanTree(buffer: Map<string, AnyExportedSpan>): SpanNode | undefined {\n // Create nodes for all spans\n const nodes = new Map<string, SpanNode>();\n let rootNode: SpanNode | undefined;\n\n for (const span of buffer.values()) {\n nodes.set(span.id, { span, children: [] });\n }\n\n // Build parent-child relationships\n for (const node of nodes.values()) {\n if (node.span.isRootSpan) {\n rootNode = node;\n } else if (node.span.parentSpanId) {\n const parentNode = nodes.get(node.span.parentSpanId);\n if (parentNode) {\n parentNode.children.push(node);\n } else {\n // Orphaned span - parent not in buffer, treat as root-level\n // This shouldn't happen normally but handles edge cases\n this.logger.warn('Orphaned span detected during tree build', {\n spanId: node.span.id,\n parentSpanId: node.span.parentSpanId,\n traceId: node.span.traceId,\n });\n }\n }\n }\n\n // Sort children by start time for consistent ordering\n for (const node of nodes.values()) {\n node.children.sort((a, b) => {\n const aTime =\n a.span.startTime instanceof Date ? a.span.startTime.getTime() : new Date(a.span.startTime).getTime();\n const bTime =\n b.span.startTime instanceof Date ? b.span.startTime.getTime() : new Date(b.span.startTime).getTime();\n return aTime - bTime;\n });\n }\n\n return rootNode;\n }\n\n /**\n * Builds LLMObs span options from a Mastra span.\n * Handles trace context, timestamps, and conditional model information for LLM spans.\n */\n private buildSpanOptions(span: AnyExportedSpan): LLMObsSpanOptions {\n const traceCtx = this.traceContext.get(span.traceId) || {\n userId: span.metadata?.userId,\n sessionId: span.metadata?.sessionId,\n };\n\n const kind = kindFor(span.type);\n const attrs = span.attributes as ModelGenerationAttributes | undefined;\n\n const startTime = toDate(span.startTime);\n // Event spans are point-in-time markers; use startTime for endTime if not set (zero duration)\n // Regular spans fall back to current time if endTime is not set\n const endTime = span.endTime ? toDate(span.endTime) : span.isEvent ? startTime : new Date();\n\n return {\n kind,\n name: span.name,\n sessionId: traceCtx.sessionId,\n userId: traceCtx.userId,\n startTime,\n endTime,\n ...(kind === 'llm' && attrs?.model ? { modelName: attrs.model } : {}),\n ...(kind === 'llm' && attrs?.provider ? { modelProvider: attrs.provider } : {}),\n };\n }\n\n /**\n * Recursively emits a span tree using nested llmobs.trace() calls.\n * This ensures parent-child relationships are properly established in Datadog\n * because child spans are created while their parent span is active in scope.\n */\n private emitSpanTree(node: SpanNode, state: TraceState): void {\n const span = node.span;\n const options = this.buildSpanOptions(span);\n\n // Use nested llmobs.trace() calls - children are emitted INSIDE the parent's callback\n // This ensures the Datadog SDK automatically establishes parent-child relationships\n tracer.llmobs.trace(options as any, (ddSpan: any) => {\n // Annotate this span\n const annotations = this.buildAnnotations(span);\n if (Object.keys(annotations).length > 0) {\n tracer.llmobs.annotate(ddSpan, annotations);\n }\n\n // Set native Datadog error status for proper UI highlighting\n if (span.errorInfo) {\n ddSpan.setTag('error', true);\n }\n\n // Store context for potential evaluation submissions\n const exported = tracer.llmobs.exportSpan ? tracer.llmobs.exportSpan(ddSpan) : undefined;\n state.contexts.set(span.id, { ddSpan, exported });\n\n // Recursively emit children INSIDE this span's callback\n // This is the key to establishing proper parent-child relationships\n for (const child of node.children) {\n this.emitSpanTree(child, state);\n }\n });\n }\n\n /**\n * Emit a single span with the proper Datadog parent context.\n * Used for late-arriving spans after the main tree has been emitted.\n */\n private emitSingleSpan(span: AnyExportedSpan, state: TraceState, parent?: any) {\n const options = this.buildSpanOptions(span);\n\n const runTrace = () =>\n tracer.llmobs.trace(options as any, (ddSpan: any) => {\n const annotations = this.buildAnnotations(span);\n if (Object.keys(annotations).length > 0) {\n tracer.llmobs.annotate(ddSpan, annotations);\n }\n\n // Set native Datadog error status for proper UI highlighting\n if (span.errorInfo) {\n ddSpan.setTag('error', true);\n }\n\n const exported = tracer.llmobs.exportSpan ? tracer.llmobs.exportSpan(ddSpan) : undefined;\n state.contexts.set(span.id, { ddSpan, exported });\n });\n\n if (parent) {\n tracer.scope().activate(parent, runTrace);\n } else {\n runTrace();\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/metrics.ts","../src/utils.ts","../src/tracing.ts"],"names":["SpanType","tracer","BaseExporter","omitKeys"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\nimport type tracer from 'dd-trace';\n\ntype DatadogAnnotationMetrics = tracer.llmobs.AnnotationOptions['metrics'];\n\nexport function formatUsageMetrics(usage?: UsageStats): DatadogAnnotationMetrics | undefined {\n if (!usage) return undefined;\n\n const result: DatadogAnnotationMetrics = {};\n\n const inputTokens = usage.inputTokens;\n if (inputTokens !== undefined) result.inputTokens = inputTokens;\n\n const outputTokens = usage.outputTokens;\n if (outputTokens !== undefined) result.outputTokens = outputTokens;\n\n if (inputTokens !== undefined && outputTokens !== undefined) {\n result.totalTokens = inputTokens + outputTokens;\n }\n\n if (usage?.outputDetails?.reasoning !== undefined) {\n result.reasoningOutputTokens = usage.outputDetails.reasoning;\n }\n\n const cacheReadTokens = usage?.inputDetails?.cacheRead;\n if (cacheReadTokens !== undefined) {\n result.cacheReadTokens = cacheReadTokens;\n }\n\n const cacheWriteTokens = usage?.inputDetails?.cacheWrite;\n if (cacheWriteTokens !== undefined) {\n result.cacheWriteTokens = cacheWriteTokens;\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n","/**\n * Utility functions for Datadog LLM Observability Exporter\n */\n\nimport { SpanType } from '@mastra/core/observability';\nimport tracer from 'dd-trace';\n\n/**\n * Datadog LLM Observability span kinds.\n */\nexport type DatadogSpanKind = 'llm' | 'agent' | 'workflow' | 'tool' | 'task' | 'retrieval' | 'embedding';\n\n/**\n * Maps Mastra SpanTypes to Datadog LLMObs span kinds.\n * Only non-task mappings are defined; unmapped types fall back to 'task'.\n */\nexport const SPAN_TYPE_TO_KIND: Partial<Record<SpanType, DatadogSpanKind>> = {\n [SpanType.AGENT_RUN]: 'agent',\n [SpanType.MODEL_GENERATION]: 'workflow',\n [SpanType.MODEL_STEP]: 'llm',\n [SpanType.TOOL_CALL]: 'tool',\n [SpanType.MCP_TOOL_CALL]: 'tool',\n [SpanType.WORKFLOW_RUN]: 'workflow',\n};\n\n/**\n * Singleton flag to prevent multiple tracer initializations.\n * dd-trace should only be initialized once per process.\n */\nconst tracerInitFlag = { done: false };\n\n/**\n * Ensures dd-trace is initialized exactly once.\n * Respects any existing tracer initialization by the application.\n */\nexport function ensureTracer(config: {\n mlApp: string;\n site: string;\n apiKey?: string;\n agentless: boolean;\n service?: string;\n env?: string;\n integrationsEnabled?: boolean;\n}): void {\n if (tracerInitFlag.done) return;\n\n // Set environment variables for dd-trace to pick up\n // (LLMObsEnableOptions only accepts mlApp and agentlessEnabled)\n // Always set when config is provided to ensure explicit config takes precedence\n // over any stale env vars that may already be set in the process\n if (config.site) {\n process.env.DD_SITE = config.site;\n }\n if (config.apiKey) {\n process.env.DD_API_KEY = config.apiKey;\n }\n\n // Check if tracer was already started by the application\n const alreadyStarted = (tracer as any)._tracer?.started;\n\n if (!alreadyStarted) {\n tracer.init({\n service: config.service || config.mlApp,\n env: config.env || process.env.DD_ENV,\n // Disable automatic integrations by default to avoid surprise instrumentation\n plugins: config.integrationsEnabled ?? false,\n });\n }\n\n // Enable LLM Observability with the resolved configuration\n tracer.llmobs.enable({\n mlApp: config.mlApp,\n agentlessEnabled: config.agentless,\n });\n\n tracerInitFlag.done = true;\n}\n\n/**\n * Returns the Datadog kind for a Mastra span type.\n */\nexport function kindFor(spanType: SpanType): DatadogSpanKind {\n return SPAN_TYPE_TO_KIND[spanType] || 'task';\n}\n\n/**\n * Converts a value to a Date object.\n */\nexport function toDate(value: Date | string | number): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\n/**\n * Safely stringifies data, handling circular references.\n */\nexport function safeStringify(data: unknown): string {\n try {\n return JSON.stringify(data);\n } catch {\n if (typeof data === 'object' && data !== null) {\n return `[Non-serializable ${data.constructor?.name || 'Object'}]`;\n }\n return String(data);\n }\n}\n\n/**\n * Checks if data is already in message array format ({role, content}[]).\n */\nfunction isMessageArray(data: any): data is Array<{ role: string; content: any }> {\n return Array.isArray(data) && data.every(m => m?.role && m?.content !== undefined);\n}\n\n/**\n * Formats input data for Datadog annotations.\n * LLM spans use message array format; others use raw or stringified data.\n */\nexport function formatInput(input: any, spanType: SpanType): any {\n // LLM spans expect {role, content}[] format\n if (spanType === SpanType.MODEL_GENERATION || spanType === SpanType.MODEL_STEP) {\n // Already in message format\n if (isMessageArray(input)) {\n return input.map(m => ({\n role: m.role,\n content: typeof m.content === 'string' ? m.content : safeStringify(m.content),\n }));\n }\n // String input becomes user message\n if (typeof input === 'string') {\n return [{ role: 'user', content: input }];\n }\n // Object input gets stringified as user message\n return [{ role: 'user', content: safeStringify(input) }];\n }\n\n // Non-LLM spans: pass through strings/arrays, stringify objects\n if (typeof input === 'string' || Array.isArray(input)) return input;\n return safeStringify(input);\n}\n\n/**\n * Formats output data for Datadog annotations.\n * LLM spans use message array format; others use raw or stringified data.\n */\nexport function formatOutput(output: any, spanType: SpanType): any {\n // LLM spans expect {role, content}[] format\n if (spanType === SpanType.MODEL_GENERATION || spanType === SpanType.MODEL_STEP) {\n // Already in message format\n if (isMessageArray(output)) {\n return output.map(m => ({\n role: m.role,\n content: typeof m.content === 'string' ? m.content : safeStringify(m.content),\n }));\n }\n // String output becomes assistant message\n if (typeof output === 'string') {\n return [{ role: 'assistant', content: output }];\n }\n // Object with text property (common AI SDK format)\n if (output?.text) {\n return [{ role: 'assistant', content: output.text }];\n }\n // Other objects get stringified as assistant message\n return [{ role: 'assistant', content: safeStringify(output) }];\n }\n\n // Non-LLM spans: pass through strings, stringify objects\n if (typeof output === 'string') return output;\n return safeStringify(output);\n}\n","/**\n * Datadog LLM Observability Exporter for Mastra\n *\n * Exports Mastra observability data to Datadog's LLM Observability product.\n * Uses a completion-only pattern where spans are emitted on span_ended events.\n *\n * Key features:\n * - Maps Mastra span types to Datadog span kinds\n * - Normalizes AI SDK v4/v5 token usage formats\n * - Formats LLM inputs/outputs as message arrays\n * - Flattens metadata into searchable tags\n * - Supports both agent and agentless modes\n */\n\nimport type {\n TracingEvent,\n AnyExportedSpan,\n ModelGenerationAttributes,\n ModelStepAttributes,\n} from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { BaseExporter } from '@mastra/observability';\nimport type { BaseExporterConfig } from '@mastra/observability';\nimport tracer from 'dd-trace';\nimport { formatUsageMetrics } from './metrics';\nimport { ensureTracer, kindFor, toDate, formatInput, formatOutput } from './utils';\nimport type { DatadogSpanKind } from './utils';\n\n/**\n * LLMObs span options passed to dd-trace's llmobs.trace().\n * Note: endTime is not included because dd-trace does not honor it in trace options.\n * Instead, we call ddSpan.finish(endTimeMs) explicitly inside the trace callback.\n */\ninterface LLMObsSpanOptions {\n kind: DatadogSpanKind;\n name: string;\n sessionId?: string;\n userId?: string;\n mlApp?: string;\n modelName?: string;\n modelProvider?: string;\n startTime?: Date;\n}\n\n/**\n * Minimal per-trace context for user/session tagging.\n */\ninterface TraceContext {\n userId?: string;\n sessionId?: string;\n}\n\ntype TraceState = {\n buffer: Map<string, AnyExportedSpan>;\n contexts: Map<string, { ddSpan: any; exported?: { traceId: string; spanId: string } }>;\n rootEnded: boolean;\n treeEmitted: boolean; // Whether the initial span tree has been emitted\n createdAt: number;\n cleanupTimer?: ReturnType<typeof setTimeout>;\n maxLifetimeTimer?: ReturnType<typeof setTimeout>;\n};\n\n/**\n * Tree node representing a span and its children for recursive emission.\n */\ninterface SpanNode {\n span: AnyExportedSpan;\n children: SpanNode[];\n}\n\n/**\n * Maximum lifetime for a trace state entry (30 minutes).\n * This is a fallback cleanup mechanism for traces that never receive a root span\n * or have all spans marked as non-root, preventing unbounded memory growth.\n */\nconst MAX_TRACE_LIFETIME_MS = 30 * 60 * 1000;\n\n/**\n * Regular cleanup interval for trace state entries (1 minute).\n */\nconst REGULAR_CLEANUP_INTERVAL_MS = 1 * 60 * 1000;\n\n/**\n * Configuration options for the Datadog LLM Observability exporter.\n */\nexport interface DatadogExporterConfig extends BaseExporterConfig {\n /**\n * Datadog API key. Required (agentless mode is the default).\n * Falls back to DD_API_KEY environment variable.\n */\n apiKey?: string;\n\n /**\n * ML application name for grouping traces.\n * Required - falls back to DD_LLMOBS_ML_APP environment variable.\n */\n mlApp?: string;\n\n /**\n * Datadog site (e.g., 'datadoghq.com', 'datadoghq.eu').\n * Falls back to DD_SITE environment variable, defaults to 'datadoghq.com'.\n */\n site?: string;\n\n /**\n * Service name for the application.\n * Falls back to mlApp if not specified.\n */\n service?: string;\n\n /**\n * Environment name (e.g., 'production', 'staging').\n * Falls back to DD_ENV environment variable.\n */\n env?: string;\n\n /**\n * Use agentless mode (direct HTTPS intake without local Datadog Agent).\n * Defaults to true for consistency with other Mastra exporters.\n * Set to false to use a local Datadog Agent instead.\n * Falls back to DD_LLMOBS_AGENTLESS_ENABLED environment variable.\n */\n agentless?: boolean;\n\n /**\n * Enable dd-trace automatic integrations.\n * Defaults to false to avoid unexpected instrumentation.\n */\n integrationsEnabled?: boolean;\n}\n\n/**\n * Datadog LLM Observability Exporter for Mastra.\n *\n * Exports observability data to Datadog's LLM Observability product using\n * a completion-only pattern where spans are emitted on span_ended events.\n */\nexport class DatadogExporter extends BaseExporter {\n name = 'datadog';\n\n private config: Required<Pick<DatadogExporterConfig, 'mlApp' | 'site'>> & DatadogExporterConfig;\n private traceContext = new Map<string, TraceContext>();\n private traceState = new Map<string, TraceState>();\n\n constructor(config: DatadogExporterConfig = {}) {\n super(config);\n\n // Resolve configuration from config object and environment variables\n const mlApp = config.mlApp ?? process.env.DD_LLMOBS_ML_APP;\n const apiKey = config.apiKey ?? process.env.DD_API_KEY;\n const site = config.site ?? process.env.DD_SITE ?? 'datadoghq.com';\n const env = config.env ?? process.env.DD_ENV;\n\n // Default to agentless mode (true) for consistency with other Mastra exporters\n // Only disable if explicitly set to false via config or env var\n const envAgentless = process.env.DD_LLMOBS_AGENTLESS_ENABLED?.toLowerCase();\n const agentless = config.agentless ?? (envAgentless === 'false' || envAgentless === '0' ? false : true);\n\n // Validate required configuration\n if (!mlApp) {\n this.setDisabled(`Missing required mlApp. Set DD_LLMOBS_ML_APP environment variable or pass mlApp in config.`);\n this.config = config as any;\n return;\n }\n\n if (agentless && !apiKey) {\n this.setDisabled(\n `Missing required apiKey for agentless mode. Set DD_API_KEY environment variable or pass apiKey in config.`,\n );\n this.config = config as any;\n return;\n }\n\n this.config = { ...config, mlApp, site, apiKey, agentless, env };\n\n // Initialize tracer and enable LLM Observability\n ensureTracer({\n mlApp,\n site,\n apiKey,\n agentless,\n service: config.service,\n env,\n integrationsEnabled: config.integrationsEnabled,\n });\n\n this.logger.info('Datadog exporter initialized', { mlApp, site, agentless });\n }\n\n /**\n * Main entry point for tracing events from Mastra.\n */\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (this.isDisabled || !(tracer as any).llmobs) return;\n\n try {\n const span = event.exportedSpan;\n\n // Handle event spans (zero-duration spans) - buffer like regular spans for parent-first emission\n if (span.isEvent) {\n if (event.type === 'span_started') {\n this.captureTraceContext(span);\n this.enqueueSpan(span); // Route through buffer for proper parent context\n }\n return; // Skip span_updated and span_ended for events\n }\n\n // Handle regular spans based on event type\n switch (event.type) {\n case 'span_started':\n this.captureTraceContext(span);\n return;\n\n case 'span_updated':\n // No-op: completion-only pattern ignores mid-span updates\n return;\n\n case 'span_ended':\n this.enqueueSpan(span);\n return;\n }\n } catch (error) {\n this.logger.error('Datadog exporter error', {\n error,\n eventType: event.type,\n spanId: event.exportedSpan?.id,\n spanName: event.exportedSpan?.name,\n });\n }\n }\n\n /**\n * Captures user/session context from root spans for tagging all spans in the trace.\n */\n private captureTraceContext(span: AnyExportedSpan): void {\n if (span.isRootSpan && !this.traceContext.has(span.traceId)) {\n this.traceContext.set(span.traceId, {\n userId: span.metadata?.userId,\n sessionId: span.metadata?.sessionId,\n });\n }\n }\n\n /**\n * Queue span until its parent context is available, then emit spans parent-first.\n */\n private enqueueSpan(span: AnyExportedSpan): void {\n const state = this.getOrCreateTraceState(span.traceId);\n if (span.isRootSpan) {\n state.rootEnded = true;\n }\n\n state.buffer.set(span.id, span);\n this.tryEmitReadySpans(span.traceId);\n }\n\n /**\n * Builds annotations object for llmobs.annotate().\n * Uses dd-trace's expected property names: inputData, outputData, metadata, tags, metrics.\n */\n private buildAnnotations(span: AnyExportedSpan): Record<string, any> {\n const annotations: Record<string, any> = {};\n\n // Format and add input (dd-trace expects 'inputData')\n if (span.input !== undefined) {\n annotations.inputData = formatInput(span.input, span.type);\n }\n\n // Format and add output (dd-trace expects 'outputData')\n if (span.output !== undefined) {\n annotations.outputData = formatOutput(span.output, span.type);\n }\n\n // Add token usage metrics (only on MODEL_GENERATION or MODEL_STEP spans)\n if (span.type === SpanType.MODEL_GENERATION || span.type === SpanType.MODEL_STEP) {\n const usage = (span.attributes as ModelGenerationAttributes | ModelStepAttributes)?.usage;\n const metrics = formatUsageMetrics(usage);\n if (metrics) {\n annotations.metrics = metrics;\n }\n }\n\n // Forward span.attributes to metadata (minus known fields handled separately)\n // This ensures tool/workflow spans preserve custom attributes like other exporters\n const knownFields = ['usage', 'model', 'provider', 'parameters'];\n const otherAttributes = omitKeys((span.attributes ?? {}) as Record<string, any>, knownFields);\n\n // Merge span.metadata + remaining attributes into metadata\n const combinedMetadata = {\n ...span.metadata,\n ...otherAttributes,\n };\n if (Object.keys(combinedMetadata).length > 0) {\n annotations.metadata = combinedMetadata;\n }\n\n // Build tags from span.tags (user-provided string[] converted to object) and error info\n // Datadog annotation tags accept Record<string, any>, so we use proper types\n // The native span error status is also set via ddSpan.setTag('error', true) in emitSpan()\n const tags: Record<string, any> = {};\n\n // Convert span.tags (string[]) to object format\n // Tags in \"key:value\" format (e.g. \"instance_name:career-scout-api\") are split into { key: \"value\" }\n // Tags without a colon (e.g. \"production\") are set as { tag: true } (preserving existing behavior)\n if (span.tags?.length) {\n for (const tag of span.tags) {\n const colonIndex = tag.indexOf(':');\n if (colonIndex > 0) {\n tags[tag.substring(0, colonIndex)] = tag.substring(colonIndex + 1);\n } else {\n tags[tag] = true;\n }\n }\n }\n\n // Add error info as consolidated tags\n if (span.errorInfo) {\n tags.error = true;\n tags.errorInfo = {\n message: span.errorInfo.message,\n ...(span.errorInfo.id ? { id: span.errorInfo.id } : {}),\n ...(span.errorInfo.domain ? { domain: span.errorInfo.domain } : {}),\n ...(span.errorInfo.category ? { category: span.errorInfo.category } : {}),\n };\n }\n\n if (Object.keys(tags).length > 0) {\n annotations.tags = tags;\n }\n\n return annotations;\n }\n\n /**\n * Force flush any buffered spans without shutting down the exporter.\n * This is useful in serverless environments where you need to ensure spans\n * are exported before the runtime instance is terminated.\n */\n async flush(): Promise<void> {\n if (this.isDisabled || !(tracer as any).llmobs) return;\n\n // Flush any pending data to Datadog\n if (tracer.llmobs?.flush) {\n try {\n await tracer.llmobs.flush();\n this.logger.debug('Datadog llmobs flushed');\n } catch (e) {\n this.logger.error('Error flushing llmobs', { error: e });\n }\n } else if ((tracer as any).flush) {\n try {\n await (tracer as any).flush();\n this.logger.debug('Datadog tracer flushed');\n } catch (e) {\n this.logger.error('Error flushing tracer', { error: e });\n }\n }\n }\n\n /**\n * Gracefully shuts down the exporter.\n */\n async shutdown(): Promise<void> {\n // Cancel all pending cleanup timers and clear state FIRST\n for (const [traceId, state] of this.traceState) {\n if (state.cleanupTimer) {\n clearTimeout(state.cleanupTimer);\n }\n if (state.maxLifetimeTimer) {\n clearTimeout(state.maxLifetimeTimer);\n }\n if (state.buffer.size > 0) {\n this.logger.warn('Shutdown with pending spans', {\n traceId,\n pendingCount: state.buffer.size,\n spanIds: Array.from(state.buffer.keys()),\n });\n }\n }\n this.traceState.clear();\n\n // Flush any pending data\n await this.flush();\n\n // Disable LLM Observability\n if (tracer.llmobs?.disable) {\n try {\n tracer.llmobs.disable();\n } catch (e) {\n this.logger.error('Error disabling llmobs', { error: e });\n }\n }\n\n // Clear local state\n this.traceContext.clear();\n\n await super.shutdown();\n }\n\n /**\n * Retrieve or initialize trace state for buffering and parent tracking.\n */\n private getOrCreateTraceState(traceId: string): TraceState {\n const existing = this.traceState.get(traceId);\n if (existing) {\n if (existing.cleanupTimer) {\n clearTimeout(existing.cleanupTimer);\n existing.cleanupTimer = undefined;\n }\n return existing;\n }\n\n const created: TraceState = {\n buffer: new Map<string, AnyExportedSpan>(),\n contexts: new Map<string, { ddSpan: any; exported?: { traceId: string; spanId: string } }>(),\n rootEnded: false,\n treeEmitted: false,\n createdAt: Date.now(),\n cleanupTimer: undefined,\n maxLifetimeTimer: undefined,\n };\n\n // Schedule fallback cleanup after max lifetime to prevent memory leaks\n // when traces never receive a root span or all spans are non-root\n const maxLifetimeTimer = setTimeout(() => {\n const state = this.traceState.get(traceId);\n if (state) {\n if (state.buffer.size > 0 || state.contexts.size > 0) {\n this.logger.warn('Discarding trace due to max lifetime exceeded', {\n traceId,\n bufferedSpans: state.buffer.size,\n emittedSpans: state.contexts.size,\n lifetimeMs: Date.now() - state.createdAt,\n });\n }\n if (state.cleanupTimer) {\n clearTimeout(state.cleanupTimer);\n }\n this.traceState.delete(traceId);\n this.traceContext.delete(traceId);\n }\n }, MAX_TRACE_LIFETIME_MS);\n // Prevent the timer from keeping the process alive\n (maxLifetimeTimer as any).unref?.();\n created.maxLifetimeTimer = maxLifetimeTimer;\n\n this.traceState.set(traceId, created);\n return created;\n }\n\n /**\n * Attempt to emit spans from the buffer.\n *\n * Two modes of operation:\n * 1. Initial tree emission: When root span ends and tree hasn't been emitted yet,\n * build a tree from all buffered spans and emit recursively using nested\n * llmobs.trace() calls. This ensures proper parent-child relationships in Datadog.\n * 2. Late-arriving spans: After the tree has been emitted, emit individual spans\n * with their parent context for proper linking.\n */\n private tryEmitReadySpans(traceId: string): void {\n const state = this.traceState.get(traceId);\n if (!state) return;\n\n // If tree hasn't been emitted yet, wait for root and emit as tree\n if (!state.treeEmitted) {\n // Wait until the root span has ended before emitting any spans\n if (!state.rootEnded) return;\n\n // Build tree and emit recursively\n const tree = this.buildSpanTree(state.buffer);\n if (tree) {\n this.emitSpanTree(tree, state);\n }\n\n // Clear the buffer and mark tree as emitted\n state.buffer.clear();\n state.treeEmitted = true;\n } else {\n // Tree already emitted - handle late-arriving spans individually\n // Use the old parent-first emission pattern for these\n let emitted = false;\n do {\n emitted = false;\n for (const [spanId, span] of state.buffer) {\n const parentCtx = span.parentSpanId ? state.contexts.get(span.parentSpanId) : undefined;\n if (span.parentSpanId && !parentCtx) {\n continue;\n }\n\n this.emitSingleSpan(span, state, parentCtx?.ddSpan);\n state.buffer.delete(spanId);\n emitted = true;\n }\n } while (emitted);\n }\n\n // Schedule cleanup if root has ended and buffer is empty\n if (state.rootEnded && state.buffer.size === 0 && !state.cleanupTimer) {\n const timer = setTimeout(() => {\n const currentState = this.traceState.get(traceId);\n if (currentState) {\n if (currentState.buffer.size > 0) {\n this.logger.warn('Discarding orphaned spans during cleanup', {\n traceId,\n orphanedCount: currentState.buffer.size,\n spanIds: Array.from(currentState.buffer.keys()),\n });\n }\n // Clear the max lifetime timer since normal cleanup is handling this\n if (currentState.maxLifetimeTimer) {\n clearTimeout(currentState.maxLifetimeTimer);\n }\n }\n this.traceState.delete(traceId);\n this.traceContext.delete(traceId);\n }, REGULAR_CLEANUP_INTERVAL_MS);\n // Prevent the timer from keeping the process alive\n (timer as any).unref?.();\n state.cleanupTimer = timer;\n }\n }\n\n /**\n * Builds a tree structure from buffered spans based on parentSpanId relationships.\n * Returns the root node of the tree, or undefined if no root span is found.\n */\n private buildSpanTree(buffer: Map<string, AnyExportedSpan>): SpanNode | undefined {\n // Create nodes for all spans\n const nodes = new Map<string, SpanNode>();\n let rootNode: SpanNode | undefined;\n\n for (const span of buffer.values()) {\n nodes.set(span.id, { span, children: [] });\n }\n\n // Build parent-child relationships\n for (const node of nodes.values()) {\n if (node.span.isRootSpan) {\n rootNode = node;\n } else if (node.span.parentSpanId) {\n const parentNode = nodes.get(node.span.parentSpanId);\n if (parentNode) {\n parentNode.children.push(node);\n } else {\n // Orphaned span - parent not in buffer, treat as root-level\n // This shouldn't happen normally but handles edge cases\n this.logger.warn('Orphaned span detected during tree build', {\n spanId: node.span.id,\n parentSpanId: node.span.parentSpanId,\n traceId: node.span.traceId,\n });\n }\n }\n }\n\n // Sort children by start time for consistent ordering\n for (const node of nodes.values()) {\n node.children.sort((a, b) => {\n const aTime =\n a.span.startTime instanceof Date ? a.span.startTime.getTime() : new Date(a.span.startTime).getTime();\n const bTime =\n b.span.startTime instanceof Date ? b.span.startTime.getTime() : new Date(b.span.startTime).getTime();\n return aTime - bTime;\n });\n }\n\n return rootNode;\n }\n\n /**\n * Builds LLMObs span options from a Mastra span.\n * Handles trace context, timestamps, and conditional model information for LLM spans.\n */\n private buildSpanOptions(span: AnyExportedSpan): { traceOptions: LLMObsSpanOptions; endTimeMs: number } {\n const traceCtx = this.traceContext.get(span.traceId) || {\n userId: span.metadata?.userId,\n sessionId: span.metadata?.sessionId,\n };\n\n const kind = kindFor(span.type);\n const attrs = span.attributes as ModelGenerationAttributes | undefined;\n\n const startTime = toDate(span.startTime);\n // Event spans are point-in-time markers; use startTime for endTime if not set (zero duration)\n // Regular spans fall back to current time if endTime is not set\n const endTime = span.endTime ? toDate(span.endTime) : span.isEvent ? startTime : new Date();\n\n return {\n traceOptions: {\n kind,\n name: span.name,\n sessionId: traceCtx.sessionId,\n userId: traceCtx.userId,\n startTime,\n ...(kind === 'llm' && attrs?.model ? { modelName: attrs.model } : {}),\n ...(kind === 'llm' && attrs?.provider ? { modelProvider: attrs.provider } : {}),\n },\n // endTime as milliseconds for ddSpan.finish() — dd-trace's llmobs.trace() does not\n // honor endTime in options, so we must call finish(ms) explicitly on the span.\n endTimeMs: endTime.getTime(),\n };\n }\n\n /**\n * Recursively emits a span tree using nested llmobs.trace() calls.\n * This ensures parent-child relationships are properly established in Datadog\n * because child spans are created while their parent span is active in scope.\n */\n private emitSpanTree(node: SpanNode, state: TraceState): void {\n const span = node.span;\n const { traceOptions, endTimeMs } = this.buildSpanOptions(span);\n\n // Use nested llmobs.trace() calls - children are emitted INSIDE the parent's callback\n // This ensures the Datadog SDK automatically establishes parent-child relationships\n tracer.llmobs.trace(traceOptions as any, (ddSpan: any) => {\n // Annotate this span (must happen before finish — annotate throws on finished spans)\n const annotations = this.buildAnnotations(span);\n if (Object.keys(annotations).length > 0) {\n tracer.llmobs.annotate(ddSpan, annotations);\n }\n\n // Set native Datadog error status for proper UI highlighting\n if (span.errorInfo) {\n ddSpan.setTag('error', true);\n }\n\n // Store context for potential evaluation submissions\n const exported = tracer.llmobs.exportSpan ? tracer.llmobs.exportSpan(ddSpan) : undefined;\n state.contexts.set(span.id, { ddSpan, exported });\n\n // Recursively emit children INSIDE this span's callback\n // This is the key to establishing proper parent-child relationships\n for (const child of node.children) {\n this.emitSpanTree(child, state);\n }\n\n // Explicitly finish with the correct end time. dd-trace's llmobs.trace() does not\n // honor endTime in span options — it auto-finishes with Date.now() when the callback\n // returns. By calling finish() here first, the auto-finish becomes a no-op (dd-trace\n // skips finish if _duration is already set).\n if (typeof ddSpan.finish === 'function') {\n ddSpan.finish(endTimeMs);\n }\n });\n }\n\n /**\n * Emit a single span with the proper Datadog parent context.\n * Used for late-arriving spans after the main tree has been emitted.\n */\n private emitSingleSpan(span: AnyExportedSpan, state: TraceState, parent?: any) {\n const { traceOptions, endTimeMs } = this.buildSpanOptions(span);\n\n const runTrace = () =>\n tracer.llmobs.trace(traceOptions as any, (ddSpan: any) => {\n const annotations = this.buildAnnotations(span);\n if (Object.keys(annotations).length > 0) {\n tracer.llmobs.annotate(ddSpan, annotations);\n }\n\n // Set native Datadog error status for proper UI highlighting\n if (span.errorInfo) {\n ddSpan.setTag('error', true);\n }\n\n const exported = tracer.llmobs.exportSpan ? tracer.llmobs.exportSpan(ddSpan) : undefined;\n state.contexts.set(span.id, { ddSpan, exported });\n\n // Explicitly finish with the correct end time (see emitSpanTree for details)\n if (typeof ddSpan.finish === 'function') {\n ddSpan.finish(endTimeMs);\n }\n });\n\n if (parent) {\n tracer.scope().activate(parent, runTrace);\n } else {\n runTrace();\n }\n }\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -17,15 +17,15 @@ function formatUsageMetrics(usage) {
|
|
|
17
17
|
result.totalTokens = inputTokens + outputTokens;
|
|
18
18
|
}
|
|
19
19
|
if (usage?.outputDetails?.reasoning !== void 0) {
|
|
20
|
-
result.
|
|
20
|
+
result.reasoningOutputTokens = usage.outputDetails.reasoning;
|
|
21
21
|
}
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
24
|
-
result.
|
|
22
|
+
const cacheReadTokens = usage?.inputDetails?.cacheRead;
|
|
23
|
+
if (cacheReadTokens !== void 0) {
|
|
24
|
+
result.cacheReadTokens = cacheReadTokens;
|
|
25
25
|
}
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
28
|
-
result.
|
|
26
|
+
const cacheWriteTokens = usage?.inputDetails?.cacheWrite;
|
|
27
|
+
if (cacheWriteTokens !== void 0) {
|
|
28
|
+
result.cacheWriteTokens = cacheWriteTokens;
|
|
29
29
|
}
|
|
30
30
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
31
31
|
}
|
|
@@ -469,14 +469,18 @@ var DatadogExporter = class extends BaseExporter {
|
|
|
469
469
|
const startTime = toDate(span.startTime);
|
|
470
470
|
const endTime = span.endTime ? toDate(span.endTime) : span.isEvent ? startTime : /* @__PURE__ */ new Date();
|
|
471
471
|
return {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
472
|
+
traceOptions: {
|
|
473
|
+
kind,
|
|
474
|
+
name: span.name,
|
|
475
|
+
sessionId: traceCtx.sessionId,
|
|
476
|
+
userId: traceCtx.userId,
|
|
477
|
+
startTime,
|
|
478
|
+
...kind === "llm" && attrs?.model ? { modelName: attrs.model } : {},
|
|
479
|
+
...kind === "llm" && attrs?.provider ? { modelProvider: attrs.provider } : {}
|
|
480
|
+
},
|
|
481
|
+
// endTime as milliseconds for ddSpan.finish() — dd-trace's llmobs.trace() does not
|
|
482
|
+
// honor endTime in options, so we must call finish(ms) explicitly on the span.
|
|
483
|
+
endTimeMs: endTime.getTime()
|
|
480
484
|
};
|
|
481
485
|
}
|
|
482
486
|
/**
|
|
@@ -486,8 +490,8 @@ var DatadogExporter = class extends BaseExporter {
|
|
|
486
490
|
*/
|
|
487
491
|
emitSpanTree(node, state) {
|
|
488
492
|
const span = node.span;
|
|
489
|
-
const
|
|
490
|
-
tracer2.llmobs.trace(
|
|
493
|
+
const { traceOptions, endTimeMs } = this.buildSpanOptions(span);
|
|
494
|
+
tracer2.llmobs.trace(traceOptions, (ddSpan) => {
|
|
491
495
|
const annotations = this.buildAnnotations(span);
|
|
492
496
|
if (Object.keys(annotations).length > 0) {
|
|
493
497
|
tracer2.llmobs.annotate(ddSpan, annotations);
|
|
@@ -500,6 +504,9 @@ var DatadogExporter = class extends BaseExporter {
|
|
|
500
504
|
for (const child of node.children) {
|
|
501
505
|
this.emitSpanTree(child, state);
|
|
502
506
|
}
|
|
507
|
+
if (typeof ddSpan.finish === "function") {
|
|
508
|
+
ddSpan.finish(endTimeMs);
|
|
509
|
+
}
|
|
503
510
|
});
|
|
504
511
|
}
|
|
505
512
|
/**
|
|
@@ -507,8 +514,8 @@ var DatadogExporter = class extends BaseExporter {
|
|
|
507
514
|
* Used for late-arriving spans after the main tree has been emitted.
|
|
508
515
|
*/
|
|
509
516
|
emitSingleSpan(span, state, parent) {
|
|
510
|
-
const
|
|
511
|
-
const runTrace = () => tracer2.llmobs.trace(
|
|
517
|
+
const { traceOptions, endTimeMs } = this.buildSpanOptions(span);
|
|
518
|
+
const runTrace = () => tracer2.llmobs.trace(traceOptions, (ddSpan) => {
|
|
512
519
|
const annotations = this.buildAnnotations(span);
|
|
513
520
|
if (Object.keys(annotations).length > 0) {
|
|
514
521
|
tracer2.llmobs.annotate(ddSpan, annotations);
|
|
@@ -518,6 +525,9 @@ var DatadogExporter = class extends BaseExporter {
|
|
|
518
525
|
}
|
|
519
526
|
const exported = tracer2.llmobs.exportSpan ? tracer2.llmobs.exportSpan(ddSpan) : void 0;
|
|
520
527
|
state.contexts.set(span.id, { ddSpan, exported });
|
|
528
|
+
if (typeof ddSpan.finish === "function") {
|
|
529
|
+
ddSpan.finish(endTimeMs);
|
|
530
|
+
}
|
|
521
531
|
});
|
|
522
532
|
if (parent) {
|
|
523
533
|
tracer2.scope().activate(parent, runTrace);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/metrics.ts","../src/utils.ts","../src/tracing.ts"],"names":["tracer","SpanType"],"mappings":";;;;;;;;AAKO,SAAS,mBAAmB,KAAA,EAA0D;AAC3F,EAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAEnB,EAAA,MAAM,SAAmC,EAAC;AAE1C,EAAA,MAAM,cAAc,KAAA,CAAM,WAAA;AAC1B,EAAA,IAAI,WAAA,KAAgB,MAAA,EAAW,MAAA,CAAO,WAAA,GAAc,WAAA;AAEpD,EAAA,MAAM,eAAe,KAAA,CAAM,YAAA;AAC3B,EAAA,IAAI,YAAA,KAAiB,MAAA,EAAW,MAAA,CAAO,YAAA,GAAe,YAAA;AAEtD,EAAA,IAAI,WAAA,KAAgB,MAAA,IAAa,YAAA,KAAiB,MAAA,EAAW;AAC3D,IAAA,MAAA,CAAO,cAAc,WAAA,GAAc,YAAA;AAAA,EACrC;AAEA,EAAA,IAAI,KAAA,EAAO,aAAA,EAAe,SAAA,KAAc,MAAA,EAAW;AACjD,IAAA,MAAA,CAAO,eAAA,GAAkB,MAAM,aAAA,CAAc,SAAA;AAAA,EAC/C;AAEA,EAAA,MAAM,YAAA,GAAe,OAAO,YAAA,EAAc,SAAA;AAC1C,EAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,IAAA,MAAA,CAAO,iBAAA,GAAoB,YAAA;AAAA,EAC7B;AAEA,EAAA,MAAM,kBAAA,GAAqB,OAAO,YAAA,EAAc,UAAA;AAChD,EAAA,IAAI,uBAAuB,MAAA,EAAW;AACpC,IAAA,MAAA,CAAO,kBAAA,GAAqB,kBAAA;AAAA,EAC9B;AAEA,EAAA,OAAO,OAAO,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,GAAS,IAAI,MAAA,GAAS,MAAA;AACnD;ACnBO,IAAM,iBAAA,GAAgE;AAAA,EAC3E,CAAC,QAAA,CAAS,SAAS,GAAG,OAAA;AAAA,EACtB,CAAC,QAAA,CAAS,gBAAgB,GAAG,UAAA;AAAA,EAC7B,CAAC,QAAA,CAAS,UAAU,GAAG,KAAA;AAAA,EACvB,CAAC,QAAA,CAAS,SAAS,GAAG,MAAA;AAAA,EACtB,CAAC,QAAA,CAAS,aAAa,GAAG,MAAA;AAAA,EAC1B,CAAC,QAAA,CAAS,YAAY,GAAG;AAC3B,CAAA;AAMA,IAAM,cAAA,GAAiB,EAAE,IAAA,EAAM,KAAA,EAAM;AAM9B,SAAS,aAAa,MAAA,EAQpB;AACP,EAAA,IAAI,eAAe,IAAA,EAAM;AAMzB,EAAA,IAAI,OAAO,IAAA,EAAM;AACf,IAAA,OAAA,CAAQ,GAAA,CAAI,UAAU,MAAA,CAAO,IAAA;AAAA,EAC/B;AACA,EAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,IAAA,OAAA,CAAQ,GAAA,CAAI,aAAa,MAAA,CAAO,MAAA;AAAA,EAClC;AAGA,EAAA,MAAM,cAAA,GAAkBA,QAAe,OAAA,EAAS,OAAA;AAEhD,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAAA,OAAA,CAAO,IAAA,CAAK;AAAA,MACV,OAAA,EAAS,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,KAAA;AAAA,MAClC,GAAA,EAAK,MAAA,CAAO,GAAA,IAAO,OAAA,CAAQ,GAAA,CAAI,MAAA;AAAA;AAAA,MAE/B,OAAA,EAAS,OAAO,mBAAA,IAAuB;AAAA,KACxC,CAAA;AAAA,EACH;AAGA,EAAAA,OAAA,CAAO,OAAO,MAAA,CAAO;AAAA,IACnB,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,kBAAkB,MAAA,CAAO;AAAA,GAC1B,CAAA;AAED,EAAA,cAAA,CAAe,IAAA,GAAO,IAAA;AACxB;AAKO,SAAS,QAAQ,QAAA,EAAqC;AAC3D,EAAA,OAAO,iBAAA,CAAkB,QAAQ,CAAA,IAAK,MAAA;AACxC;AAKO,SAAS,OAAO,KAAA,EAAqC;AAC1D,EAAA,OAAO,KAAA,YAAiB,IAAA,GAAO,KAAA,GAAQ,IAAI,KAAK,KAAK,CAAA;AACvD;AAKO,SAAS,cAAc,IAAA,EAAuB;AACnD,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,EAC5B,CAAA,CAAA,MAAQ;AACN,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,IAAA,EAAM;AAC7C,MAAA,OAAO,CAAA,kBAAA,EAAqB,IAAA,CAAK,WAAA,EAAa,IAAA,IAAQ,QAAQ,CAAA,CAAA,CAAA;AAAA,IAChE;AACA,IAAA,OAAO,OAAO,IAAI,CAAA;AAAA,EACpB;AACF;AAKA,SAAS,eAAe,IAAA,EAA0D;AAChF,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,IAAK,IAAA,CAAK,KAAA,CAAM,CAAA,CAAA,KAAK,CAAA,EAAG,IAAA,IAAQ,CAAA,EAAG,OAAA,KAAY,MAAS,CAAA;AACnF;AAMO,SAAS,WAAA,CAAY,OAAY,QAAA,EAAyB;AAE/D,EAAA,IAAI,QAAA,KAAa,QAAA,CAAS,gBAAA,IAAoB,QAAA,KAAa,SAAS,UAAA,EAAY;AAE9E,IAAA,IAAI,cAAA,CAAe,KAAK,CAAA,EAAG;AACzB,MAAA,OAAO,KAAA,CAAM,IAAI,CAAA,CAAA,MAAM;AAAA,QACrB,MAAM,CAAA,CAAE,IAAA;AAAA,QACR,OAAA,EAAS,OAAO,CAAA,CAAE,OAAA,KAAY,WAAW,CAAA,CAAE,OAAA,GAAU,aAAA,CAAc,CAAA,CAAE,OAAO;AAAA,OAC9E,CAAE,CAAA;AAAA,IACJ;AAEA,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,MAAA,OAAO,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,OAAO,CAAA;AAAA,IAC1C;AAEA,IAAA,OAAO,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAS,aAAA,CAAc,KAAK,GAAG,CAAA;AAAA,EACzD;AAGA,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,MAAM,OAAA,CAAQ,KAAK,GAAG,OAAO,KAAA;AAC9D,EAAA,OAAO,cAAc,KAAK,CAAA;AAC5B;AAMO,SAAS,YAAA,CAAa,QAAa,QAAA,EAAyB;AAEjE,EAAA,IAAI,QAAA,KAAa,QAAA,CAAS,gBAAA,IAAoB,QAAA,KAAa,SAAS,UAAA,EAAY;AAE9E,IAAA,IAAI,cAAA,CAAe,MAAM,CAAA,EAAG;AAC1B,MAAA,OAAO,MAAA,CAAO,IAAI,CAAA,CAAA,MAAM;AAAA,QACtB,MAAM,CAAA,CAAE,IAAA;AAAA,QACR,OAAA,EAAS,OAAO,CAAA,CAAE,OAAA,KAAY,WAAW,CAAA,CAAE,OAAA,GAAU,aAAA,CAAc,CAAA,CAAE,OAAO;AAAA,OAC9E,CAAE,CAAA;AAAA,IACJ;AAEA,IAAA,IAAI,OAAO,WAAW,QAAA,EAAU;AAC9B,MAAA,OAAO,CAAC,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,QAAQ,CAAA;AAAA,IAChD;AAEA,IAAA,IAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,OAAO,CAAC,EAAE,IAAA,EAAM,aAAa,OAAA,EAAS,MAAA,CAAO,MAAM,CAAA;AAAA,IACrD;AAEA,IAAA,OAAO,CAAC,EAAE,IAAA,EAAM,WAAA,EAAa,SAAS,aAAA,CAAc,MAAM,GAAG,CAAA;AAAA,EAC/D;AAGA,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,EAAU,OAAO,MAAA;AACvC,EAAA,OAAO,cAAc,MAAM,CAAA;AAC7B;;;AC9FA,IAAM,qBAAA,GAAwB,KAAK,EAAA,GAAK,GAAA;AAKxC,IAAM,2BAAA,GAA8B,IAAI,EAAA,GAAK,GAAA;AAyDtC,IAAM,eAAA,GAAN,cAA8B,YAAA,CAAa;AAAA,EAChD,IAAA,GAAO,SAAA;AAAA,EAEC,MAAA;AAAA,EACA,YAAA,uBAAmB,GAAA,EAA0B;AAAA,EAC7C,UAAA,uBAAiB,GAAA,EAAwB;AAAA,EAEjD,WAAA,CAAY,MAAA,GAAgC,EAAC,EAAG;AAC9C,IAAA,KAAA,CAAM,MAAM,CAAA;AAGZ,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,IAAS,OAAA,CAAQ,GAAA,CAAI,gBAAA;AAC1C,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI,UAAA;AAC5C,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,IAAQ,OAAA,CAAQ,IAAI,OAAA,IAAW,eAAA;AACnD,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,GAAA,IAAO,OAAA,CAAQ,GAAA,CAAI,MAAA;AAItC,IAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,GAAA,CAAI,2BAAA,EAA6B,WAAA,EAAY;AAC1E,IAAA,MAAM,YAAY,MAAA,CAAO,SAAA,KAAc,iBAAiB,OAAA,IAAW,YAAA,KAAiB,MAAM,KAAA,GAAQ,IAAA,CAAA;AAGlG,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,IAAA,CAAK,YAAY,CAAA,0FAAA,CAA4F,CAAA;AAC7G,MAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,SAAA,IAAa,CAAC,MAAA,EAAQ;AACxB,MAAA,IAAA,CAAK,WAAA;AAAA,QACH,CAAA,yGAAA;AAAA,OACF;AACA,MAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,EAAE,GAAG,MAAA,EAAQ,OAAO,IAAA,EAAM,MAAA,EAAQ,WAAW,GAAA,EAAI;AAG/D,IAAA,YAAA,CAAa;AAAA,MACX,KAAA;AAAA,MACA,IAAA;AAAA,MACA,MAAA;AAAA,MACA,SAAA;AAAA,MACA,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,GAAA;AAAA,MACA,qBAAqB,MAAA,CAAO;AAAA,KAC7B,CAAA;AAED,IAAA,IAAA,CAAK,OAAO,IAAA,CAAK,8BAAA,EAAgC,EAAE,KAAA,EAAO,IAAA,EAAM,WAAW,CAAA;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAgB,oBAAoB,KAAA,EAAoC;AACtE,IAAA,IAAI,IAAA,CAAK,UAAA,IAAc,CAAEA,OAAAA,CAAe,MAAA,EAAQ;AAEhD,IAAA,IAAI;AACF,MAAA,MAAM,OAAO,KAAA,CAAM,YAAA;AAGnB,MAAA,IAAI,KAAK,OAAA,EAAS;AAChB,QAAA,IAAI,KAAA,CAAM,SAAS,cAAA,EAAgB;AACjC,UAAA,IAAA,CAAK,oBAAoB,IAAI,CAAA;AAC7B,UAAA,IAAA,CAAK,YAAY,IAAI,CAAA;AAAA,QACvB;AACA,QAAA;AAAA,MACF;AAGA,MAAA,QAAQ,MAAM,IAAA;AAAM,QAClB,KAAK,cAAA;AACH,UAAA,IAAA,CAAK,oBAAoB,IAAI,CAAA;AAC7B,UAAA;AAAA,QAEF,KAAK,cAAA;AAEH,UAAA;AAAA,QAEF,KAAK,YAAA;AACH,UAAA,IAAA,CAAK,YAAY,IAAI,CAAA;AACrB,UAAA;AAAA;AACJ,IACF,SAAS,KAAA,EAAO;AACd,MAAA,IAAA,CAAK,MAAA,CAAO,MAAM,wBAAA,EAA0B;AAAA,QAC1C,KAAA;AAAA,QACA,WAAW,KAAA,CAAM,IAAA;AAAA,QACjB,MAAA,EAAQ,MAAM,YAAA,EAAc,EAAA;AAAA,QAC5B,QAAA,EAAU,MAAM,YAAA,EAAc;AAAA,OAC/B,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,IAAA,EAA6B;AACvD,IAAA,IAAI,IAAA,CAAK,cAAc,CAAC,IAAA,CAAK,aAAa,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA,EAAG;AAC3D,MAAA,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS;AAAA,QAClC,MAAA,EAAQ,KAAK,QAAA,EAAU,MAAA;AAAA,QACvB,SAAA,EAAW,KAAK,QAAA,EAAU;AAAA,OAC3B,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,IAAA,EAA6B;AAC/C,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,qBAAA,CAAsB,IAAA,CAAK,OAAO,CAAA;AACrD,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,KAAA,CAAM,SAAA,GAAY,IAAA;AAAA,IACpB;AAEA,IAAA,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,IAAI,CAAA;AAC9B,IAAA,IAAA,CAAK,iBAAA,CAAkB,KAAK,OAAO,CAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAiB,IAAA,EAA4C;AACnE,IAAA,MAAM,cAAmC,EAAC;AAG1C,IAAA,IAAI,IAAA,CAAK,UAAU,MAAA,EAAW;AAC5B,MAAA,WAAA,CAAY,SAAA,GAAY,WAAA,CAAY,IAAA,CAAK,KAAA,EAAO,KAAK,IAAI,CAAA;AAAA,IAC3D;AAGA,IAAA,IAAI,IAAA,CAAK,WAAW,MAAA,EAAW;AAC7B,MAAA,WAAA,CAAY,UAAA,GAAa,YAAA,CAAa,IAAA,CAAK,MAAA,EAAQ,KAAK,IAAI,CAAA;AAAA,IAC9D;AAGA,IAAA,IAAI,KAAK,IAAA,KAASC,QAAAA,CAAS,oBAAoB,IAAA,CAAK,IAAA,KAASA,SAAS,UAAA,EAAY;AAChF,MAAA,MAAM,KAAA,GAAS,KAAK,UAAA,EAAgE,KAAA;AACpF,MAAA,MAAM,OAAA,GAAU,mBAAmB,KAAK,CAAA;AACxC,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,WAAA,CAAY,OAAA,GAAU,OAAA;AAAA,MACxB;AAAA,IACF;AAIA,IAAA,MAAM,WAAA,GAAc,CAAC,OAAA,EAAS,OAAA,EAAS,YAAY,YAAY,CAAA;AAC/D,IAAA,MAAM,kBAAkB,QAAA,CAAU,IAAA,CAAK,UAAA,IAAc,IAA4B,WAAW,CAAA;AAG5F,IAAA,MAAM,gBAAA,GAAmB;AAAA,MACvB,GAAG,IAAA,CAAK,QAAA;AAAA,MACR,GAAG;AAAA,KACL;AACA,IAAA,IAAI,MAAA,CAAO,IAAA,CAAK,gBAAgB,CAAA,CAAE,SAAS,CAAA,EAAG;AAC5C,MAAA,WAAA,CAAY,QAAA,GAAW,gBAAA;AAAA,IACzB;AAKA,IAAA,MAAM,OAA4B,EAAC;AAKnC,IAAA,IAAI,IAAA,CAAK,MAAM,MAAA,EAAQ;AACrB,MAAA,KAAA,MAAW,GAAA,IAAO,KAAK,IAAA,EAAM;AAC3B,QAAA,MAAM,UAAA,GAAa,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAClC,QAAA,IAAI,aAAa,CAAA,EAAG;AAClB,UAAA,IAAA,CAAK,GAAA,CAAI,UAAU,CAAA,EAAG,UAAU,CAAC,CAAA,GAAI,GAAA,CAAI,SAAA,CAAU,UAAA,GAAa,CAAC,CAAA;AAAA,QACnE,CAAA,MAAO;AACL,UAAA,IAAA,CAAK,GAAG,CAAA,GAAI,IAAA;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAGA,IAAA,IAAI,KAAK,SAAA,EAAW;AAClB,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,MAAA,IAAA,CAAK,SAAA,GAAY;AAAA,QACf,OAAA,EAAS,KAAK,SAAA,CAAU,OAAA;AAAA,QACxB,GAAI,IAAA,CAAK,SAAA,CAAU,EAAA,GAAK,EAAE,IAAI,IAAA,CAAK,SAAA,CAAU,EAAA,EAAG,GAAI,EAAC;AAAA,QACrD,GAAI,IAAA,CAAK,SAAA,CAAU,MAAA,GAAS,EAAE,QAAQ,IAAA,CAAK,SAAA,CAAU,MAAA,EAAO,GAAI,EAAC;AAAA,QACjE,GAAI,IAAA,CAAK,SAAA,CAAU,QAAA,GAAW,EAAE,UAAU,IAAA,CAAK,SAAA,CAAU,QAAA,EAAS,GAAI;AAAC,OACzE;AAAA,IACF;AAEA,IAAA,IAAI,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,SAAS,CAAA,EAAG;AAChC,MAAA,WAAA,CAAY,IAAA,GAAO,IAAA;AAAA,IACrB;AAEA,IAAA,OAAO,WAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAA,GAAuB;AAC3B,IAAA,IAAI,IAAA,CAAK,UAAA,IAAc,CAAED,OAAAA,CAAe,MAAA,EAAQ;AAGhD,IAAA,IAAIA,OAAAA,CAAO,QAAQ,KAAA,EAAO;AACxB,MAAA,IAAI;AACF,QAAA,MAAMA,OAAAA,CAAO,OAAO,KAAA,EAAM;AAC1B,QAAA,IAAA,CAAK,MAAA,CAAO,MAAM,wBAAwB,CAAA;AAAA,MAC5C,SAAS,CAAA,EAAG;AACV,QAAA,IAAA,CAAK,OAAO,KAAA,CAAM,uBAAA,EAAyB,EAAE,KAAA,EAAO,GAAG,CAAA;AAAA,MACzD;AAAA,IACF,CAAA,MAAA,IAAYA,QAAe,KAAA,EAAO;AAChC,MAAA,IAAI;AACF,QAAA,MAAOA,QAAe,KAAA,EAAM;AAC5B,QAAA,IAAA,CAAK,MAAA,CAAO,MAAM,wBAAwB,CAAA;AAAA,MAC5C,SAAS,CAAA,EAAG;AACV,QAAA,IAAA,CAAK,OAAO,KAAA,CAAM,uBAAA,EAAyB,EAAE,KAAA,EAAO,GAAG,CAAA;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAA,GAA0B;AAE9B,IAAA,KAAA,MAAW,CAAC,OAAA,EAAS,KAAK,CAAA,IAAK,KAAK,UAAA,EAAY;AAC9C,MAAA,IAAI,MAAM,YAAA,EAAc;AACtB,QAAA,YAAA,CAAa,MAAM,YAAY,CAAA;AAAA,MACjC;AACA,MAAA,IAAI,MAAM,gBAAA,EAAkB;AAC1B,QAAA,YAAA,CAAa,MAAM,gBAAgB,CAAA;AAAA,MACrC;AACA,MAAA,IAAI,KAAA,CAAM,MAAA,CAAO,IAAA,GAAO,CAAA,EAAG;AACzB,QAAA,IAAA,CAAK,MAAA,CAAO,KAAK,6BAAA,EAA+B;AAAA,UAC9C,OAAA;AAAA,UACA,YAAA,EAAc,MAAM,MAAA,CAAO,IAAA;AAAA,UAC3B,SAAS,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,MAAM;AAAA,SACxC,CAAA;AAAA,MACH;AAAA,IACF;AACA,IAAA,IAAA,CAAK,WAAW,KAAA,EAAM;AAGtB,IAAA,MAAM,KAAK,KAAA,EAAM;AAGjB,IAAA,IAAIA,OAAAA,CAAO,QAAQ,OAAA,EAAS;AAC1B,MAAA,IAAI;AACF,QAAAA,OAAAA,CAAO,OAAO,OAAA,EAAQ;AAAA,MACxB,SAAS,CAAA,EAAG;AACV,QAAA,IAAA,CAAK,OAAO,KAAA,CAAM,wBAAA,EAA0B,EAAE,KAAA,EAAO,GAAG,CAAA;AAAA,MAC1D;AAAA,IACF;AAGA,IAAA,IAAA,CAAK,aAAa,KAAA,EAAM;AAExB,IAAA,MAAM,MAAM,QAAA,EAAS;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAsB,OAAA,EAA6B;AACzD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,OAAO,CAAA;AAC5C,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,IAAI,SAAS,YAAA,EAAc;AACzB,QAAA,YAAA,CAAa,SAAS,YAAY,CAAA;AAClC,QAAA,QAAA,CAAS,YAAA,GAAe,MAAA;AAAA,MAC1B;AACA,MAAA,OAAO,QAAA;AAAA,IACT;AAEA,IAAA,MAAM,OAAA,GAAsB;AAAA,MAC1B,MAAA,sBAAY,GAAA,EAA6B;AAAA,MACzC,QAAA,sBAAc,GAAA,EAA6E;AAAA,MAC3F,SAAA,EAAW,KAAA;AAAA,MACX,WAAA,EAAa,KAAA;AAAA,MACb,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,MACpB,YAAA,EAAc,MAAA;AAAA,MACd,gBAAA,EAAkB;AAAA,KACpB;AAIA,IAAA,MAAM,gBAAA,GAAmB,WAAW,MAAM;AACxC,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,OAAO,CAAA;AACzC,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,IAAI,MAAM,MAAA,CAAO,IAAA,GAAO,KAAK,KAAA,CAAM,QAAA,CAAS,OAAO,CAAA,EAAG;AACpD,UAAA,IAAA,CAAK,MAAA,CAAO,KAAK,+CAAA,EAAiD;AAAA,YAChE,OAAA;AAAA,YACA,aAAA,EAAe,MAAM,MAAA,CAAO,IAAA;AAAA,YAC5B,YAAA,EAAc,MAAM,QAAA,CAAS,IAAA;AAAA,YAC7B,UAAA,EAAY,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA,CAAM;AAAA,WAChC,CAAA;AAAA,QACH;AACA,QAAA,IAAI,MAAM,YAAA,EAAc;AACtB,UAAA,YAAA,CAAa,MAAM,YAAY,CAAA;AAAA,QACjC;AACA,QAAA,IAAA,CAAK,UAAA,CAAW,OAAO,OAAO,CAAA;AAC9B,QAAA,IAAA,CAAK,YAAA,CAAa,OAAO,OAAO,CAAA;AAAA,MAClC;AAAA,IACF,GAAG,qBAAqB,CAAA;AAExB,IAAC,iBAAyB,KAAA,IAAQ;AAClC,IAAA,OAAA,CAAQ,gBAAA,GAAmB,gBAAA;AAE3B,IAAA,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,OAAA,EAAS,OAAO,CAAA;AACpC,IAAA,OAAO,OAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,kBAAkB,OAAA,EAAuB;AAC/C,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,OAAO,CAAA;AACzC,IAAA,IAAI,CAAC,KAAA,EAAO;AAGZ,IAAA,IAAI,CAAC,MAAM,WAAA,EAAa;AAEtB,MAAA,IAAI,CAAC,MAAM,SAAA,EAAW;AAGtB,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,aAAA,CAAc,KAAA,CAAM,MAAM,CAAA;AAC5C,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,IAAA,CAAK,YAAA,CAAa,MAAM,KAAK,CAAA;AAAA,MAC/B;AAGA,MAAA,KAAA,CAAM,OAAO,KAAA,EAAM;AACnB,MAAA,KAAA,CAAM,WAAA,GAAc,IAAA;AAAA,IACtB,CAAA,MAAO;AAGL,MAAA,IAAI,OAAA,GAAU,KAAA;AACd,MAAA,GAAG;AACD,QAAA,OAAA,GAAU,KAAA;AACV,QAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,IAAI,CAAA,IAAK,MAAM,MAAA,EAAQ;AACzC,UAAA,MAAM,SAAA,GAAY,KAAK,YAAA,GAAe,KAAA,CAAM,SAAS,GAAA,CAAI,IAAA,CAAK,YAAY,CAAA,GAAI,MAAA;AAC9E,UAAA,IAAI,IAAA,CAAK,YAAA,IAAgB,CAAC,SAAA,EAAW;AACnC,YAAA;AAAA,UACF;AAEA,UAAA,IAAA,CAAK,cAAA,CAAe,IAAA,EAAM,KAAA,EAAO,SAAA,EAAW,MAAM,CAAA;AAClD,UAAA,KAAA,CAAM,MAAA,CAAO,OAAO,MAAM,CAAA;AAC1B,UAAA,OAAA,GAAU,IAAA;AAAA,QACZ;AAAA,MACF,CAAA,QAAS,OAAA;AAAA,IACX;AAGA,IAAA,IAAI,KAAA,CAAM,aAAa,KAAA,CAAM,MAAA,CAAO,SAAS,CAAA,IAAK,CAAC,MAAM,YAAA,EAAc;AACrE,MAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,QAAA,MAAM,YAAA,GAAe,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,OAAO,CAAA;AAChD,QAAA,IAAI,YAAA,EAAc;AAChB,UAAA,IAAI,YAAA,CAAa,MAAA,CAAO,IAAA,GAAO,CAAA,EAAG;AAChC,YAAA,IAAA,CAAK,MAAA,CAAO,KAAK,0CAAA,EAA4C;AAAA,cAC3D,OAAA;AAAA,cACA,aAAA,EAAe,aAAa,MAAA,CAAO,IAAA;AAAA,cACnC,SAAS,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,MAAA,CAAO,MAAM;AAAA,aAC/C,CAAA;AAAA,UACH;AAEA,UAAA,IAAI,aAAa,gBAAA,EAAkB;AACjC,YAAA,YAAA,CAAa,aAAa,gBAAgB,CAAA;AAAA,UAC5C;AAAA,QACF;AACA,QAAA,IAAA,CAAK,UAAA,CAAW,OAAO,OAAO,CAAA;AAC9B,QAAA,IAAA,CAAK,YAAA,CAAa,OAAO,OAAO,CAAA;AAAA,MAClC,GAAG,2BAA2B,CAAA;AAE9B,MAAC,MAAc,KAAA,IAAQ;AACvB,MAAA,KAAA,CAAM,YAAA,GAAe,KAAA;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAc,MAAA,EAA4D;AAEhF,IAAA,MAAM,KAAA,uBAAY,GAAA,EAAsB;AACxC,IAAA,IAAI,QAAA;AAEJ,IAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,MAAA,EAAO,EAAG;AAClC,MAAA,KAAA,CAAM,GAAA,CAAI,KAAK,EAAA,EAAI,EAAE,MAAM,QAAA,EAAU,IAAI,CAAA;AAAA,IAC3C;AAGA,IAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,CAAM,MAAA,EAAO,EAAG;AACjC,MAAA,IAAI,IAAA,CAAK,KAAK,UAAA,EAAY;AACxB,QAAA,QAAA,GAAW,IAAA;AAAA,MACb,CAAA,MAAA,IAAW,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc;AACjC,QAAA,MAAM,UAAA,GAAa,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,KAAK,YAAY,CAAA;AACnD,QAAA,IAAI,UAAA,EAAY;AACd,UAAA,UAAA,CAAW,QAAA,CAAS,KAAK,IAAI,CAAA;AAAA,QAC/B,CAAA,MAAO;AAGL,UAAA,IAAA,CAAK,MAAA,CAAO,KAAK,0CAAA,EAA4C;AAAA,YAC3D,MAAA,EAAQ,KAAK,IAAA,CAAK,EAAA;AAAA,YAClB,YAAA,EAAc,KAAK,IAAA,CAAK,YAAA;AAAA,YACxB,OAAA,EAAS,KAAK,IAAA,CAAK;AAAA,WACpB,CAAA;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAGA,IAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,CAAM,MAAA,EAAO,EAAG;AACjC,MAAA,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM;AAC3B,QAAA,MAAM,QACJ,CAAA,CAAE,IAAA,CAAK,SAAA,YAAqB,IAAA,GAAO,EAAE,IAAA,CAAK,SAAA,CAAU,OAAA,EAAQ,GAAI,IAAI,IAAA,CAAK,CAAA,CAAE,IAAA,CAAK,SAAS,EAAE,OAAA,EAAQ;AACrG,QAAA,MAAM,QACJ,CAAA,CAAE,IAAA,CAAK,SAAA,YAAqB,IAAA,GAAO,EAAE,IAAA,CAAK,SAAA,CAAU,OAAA,EAAQ,GAAI,IAAI,IAAA,CAAK,CAAA,CAAE,IAAA,CAAK,SAAS,EAAE,OAAA,EAAQ;AACrG,QAAA,OAAO,KAAA,GAAQ,KAAA;AAAA,MACjB,CAAC,CAAA;AAAA,IACH;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAiB,IAAA,EAA0C;AACjE,IAAA,MAAM,WAAW,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA,IAAK;AAAA,MACtD,MAAA,EAAQ,KAAK,QAAA,EAAU,MAAA;AAAA,MACvB,SAAA,EAAW,KAAK,QAAA,EAAU;AAAA,KAC5B;AAEA,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA;AAC9B,IAAA,MAAM,QAAQ,IAAA,CAAK,UAAA;AAEnB,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA;AAGvC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,GAAU,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,GAAI,IAAA,CAAK,OAAA,GAAU,SAAA,mBAAY,IAAI,IAAA,EAAK;AAE1F,IAAA,OAAO;AAAA,MACL,IAAA;AAAA,MACA,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,WAAW,QAAA,CAAS,SAAA;AAAA,MACpB,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,SAAA;AAAA,MACA,OAAA;AAAA,MACA,GAAI,IAAA,KAAS,KAAA,IAAS,KAAA,EAAO,KAAA,GAAQ,EAAE,SAAA,EAAW,KAAA,CAAM,KAAA,EAAM,GAAI,EAAC;AAAA,MACnE,GAAI,IAAA,KAAS,KAAA,IAAS,KAAA,EAAO,QAAA,GAAW,EAAE,aAAA,EAAe,KAAA,CAAM,QAAA,EAAS,GAAI;AAAC,KAC/E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,YAAA,CAAa,MAAgB,KAAA,EAAyB;AAC5D,IAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,gBAAA,CAAiB,IAAI,CAAA;AAI1C,IAAAA,OAAAA,CAAO,MAAA,CAAO,KAAA,CAAM,OAAA,EAAgB,CAAC,MAAA,KAAgB;AAEnD,MAAA,MAAM,WAAA,GAAc,IAAA,CAAK,gBAAA,CAAiB,IAAI,CAAA;AAC9C,MAAA,IAAI,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,CAAE,SAAS,CAAA,EAAG;AACvC,QAAAA,OAAAA,CAAO,MAAA,CAAO,QAAA,CAAS,MAAA,EAAQ,WAAW,CAAA;AAAA,MAC5C;AAGA,MAAA,IAAI,KAAK,SAAA,EAAW;AAClB,QAAA,MAAA,CAAO,MAAA,CAAO,SAAS,IAAI,CAAA;AAAA,MAC7B;AAGA,MAAA,MAAM,QAAA,GAAWA,QAAO,MAAA,CAAO,UAAA,GAAaA,QAAO,MAAA,CAAO,UAAA,CAAW,MAAM,CAAA,GAAI,MAAA;AAC/E,MAAA,KAAA,CAAM,SAAS,GAAA,CAAI,IAAA,CAAK,IAAI,EAAE,MAAA,EAAQ,UAAU,CAAA;AAIhD,MAAA,KAAA,MAAW,KAAA,IAAS,KAAK,QAAA,EAAU;AACjC,QAAA,IAAA,CAAK,YAAA,CAAa,OAAO,KAAK,CAAA;AAAA,MAChC;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAA,CAAe,IAAA,EAAuB,KAAA,EAAmB,MAAA,EAAc;AAC7E,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,gBAAA,CAAiB,IAAI,CAAA;AAE1C,IAAA,MAAM,WAAW,MACfA,OAAAA,CAAO,OAAO,KAAA,CAAM,OAAA,EAAgB,CAAC,MAAA,KAAgB;AACnD,MAAA,MAAM,WAAA,GAAc,IAAA,CAAK,gBAAA,CAAiB,IAAI,CAAA;AAC9C,MAAA,IAAI,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,CAAE,SAAS,CAAA,EAAG;AACvC,QAAAA,OAAAA,CAAO,MAAA,CAAO,QAAA,CAAS,MAAA,EAAQ,WAAW,CAAA;AAAA,MAC5C;AAGA,MAAA,IAAI,KAAK,SAAA,EAAW;AAClB,QAAA,MAAA,CAAO,MAAA,CAAO,SAAS,IAAI,CAAA;AAAA,MAC7B;AAEA,MAAA,MAAM,QAAA,GAAWA,QAAO,MAAA,CAAO,UAAA,GAAaA,QAAO,MAAA,CAAO,UAAA,CAAW,MAAM,CAAA,GAAI,MAAA;AAC/E,MAAA,KAAA,CAAM,SAAS,GAAA,CAAI,IAAA,CAAK,IAAI,EAAE,MAAA,EAAQ,UAAU,CAAA;AAAA,IAClD,CAAC,CAAA;AAEH,IAAA,IAAI,MAAA,EAAQ;AACV,MAAAA,OAAAA,CAAO,KAAA,EAAM,CAAE,QAAA,CAAS,QAAQ,QAAQ,CAAA;AAAA,IAC1C,CAAA,MAAO;AACL,MAAA,QAAA,EAAS;AAAA,IACX;AAAA,EACF;AACF","file":"index.js","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\nimport type tracer from 'dd-trace';\n\ntype DatadogAnnotationMetrics = tracer.llmobs.AnnotationOptions['metrics'];\n\nexport function formatUsageMetrics(usage?: UsageStats): DatadogAnnotationMetrics | undefined {\n if (!usage) return undefined;\n\n const result: DatadogAnnotationMetrics = {};\n\n const inputTokens = usage.inputTokens;\n if (inputTokens !== undefined) result.inputTokens = inputTokens;\n\n const outputTokens = usage.outputTokens;\n if (outputTokens !== undefined) result.outputTokens = outputTokens;\n\n if (inputTokens !== undefined && outputTokens !== undefined) {\n result.totalTokens = inputTokens + outputTokens;\n }\n\n if (usage?.outputDetails?.reasoning !== undefined) {\n result.reasoningTokens = usage.outputDetails.reasoning;\n }\n\n const cachedTokens = usage?.inputDetails?.cacheRead;\n if (cachedTokens !== undefined) {\n result.cachedInputTokens = cachedTokens;\n }\n\n const cachedOutputTokens = usage?.inputDetails?.cacheWrite;\n if (cachedOutputTokens !== undefined) {\n result.cachedOutputTokens = cachedOutputTokens;\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n","/**\n * Utility functions for Datadog LLM Observability Exporter\n */\n\nimport { SpanType } from '@mastra/core/observability';\nimport tracer from 'dd-trace';\n\n/**\n * Datadog LLM Observability span kinds.\n */\nexport type DatadogSpanKind = 'llm' | 'agent' | 'workflow' | 'tool' | 'task' | 'retrieval' | 'embedding';\n\n/**\n * Maps Mastra SpanTypes to Datadog LLMObs span kinds.\n * Only non-task mappings are defined; unmapped types fall back to 'task'.\n */\nexport const SPAN_TYPE_TO_KIND: Partial<Record<SpanType, DatadogSpanKind>> = {\n [SpanType.AGENT_RUN]: 'agent',\n [SpanType.MODEL_GENERATION]: 'workflow',\n [SpanType.MODEL_STEP]: 'llm',\n [SpanType.TOOL_CALL]: 'tool',\n [SpanType.MCP_TOOL_CALL]: 'tool',\n [SpanType.WORKFLOW_RUN]: 'workflow',\n};\n\n/**\n * Singleton flag to prevent multiple tracer initializations.\n * dd-trace should only be initialized once per process.\n */\nconst tracerInitFlag = { done: false };\n\n/**\n * Ensures dd-trace is initialized exactly once.\n * Respects any existing tracer initialization by the application.\n */\nexport function ensureTracer(config: {\n mlApp: string;\n site: string;\n apiKey?: string;\n agentless: boolean;\n service?: string;\n env?: string;\n integrationsEnabled?: boolean;\n}): void {\n if (tracerInitFlag.done) return;\n\n // Set environment variables for dd-trace to pick up\n // (LLMObsEnableOptions only accepts mlApp and agentlessEnabled)\n // Always set when config is provided to ensure explicit config takes precedence\n // over any stale env vars that may already be set in the process\n if (config.site) {\n process.env.DD_SITE = config.site;\n }\n if (config.apiKey) {\n process.env.DD_API_KEY = config.apiKey;\n }\n\n // Check if tracer was already started by the application\n const alreadyStarted = (tracer as any)._tracer?.started;\n\n if (!alreadyStarted) {\n tracer.init({\n service: config.service || config.mlApp,\n env: config.env || process.env.DD_ENV,\n // Disable automatic integrations by default to avoid surprise instrumentation\n plugins: config.integrationsEnabled ?? false,\n });\n }\n\n // Enable LLM Observability with the resolved configuration\n tracer.llmobs.enable({\n mlApp: config.mlApp,\n agentlessEnabled: config.agentless,\n });\n\n tracerInitFlag.done = true;\n}\n\n/**\n * Returns the Datadog kind for a Mastra span type.\n */\nexport function kindFor(spanType: SpanType): DatadogSpanKind {\n return SPAN_TYPE_TO_KIND[spanType] || 'task';\n}\n\n/**\n * Converts a value to a Date object.\n */\nexport function toDate(value: Date | string | number): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\n/**\n * Safely stringifies data, handling circular references.\n */\nexport function safeStringify(data: unknown): string {\n try {\n return JSON.stringify(data);\n } catch {\n if (typeof data === 'object' && data !== null) {\n return `[Non-serializable ${data.constructor?.name || 'Object'}]`;\n }\n return String(data);\n }\n}\n\n/**\n * Checks if data is already in message array format ({role, content}[]).\n */\nfunction isMessageArray(data: any): data is Array<{ role: string; content: any }> {\n return Array.isArray(data) && data.every(m => m?.role && m?.content !== undefined);\n}\n\n/**\n * Formats input data for Datadog annotations.\n * LLM spans use message array format; others use raw or stringified data.\n */\nexport function formatInput(input: any, spanType: SpanType): any {\n // LLM spans expect {role, content}[] format\n if (spanType === SpanType.MODEL_GENERATION || spanType === SpanType.MODEL_STEP) {\n // Already in message format\n if (isMessageArray(input)) {\n return input.map(m => ({\n role: m.role,\n content: typeof m.content === 'string' ? m.content : safeStringify(m.content),\n }));\n }\n // String input becomes user message\n if (typeof input === 'string') {\n return [{ role: 'user', content: input }];\n }\n // Object input gets stringified as user message\n return [{ role: 'user', content: safeStringify(input) }];\n }\n\n // Non-LLM spans: pass through strings/arrays, stringify objects\n if (typeof input === 'string' || Array.isArray(input)) return input;\n return safeStringify(input);\n}\n\n/**\n * Formats output data for Datadog annotations.\n * LLM spans use message array format; others use raw or stringified data.\n */\nexport function formatOutput(output: any, spanType: SpanType): any {\n // LLM spans expect {role, content}[] format\n if (spanType === SpanType.MODEL_GENERATION || spanType === SpanType.MODEL_STEP) {\n // Already in message format\n if (isMessageArray(output)) {\n return output.map(m => ({\n role: m.role,\n content: typeof m.content === 'string' ? m.content : safeStringify(m.content),\n }));\n }\n // String output becomes assistant message\n if (typeof output === 'string') {\n return [{ role: 'assistant', content: output }];\n }\n // Object with text property (common AI SDK format)\n if (output?.text) {\n return [{ role: 'assistant', content: output.text }];\n }\n // Other objects get stringified as assistant message\n return [{ role: 'assistant', content: safeStringify(output) }];\n }\n\n // Non-LLM spans: pass through strings, stringify objects\n if (typeof output === 'string') return output;\n return safeStringify(output);\n}\n","/**\n * Datadog LLM Observability Exporter for Mastra\n *\n * Exports Mastra observability data to Datadog's LLM Observability product.\n * Uses a completion-only pattern where spans are emitted on span_ended events.\n *\n * Key features:\n * - Maps Mastra span types to Datadog span kinds\n * - Normalizes AI SDK v4/v5 token usage formats\n * - Formats LLM inputs/outputs as message arrays\n * - Flattens metadata into searchable tags\n * - Supports both agent and agentless modes\n */\n\nimport type {\n TracingEvent,\n AnyExportedSpan,\n ModelGenerationAttributes,\n ModelStepAttributes,\n} from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { BaseExporter } from '@mastra/observability';\nimport type { BaseExporterConfig } from '@mastra/observability';\nimport tracer from 'dd-trace';\nimport { formatUsageMetrics } from './metrics';\nimport { ensureTracer, kindFor, toDate, formatInput, formatOutput } from './utils';\nimport type { DatadogSpanKind } from './utils';\n\n/**\n * LLMObs span options with required name and kind properties.\n */\ninterface LLMObsSpanOptions {\n kind: DatadogSpanKind;\n name: string;\n sessionId?: string;\n userId?: string;\n mlApp?: string;\n modelName?: string;\n modelProvider?: string;\n startTime?: Date;\n endTime?: Date;\n}\n\n/**\n * Minimal per-trace context for user/session tagging.\n */\ninterface TraceContext {\n userId?: string;\n sessionId?: string;\n}\n\ntype TraceState = {\n buffer: Map<string, AnyExportedSpan>;\n contexts: Map<string, { ddSpan: any; exported?: { traceId: string; spanId: string } }>;\n rootEnded: boolean;\n treeEmitted: boolean; // Whether the initial span tree has been emitted\n createdAt: number;\n cleanupTimer?: ReturnType<typeof setTimeout>;\n maxLifetimeTimer?: ReturnType<typeof setTimeout>;\n};\n\n/**\n * Tree node representing a span and its children for recursive emission.\n */\ninterface SpanNode {\n span: AnyExportedSpan;\n children: SpanNode[];\n}\n\n/**\n * Maximum lifetime for a trace state entry (30 minutes).\n * This is a fallback cleanup mechanism for traces that never receive a root span\n * or have all spans marked as non-root, preventing unbounded memory growth.\n */\nconst MAX_TRACE_LIFETIME_MS = 30 * 60 * 1000;\n\n/**\n * Regular cleanup interval for trace state entries (1 minute).\n */\nconst REGULAR_CLEANUP_INTERVAL_MS = 1 * 60 * 1000;\n\n/**\n * Configuration options for the Datadog LLM Observability exporter.\n */\nexport interface DatadogExporterConfig extends BaseExporterConfig {\n /**\n * Datadog API key. Required (agentless mode is the default).\n * Falls back to DD_API_KEY environment variable.\n */\n apiKey?: string;\n\n /**\n * ML application name for grouping traces.\n * Required - falls back to DD_LLMOBS_ML_APP environment variable.\n */\n mlApp?: string;\n\n /**\n * Datadog site (e.g., 'datadoghq.com', 'datadoghq.eu').\n * Falls back to DD_SITE environment variable, defaults to 'datadoghq.com'.\n */\n site?: string;\n\n /**\n * Service name for the application.\n * Falls back to mlApp if not specified.\n */\n service?: string;\n\n /**\n * Environment name (e.g., 'production', 'staging').\n * Falls back to DD_ENV environment variable.\n */\n env?: string;\n\n /**\n * Use agentless mode (direct HTTPS intake without local Datadog Agent).\n * Defaults to true for consistency with other Mastra exporters.\n * Set to false to use a local Datadog Agent instead.\n * Falls back to DD_LLMOBS_AGENTLESS_ENABLED environment variable.\n */\n agentless?: boolean;\n\n /**\n * Enable dd-trace automatic integrations.\n * Defaults to false to avoid unexpected instrumentation.\n */\n integrationsEnabled?: boolean;\n}\n\n/**\n * Datadog LLM Observability Exporter for Mastra.\n *\n * Exports observability data to Datadog's LLM Observability product using\n * a completion-only pattern where spans are emitted on span_ended events.\n */\nexport class DatadogExporter extends BaseExporter {\n name = 'datadog';\n\n private config: Required<Pick<DatadogExporterConfig, 'mlApp' | 'site'>> & DatadogExporterConfig;\n private traceContext = new Map<string, TraceContext>();\n private traceState = new Map<string, TraceState>();\n\n constructor(config: DatadogExporterConfig = {}) {\n super(config);\n\n // Resolve configuration from config object and environment variables\n const mlApp = config.mlApp ?? process.env.DD_LLMOBS_ML_APP;\n const apiKey = config.apiKey ?? process.env.DD_API_KEY;\n const site = config.site ?? process.env.DD_SITE ?? 'datadoghq.com';\n const env = config.env ?? process.env.DD_ENV;\n\n // Default to agentless mode (true) for consistency with other Mastra exporters\n // Only disable if explicitly set to false via config or env var\n const envAgentless = process.env.DD_LLMOBS_AGENTLESS_ENABLED?.toLowerCase();\n const agentless = config.agentless ?? (envAgentless === 'false' || envAgentless === '0' ? false : true);\n\n // Validate required configuration\n if (!mlApp) {\n this.setDisabled(`Missing required mlApp. Set DD_LLMOBS_ML_APP environment variable or pass mlApp in config.`);\n this.config = config as any;\n return;\n }\n\n if (agentless && !apiKey) {\n this.setDisabled(\n `Missing required apiKey for agentless mode. Set DD_API_KEY environment variable or pass apiKey in config.`,\n );\n this.config = config as any;\n return;\n }\n\n this.config = { ...config, mlApp, site, apiKey, agentless, env };\n\n // Initialize tracer and enable LLM Observability\n ensureTracer({\n mlApp,\n site,\n apiKey,\n agentless,\n service: config.service,\n env,\n integrationsEnabled: config.integrationsEnabled,\n });\n\n this.logger.info('Datadog exporter initialized', { mlApp, site, agentless });\n }\n\n /**\n * Main entry point for tracing events from Mastra.\n */\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (this.isDisabled || !(tracer as any).llmobs) return;\n\n try {\n const span = event.exportedSpan;\n\n // Handle event spans (zero-duration spans) - buffer like regular spans for parent-first emission\n if (span.isEvent) {\n if (event.type === 'span_started') {\n this.captureTraceContext(span);\n this.enqueueSpan(span); // Route through buffer for proper parent context\n }\n return; // Skip span_updated and span_ended for events\n }\n\n // Handle regular spans based on event type\n switch (event.type) {\n case 'span_started':\n this.captureTraceContext(span);\n return;\n\n case 'span_updated':\n // No-op: completion-only pattern ignores mid-span updates\n return;\n\n case 'span_ended':\n this.enqueueSpan(span);\n return;\n }\n } catch (error) {\n this.logger.error('Datadog exporter error', {\n error,\n eventType: event.type,\n spanId: event.exportedSpan?.id,\n spanName: event.exportedSpan?.name,\n });\n }\n }\n\n /**\n * Captures user/session context from root spans for tagging all spans in the trace.\n */\n private captureTraceContext(span: AnyExportedSpan): void {\n if (span.isRootSpan && !this.traceContext.has(span.traceId)) {\n this.traceContext.set(span.traceId, {\n userId: span.metadata?.userId,\n sessionId: span.metadata?.sessionId,\n });\n }\n }\n\n /**\n * Queue span until its parent context is available, then emit spans parent-first.\n */\n private enqueueSpan(span: AnyExportedSpan): void {\n const state = this.getOrCreateTraceState(span.traceId);\n if (span.isRootSpan) {\n state.rootEnded = true;\n }\n\n state.buffer.set(span.id, span);\n this.tryEmitReadySpans(span.traceId);\n }\n\n /**\n * Builds annotations object for llmobs.annotate().\n * Uses dd-trace's expected property names: inputData, outputData, metadata, tags, metrics.\n */\n private buildAnnotations(span: AnyExportedSpan): Record<string, any> {\n const annotations: Record<string, any> = {};\n\n // Format and add input (dd-trace expects 'inputData')\n if (span.input !== undefined) {\n annotations.inputData = formatInput(span.input, span.type);\n }\n\n // Format and add output (dd-trace expects 'outputData')\n if (span.output !== undefined) {\n annotations.outputData = formatOutput(span.output, span.type);\n }\n\n // Add token usage metrics (only on MODEL_GENERATION or MODEL_STEP spans)\n if (span.type === SpanType.MODEL_GENERATION || span.type === SpanType.MODEL_STEP) {\n const usage = (span.attributes as ModelGenerationAttributes | ModelStepAttributes)?.usage;\n const metrics = formatUsageMetrics(usage);\n if (metrics) {\n annotations.metrics = metrics;\n }\n }\n\n // Forward span.attributes to metadata (minus known fields handled separately)\n // This ensures tool/workflow spans preserve custom attributes like other exporters\n const knownFields = ['usage', 'model', 'provider', 'parameters'];\n const otherAttributes = omitKeys((span.attributes ?? {}) as Record<string, any>, knownFields);\n\n // Merge span.metadata + remaining attributes into metadata\n const combinedMetadata = {\n ...span.metadata,\n ...otherAttributes,\n };\n if (Object.keys(combinedMetadata).length > 0) {\n annotations.metadata = combinedMetadata;\n }\n\n // Build tags from span.tags (user-provided string[] converted to object) and error info\n // Datadog annotation tags accept Record<string, any>, so we use proper types\n // The native span error status is also set via ddSpan.setTag('error', true) in emitSpan()\n const tags: Record<string, any> = {};\n\n // Convert span.tags (string[]) to object format\n // Tags in \"key:value\" format (e.g. \"instance_name:career-scout-api\") are split into { key: \"value\" }\n // Tags without a colon (e.g. \"production\") are set as { tag: true } (preserving existing behavior)\n if (span.tags?.length) {\n for (const tag of span.tags) {\n const colonIndex = tag.indexOf(':');\n if (colonIndex > 0) {\n tags[tag.substring(0, colonIndex)] = tag.substring(colonIndex + 1);\n } else {\n tags[tag] = true;\n }\n }\n }\n\n // Add error info as consolidated tags\n if (span.errorInfo) {\n tags.error = true;\n tags.errorInfo = {\n message: span.errorInfo.message,\n ...(span.errorInfo.id ? { id: span.errorInfo.id } : {}),\n ...(span.errorInfo.domain ? { domain: span.errorInfo.domain } : {}),\n ...(span.errorInfo.category ? { category: span.errorInfo.category } : {}),\n };\n }\n\n if (Object.keys(tags).length > 0) {\n annotations.tags = tags;\n }\n\n return annotations;\n }\n\n /**\n * Force flush any buffered spans without shutting down the exporter.\n * This is useful in serverless environments where you need to ensure spans\n * are exported before the runtime instance is terminated.\n */\n async flush(): Promise<void> {\n if (this.isDisabled || !(tracer as any).llmobs) return;\n\n // Flush any pending data to Datadog\n if (tracer.llmobs?.flush) {\n try {\n await tracer.llmobs.flush();\n this.logger.debug('Datadog llmobs flushed');\n } catch (e) {\n this.logger.error('Error flushing llmobs', { error: e });\n }\n } else if ((tracer as any).flush) {\n try {\n await (tracer as any).flush();\n this.logger.debug('Datadog tracer flushed');\n } catch (e) {\n this.logger.error('Error flushing tracer', { error: e });\n }\n }\n }\n\n /**\n * Gracefully shuts down the exporter.\n */\n async shutdown(): Promise<void> {\n // Cancel all pending cleanup timers and clear state FIRST\n for (const [traceId, state] of this.traceState) {\n if (state.cleanupTimer) {\n clearTimeout(state.cleanupTimer);\n }\n if (state.maxLifetimeTimer) {\n clearTimeout(state.maxLifetimeTimer);\n }\n if (state.buffer.size > 0) {\n this.logger.warn('Shutdown with pending spans', {\n traceId,\n pendingCount: state.buffer.size,\n spanIds: Array.from(state.buffer.keys()),\n });\n }\n }\n this.traceState.clear();\n\n // Flush any pending data\n await this.flush();\n\n // Disable LLM Observability\n if (tracer.llmobs?.disable) {\n try {\n tracer.llmobs.disable();\n } catch (e) {\n this.logger.error('Error disabling llmobs', { error: e });\n }\n }\n\n // Clear local state\n this.traceContext.clear();\n\n await super.shutdown();\n }\n\n /**\n * Retrieve or initialize trace state for buffering and parent tracking.\n */\n private getOrCreateTraceState(traceId: string): TraceState {\n const existing = this.traceState.get(traceId);\n if (existing) {\n if (existing.cleanupTimer) {\n clearTimeout(existing.cleanupTimer);\n existing.cleanupTimer = undefined;\n }\n return existing;\n }\n\n const created: TraceState = {\n buffer: new Map<string, AnyExportedSpan>(),\n contexts: new Map<string, { ddSpan: any; exported?: { traceId: string; spanId: string } }>(),\n rootEnded: false,\n treeEmitted: false,\n createdAt: Date.now(),\n cleanupTimer: undefined,\n maxLifetimeTimer: undefined,\n };\n\n // Schedule fallback cleanup after max lifetime to prevent memory leaks\n // when traces never receive a root span or all spans are non-root\n const maxLifetimeTimer = setTimeout(() => {\n const state = this.traceState.get(traceId);\n if (state) {\n if (state.buffer.size > 0 || state.contexts.size > 0) {\n this.logger.warn('Discarding trace due to max lifetime exceeded', {\n traceId,\n bufferedSpans: state.buffer.size,\n emittedSpans: state.contexts.size,\n lifetimeMs: Date.now() - state.createdAt,\n });\n }\n if (state.cleanupTimer) {\n clearTimeout(state.cleanupTimer);\n }\n this.traceState.delete(traceId);\n this.traceContext.delete(traceId);\n }\n }, MAX_TRACE_LIFETIME_MS);\n // Prevent the timer from keeping the process alive\n (maxLifetimeTimer as any).unref?.();\n created.maxLifetimeTimer = maxLifetimeTimer;\n\n this.traceState.set(traceId, created);\n return created;\n }\n\n /**\n * Attempt to emit spans from the buffer.\n *\n * Two modes of operation:\n * 1. Initial tree emission: When root span ends and tree hasn't been emitted yet,\n * build a tree from all buffered spans and emit recursively using nested\n * llmobs.trace() calls. This ensures proper parent-child relationships in Datadog.\n * 2. Late-arriving spans: After the tree has been emitted, emit individual spans\n * with their parent context for proper linking.\n */\n private tryEmitReadySpans(traceId: string): void {\n const state = this.traceState.get(traceId);\n if (!state) return;\n\n // If tree hasn't been emitted yet, wait for root and emit as tree\n if (!state.treeEmitted) {\n // Wait until the root span has ended before emitting any spans\n if (!state.rootEnded) return;\n\n // Build tree and emit recursively\n const tree = this.buildSpanTree(state.buffer);\n if (tree) {\n this.emitSpanTree(tree, state);\n }\n\n // Clear the buffer and mark tree as emitted\n state.buffer.clear();\n state.treeEmitted = true;\n } else {\n // Tree already emitted - handle late-arriving spans individually\n // Use the old parent-first emission pattern for these\n let emitted = false;\n do {\n emitted = false;\n for (const [spanId, span] of state.buffer) {\n const parentCtx = span.parentSpanId ? state.contexts.get(span.parentSpanId) : undefined;\n if (span.parentSpanId && !parentCtx) {\n continue;\n }\n\n this.emitSingleSpan(span, state, parentCtx?.ddSpan);\n state.buffer.delete(spanId);\n emitted = true;\n }\n } while (emitted);\n }\n\n // Schedule cleanup if root has ended and buffer is empty\n if (state.rootEnded && state.buffer.size === 0 && !state.cleanupTimer) {\n const timer = setTimeout(() => {\n const currentState = this.traceState.get(traceId);\n if (currentState) {\n if (currentState.buffer.size > 0) {\n this.logger.warn('Discarding orphaned spans during cleanup', {\n traceId,\n orphanedCount: currentState.buffer.size,\n spanIds: Array.from(currentState.buffer.keys()),\n });\n }\n // Clear the max lifetime timer since normal cleanup is handling this\n if (currentState.maxLifetimeTimer) {\n clearTimeout(currentState.maxLifetimeTimer);\n }\n }\n this.traceState.delete(traceId);\n this.traceContext.delete(traceId);\n }, REGULAR_CLEANUP_INTERVAL_MS);\n // Prevent the timer from keeping the process alive\n (timer as any).unref?.();\n state.cleanupTimer = timer;\n }\n }\n\n /**\n * Builds a tree structure from buffered spans based on parentSpanId relationships.\n * Returns the root node of the tree, or undefined if no root span is found.\n */\n private buildSpanTree(buffer: Map<string, AnyExportedSpan>): SpanNode | undefined {\n // Create nodes for all spans\n const nodes = new Map<string, SpanNode>();\n let rootNode: SpanNode | undefined;\n\n for (const span of buffer.values()) {\n nodes.set(span.id, { span, children: [] });\n }\n\n // Build parent-child relationships\n for (const node of nodes.values()) {\n if (node.span.isRootSpan) {\n rootNode = node;\n } else if (node.span.parentSpanId) {\n const parentNode = nodes.get(node.span.parentSpanId);\n if (parentNode) {\n parentNode.children.push(node);\n } else {\n // Orphaned span - parent not in buffer, treat as root-level\n // This shouldn't happen normally but handles edge cases\n this.logger.warn('Orphaned span detected during tree build', {\n spanId: node.span.id,\n parentSpanId: node.span.parentSpanId,\n traceId: node.span.traceId,\n });\n }\n }\n }\n\n // Sort children by start time for consistent ordering\n for (const node of nodes.values()) {\n node.children.sort((a, b) => {\n const aTime =\n a.span.startTime instanceof Date ? a.span.startTime.getTime() : new Date(a.span.startTime).getTime();\n const bTime =\n b.span.startTime instanceof Date ? b.span.startTime.getTime() : new Date(b.span.startTime).getTime();\n return aTime - bTime;\n });\n }\n\n return rootNode;\n }\n\n /**\n * Builds LLMObs span options from a Mastra span.\n * Handles trace context, timestamps, and conditional model information for LLM spans.\n */\n private buildSpanOptions(span: AnyExportedSpan): LLMObsSpanOptions {\n const traceCtx = this.traceContext.get(span.traceId) || {\n userId: span.metadata?.userId,\n sessionId: span.metadata?.sessionId,\n };\n\n const kind = kindFor(span.type);\n const attrs = span.attributes as ModelGenerationAttributes | undefined;\n\n const startTime = toDate(span.startTime);\n // Event spans are point-in-time markers; use startTime for endTime if not set (zero duration)\n // Regular spans fall back to current time if endTime is not set\n const endTime = span.endTime ? toDate(span.endTime) : span.isEvent ? startTime : new Date();\n\n return {\n kind,\n name: span.name,\n sessionId: traceCtx.sessionId,\n userId: traceCtx.userId,\n startTime,\n endTime,\n ...(kind === 'llm' && attrs?.model ? { modelName: attrs.model } : {}),\n ...(kind === 'llm' && attrs?.provider ? { modelProvider: attrs.provider } : {}),\n };\n }\n\n /**\n * Recursively emits a span tree using nested llmobs.trace() calls.\n * This ensures parent-child relationships are properly established in Datadog\n * because child spans are created while their parent span is active in scope.\n */\n private emitSpanTree(node: SpanNode, state: TraceState): void {\n const span = node.span;\n const options = this.buildSpanOptions(span);\n\n // Use nested llmobs.trace() calls - children are emitted INSIDE the parent's callback\n // This ensures the Datadog SDK automatically establishes parent-child relationships\n tracer.llmobs.trace(options as any, (ddSpan: any) => {\n // Annotate this span\n const annotations = this.buildAnnotations(span);\n if (Object.keys(annotations).length > 0) {\n tracer.llmobs.annotate(ddSpan, annotations);\n }\n\n // Set native Datadog error status for proper UI highlighting\n if (span.errorInfo) {\n ddSpan.setTag('error', true);\n }\n\n // Store context for potential evaluation submissions\n const exported = tracer.llmobs.exportSpan ? tracer.llmobs.exportSpan(ddSpan) : undefined;\n state.contexts.set(span.id, { ddSpan, exported });\n\n // Recursively emit children INSIDE this span's callback\n // This is the key to establishing proper parent-child relationships\n for (const child of node.children) {\n this.emitSpanTree(child, state);\n }\n });\n }\n\n /**\n * Emit a single span with the proper Datadog parent context.\n * Used for late-arriving spans after the main tree has been emitted.\n */\n private emitSingleSpan(span: AnyExportedSpan, state: TraceState, parent?: any) {\n const options = this.buildSpanOptions(span);\n\n const runTrace = () =>\n tracer.llmobs.trace(options as any, (ddSpan: any) => {\n const annotations = this.buildAnnotations(span);\n if (Object.keys(annotations).length > 0) {\n tracer.llmobs.annotate(ddSpan, annotations);\n }\n\n // Set native Datadog error status for proper UI highlighting\n if (span.errorInfo) {\n ddSpan.setTag('error', true);\n }\n\n const exported = tracer.llmobs.exportSpan ? tracer.llmobs.exportSpan(ddSpan) : undefined;\n state.contexts.set(span.id, { ddSpan, exported });\n });\n\n if (parent) {\n tracer.scope().activate(parent, runTrace);\n } else {\n runTrace();\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/metrics.ts","../src/utils.ts","../src/tracing.ts"],"names":["tracer","SpanType"],"mappings":"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","file":"index.js","sourcesContent":["import type { UsageStats } from '@mastra/core/observability';\nimport type tracer from 'dd-trace';\n\ntype DatadogAnnotationMetrics = tracer.llmobs.AnnotationOptions['metrics'];\n\nexport function formatUsageMetrics(usage?: UsageStats): DatadogAnnotationMetrics | undefined {\n if (!usage) return undefined;\n\n const result: DatadogAnnotationMetrics = {};\n\n const inputTokens = usage.inputTokens;\n if (inputTokens !== undefined) result.inputTokens = inputTokens;\n\n const outputTokens = usage.outputTokens;\n if (outputTokens !== undefined) result.outputTokens = outputTokens;\n\n if (inputTokens !== undefined && outputTokens !== undefined) {\n result.totalTokens = inputTokens + outputTokens;\n }\n\n if (usage?.outputDetails?.reasoning !== undefined) {\n result.reasoningOutputTokens = usage.outputDetails.reasoning;\n }\n\n const cacheReadTokens = usage?.inputDetails?.cacheRead;\n if (cacheReadTokens !== undefined) {\n result.cacheReadTokens = cacheReadTokens;\n }\n\n const cacheWriteTokens = usage?.inputDetails?.cacheWrite;\n if (cacheWriteTokens !== undefined) {\n result.cacheWriteTokens = cacheWriteTokens;\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n","/**\n * Utility functions for Datadog LLM Observability Exporter\n */\n\nimport { SpanType } from '@mastra/core/observability';\nimport tracer from 'dd-trace';\n\n/**\n * Datadog LLM Observability span kinds.\n */\nexport type DatadogSpanKind = 'llm' | 'agent' | 'workflow' | 'tool' | 'task' | 'retrieval' | 'embedding';\n\n/**\n * Maps Mastra SpanTypes to Datadog LLMObs span kinds.\n * Only non-task mappings are defined; unmapped types fall back to 'task'.\n */\nexport const SPAN_TYPE_TO_KIND: Partial<Record<SpanType, DatadogSpanKind>> = {\n [SpanType.AGENT_RUN]: 'agent',\n [SpanType.MODEL_GENERATION]: 'workflow',\n [SpanType.MODEL_STEP]: 'llm',\n [SpanType.TOOL_CALL]: 'tool',\n [SpanType.MCP_TOOL_CALL]: 'tool',\n [SpanType.WORKFLOW_RUN]: 'workflow',\n};\n\n/**\n * Singleton flag to prevent multiple tracer initializations.\n * dd-trace should only be initialized once per process.\n */\nconst tracerInitFlag = { done: false };\n\n/**\n * Ensures dd-trace is initialized exactly once.\n * Respects any existing tracer initialization by the application.\n */\nexport function ensureTracer(config: {\n mlApp: string;\n site: string;\n apiKey?: string;\n agentless: boolean;\n service?: string;\n env?: string;\n integrationsEnabled?: boolean;\n}): void {\n if (tracerInitFlag.done) return;\n\n // Set environment variables for dd-trace to pick up\n // (LLMObsEnableOptions only accepts mlApp and agentlessEnabled)\n // Always set when config is provided to ensure explicit config takes precedence\n // over any stale env vars that may already be set in the process\n if (config.site) {\n process.env.DD_SITE = config.site;\n }\n if (config.apiKey) {\n process.env.DD_API_KEY = config.apiKey;\n }\n\n // Check if tracer was already started by the application\n const alreadyStarted = (tracer as any)._tracer?.started;\n\n if (!alreadyStarted) {\n tracer.init({\n service: config.service || config.mlApp,\n env: config.env || process.env.DD_ENV,\n // Disable automatic integrations by default to avoid surprise instrumentation\n plugins: config.integrationsEnabled ?? false,\n });\n }\n\n // Enable LLM Observability with the resolved configuration\n tracer.llmobs.enable({\n mlApp: config.mlApp,\n agentlessEnabled: config.agentless,\n });\n\n tracerInitFlag.done = true;\n}\n\n/**\n * Returns the Datadog kind for a Mastra span type.\n */\nexport function kindFor(spanType: SpanType): DatadogSpanKind {\n return SPAN_TYPE_TO_KIND[spanType] || 'task';\n}\n\n/**\n * Converts a value to a Date object.\n */\nexport function toDate(value: Date | string | number): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\n/**\n * Safely stringifies data, handling circular references.\n */\nexport function safeStringify(data: unknown): string {\n try {\n return JSON.stringify(data);\n } catch {\n if (typeof data === 'object' && data !== null) {\n return `[Non-serializable ${data.constructor?.name || 'Object'}]`;\n }\n return String(data);\n }\n}\n\n/**\n * Checks if data is already in message array format ({role, content}[]).\n */\nfunction isMessageArray(data: any): data is Array<{ role: string; content: any }> {\n return Array.isArray(data) && data.every(m => m?.role && m?.content !== undefined);\n}\n\n/**\n * Formats input data for Datadog annotations.\n * LLM spans use message array format; others use raw or stringified data.\n */\nexport function formatInput(input: any, spanType: SpanType): any {\n // LLM spans expect {role, content}[] format\n if (spanType === SpanType.MODEL_GENERATION || spanType === SpanType.MODEL_STEP) {\n // Already in message format\n if (isMessageArray(input)) {\n return input.map(m => ({\n role: m.role,\n content: typeof m.content === 'string' ? m.content : safeStringify(m.content),\n }));\n }\n // String input becomes user message\n if (typeof input === 'string') {\n return [{ role: 'user', content: input }];\n }\n // Object input gets stringified as user message\n return [{ role: 'user', content: safeStringify(input) }];\n }\n\n // Non-LLM spans: pass through strings/arrays, stringify objects\n if (typeof input === 'string' || Array.isArray(input)) return input;\n return safeStringify(input);\n}\n\n/**\n * Formats output data for Datadog annotations.\n * LLM spans use message array format; others use raw or stringified data.\n */\nexport function formatOutput(output: any, spanType: SpanType): any {\n // LLM spans expect {role, content}[] format\n if (spanType === SpanType.MODEL_GENERATION || spanType === SpanType.MODEL_STEP) {\n // Already in message format\n if (isMessageArray(output)) {\n return output.map(m => ({\n role: m.role,\n content: typeof m.content === 'string' ? m.content : safeStringify(m.content),\n }));\n }\n // String output becomes assistant message\n if (typeof output === 'string') {\n return [{ role: 'assistant', content: output }];\n }\n // Object with text property (common AI SDK format)\n if (output?.text) {\n return [{ role: 'assistant', content: output.text }];\n }\n // Other objects get stringified as assistant message\n return [{ role: 'assistant', content: safeStringify(output) }];\n }\n\n // Non-LLM spans: pass through strings, stringify objects\n if (typeof output === 'string') return output;\n return safeStringify(output);\n}\n","/**\n * Datadog LLM Observability Exporter for Mastra\n *\n * Exports Mastra observability data to Datadog's LLM Observability product.\n * Uses a completion-only pattern where spans are emitted on span_ended events.\n *\n * Key features:\n * - Maps Mastra span types to Datadog span kinds\n * - Normalizes AI SDK v4/v5 token usage formats\n * - Formats LLM inputs/outputs as message arrays\n * - Flattens metadata into searchable tags\n * - Supports both agent and agentless modes\n */\n\nimport type {\n TracingEvent,\n AnyExportedSpan,\n ModelGenerationAttributes,\n ModelStepAttributes,\n} from '@mastra/core/observability';\nimport { SpanType } from '@mastra/core/observability';\nimport { omitKeys } from '@mastra/core/utils';\nimport { BaseExporter } from '@mastra/observability';\nimport type { BaseExporterConfig } from '@mastra/observability';\nimport tracer from 'dd-trace';\nimport { formatUsageMetrics } from './metrics';\nimport { ensureTracer, kindFor, toDate, formatInput, formatOutput } from './utils';\nimport type { DatadogSpanKind } from './utils';\n\n/**\n * LLMObs span options passed to dd-trace's llmobs.trace().\n * Note: endTime is not included because dd-trace does not honor it in trace options.\n * Instead, we call ddSpan.finish(endTimeMs) explicitly inside the trace callback.\n */\ninterface LLMObsSpanOptions {\n kind: DatadogSpanKind;\n name: string;\n sessionId?: string;\n userId?: string;\n mlApp?: string;\n modelName?: string;\n modelProvider?: string;\n startTime?: Date;\n}\n\n/**\n * Minimal per-trace context for user/session tagging.\n */\ninterface TraceContext {\n userId?: string;\n sessionId?: string;\n}\n\ntype TraceState = {\n buffer: Map<string, AnyExportedSpan>;\n contexts: Map<string, { ddSpan: any; exported?: { traceId: string; spanId: string } }>;\n rootEnded: boolean;\n treeEmitted: boolean; // Whether the initial span tree has been emitted\n createdAt: number;\n cleanupTimer?: ReturnType<typeof setTimeout>;\n maxLifetimeTimer?: ReturnType<typeof setTimeout>;\n};\n\n/**\n * Tree node representing a span and its children for recursive emission.\n */\ninterface SpanNode {\n span: AnyExportedSpan;\n children: SpanNode[];\n}\n\n/**\n * Maximum lifetime for a trace state entry (30 minutes).\n * This is a fallback cleanup mechanism for traces that never receive a root span\n * or have all spans marked as non-root, preventing unbounded memory growth.\n */\nconst MAX_TRACE_LIFETIME_MS = 30 * 60 * 1000;\n\n/**\n * Regular cleanup interval for trace state entries (1 minute).\n */\nconst REGULAR_CLEANUP_INTERVAL_MS = 1 * 60 * 1000;\n\n/**\n * Configuration options for the Datadog LLM Observability exporter.\n */\nexport interface DatadogExporterConfig extends BaseExporterConfig {\n /**\n * Datadog API key. Required (agentless mode is the default).\n * Falls back to DD_API_KEY environment variable.\n */\n apiKey?: string;\n\n /**\n * ML application name for grouping traces.\n * Required - falls back to DD_LLMOBS_ML_APP environment variable.\n */\n mlApp?: string;\n\n /**\n * Datadog site (e.g., 'datadoghq.com', 'datadoghq.eu').\n * Falls back to DD_SITE environment variable, defaults to 'datadoghq.com'.\n */\n site?: string;\n\n /**\n * Service name for the application.\n * Falls back to mlApp if not specified.\n */\n service?: string;\n\n /**\n * Environment name (e.g., 'production', 'staging').\n * Falls back to DD_ENV environment variable.\n */\n env?: string;\n\n /**\n * Use agentless mode (direct HTTPS intake without local Datadog Agent).\n * Defaults to true for consistency with other Mastra exporters.\n * Set to false to use a local Datadog Agent instead.\n * Falls back to DD_LLMOBS_AGENTLESS_ENABLED environment variable.\n */\n agentless?: boolean;\n\n /**\n * Enable dd-trace automatic integrations.\n * Defaults to false to avoid unexpected instrumentation.\n */\n integrationsEnabled?: boolean;\n}\n\n/**\n * Datadog LLM Observability Exporter for Mastra.\n *\n * Exports observability data to Datadog's LLM Observability product using\n * a completion-only pattern where spans are emitted on span_ended events.\n */\nexport class DatadogExporter extends BaseExporter {\n name = 'datadog';\n\n private config: Required<Pick<DatadogExporterConfig, 'mlApp' | 'site'>> & DatadogExporterConfig;\n private traceContext = new Map<string, TraceContext>();\n private traceState = new Map<string, TraceState>();\n\n constructor(config: DatadogExporterConfig = {}) {\n super(config);\n\n // Resolve configuration from config object and environment variables\n const mlApp = config.mlApp ?? process.env.DD_LLMOBS_ML_APP;\n const apiKey = config.apiKey ?? process.env.DD_API_KEY;\n const site = config.site ?? process.env.DD_SITE ?? 'datadoghq.com';\n const env = config.env ?? process.env.DD_ENV;\n\n // Default to agentless mode (true) for consistency with other Mastra exporters\n // Only disable if explicitly set to false via config or env var\n const envAgentless = process.env.DD_LLMOBS_AGENTLESS_ENABLED?.toLowerCase();\n const agentless = config.agentless ?? (envAgentless === 'false' || envAgentless === '0' ? false : true);\n\n // Validate required configuration\n if (!mlApp) {\n this.setDisabled(`Missing required mlApp. Set DD_LLMOBS_ML_APP environment variable or pass mlApp in config.`);\n this.config = config as any;\n return;\n }\n\n if (agentless && !apiKey) {\n this.setDisabled(\n `Missing required apiKey for agentless mode. Set DD_API_KEY environment variable or pass apiKey in config.`,\n );\n this.config = config as any;\n return;\n }\n\n this.config = { ...config, mlApp, site, apiKey, agentless, env };\n\n // Initialize tracer and enable LLM Observability\n ensureTracer({\n mlApp,\n site,\n apiKey,\n agentless,\n service: config.service,\n env,\n integrationsEnabled: config.integrationsEnabled,\n });\n\n this.logger.info('Datadog exporter initialized', { mlApp, site, agentless });\n }\n\n /**\n * Main entry point for tracing events from Mastra.\n */\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (this.isDisabled || !(tracer as any).llmobs) return;\n\n try {\n const span = event.exportedSpan;\n\n // Handle event spans (zero-duration spans) - buffer like regular spans for parent-first emission\n if (span.isEvent) {\n if (event.type === 'span_started') {\n this.captureTraceContext(span);\n this.enqueueSpan(span); // Route through buffer for proper parent context\n }\n return; // Skip span_updated and span_ended for events\n }\n\n // Handle regular spans based on event type\n switch (event.type) {\n case 'span_started':\n this.captureTraceContext(span);\n return;\n\n case 'span_updated':\n // No-op: completion-only pattern ignores mid-span updates\n return;\n\n case 'span_ended':\n this.enqueueSpan(span);\n return;\n }\n } catch (error) {\n this.logger.error('Datadog exporter error', {\n error,\n eventType: event.type,\n spanId: event.exportedSpan?.id,\n spanName: event.exportedSpan?.name,\n });\n }\n }\n\n /**\n * Captures user/session context from root spans for tagging all spans in the trace.\n */\n private captureTraceContext(span: AnyExportedSpan): void {\n if (span.isRootSpan && !this.traceContext.has(span.traceId)) {\n this.traceContext.set(span.traceId, {\n userId: span.metadata?.userId,\n sessionId: span.metadata?.sessionId,\n });\n }\n }\n\n /**\n * Queue span until its parent context is available, then emit spans parent-first.\n */\n private enqueueSpan(span: AnyExportedSpan): void {\n const state = this.getOrCreateTraceState(span.traceId);\n if (span.isRootSpan) {\n state.rootEnded = true;\n }\n\n state.buffer.set(span.id, span);\n this.tryEmitReadySpans(span.traceId);\n }\n\n /**\n * Builds annotations object for llmobs.annotate().\n * Uses dd-trace's expected property names: inputData, outputData, metadata, tags, metrics.\n */\n private buildAnnotations(span: AnyExportedSpan): Record<string, any> {\n const annotations: Record<string, any> = {};\n\n // Format and add input (dd-trace expects 'inputData')\n if (span.input !== undefined) {\n annotations.inputData = formatInput(span.input, span.type);\n }\n\n // Format and add output (dd-trace expects 'outputData')\n if (span.output !== undefined) {\n annotations.outputData = formatOutput(span.output, span.type);\n }\n\n // Add token usage metrics (only on MODEL_GENERATION or MODEL_STEP spans)\n if (span.type === SpanType.MODEL_GENERATION || span.type === SpanType.MODEL_STEP) {\n const usage = (span.attributes as ModelGenerationAttributes | ModelStepAttributes)?.usage;\n const metrics = formatUsageMetrics(usage);\n if (metrics) {\n annotations.metrics = metrics;\n }\n }\n\n // Forward span.attributes to metadata (minus known fields handled separately)\n // This ensures tool/workflow spans preserve custom attributes like other exporters\n const knownFields = ['usage', 'model', 'provider', 'parameters'];\n const otherAttributes = omitKeys((span.attributes ?? {}) as Record<string, any>, knownFields);\n\n // Merge span.metadata + remaining attributes into metadata\n const combinedMetadata = {\n ...span.metadata,\n ...otherAttributes,\n };\n if (Object.keys(combinedMetadata).length > 0) {\n annotations.metadata = combinedMetadata;\n }\n\n // Build tags from span.tags (user-provided string[] converted to object) and error info\n // Datadog annotation tags accept Record<string, any>, so we use proper types\n // The native span error status is also set via ddSpan.setTag('error', true) in emitSpan()\n const tags: Record<string, any> = {};\n\n // Convert span.tags (string[]) to object format\n // Tags in \"key:value\" format (e.g. \"instance_name:career-scout-api\") are split into { key: \"value\" }\n // Tags without a colon (e.g. \"production\") are set as { tag: true } (preserving existing behavior)\n if (span.tags?.length) {\n for (const tag of span.tags) {\n const colonIndex = tag.indexOf(':');\n if (colonIndex > 0) {\n tags[tag.substring(0, colonIndex)] = tag.substring(colonIndex + 1);\n } else {\n tags[tag] = true;\n }\n }\n }\n\n // Add error info as consolidated tags\n if (span.errorInfo) {\n tags.error = true;\n tags.errorInfo = {\n message: span.errorInfo.message,\n ...(span.errorInfo.id ? { id: span.errorInfo.id } : {}),\n ...(span.errorInfo.domain ? { domain: span.errorInfo.domain } : {}),\n ...(span.errorInfo.category ? { category: span.errorInfo.category } : {}),\n };\n }\n\n if (Object.keys(tags).length > 0) {\n annotations.tags = tags;\n }\n\n return annotations;\n }\n\n /**\n * Force flush any buffered spans without shutting down the exporter.\n * This is useful in serverless environments where you need to ensure spans\n * are exported before the runtime instance is terminated.\n */\n async flush(): Promise<void> {\n if (this.isDisabled || !(tracer as any).llmobs) return;\n\n // Flush any pending data to Datadog\n if (tracer.llmobs?.flush) {\n try {\n await tracer.llmobs.flush();\n this.logger.debug('Datadog llmobs flushed');\n } catch (e) {\n this.logger.error('Error flushing llmobs', { error: e });\n }\n } else if ((tracer as any).flush) {\n try {\n await (tracer as any).flush();\n this.logger.debug('Datadog tracer flushed');\n } catch (e) {\n this.logger.error('Error flushing tracer', { error: e });\n }\n }\n }\n\n /**\n * Gracefully shuts down the exporter.\n */\n async shutdown(): Promise<void> {\n // Cancel all pending cleanup timers and clear state FIRST\n for (const [traceId, state] of this.traceState) {\n if (state.cleanupTimer) {\n clearTimeout(state.cleanupTimer);\n }\n if (state.maxLifetimeTimer) {\n clearTimeout(state.maxLifetimeTimer);\n }\n if (state.buffer.size > 0) {\n this.logger.warn('Shutdown with pending spans', {\n traceId,\n pendingCount: state.buffer.size,\n spanIds: Array.from(state.buffer.keys()),\n });\n }\n }\n this.traceState.clear();\n\n // Flush any pending data\n await this.flush();\n\n // Disable LLM Observability\n if (tracer.llmobs?.disable) {\n try {\n tracer.llmobs.disable();\n } catch (e) {\n this.logger.error('Error disabling llmobs', { error: e });\n }\n }\n\n // Clear local state\n this.traceContext.clear();\n\n await super.shutdown();\n }\n\n /**\n * Retrieve or initialize trace state for buffering and parent tracking.\n */\n private getOrCreateTraceState(traceId: string): TraceState {\n const existing = this.traceState.get(traceId);\n if (existing) {\n if (existing.cleanupTimer) {\n clearTimeout(existing.cleanupTimer);\n existing.cleanupTimer = undefined;\n }\n return existing;\n }\n\n const created: TraceState = {\n buffer: new Map<string, AnyExportedSpan>(),\n contexts: new Map<string, { ddSpan: any; exported?: { traceId: string; spanId: string } }>(),\n rootEnded: false,\n treeEmitted: false,\n createdAt: Date.now(),\n cleanupTimer: undefined,\n maxLifetimeTimer: undefined,\n };\n\n // Schedule fallback cleanup after max lifetime to prevent memory leaks\n // when traces never receive a root span or all spans are non-root\n const maxLifetimeTimer = setTimeout(() => {\n const state = this.traceState.get(traceId);\n if (state) {\n if (state.buffer.size > 0 || state.contexts.size > 0) {\n this.logger.warn('Discarding trace due to max lifetime exceeded', {\n traceId,\n bufferedSpans: state.buffer.size,\n emittedSpans: state.contexts.size,\n lifetimeMs: Date.now() - state.createdAt,\n });\n }\n if (state.cleanupTimer) {\n clearTimeout(state.cleanupTimer);\n }\n this.traceState.delete(traceId);\n this.traceContext.delete(traceId);\n }\n }, MAX_TRACE_LIFETIME_MS);\n // Prevent the timer from keeping the process alive\n (maxLifetimeTimer as any).unref?.();\n created.maxLifetimeTimer = maxLifetimeTimer;\n\n this.traceState.set(traceId, created);\n return created;\n }\n\n /**\n * Attempt to emit spans from the buffer.\n *\n * Two modes of operation:\n * 1. Initial tree emission: When root span ends and tree hasn't been emitted yet,\n * build a tree from all buffered spans and emit recursively using nested\n * llmobs.trace() calls. This ensures proper parent-child relationships in Datadog.\n * 2. Late-arriving spans: After the tree has been emitted, emit individual spans\n * with their parent context for proper linking.\n */\n private tryEmitReadySpans(traceId: string): void {\n const state = this.traceState.get(traceId);\n if (!state) return;\n\n // If tree hasn't been emitted yet, wait for root and emit as tree\n if (!state.treeEmitted) {\n // Wait until the root span has ended before emitting any spans\n if (!state.rootEnded) return;\n\n // Build tree and emit recursively\n const tree = this.buildSpanTree(state.buffer);\n if (tree) {\n this.emitSpanTree(tree, state);\n }\n\n // Clear the buffer and mark tree as emitted\n state.buffer.clear();\n state.treeEmitted = true;\n } else {\n // Tree already emitted - handle late-arriving spans individually\n // Use the old parent-first emission pattern for these\n let emitted = false;\n do {\n emitted = false;\n for (const [spanId, span] of state.buffer) {\n const parentCtx = span.parentSpanId ? state.contexts.get(span.parentSpanId) : undefined;\n if (span.parentSpanId && !parentCtx) {\n continue;\n }\n\n this.emitSingleSpan(span, state, parentCtx?.ddSpan);\n state.buffer.delete(spanId);\n emitted = true;\n }\n } while (emitted);\n }\n\n // Schedule cleanup if root has ended and buffer is empty\n if (state.rootEnded && state.buffer.size === 0 && !state.cleanupTimer) {\n const timer = setTimeout(() => {\n const currentState = this.traceState.get(traceId);\n if (currentState) {\n if (currentState.buffer.size > 0) {\n this.logger.warn('Discarding orphaned spans during cleanup', {\n traceId,\n orphanedCount: currentState.buffer.size,\n spanIds: Array.from(currentState.buffer.keys()),\n });\n }\n // Clear the max lifetime timer since normal cleanup is handling this\n if (currentState.maxLifetimeTimer) {\n clearTimeout(currentState.maxLifetimeTimer);\n }\n }\n this.traceState.delete(traceId);\n this.traceContext.delete(traceId);\n }, REGULAR_CLEANUP_INTERVAL_MS);\n // Prevent the timer from keeping the process alive\n (timer as any).unref?.();\n state.cleanupTimer = timer;\n }\n }\n\n /**\n * Builds a tree structure from buffered spans based on parentSpanId relationships.\n * Returns the root node of the tree, or undefined if no root span is found.\n */\n private buildSpanTree(buffer: Map<string, AnyExportedSpan>): SpanNode | undefined {\n // Create nodes for all spans\n const nodes = new Map<string, SpanNode>();\n let rootNode: SpanNode | undefined;\n\n for (const span of buffer.values()) {\n nodes.set(span.id, { span, children: [] });\n }\n\n // Build parent-child relationships\n for (const node of nodes.values()) {\n if (node.span.isRootSpan) {\n rootNode = node;\n } else if (node.span.parentSpanId) {\n const parentNode = nodes.get(node.span.parentSpanId);\n if (parentNode) {\n parentNode.children.push(node);\n } else {\n // Orphaned span - parent not in buffer, treat as root-level\n // This shouldn't happen normally but handles edge cases\n this.logger.warn('Orphaned span detected during tree build', {\n spanId: node.span.id,\n parentSpanId: node.span.parentSpanId,\n traceId: node.span.traceId,\n });\n }\n }\n }\n\n // Sort children by start time for consistent ordering\n for (const node of nodes.values()) {\n node.children.sort((a, b) => {\n const aTime =\n a.span.startTime instanceof Date ? a.span.startTime.getTime() : new Date(a.span.startTime).getTime();\n const bTime =\n b.span.startTime instanceof Date ? b.span.startTime.getTime() : new Date(b.span.startTime).getTime();\n return aTime - bTime;\n });\n }\n\n return rootNode;\n }\n\n /**\n * Builds LLMObs span options from a Mastra span.\n * Handles trace context, timestamps, and conditional model information for LLM spans.\n */\n private buildSpanOptions(span: AnyExportedSpan): { traceOptions: LLMObsSpanOptions; endTimeMs: number } {\n const traceCtx = this.traceContext.get(span.traceId) || {\n userId: span.metadata?.userId,\n sessionId: span.metadata?.sessionId,\n };\n\n const kind = kindFor(span.type);\n const attrs = span.attributes as ModelGenerationAttributes | undefined;\n\n const startTime = toDate(span.startTime);\n // Event spans are point-in-time markers; use startTime for endTime if not set (zero duration)\n // Regular spans fall back to current time if endTime is not set\n const endTime = span.endTime ? toDate(span.endTime) : span.isEvent ? startTime : new Date();\n\n return {\n traceOptions: {\n kind,\n name: span.name,\n sessionId: traceCtx.sessionId,\n userId: traceCtx.userId,\n startTime,\n ...(kind === 'llm' && attrs?.model ? { modelName: attrs.model } : {}),\n ...(kind === 'llm' && attrs?.provider ? { modelProvider: attrs.provider } : {}),\n },\n // endTime as milliseconds for ddSpan.finish() — dd-trace's llmobs.trace() does not\n // honor endTime in options, so we must call finish(ms) explicitly on the span.\n endTimeMs: endTime.getTime(),\n };\n }\n\n /**\n * Recursively emits a span tree using nested llmobs.trace() calls.\n * This ensures parent-child relationships are properly established in Datadog\n * because child spans are created while their parent span is active in scope.\n */\n private emitSpanTree(node: SpanNode, state: TraceState): void {\n const span = node.span;\n const { traceOptions, endTimeMs } = this.buildSpanOptions(span);\n\n // Use nested llmobs.trace() calls - children are emitted INSIDE the parent's callback\n // This ensures the Datadog SDK automatically establishes parent-child relationships\n tracer.llmobs.trace(traceOptions as any, (ddSpan: any) => {\n // Annotate this span (must happen before finish — annotate throws on finished spans)\n const annotations = this.buildAnnotations(span);\n if (Object.keys(annotations).length > 0) {\n tracer.llmobs.annotate(ddSpan, annotations);\n }\n\n // Set native Datadog error status for proper UI highlighting\n if (span.errorInfo) {\n ddSpan.setTag('error', true);\n }\n\n // Store context for potential evaluation submissions\n const exported = tracer.llmobs.exportSpan ? tracer.llmobs.exportSpan(ddSpan) : undefined;\n state.contexts.set(span.id, { ddSpan, exported });\n\n // Recursively emit children INSIDE this span's callback\n // This is the key to establishing proper parent-child relationships\n for (const child of node.children) {\n this.emitSpanTree(child, state);\n }\n\n // Explicitly finish with the correct end time. dd-trace's llmobs.trace() does not\n // honor endTime in span options — it auto-finishes with Date.now() when the callback\n // returns. By calling finish() here first, the auto-finish becomes a no-op (dd-trace\n // skips finish if _duration is already set).\n if (typeof ddSpan.finish === 'function') {\n ddSpan.finish(endTimeMs);\n }\n });\n }\n\n /**\n * Emit a single span with the proper Datadog parent context.\n * Used for late-arriving spans after the main tree has been emitted.\n */\n private emitSingleSpan(span: AnyExportedSpan, state: TraceState, parent?: any) {\n const { traceOptions, endTimeMs } = this.buildSpanOptions(span);\n\n const runTrace = () =>\n tracer.llmobs.trace(traceOptions as any, (ddSpan: any) => {\n const annotations = this.buildAnnotations(span);\n if (Object.keys(annotations).length > 0) {\n tracer.llmobs.annotate(ddSpan, annotations);\n }\n\n // Set native Datadog error status for proper UI highlighting\n if (span.errorInfo) {\n ddSpan.setTag('error', true);\n }\n\n const exported = tracer.llmobs.exportSpan ? tracer.llmobs.exportSpan(ddSpan) : undefined;\n state.contexts.set(span.id, { ddSpan, exported });\n\n // Explicitly finish with the correct end time (see emitSpanTree for details)\n if (typeof ddSpan.finish === 'function') {\n ddSpan.finish(endTimeMs);\n }\n });\n\n if (parent) {\n tracer.scope().activate(parent, runTrace);\n } else {\n runTrace();\n }\n }\n}\n"]}
|
package/dist/tracing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,YAAY,EAIb,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,YAAY,EAIb,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AA4DhE;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,IAAI,SAAa;IAEjB,OAAO,CAAC,MAAM,CAAkF;IAChG,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,UAAU,CAAiC;gBAEvC,MAAM,GAAE,qBAA0B;IA6C9C;;OAEG;cACa,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCvE;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAS3B;;OAEG;IACH,OAAO,CAAC,WAAW;IAUnB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAyExB;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB5B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC/B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAgD7B;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;IA+DzB;;;OAGG;IACH,OAAO,CAAC,aAAa;IA2CrB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA8BxB;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAsCpB;;;OAGG;IACH,OAAO,CAAC,cAAc;CA8BvB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/datadog",
|
|
3
|
-
"version": "1.0.8
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Datadog LLM Observability exporter for Mastra - exports tracing data to Datadog's LLM Observability product",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"dd-trace": "^5.89.0",
|
|
28
|
-
"@mastra/observability": "1.5.1
|
|
28
|
+
"@mastra/observability": "1.5.1"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "22.19.15",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"tsup": "^8.5.1",
|
|
36
36
|
"typescript": "^5.9.3",
|
|
37
37
|
"vitest": "4.0.18",
|
|
38
|
-
"@
|
|
39
|
-
"@internal/types-builder": "0.0.
|
|
40
|
-
"@
|
|
38
|
+
"@internal/lint": "0.0.73",
|
|
39
|
+
"@internal/types-builder": "0.0.48",
|
|
40
|
+
"@mastra/core": "1.15.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@mastra/core": ">=1.0.0-0 <2.0.0-0",
|