The Atomic Unit of Work: The Span
A Span represents a single, distinct operation within your system — one unit of work with a clear beginning and end. It is the fundamental building block of distributed tracing.
Every span carries:
- A name describing the operation (e.g.,
http.request,db.query,cache.get). - A start timestamp and an end timestamp, which together define its duration.
- A Span ID — a unique identifier for this specific operation.
- A Trace ID — the identifier shared by every span in the same request journey.
- A Parent Span ID — the ID of the span that triggered this one, establishing the call hierarchy.
- Attributes (also called tags) — key-value metadata like
http.status_code=200,db.statement="SELECT * FROM users WHERE id=42", orservice.name="payment-service". - Events — timestamped annotations within the span (covered in the next section).
- A Status —
OK,ERROR, orUNSET.
The Full Picture: The Trace
A Trace is a directed acyclic graph (DAG) of spans connected by their parent/child relationships. It represents the entire end-to-end lifecycle of a single request, from the moment it enters your system to the moment a response is returned.
Every span in a trace shares the same Trace ID. The root span — the one with no parent — is typically created by the entry point of your system (an API gateway or a frontend service). Every downstream call creates a child span that references the root or an intermediate span as its parent.
When you view a trace in a visualization tool like Jaeger or Grafana Tempo, it is rendered as a Gantt chart — a horizontal timeline where each row is a span, and the width of the bar represents its duration. This makes it instantly obvious which service took the longest, which calls happened in parallel, and where time was wasted waiting.