What is a span in OpenTelemetry and what information does it contain?
Quick Answer
A span represents a single unit of work within a trace, such as an HTTP request, a database query, or a function call. Each span contains a name, trace ID, span ID, parent span ID, start and end timestamps, status, attributes (key-value metadata), and events (timestamped annotations).
Detailed Answer
Think of a span as a single entry in a detailed travel itinerary. If a trace is the complete trip from New York to London, then each span is a leg: taxi to JFK airport, check-in at the counter, flight to Heathrow, customs processing. Each leg has a start time, end time, and notes about what happened. Some legs contain sub-legs, like the flight leg containing takeoff, cruising, and landing as child spans.
A span is the fundamental building block of distributed tracing in OpenTelemetry. Every span has a unique span ID and belongs to a trace identified by a trace ID. When checkout-service receives a user request, it creates a root span. When checkout-service calls order-processing-service, a new child span is created with the checkout-service span as its parent. This parent-child relationship forms a tree structure that visualizes the entire request flow. The span's start and end timestamps tell you exactly how long each operation took, making it straightforward to identify which service or operation is the bottleneck.
Each span carries several categories of information. The span name identifies the operation, like 'POST /api/orders' or 'SELECT orders WHERE user_id = ?' for a database query. Attributes are key-value pairs that add context: http.method=POST, http.status_code=200, db.system=postgresql, or custom attributes like order.total=149.99. The span kind indicates the role: CLIENT for outgoing calls, SERVER for incoming requests, PRODUCER for async message sends, CONSUMER for message processing, and INTERNAL for in-process operations. The status field indicates whether the operation succeeded (OK), encountered an error (ERROR), or is unset. When an error occurs, the status description provides a human-readable explanation.
Spans also support events and links. Events are timestamped annotations within a span, useful for recording notable moments without creating a child span. For example, a span in inventory-sync might record an event 'cache miss for SKU-45678' at timestamp T1 and 'fetched from database' at timestamp T2. Links connect spans across different traces, which is valuable for batch processing: a span in order-processing-service that processes 50 orders might link to the 50 individual order creation spans from checkout-service. Events and links are often overlooked by beginners but are essential for modeling real-world distributed systems.
In production, span attributes are critical for debugging. When payments-api returns a 500 error, the span attributes tell you the payment method (credit_card), the provider (stripe), the customer ID, and the error message. Platform teams typically define attribute naming conventions following OpenTelemetry semantic conventions, which standardize attribute names across services. For example, all HTTP spans use http.request.method instead of each team inventing their own attribute name. This standardization enables consistent querying across services: 'show me all spans where http.response.status_code >= 500' works across checkout-service, payments-api, and user-auth-service because they all use the same attribute names.