Span
A single operation within a trace: one LLM call, one tool invocation, one retrieval. The granular unit of observability data.
Last updated: April 26, 2026
What Is Span?
A span represents one unit of work inside a trace. In OpenTelemetry a span has a name, a parent span id (empty for the root span), start and end timestamps, a span context holding the trace id and span id, attributes, optional events and links, and a status of Unset, Ok or Error. For agents, the useful spans follow the steps of a run: the whole agent invocation, each model call, each tool execution and each retrieval. Spans nest, so a model call and the tool call it triggered both appear as children of the agent span, and the resulting tree shows where time and tokens went.
The OpenTelemetry GenAI semantic conventions name these spans, and their status is Development as of October 2026. A model call is named with the operation and model, for example chat followed by the model name, with attributes such as gen_ai.request.model and gen_ai.usage.input_tokens. Tool execution is execute_tool followed by the tool name, and an agent run is invoke_agent followed by the agent name. Prompt text is an Opt In attribute because it can hold personal data.
Code Example
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
tracer = provider.get_tracer("support-agent")
with tracer.start_as_current_span("invoke_agent support_bot") as agent:
agent.set_attribute("gen_ai.operation.name", "invoke_agent")
agent.set_attribute("gen_ai.agent.name", "support_bot")
with tracer.start_as_current_span("chat example-model") as llm:
llm.set_attribute("gen_ai.operation.name", "chat")
llm.set_attribute("gen_ai.provider.name", "anthropic")
llm.set_attribute("gen_ai.request.model", "example-model")
llm.set_attribute("gen_ai.usage.input_tokens", 812)
llm.set_attribute("gen_ai.usage.output_tokens", 64)
with tracer.start_as_current_span("execute_tool get_order_status") as tool:
tool.set_attribute("gen_ai.operation.name", "execute_tool")
tool.set_attribute("gen_ai.tool.name", "get_order_status")Run it after pip install opentelemetry-sdk. The two child spans print with the agent span as their parent. The model name and token counts are placeholders.
When Should You Use Span?
Use the OpenTelemetry span model wherever possible. LangSmith and Phoenix both accept traces over OpenTelemetry, so spans you emit are not tied to one vendor. One span per step is the right grain. Common mistakes are forgetting to end a span, which a context manager prevents, and losing the parent context across threads or queues, which leaves orphan spans.
Common Questions
What is the difference between a trace and a span?
A trace is the whole path of one request or agent run. It is made of spans that share one trace id. Each span covers one operation, and its parent id links it into a tree.
Sources
Related Terms
Building with Span?
I've shipped this pattern in real production systems. If you want a second pair of eyes on your architecture, that's what I do.