Jaeger is an open-source distributed tracing platform. It receives traces, which record the path of a single request through many services, stores them, and provides a user interface and API to search them and analyse latency and failures. It addresses a problem that metrics and logs alone cannot: in a microservice architecture, a slow request may cross dozens of services, and only a trace shows which hop is responsible. Jaeger was created at Uber, inspired by Google Dapper and OpenZipkin, and joined the CNCF in September 2017. It graduated in October 2019. Its second major version, Jaeger v2, is rebuilt on the OpenTelemetry Collector and accepts OpenTelemetry data natively.
CNCF daily · Sprint 2, day 7 · Observability
At a glance
| Category | Observability and Analysis › Observability |
| CNCF status | Graduated. Accepted September 13, 2017; graduated October 31, 2019 |
| Written in | Go (backend); TypeScript and React (UI) |
| License | Apache 2.0 |
| Ingest protocol | OTLP (gRPC and HTTP), produced by OpenTelemetry SDKs |
| Storage | Elasticsearch or OpenSearch, Cassandra, Badger (single node), in-memory, with additional backends through the storage interface |
| Instrumentation | OpenTelemetry SDKs; the older Jaeger client libraries are deprecated |
Architecture
flowchart TB
APP[Instrumented services<br/>OpenTelemetry SDKs] ==>|OTLP| COL[Jaeger v2<br/>collector pipeline]
COL ==>|batch and sample| KAF[Kafka<br/>optional buffer]
KAF ==> ING[Jaeger ingester]
COL ==> STO[Trace storage<br/>Elasticsearch or Cassandra]
ING ==> STO
STO ==> QRY[Jaeger query<br/>API and UI]
QRY ==> USER[Engineers<br/>search and compare traces]
COL -.->|remote sampling<br/>strategies| APP
classDef actor fill:#eceff1,stroke:#455a64,stroke-width:1.5px,color:#1d1c1a
classDef core fill:#0f766e,stroke:#064e4a,stroke-width:2px,color:#ffffff
classDef data fill:#e3f2fd,stroke:#1565c0,stroke-width:1.5px,color:#1d1c1a
classDef ctrl fill:#ede7f6,stroke:#5e35b1,stroke-width:1.5px,color:#1d1c1a
class USER actor
class COL,ING,QRY core
class APP,STO data
class KAF ctrl
Key: teal blocks are Jaeger components, blue are instrumented workloads and storage, purple is the optional buffer, grey are people. Thick arrows show the trace path, the dashed arrow the sampling configuration sent back to applications.
| Component | Responsibility |
|---|---|
| Instrumented services | Create spans with OpenTelemetry SDKs and propagate trace context between services. |
| Collector pipeline | Receives OTLP data, applies processors such as batching and sampling, and writes to storage. In Jaeger v2 this is the OpenTelemetry Collector with Jaeger extensions. |
| Kafka and ingester | Optional buffer that absorbs traffic spikes and decouples collection from storage writes. |
| Storage | Persists traces. Elasticsearch or OpenSearch and Cassandra are the usual production choices. |
| Query service and UI | Serves the API and web interface for search, trace timelines, service dependency graphs and trace comparison. |
Design principle. Keep instrumentation vendor-neutral and make the backend replaceable. Applications emit standard OpenTelemetry data, and Jaeger concentrates on storage, sampling and analysis, so the tracing backend can change without re-instrumenting code.
Production reference design
A typical deployment on Kubernetes (EKS, GKE, AKS or on-premises) serves many teams from one shared tracing platform.
- Provide storage. Run Elasticsearch or OpenSearch with replicas and index lifecycle management to expire old traces, or use Cassandra if it is already operated.
- Deploy Jaeger. Install with the project Helm chart, supplying a configuration that points at the storage backend:
helm repo add jaegertracing https://jaegertracing.github.io/helm-charts helm install jaeger jaegertracing/jaeger --namespace observability --create-namespace - Configure the pipeline. Jaeger v2 uses an OpenTelemetry Collector style configuration. A minimal example:
service: extensions: [jaeger_storage, jaeger_query] pipelines: traces: receivers: [otlp] processors: [batch] exporters: [jaeger_storage_exporter] extensions: jaeger_query: storage: traces: main jaeger_storage: backends: main: elasticsearch: server_urls: ["http://elasticsearch:9200"] receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: batch: exporters: jaeger_storage_exporter: trace_storage: main - Instrument applications. Point OpenTelemetry SDKs or an OpenTelemetry Collector at the Jaeger OTLP endpoint (port 4317 for gRPC, 4318 for HTTP).
- Sample deliberately. Start with a low head-sampling rate on busy services and raise it for critical paths. Use the sampling strategies served by Jaeger, or tail sampling in a Collector, to keep slow and failed traces.
Typical uses include finding the service responsible for a latency regression, understanding service dependencies, and investigating errors that cross service boundaries. Always confirm option names against the documentation for the version you deploy, as the v2 configuration schema continues to evolve.
Operational considerations
- Storage dominates cost. Traces are large. Control volume with sampling, set a short retention period such as 7 to 14 days, and size the Elasticsearch or Cassandra cluster for write throughput.
- Sampling strategy. Head sampling is cheap but may drop the rare slow trace you need. Tail sampling keeps interesting traces but needs a Collector tier with enough memory.
- Buffering. For bursty traffic, place Kafka between collection and storage so storage slowdowns do not drop spans or back-pressure applications.
- Upgrades. Jaeger v1 reached end of life as v2 became the supported line. Plan the move to v2 and to OpenTelemetry instrumentation rather than the deprecated Jaeger client libraries.
- Security. Traces can contain sensitive attributes such as user identifiers and query text. Scrub attributes in the pipeline, enable TLS and authentication on the query endpoint, and restrict UI access.
Adoption
- Uber created Jaeger to trace its microservice platform and contributed it to the CNCF.
- Red Hat ships Jaeger as the basis of the distributed tracing platform in OpenShift.
- The project maintains an ADOPTERS file in its repository listing further organisations that run Jaeger in production.
Alternatives
| Solution | Model | Best suited to |
|---|---|---|
| Grafana Tempo | Open-source tracing backend using object storage | Low-cost storage at high volume, integrated with Grafana |
| OpenZipkin | Open-source tracing system | Existing Zipkin instrumentation and smaller deployments |
| Commercial APM (Datadog, New Relic, Dynatrace) | Managed observability platforms | Teams that prefer a managed service and unified tooling |
| Cloud tracing (AWS X-Ray, Google Cloud Trace) | Provider-native tracing | Workloads concentrated on one cloud |
| OpenTelemetry (CNCF Graduated) | Instrumentation and Collector, not a backend | Generating telemetry; pairs with Jaeger. See the OpenTelemetry brief |
Strengths and limitations
| Strengths | Limitations |
|---|---|
| Graduated CNCF project with a mature, widely used tracing UI | Storage backends need real operational effort at scale |
| Native OTLP support and vendor-neutral instrumentation | Traces only; metrics and logs need other tools such as Prometheus |
| Flexible storage and optional Kafka buffering | Tail sampling and long retention increase infrastructure cost |
| Service dependency graph and trace comparison in the UI | The v1 to v2 transition requires planning |
| Open source with no licence cost | Fewer built-in analytics than commercial APM products |
Recommendation
Adopt. Jaeger is a proven, mature choice for self-hosted distributed tracing, and its OpenTelemetry-native v2 fits current instrumentation practice. Start with OpenTelemetry SDKs, a modest sampling rate and a short retention period, and add Kafka or tail sampling only when volume demands it. Teams that already run Grafana at scale may also evaluate Tempo for cheaper object-storage retention.
References: CNCF project page · Jaeger website · Jaeger repository · CNCF Landscape