Skip to main content
When we talk about distributed tracing with OpenTelemetry, everything begins with spans. A span records a single operation: what happened, when it started and ended, and contextual details that help you understand behavior and performance. Spans link together into traces to tell the full story of a request as it traverses services. So, a trace represents the full journey
The image depicts a funnel diagram representing a trace composed of several spans labeled A to H, with an arrow indicating the flow from top to bottom.
of a request across multiple services. Each bar here is a span — a discrete operation — and the connections between them form the trace. The root span starts the trace; child spans represent downstream operations. Together, they form an end-to-end timeline of work. A span represents a single operation within a trace, clearly marked
The image explains the concept of a "Span," describing it as a fundamental unit of work within a trace with a defined start and end.
with a defined start and end time. A span is the fundamental unit of work: combine many spans and you reconstruct the request lifecycle.

What can a span represent?

Think of a span as one measurable piece of work inside your application. Typical examples include:
  • A function or internal business-logic execution.
  • An outgoing HTTP/gRPC call (for example, fetching product details from another service).
  • A database operation such as a SQL query.
  • File I/O, encryption/decryption, or image compression.
  • Lightweight work like JSON parsing or payload validation.
  • Message processing (consuming a single Kafka message).
  • UI rendering (for instance, a React component render).
  • Background tasks, retries, authentication flows, and notification delivery.
Choose spans around the operations you care about measuring (latency and errors). Too coarse and you miss detail; too fine and you generate noise and overhead. This table shows practical examples and typical measurements.
The image is a table showing different span operations, what they measure in duration, possible exceptions, span type, and status for each operation in a monitoring or tracing system.
Additional examples include parsing JSON payloads (measuring payload handling), internal business functions (execution time and logic errors), external API calls (network latency and authentication failures), and cache lookups (e.g., Redis key lookup latency and misses).
The image is a table explaining what a span can represent in a computing context, detailing the span operation, what it measures, possible exceptions, span kind, and status. Different operations like JSON parsing, internal functions, and external API calls are mentioned with their related exceptions and statuses.

Span structure: what a span includes

An OpenTelemetry span captures a consistent set of fields that let you reason about the operation and how it relates to other work:
  • The span name (human-readable).
  • The span ID and the parent span ID (parent_id is null for a root span).
  • Start and end timestamps.
  • The span context (the trace identifiers that propagate across services).
  • Attributes (key/value pairs that add descriptive metadata).
  • Events (time-stamped annotations, commonly used to record exceptions or milestones).
  • Links (optional references to other spans or traces).
  • Span status (for example, OK, ERROR, or UNSET).
Resource attributes indicate where the span originated (for example, service.name). The schema_url can describe the semantics of attribute keys.
The image lists components included in a span in OpenTelemetry, such as Name, Span ID, Parent span ID, Timestamps, Span Context, Attributes, Span Events, and Span Links.

Example: a recorded span (JSON)

Below is a representative OpenTelemetry span encoded as JSON. It models a client span that performed an HTTP GET and recorded an event when the response arrived.
Key fields to note:
  • name: human-readable operation name.
  • context.trace_id and context.span_id: identifiers that link spans into traces.
  • kind: the span kind (for example, SpanKind.CLIENT or SpanKind.SERVER).
  • parent_id: links a span to its parent (or is null for the root).
  • start_time and end_time: timestamps; duration = end_time - start_time.
  • status.status_code: for example, OK, ERROR, or UNSET.
  • attributes: contextual key/value pairs (network info, DB statement, user id, etc.).
  • events: time-stamped events within the span (exceptions, response reception).
  • links: optional cross-trace relations, useful for batching or forks.
  • resource.attributes: metadata about the originating service (for example, service.name).
  • schema_url: optional pointer to attribute semantics.
A span marked with status.status_code: "OK" indicates success. When an exception occurs, it’s common to record the exception as an event and set the span status to ERROR.
Choose span granularity deliberately — capture operations you need for latency and error visibility. Avoid over-instrumentation (which creates noise and overhead) and under-instrumentation (which loses useful diagnostic detail).

Summary

  • A span captures one operation or unit of work with start/end times and contextual data.
  • Parent/child relationships and links join spans into traces that represent the end-to-end request journey.
  • Spans include IDs, timestamps, attributes, events, links, status, and resource metadata.
  • Be intentional about span boundaries: balance observability detail against system overhead.

Watch Video