The MutagenT SDK provides three levels of abstraction for manual tracing. Choose the one that fits your use case:
Approach
Best For
Effort
@trace() decorator
Class methods with automatic I/O capture
Lowest
withTrace() wrapper
Functions with manual enrichment via SpanHandle
Medium
startSpan() / endSpan()
Integration adapters, full manual control
Highest
All tracing functions are no-ops when tracing is not active, so you can safely leave instrumentation in place without runtime overhead when tracing is disabled. The @trace() decorator and withTrace() wrapper check for an existing tracing configuration only, while the low-level startSpan() / endSpan() API will additionally attempt lazy initialization from the MUTAGENT_API_KEY environment variable on first use.
A method decorator that wraps class methods with automatic span creation. It captures arguments as input, the return value as output, and sets the span status based on success or failure.Import:
import { trace } from "@mutagent/sdk/tracing";
Options:
interface TraceDecoratorOptions { kind: SpanKind; // Required -- the type of operation name?: string; // Span name (defaults to the method name) attributes?: Record<string, unknown>; // Custom attributes}
Behavior:
Captures method arguments as input.raw
Captures the return value as output.raw
Sets status: "ok" on successful return
Sets status: "error" with the error message on throw (re-throws the error)
Works with both synchronous and asynchronous methods
Preserves this context
Runs the method inside a span context, so nested @trace() calls or getCurrentSpan() calls see the correct parent
The @trace() decorator uses the legacy TypeScript decorator syntax (experimentalDecorators). Make sure your tsconfig.json includes "experimentalDecorators": true if you use this pattern.
Create and start a new span. If no trace is active, a new trace ID is generated. If a parent span exists in the current async context, the new span is automatically linked as a child.If tracing has not been explicitly initialized via initTracing(), startSpan() will attempt lazy initialization from the MUTAGENT_API_KEY environment variable (once per lifecycle).Import:
import { startSpan } from "@mutagent/sdk/tracing";
Signature:
function startSpan(options: SpanOptions): MutagentSpan | undefined;
Options:
interface SpanOptions { kind: SpanKind; // Required -- the type of operation name?: string; // Span name (defaults to kind) input?: SpanIO; // Structured input data attributes?: Record<string, unknown>; // Custom attributes parentSpanId?: string; // Explicit parent (overrides context)}
import { getCurrentTraceId } from "@mutagent/sdk/tracing";const traceId = getCurrentTraceId();// Useful for correlating logs with tracesconsole.log(`Processing request in trace: ${traceId}`);
Returns undefined if no trace is active or tracing is not initialized.
Run a function within the async context of a span. This makes the span visible to getCurrentSpan() and getCurrentTraceId() inside the function, and ensures any child spans created within are linked to this span as their parent.
import { startSpan, endSpan, runInSpanContext } from "@mutagent/sdk/tracing";const span = startSpan({ kind: "agent", name: "my-agent" });if (span) { const result = await runInSpanContext(span, async () => { // getCurrentSpan() returns `span` here // Any startSpan() calls here will have `span` as their parent return await doWork(); }); endSpan(span, { status: "ok", output: { raw: result } });}
If tracing is not initialized, the function runs directly without any context wrapping.
The HTTP payload format sent to POST /api/traces. Spans are grouped by trace ID. You do not construct this manually — the BatchCollector builds it automatically.
The MutagenT server exposes these REST endpoints for trace ingestion and retrieval. The SDK handles ingestion automatically via the BatchCollector, but you can also call these endpoints directly.All endpoints require workspace context via the x-workspace-id header and authentication via x-api-key (API key) or Authorization: Bearer (OAuth token).
The Python SDK provides the same low-level API with snake_case naming. Decorators and wrappers are not yet available in Python — use the low-level API directly.
from mutagent_tracing import ( init_tracing, shutdown_tracing, start_span, end_span, get_current_span, get_current_trace_id, SpanOptions, SpanEndOptions, SpanIO, SpanMetrics, SpanKind, SpanStatus,)init_tracing(api_key="mt_xxxxxxxxxxxx")# Create a spanspan = start_span(SpanOptions( kind=SpanKind.CHAIN, name="rag-pipeline", input=SpanIO(text="What is MutagenT?"),))if span: # Do work... result = generate_answer("What is MutagenT?") # End the span end_span(span, SpanEndOptions( status=SpanStatus.OK, output=SpanIO(text=result), metrics=SpanMetrics( model="gpt-4o", provider="openai", input_tokens=800, output_tokens=200, total_tokens=1000, ), ))shutdown_tracing()
Python context propagation uses contextvars, which works across async/await and threads. Parent-child linking is automatic when spans are nested within the same execution context.