Span
Span attributes, common span names, and OpenTelemetry attribute conventions.
A Span represents a single operation within an agent execution. Spans form a parent-child hierarchy within a trace, allowing you to understand the execution flow.
Span Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
span_id | str | Required | Unique span identifier |
trace_id | str | Required | Unique identifier of the trace that contains this span |
parent_span_id | Optional[str] | Required | Parent span ID (None for root spans) |
name | str | Required | Operation name (e.g., OpenAIChat.invoke, get_weather) |
span_kind | str | Required | Span kind (e.g., INTERNAL, CLIENT) |
status_code | str | Required | Status: OK, ERROR, or UNSET |
status_message | Optional[str] | Required | Status message (typically error details, None when there is none) |
duration_ms | int | Required | Execution time in milliseconds |
start_time | datetime | Required | When the span started |
end_time | datetime | Required | When the span completed |
attributes | Dict[str, Any] | Required | OpenTelemetry attributes (tokens, params, etc.) |
created_at | datetime | Required | When the span record was created |
Common Span Names
Configured instrumentation creates spans for operations such as those below. Exact names vary with the instrumentor and synchronous or asynchronous execution path:
| Span Name Pattern | Description |
|---|---|
{AgentName}.run | Agent execution |
{TeamName}.run | Team execution |
{ModelName}.invoke | LLM model call |
{tool_name} | Tool execution |
Attributes by Operation Type
The attributes field contains OpenTelemetry semantic attributes that vary by operation:
LLM Spans
| Attribute | Description |
|---|---|
llm.token_count.prompt | Input token count |
llm.token_count.completion | Output token count |
llm.model_name | Model identifier |
llm.provider | Model provider name |
Tool Spans
| Attribute | Description |
|---|---|
tool.name | Tool function name |
tool.parameters | Tool input parameters (JSON) |
Methods
The following method snippets assume an existing span object or its serialized data. Import the type with from agno.tracing.schemas import Span.
to_dict()
Convert the span to a dictionary.
span_dict = span.to_dict()Returns: dict
from_dict()
Create a span from a dictionary.
span = Span.from_dict(data)Parameters:
data(dict): Dictionary containing span data
Returns: Span
Usage
First follow the tracing setup, including its OpenTelemetry and instrumentation dependencies, to record a run in tmp/traces.db. Run this query from the same working directory after spans have been exported. Creating SqliteDb alone does not enable instrumentation or populate traces. For a separate query environment, install uv pip install -U agno sqlalchemy opentelemetry-sdk.
from agno.db.sqlite import SqliteDb
db = SqliteDb(db_file="tmp/traces.db")
# Get the most recent trace, then load its spans
traces, _ = db.get_traces(limit=1)
if not traces:
raise RuntimeError("No traces found")
trace_id = traces[0].trace_id
spans = db.get_spans(trace_id=trace_id)
for span in spans:
print(f"Span: {span.name}")
print(f" Duration: {span.duration_ms}ms")
print(f" Status: {span.status_code}")
# Check for token usage (LLM spans)
if span.attributes:
tokens = span.attributes.get("llm.token_count.completion")
if tokens:
print(f" Tokens: {tokens}")Building a Span Tree
def print_span_tree(spans, parent_id=None, indent=0):
"""Recursively print spans as a tree."""
for span in spans:
if span.parent_span_id == parent_id:
prefix = " " * indent + ("└─ " if indent > 0 else "")
print(f"{prefix}{span.name} ({span.duration_ms}ms)")
print_span_tree(spans, span.span_id, indent + 1)
# Print the spans loaded above
print_span_tree(spans)See Also
- Trace Reference - Complete execution trace
- DB Functions - Query functions for traces and spans