Distributed Tracing with OpenTelemetry: From Zero to Production
Set up distributed tracing with OpenTelemetry in Go — instrument your services, propagate context across network boundaries, and visualize traces in Jaeger.
In a microservices system, a single user request touches 5–10 services. When something is slow or broken, how do you know which service is responsible? Distributed tracing gives you the complete picture.
Core Concepts
- Trace: A complete end-to-end journey of one request through your system
- Span: A single operation within a trace (one HTTP call, one DB query)
- Context propagation: Passing trace metadata (trace ID, span ID) across service boundaries via headers
- Baggage: Key-value pairs that travel with the trace (e.g., user ID, request ID)
OpenTelemetry Setup in Go
Initialize the Tracer Provider
Instrument HTTP Handlers
Create Custom Spans
Propagate Context Across HTTP Calls
Docker Compose for Jaeger
Open http://localhost:16686 to see traces.
Production Sampling Strategy
For critical paths (payment, auth), use AlwaysSample. For high-volume health checks, use NeverSample.
What Good Traces Tell You
- Latency breakdown: Which service/query is slow?
- Error propagation: Where did the error originate?
- Dependency map: Which services call which?
- Bottlenecks: Sequential calls that could be parallelized
A single trace showing DB query: 2.3s out of a total: 2.5s request tells you exactly where to optimize — no guesswork.