Distributed tracing is the capture of a request's lifecycle as it traverses service boundaries. Each segment of work is a span, and the entire tree of spans for a single request is the trace.
Tracing relies on three pillars: Propagation, Instrumentation, and Aggregation.
The traceparent header (W3C standard) must be passed between all services. It prevents "trace fragmentation" where a single request appears as disconnected spans.
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
ver trace-id (32 hex) span-id (16 hex) flags
The industry standard is OpenTelemetry (OTel). Manual instrumentation is required for business-critical operations that cross multiple async or framework boundaries.
Concrete Example (Java/OpenTelemetry):
// Manual span creation for a complex business operation
Span span = tracer.spanBuilder("process-order")
.setAttribute("order.id", order.getId())
.setAttribute("customer.tier", customer.getTier())
.startSpan();
try (Scope scope = span.makeCurrent()) {
// Perform work...
validateOrder(order);
} catch (Exception e) {
span.setStatus(StatusCode.ERROR, "Order validation failed");
span.recordException(e);
throw e;
} finally {
span.end();
}
Tracing generates massive data volumes. At 1,000 requests per second (RPS), with 20 spans per request and 500 bytes per span, the daily uncompressed volume is:
Do not span every function. Focus on:
| Pattern | Detection | Fix |
|---|---|---|
| N+1 Queries | Trace shows many small, sequential DB spans. | Implement batching or joins. |
| Silent Retries | Multiple identical child spans for one logical request. | Check retry policy; ensure idempotency. |
| Clock Skew | Child span appears to start before parent. | Sync via NTP/PTP; use tracer-specific skew correction. |
| Gaps in Timeline | Large time gaps between spans. | Uninstrumented work (CPU/GC) or network latency. |
trace_id field to jump from an error log to its trace.