Trace vs span
A span is one timed operation, such as a model call. A trace is the tree of spans for one request, and in an LLM app it covers one agent run.
A span is one timed operation. A trace is the tree of spans that together make up one request. In OpenTelemetry, spans are the building blocks of traces, and every span in a trace carries the same trace ID.
For an LLM application, an agent run is the trace, and each model call, tool call or sub-agent step inside it is a span. The rest of this page covers what lives on each, with the OpenTelemetry terms. For how context travels between services, see distributed tracing.
Side by side
| Trace | Span | |
|---|---|---|
| What it is | The “big picture of what happens when a request is made to an application” | “A unit of work or operation” |
| Has its own record | No, it is the set of spans that share a trace ID | Yes: name, parent span ID, start and end time, span context, attributes, events, links, status |
| Identified by | Trace ID | Span ID, plus its trace ID and parent span ID |
| Timing | Read from the root span | Its own start and end time |
| Error state | Read from the spans in it | Its own status: Unset, Error or Ok |
| Structure | A tree of spans | One node, linked to its parent |
The quotes and the span fields come from the OpenTelemetry traces docs.
What a span holds
A span is where the data is. The OpenTelemetry docs list its parts:
- A name, a parent span ID (empty for a root span), and start and end timestamps.
- A span context: an “immutable object on every span” holding the trace ID, span ID, trace flags and trace state.
- Attributes, which are key-value metadata.
- Span events, which the docs compare to “a structured log message (or annotation)” on the span.
- Span links, which “associate one span with one or more spans, implying a causal relationship.”
- A status.
Unsetmeans the span completed without an error,Errormeans an error occurred, andOkmeans a developer explicitly marked it successful.
Each span also has a kind. Client and server spans cover synchronous remote calls going out and coming in. Internal spans cover operations that do not cross a process boundary. Producer and consumer spans cover jobs created and processed asynchronously, as the traces docs define them.
How spans form a trace
The span context ties them together. Spans in one trace share the trace ID. A child span records its parent’s span ID, so the spans form a hierarchy, and the docs describe child spans as sub-operations. The span with no parent is the root, which spans the whole operation.
Nothing stores a trace as a separate object. It exists because spans point to each other and share an ID. That is why a lost parent link, such as a service that never extracted the incoming context, splits one request into two traces.
Trace and span for LLM agents
The OpenTelemetry GenAI conventions, marked Development as of November 2026, define span names for agent work. An agent run is an invoke_agent span (or invoke_workflow) of kind INTERNAL, create_agent is CLIENT, and plan is INTERNAL. The agent spans spec gives chat and generate_content as example operation names for model calls.
The conventions also say how the pieces nest. The LLM call that generates a plan should be a child of the plan span, and tool or task spans from that plan are typically siblings under the same invoke_agent span. A trace of one agent task is then a tree: the agent span at the root, with plan, model and tool spans beneath it. See agent tracing for how to build one and OpenTelemetry for LLMs for the conventions in more detail.
The unit you pick matters when you debug. A slow or wrong answer is a trace-level symptom, but the cause sits in a span, because timing and status live there: a model call with a long duration, or a tool call whose status is Error. Start at the trace to see the shape of the run, then open the span.
Trace, session and event in HoneyHive
Some tools use other words. HoneyHive’s docs say “a session maps to a trace and an event maps to a span.” A session is itself an event with event_type: "session" and no parent, and its child events carry the same session_id. Child events are typed model, tool or chain, and each links to its parent through parent_id.
To add your own spans, HoneyHive’s custom spans guide uses the @trace decorator, which captures a function’s inputs and outputs and nests decorated calls into a hierarchy. For the wider picture of recording and reading agent traces, see agent observability.
FAQ
What is the difference between a trace and a span?
A span is a single unit of work. A trace is the collection of spans that belong to one request, sharing a trace ID. OpenTelemetry calls spans the building blocks of traces.
Can a trace have only one span?
Yes. A trace with a single span is just a root span with no children. The root span, in OpenTelemetry's words, denotes "the beginning and end of the entire operation."
Is an LLM call a trace or a span?
A span. The OpenTelemetry GenAI agent conventions list operation names such as chat for model calls and nest the planning model call under a plan span, with the plan's tool spans under the same invoke_agent span. The agent run is the trace, and each model call is one span in it.
What is a session in LLM tracing?
It depends on the tool. In HoneyHive, a session is the root of the tree and maps to a trace, and each event maps to a span, per its tracing concepts.
Where do errors and latency show up, on the trace or the span?
On the span. Each span has its own start and end time and its own status (Unset, Error or Ok). You read a trace's total time from its root span.