Modern applications are rarely a single service anymore. A single user request might touch ten different microservices before a response comes back — and when something goes wrong, finding out where it broke is nearly impossible with logs and metrics alone. This is the exact problem distributed tracing was built to solve, and Jaeger is one of the most widely adopted tools for doing it.
This guide covers what distributed tracing is, how Jaeger works, how to set it up, and how to read your first trace — written for engineers who are completely new to the concept.
What Is Distributed Tracing?
Distributed tracing is a method of tracking a single request as it moves across multiple services, so you can see exactly where time was spent and where failures happened. Instead of looking at isolated logs from five different services, it gives you one connected timeline showing the full journey of that request, end to end.
Each request is represented as a trace, and each step within it — a database call, an API request, a function execution — is represented as a span. Spans are nested and connected by parent-child relationships, which is what lets a tracing tool reconstruct the full path a request took.
What Is Jaeger?
Jaeger is an open-source tracing system originally built by Uber and now part of the Cloud Native Computing Foundation (CNCF). It collects, stores, and visualizes traces from your services, giving you a clear picture of latency, bottlenecks, and errors across a distributed system.
It's especially popular in Kubernetes and microservices environments because it was designed from the ground up for systems where requests cross many service boundaries — which is exactly where traditional logging and monitoring fall short.
Why This Matters in DevOps
As systems move toward microservices, the biggest operational challenge shifts from "is the service up" to "why is this specific request slow." Tracing answers that question directly by showing:
- Which service in the chain is adding the most latency
- Where errors are actually originating, not just where they surfaced
- How services depend on each other in practice, not just on paper
- Whether a slowdown is caused by application code, a database, or a downstream API call
Without this visibility, debugging a slow request across ten services usually means manually correlating timestamps across ten different log files. With the right tooling, it becomes a single visual timeline instead.
Core Concepts to Know First
Before setting anything up, it helps to understand the vocabulary you'll see throughout the UI and documentation.
Trace
A trace represents the complete journey of a single request through your system, from the moment it enters to the moment a response is returned.
Span
A span is one unit of work within that journey — for example, an API call, a database query, or a function execution. Every trace is made up of one or more spans, nested to represent parent-child relationships between operations.
Span Context
Span context carries the trace identifier and span identifier across service boundaries, which is what allows spans from different services to be stitched together into one coherent view.
Tags and Logs
Tags are key-value pairs attached to a span (like an HTTP status code or a user ID), and logs are timestamped events within a span. Both add debugging detail without needing to jump into separate log files.
Architecture Overview
The system is made up of a few core components working together:
- Client (or SDK) — instrumented into your application to generate spans as requests move through the code
- Agent — a lightweight daemon that receives spans from the client and forwards them onward
- Collector — receives spans from agents, validates them, and writes them to storage
- Storage backend — typically Elasticsearch, Cassandra, or Kafka, used to persist the data
- Query service and UI — retrieves records from storage and renders them visually so you can inspect them
In most modern setups, applications are instrumented using OpenTelemetry rather than native client libraries, since OpenTelemetry has become the standard instrumentation layer while Jaeger works as a backend that receives that data. If you haven't instrumented a service yet, our guide on how to instrument a Node.js app with OpenTelemetry walks through that exact setup, and it pairs directly with what's covered here.
Setting It Up: Step-by-Step
Step 1: Get It Running
The fastest way to try this locally is through the all-in-one image, which bundles the agent, collector, query service, and UI into a single container — ideal for evaluating the workflow before rolling it out across real services. In production, each component is typically deployed separately so it can scale independently.
If you're new to running tools this way, our guide on Docker in DevOps explains why containerizing tools like this has become the standard approach instead of installing them directly on a host.
Step 2: Instrument Your Application
Your application needs to generate spans for the backend to collect. This is done through instrumentation — either manually adding spans around key operations, or using auto-instrumentation libraries that handle common frameworks automatically. OpenTelemetry is the recommended path here since it's vendor-neutral and works across most backends without locking you into one tool.
Step 3: Send Data to the Backend
Once instrumented, your application exports spans over gRPC or HTTP. The collector receives them, processes them, and writes them to your chosen storage backend.
Step 4: View Results in the UI
Open the UI and select your service from the dropdown. You'll see a list of recent requests, each showing total duration and the number of spans involved. Clicking into one shows a waterfall view — a visual breakdown of every step, how long it took, and how it relates to the others in that request.
Step 5: Analyze Latency and Errors
This is where the real value shows up. In the waterfall view, you can immediately spot which step took the longest, whether a particular service is consistently slow, and where errors are actually originating rather than just where they were logged. This turns debugging from a guessing game into a direct visual inspection.
Running This in Kubernetes
Jaeger is commonly deployed inside Kubernetes clusters using its Operator, which manages the lifecycle of each component as native Kubernetes resources. This is particularly useful in environments with many microservices, since the value of this kind of visibility grows fast alongside the number of services — and the number of possible failure points between them.
If your team is also exploring automation around Kubernetes operations, our article on how AI agents work on Kubernetes covers a related layer of the same observability problem: using automated systems to act on the signals that traces and metrics surface.
Getting hands-on with tools like this, Prometheus, and Grafana as part of a real Kubernetes and microservices workflow is exactly what our DevOps Course is built around — it covers observability alongside CI/CD, containers, and infrastructure as code, with hands-on labs instead of just slides.
Best Practices
- Instrument critical paths first — don't try to cover everything on day one; start with the request paths that matter most to users
- Use consistent service naming across everything you instrument, since inconsistent names make correlation harder
- Sample intelligently — capturing every single request at scale gets expensive fast; use sampling strategies to capture a representative subset instead
- Add meaningful tags to spans, like user IDs or request types, so you can filter and search effectively later
- Correlate with logs and metrics rather than treating this as a separate tool, since the real value comes from combining it with your existing observability stack
Common Mistakes Beginners Make
- Instrumenting everything at once instead of starting with one or two critical services and expanding gradually
- Ignoring sampling, which leads to storage costs spiraling as data volume grows unchecked
- Treating this as separate from CI/CD visibility — pipeline and deployment issues benefit from the same principles; our guide on what an intelligent CI/CD pipeline is and how AI improves it covers where this kind of visibility fits into delivery pipelines, not just runtime systems
- Not tying it back to developer experience — teams that adopt this well tend to treat it as a core DevEx investment; our piece on developer experience metrics that matter in 2026 covers how observability ties into the metrics that actually reflect engineering health
If you're building a broader observability skill set — this, Prometheus, Grafana, and OpenTelemetry together — our DevOps Training program covers each of these tools as part of a connected, hands-on curriculum rather than isolated tutorials.
How It Compares to Other Tools
It's often compared to tools like Zipkin and commercial APM platforms. The main advantages here are that it's open-source, CNCF-backed, and built specifically for cloud-native and Kubernetes-based environments. Since most teams now instrument applications using OpenTelemetry rather than a tool-specific SDK, switching between backends has become far less of a lock-in decision than it used to be.
FAQs
What is distributed tracing used for?
It's used to track a single request as it moves across multiple services, helping teams identify latency bottlenecks and pinpoint exactly where failures occur in a distributed system.
Is Jaeger free to use?
Yes. It's fully open-source and maintained under the Cloud Native Computing Foundation, with no licensing cost for any of its core components.
Do I need OpenTelemetry to use it?
Not strictly, but it's the recommended approach. OpenTelemetry has become the standard instrumentation layer, and using it keeps your application code vendor-neutral rather than tied to a specific set of libraries.
What's the difference between a trace and a span?
A trace represents the entire journey of one request across a system, while a span represents a single unit of work within that trace, such as one API call or database query.
Can this be used outside of Kubernetes?
Yes. While it's commonly deployed in Kubernetes environments, it works equally well with services running on virtual machines, bare metal, or other container platforms.
How is Jaeger different from Zipkin?
Both are open-source tools with similar core concepts, but Jaeger was built with tighter Kubernetes and cloud-native integration in mind, and has broader adoption in CNCF-based ecosystems.


