Traces & Spans
What is a Trace?
A trace represents a complete unit of work — like handling a user request, processing a document, or running an agent workflow. Think of it as a timeline:| Property | Description |
|---|---|
traceId | Unique identifier (UUID) |
name | Human-readable name (optional) |
startTime / endTime | When the trace began and completed |
duration | Total time in milliseconds |
status | completed, error, or running |
spans | Array of child spans |
What is a Span?
A span represents a single operation within a trace — like an LLM call, tool execution, or retrieval step.| Property | Description |
|---|---|
spanId | Unique identifier |
traceId | Parent trace identifier |
parentSpanId | Parent span (for nesting) |
spanKind | Type of operation |
name | Operation name (e.g., model name, tool name) |
startTime / endTime | When operation began and completed |
durationMs | Duration in milliseconds |
input / output | Input and output data |
status | completed or error |
tokens | Token usage (for LLM spans) |
Span Types
| Type | Description | Convenience Method |
|---|---|---|
llm | LLM API calls | ctx.llmCall(model, fn) |
tool | Tool/function executions | ctx.executeTools(response, toolMap) or ctx.tool(name, fn) |
retriever | RAG retrieval operations | ctx.retriever(name, fn) |
embedding | Embedding generation | ctx.embedding(model, fn) |
agent | High-level agent orchestration | ctx.startSpan(SpanKind.AGENT, ...) |
chain | Pipeline/chain steps | ctx.startSpan(SpanKind.CHAIN, ...) |
custom | Any other operation | ctx.wrapInSpan(SpanKind.CUSTOM, ...) |
Trace Hierarchy
Traces contain spans organized in a tree structure:Best Practices
One trace per user request
One trace per user request
Create a new trace for each distinct user interaction. Don’t reuse trace IDs across requests.
Name traces descriptively
Name traces descriptively
Use names that describe the workflow:
process-customer-query, generate-report, analyze-document.Use appropriate span types
Use appropriate span types
Choose the span type that best represents the operation. This enables better filtering and analytics in the dashboard.
Always record tokens for LLM spans
Always record tokens for LLM spans
Token counts are essential for cost tracking and optimization.
End spans properly
End spans properly
Always call
span.end() even on errors. Use try/finally or convenience methods like ctx.llmCall() for automatic handling.Don't over-nest
Don't over-nest
Keep span depth reasonable (typically 3-5 levels max). Deep nesting makes traces hard to read.