1. Project Overview & Quickstart (jaegertracing/jaeger)
File: README.md
Jaeger - a Distributed Tracing System
๐ฅ๐ฅ๐ฅ Jaeger v2 is out! Read the blog post and try it out.
Quick Start
Get Jaeger running in seconds with Docker:
# Run Jaeger all-in-one (includes UI, collector, query, and in-memory storage)
docker run --rm --name jaeger \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
jaegertracing/jaeger:latest
# Access the UI at http://localhost:16686
# Send traces via OTLP: gRPC on port 4317, HTTP on port 4318For production deployments and more options, see the Getting Started Guide.
Architecture
graph TD
SDK["OpenTelemetry SDK"] --> |HTTP or gRPC| COLLECTOR
COLLECTOR["Jaeger Collector"] --> STORE[Storage]
COLLECTOR --> |gRPC| PLUGIN[Storage Plugin]
COLLECTOR --> |gRPC/sampling| SDK
PLUGIN --> STORE
QUERY[Jaeger Query Service] --> STORE
QUERY --> |gRPC| PLUGIN
UI[Jaeger UI] --> |HTTP| QUERY
subgraph Application Host
subgraph User Application
SDK
end
endJaeger is a distributed tracing platform created by Uber Technologies and donated to Cloud Native Computing Foundation.
See Jaeger documentation for getting started, operational details, and other information.
Jaeger is hosted by the Cloud Native Computing Foundation (CNCF) as the 7th top-level project, graduated in October 2019. See the CNCF Jaeger incubation announcement and Jaeger graduation announcement.
Get Involved
Jaeger is an open source project with open governance. We welcome contributions from the community, and we would love your help to improve and extend the project. Here are some ideas for how to get involved. Many of them do not even require any coding.
Version Compatibility Guarantees
Since Jaeger uses many components from the OpenTelemetry Collector we try to maintain configuration compatibility between Jaeger releases. Occasionally, configuration options in Jaeger (or in Jaeger v1 CLI flags) can be deprecated due to usability improvements, new functionality, or changes in our dependencies.
In such situations, developers introducing the deprecation are required to follow these guidelines.
In short, for a deprecated configuration option, you should expect to see the following message in the documentation or release notes:
(deprecated, will be removed after yyyy-mm-dd or in release vX.Y.Z, whichever is later)A grace period of at least 3 months or two minor version bumps (whichever is later) from the first release
containing the deprecation notice will be provided before the deprecated configuration option can be deleted.
For example, consider a scenario where v2.0.0 is released on 01-Sep-2024 containing a deprecation notice for a configuration option.
This configuration option will remain in a deprecated state until the later of 01-Dec-2024 or v2.2.0 where it can be removed on or after either of those events.
It may remain deprecated for longer than the aforementioned grace period.
Go Version Compatibility Guarantees
The Jaeger project attempts to track the currently supported versions of Go, as defined by the Go team.
Removing support for an unsupported Go version is not considered a breaking change.
Starting with the release of Go 1.21, support for Go versions will be updated as follows:
- Soon after the release of a new Go minor version
N, updates will be made to the build and tests steps to accommodate the latest Go minor version. - Soon after the release of a new Go minor version
N, support for Go versionN-1will be removed and versionNwill become the minimum required version.
Note: All importable code has been moved to internal packages, so there is no need to maintain backward compatibility with older compilers (previously version N-1 was used).
Storage Backend Version Support Policy
This policy covers storage backend versions only while they are reasonable for the project to test, maintain, and recommend for production use. Policy coverage is distinct from versions that may remain technically compatible with Jaeger.
For backends with a published upstream lifecycle, Jaeger bases its policy on the backend project's or vendor's supported-version or end-of-life policy, with the exact coverage defined below. Once upstream support ends, Jaeger may remove CI coverage, stop proactively fixing backend-specific issues for that version, and require users to upgrade before troubleshooting.
For backends without a clear upstream lifecycle, Jaeger supports the current stable major version and the immediately preceding major version. Older versions are best-effort only and may be removed when they block development, security fixes, dependency updates, or CI reliability.
Backend-specific policy:
- Elasticsearch: follow Elastic's Product and Version End of Life Policy.
- OpenSearch: follow the OpenSearch Release Schedule and Maintenance Policy. In practice, this means the current major version and the previous major version while they remain maintained.
- Cassandra: follow Apache Cassandra's maintained release lines, as published on the Cassandra download page, with the Jaeger support target being the current major version and the previous major version.
- ClickHouse: follow ClickHouse's release and backport policy and production guidance for stable and LTS releases. Jaeger treats LTS releases as its support lines and covers the current and previous LTS releases, which ClickHouse supports simultaneously for at least 12 months. Monthly stable releases may remain compatible or appear in CI but are not covered by this policy.
Support means backend versions are in scope for proactive compatibility fixes. CI coverage is not the definitive support matrix: it may test only a subset of supported versions and may retain older versions on a best-effort basis. CI coverage alone does not make a backend version supported. Jaeger does not provide support for the backend product itself, vendor-specific distributions, or versions outside the upstream maintenance window.
As of July 6, 2026, this policy means:
| Backend | Jaeger policy basis | Versions covered by policy | Versions not covered |
|---|---|---|---|
| Elasticsearch | Elastic EOL policy | 9.x; 8.19.x until Elastic's published 8.x maintenance window ends |
8.18.x and earlier |
| OpenSearch | OpenSearch maintenance policy | 3.x; 2.x, with 2.19.x as the currently maintained 2.x line |
1.x and earlier |
| Cassandra | Current major plus previous major, using maintained Apache release lines | 5.0.x; maintained 4.x lines, currently 4.1.x and 4.0.x |
3.x and earlier |
| ClickHouse | Current and previous ClickHouse LTS releases | 26.3 LTS and 25.8 LTS |
Monthly stable releases and older LTS branches |
This table is informational and should be refreshed when upstream policies or release lines change. Versions listed as not covered may still appear in CI on a best-effort basis; their presence in CI does not extend the support policy.
Related Repositories
Components
Documentation
- Published: https://www.jaegertracing.io/docs/
- Source: https://github.com/jaegertracing/documentation
Building From Source
See CONTRIBUTING.
Contributing
See CONTRIBUTING.
Thanks to all the people who already contributed!
Maintainers
Rules for becoming a maintainer are defined in the GOVERNANCE document.
The official maintainers of the Jaeger project are listed in the MAINTAINERS file.
Please use @jaegertracing/jaeger-maintainers to tag them on issues / PRs.
Some repositories under jaegertracing org have additional maintainers.
Project Status Meetings
The Jaeger maintainers and contributors meet regularly on a video call. Everyone is welcome to join, including end users. For meeting details, see https://www.jaegertracing.io/get-in-touch/.
Roadmap
See https://www.jaegertracing.io/docs/roadmap/
Get in Touch
Have questions, suggestions, bug reports? Reach the project community via these channels:
- Slack chat room
#jaeger(need to join CNCF Slack for the first time) jaeger-tracingmail group- GitHub issues and discussions
Security
Third-party security audits of Jaeger are available in https://github.com/jaegertracing/security-audits. Please see Issue #1718 for the summary of available security mechanisms in Jaeger.
Adopters
Jaeger as a product consists of multiple components. We want to support different types of users,
whether they are only using our instrumentation libraries or full end to end Jaeger installation,
whether it runs in production or you use it to troubleshoot issues in development.
Please see ADOPTERS.md for some of the organizations using Jaeger today.
If you would like to add your organization to the list, please comment on our
survey issue.
Sponsors
The Jaeger project owes its success in open source largely to the Cloud Native Computing Foundation (CNCF), our primary supporter. We deeply appreciate their vital support. Furthermore, we are grateful to Uber for their initial, project-launching donation, and for the continuous contributions of software and infrastructure from 1Password, Codecov.io, Dosu, GitHub, Google Analytics, Netlify, and Oracle Cloud Infrastructure. Thank you for your generous support.
License
Copyright (c) The Jaeger Authors. Apache 2.0 License.
File: cmd/tracegen/README.md
tracegen
tracegen is a utility that can generate a steady flow of simple traces useful for performance tuning.
Traces are produced concurrently from one or more worker goroutines. Run with -h to see all cli flags.
The binary is available from the Releases page, as well as a Docker image:
$ docker run jaegertracing/jaeger-tracegen -service abcd -traces 10The generator can be configured to export traces in different formats, via -exporter flag.
By default, the exporters send data to localhost. If running in a container, this refers
to the networking namespace of the container itself, so to export to another container,
the exporters need to be provided with appropriate location.
OTLP exporter accepts configuration via environment variables.
For more information about configuring OTLP exporter, see OpenTelemetry Protocol Exporter.
See example in the included docker-compose file.
File: cmd/jaeger/docs/migration/all-in-one-metrics.md
ALL-IN-ONE METRICS
Combined Metrics
| V1 Metric | V1 Labels | V2 Metric | V2 Labels |
|---|---|---|---|
| jaeger_query_latency | operation, result | jaeger_query_latency | operation, result |
| jaeger_query_responses | operation | jaeger_query_responses | operation |
| jaeger_query_requests_total | operation, result | jaeger_query_requests_total | operation, result |
| go_gc_duration_seconds | N/A | N/A | N/A |
| go_goroutines | N/A | N/A | N/A |
| go_info | version | N/A | N/A |
| go_memstats_alloc_bytes | N/A | N/A | N/A |
| go_memstats_alloc_bytes_total | N/A | N/A | N/A |
| go_memstats_buck_hash_sys_bytes | N/A | N/A | N/A |
| go_memstats_frees_total | N/A | N/A | N/A |
| go_memstats_gc_sys_bytes | N/A | N/A | N/A |
| go_memstats_heap_alloc_bytes | N/A | N/A | N/A |
| go_memstats_heap_idle_bytes | N/A | N/A | N/A |
| go_memstats_heap_inuse_bytes | N/A | N/A | N/A |
| go_memstats_heap_objects | N/A | N/A | N/A |
| go_memstats_heap_released_bytes | N/A | N/A | N/A |
| go_memstats_heap_sys_bytes | N/A | N/A | N/A |
| go_memstats_last_gc_time_seconds | N/A | N/A | N/A |
| go_memstats_lookups_total | N/A | N/A | N/A |
| go_memstats_mallocs_total | N/A | N/A | N/A |
| go_memstats_mcache_inuse_bytes | N/A | N/A | N/A |
| go_memstats_mcache_sys_bytes | N/A | N/A | N/A |
| go_memstats_mspan_inuse_bytes | N/A | N/A | N/A |
| go_memstats_mspan_sys_bytes | N/A | N/A | N/A |
| go_memstats_next_gc_bytes | N/A | N/A | N/A |
| go_memstats_other_sys_bytes | N/A | N/A | N/A |
| go_memstats_stack_inuse_bytes | N/A | N/A | N/A |
| go_memstats_stack_sys_bytes | N/A | N/A | N/A |
| go_memstats_sys_bytes | N/A | N/A | N/A |
| go_threads | N/A | N/A | N/A |
| jaeger_build_info | build_date, revision, version | N/A | N/A |
| jaeger_collector_batch_size | host | N/A | N/A |
| jaeger_collector_http_request_duration | method, path, status | N/A | N/A |
| jaeger_collector_http_server_errors_total | source, status | N/A | N/A |
| jaeger_collector_http_server_requests_total | type | N/A | N/A |
| jaeger_collector_in_queue_latency | host | N/A | N/A |
| jaeger_collector_queue_capacity | host | N/A | N/A |
| jaeger_collector_queue_length | host | N/A | N/A |
| jaeger_collector_save_latency | host | N/A | N/A |
| jaeger_collector_spans_bytes | host | N/A | N/A |
| jaeger_collector_spans_dropped_total | host | N/A | N/A |
| jaeger_collector_spans_received_total | debug, format, svc, transport | N/A | N/A |
| jaeger_collector_spans_rejected_total | debug, format, svc, transport | N/A | N/A |
| jaeger_collector_spans_saved_by_svc_total | debug, result, svc | N/A | N/A |
| jaeger_collector_spans_serviceNames | host | N/A | N/A |
| jaeger_collector_traces_received_total | debug, format, sampler_type, svc, transport | N/A | N/A |
| jaeger_collector_traces_rejected_total | debug, format, sampler_type, svc, transport | N/A | N/A |
| jaeger_collector_traces_saved_by_svc_total | debug, result, sampler_type, svc | N/A | N/A |
| process_cpu_seconds_total | N/A | N/A | N/A |
| process_max_fds | N/A | N/A | N/A |
| process_open_fds | N/A | N/A | N/A |
| process_resident_memory_bytes | N/A | N/A | N/A |
| process_start_time_seconds | N/A | N/A | N/A |
| process_virtual_memory_bytes | N/A | N/A | N/A |
| process_virtual_memory_max_bytes | N/A | N/A | N/A |
| N/A | N/A | exporter_send_failed_spans | exporter, service_instance_id, service_name, service_version |
| N/A | N/A | exporter_sent_spans | exporter, service_instance_id, service_name, service_version |
| N/A | N/A | process_cpu_seconds | service_instance_id, service_name, service_version |
| N/A | N/A | process_memory_rss | service_instance_id, service_name, service_version |
| N/A | N/A | process_runtime_heap_alloc_bytes | service_instance_id, service_name, service_version |
| N/A | N/A | process_runtime_total_alloc_bytes | service_instance_id, service_name, service_version |
| N/A | N/A | process_runtime_total_sys_memory_bytes | service_instance_id, service_name, service_version |
| N/A | N/A | process_uptime | service_instance_id, service_name, service_version |
| N/A | N/A | processor_batch_batch_send_size | processor, service_instance_id, service_name, service_version |
| N/A | N/A | processor_batch_batch_send_size_bytes | processor, service_instance_id, service_name, service_version |
| N/A | N/A | processor_batch_metadata_cardinality | processor, service_instance_id, service_name, service_version |
| N/A | N/A | processor_batch_timeout_trigger_send | processor, service_instance_id, service_name, service_version |
| N/A | N/A | receiver_accepted_spans | receiver, service_instance_id, service_name, service_version, transport |
| N/A | N/A | receiver_refused_spans | receiver, service_instance_id, service_name, service_version, transport |
| N/A | N/A | rpc_server_duration | rpc_grpc_status_code, rpc_method, rpc_service, rpc_system, service_instance_id, service_name, service_version |
| N/A | N/A | rpc_server_request_size | rpc_method, rpc_service, rpc_system, service_instance_id, service_name, service_version |
| N/A | N/A | rpc_server_requests_per_rpc | rpc_grpc_status_code, rpc_method, rpc_service, rpc_system, service_instance_id, service_name, service_version |
| N/A | N/A | rpc_server_response_size | rpc_method, rpc_service, rpc_system, service_instance_id, service_name, service_version |
| N/A | N/A | rpc_server_responses_per_rpc | rpc_grpc_status_code, rpc_method, rpc_service, rpc_system, service_instance_id, service_name, service_version |
| N/A | N/A | target_info | service_instance_id, service_name, service_version |
Equivalent Metrics
| V1 Metric | V1 Labels | V2 Metric | V2 Labels |
|---|---|---|---|
| jaeger_collector_spans_rejected_total | debug, format, svc, transport | receiver_refused_spans | receiver, service_instance_id, service_name, service_version, transport |
| jaeger_build_info | build_date, revision, version | target_info | service_instance_id, service_name, service_version |
File: cmd/jaeger/docs/migration/badger-metrics.md
BADGER METRICS
Combined Metrics
| V1 Metric | V1 Parameters | V2 Metric | V2 Parameters |
|---|---|---|---|
| jaeger_badger_compaction_current_num_lsm | N/A | jaeger_badger_compaction_current_num_lsm | N/A |
| jaeger_badger_get_num_memtable | N/A | jaeger_badger_get_num_memtable | N/A |
| jaeger_badger_get_num_user | N/A | jaeger_badger_get_num_user | N/A |
| jaeger_badger_get_with_result_num_user | N/A | jaeger_badger_get_with_result_num_user | N/A |
| jaeger_badger_iterator_num_user | N/A | jaeger_badger_iterator_num_user | N/A |
| jaeger_badger_put_num_user | N/A | jaeger_badger_put_num_user | N/A |
| jaeger_badger_read_bytes_lsm | N/A | jaeger_badger_read_bytes_lsm | N/A |
| jaeger_badger_read_bytes_vlog | N/A | jaeger_badger_read_bytes_vlog | N/A |
| jaeger_badger_read_num_vlog | N/A | jaeger_badger_read_num_vlog | N/A |
| jaeger_badger_size_bytes_lsm | N/A | jaeger_badger_size_bytes_lsm | N/A |
| jaeger_badger_size_bytes_vlog | N/A | jaeger_badger_size_bytes_vlog | N/A |
| jaeger_badger_write_bytes_l0 | N/A | jaeger_badger_write_bytes_l0 | N/A |
| jaeger_badger_write_bytes_user | N/A | jaeger_badger_write_bytes_user | N/A |
| jaeger_badger_write_bytes_vlog | N/A | jaeger_badger_write_bytes_vlog | N/A |
| jaeger_badger_write_num_vlog | N/A | jaeger_badger_write_num_vlog | N/A |
| jaeger_badger_write_pending_num_memtable | N/A | jaeger_badger_write_pending_num_memtable | N/A |
| jaeger_badger_key_log_bytes_available | N/A | N/A | N/A |
| jaeger_badger_storage_maintenance_last_run | N/A | N/A | N/A |
| jaeger_badger_storage_valueloggc_last_run | N/A | N/A | N/A |
| jaeger_badger_value_log_bytes_available | N/A | N/A | N/A |
Equivalent Metrics
| V1 Metric | V1 Parameters | V2 Metric | V2 Parameters |
|---|---|---|---|
| jaeger_collector_spans_rejected_total | debug, format, svc, transport | receiver_refused_spans | receiver, service_instance_id, service_name, service_version, transport |
| jaeger_build_info | build_date, revision, version | target_info | service_instance_id, service_name, service_version |
File: cmd/jaeger/docs/migration/cassandra-metrics.md
CASSANDRA METRICS
Combined Metrics
| V1 Metric | V1 Parameters | V2 Metric | V2 Parameters |
|---|---|---|---|
| jaeger_cassandra_attempts_total | table | jaeger_cassandra_attempts_total | table |
| jaeger_cassandra_errors_total | table | jaeger_cassandra_errors_total | table |
| jaeger_cassandra_inserts_total | table | jaeger_cassandra_inserts_total | table |
| jaeger_cassandra_latency_err | table | jaeger_cassandra_latency_err | table |
| jaeger_cassandra_latency_ok | table | jaeger_cassandra_latency_ok | table |
| jaeger_cassandra_read_attempts_total | table | jaeger_cassandra_read_attempts_total | table |
| jaeger_cassandra_read_errors_total | table | jaeger_cassandra_read_errors_total | table |
| jaeger_cassandra_read_inserts_total | table | jaeger_cassandra_read_inserts_total | table |
| jaeger_cassandra_read_latency_err | table | jaeger_cassandra_read_latency_err | table |
| jaeger_cassandra_read_latency_ok | table | jaeger_cassandra_read_latency_ok | table |
| jaeger_cassandra_tag_index_skipped_total | N/A | jaeger_cassandra_tag_index_skipped_total | N/A |
Equivalent Metrics
| V1 Metric | V1 Parameters | V2 Metric | V2 Parameters |
|---|---|---|---|
| jaeger_collector_spans_rejected_total | debug, format, svc, transport | receiver_refused_spans | receiver, service_instance_id, service_name, service_version, transport |
| jaeger_build_info | build_date, revision, version | target_info | service_instance_id, service_name, service_version |
File: cmd/jaeger/docs/migration/elasticsearch-metrics.md
ELASTICSEARCH METRICS
Combined Metrics
| V1 Metric | V1 Parameters | V2 Metric | V2 Parameters |
|---|---|---|---|
| jaeger_bulk_index_attempts_total | N/A | jaeger_bulk_index_attempts_total | N/A |
| jaeger_bulk_index_errors_total | N/A | jaeger_bulk_index_errors_total | N/A |
| jaeger_bulk_index_inserts_total | N/A | jaeger_bulk_index_inserts_total | N/A |
| jaeger_bulk_index_latency_err | N/A | jaeger_bulk_index_latency_err | N/A |
| jaeger_bulk_index_latency_ok | N/A | jaeger_bulk_index_latency_ok | N/A |
| jaeger_index_create_attempts_total | N/A | jaeger_index_create_attempts_total | N/A |
| jaeger_index_create_errors_total | N/A | jaeger_index_create_errors_total | N/A |
| jaeger_index_create_inserts_total | N/A | jaeger_index_create_inserts_total | N/A |
| jaeger_index_create_latency_err | N/A | jaeger_index_create_latency_err | N/A |
| jaeger_index_create_latency_ok | N/A | jaeger_index_create_latency_ok | N/A |
Equivalent Metrics
| V1 Metric | V1 Parameters | V2 Metric | V2 Parameters |
|---|---|---|---|
| jaeger_collector_spans_rejected_total | debug, format, svc, transport | receiver_refused_spans | receiver, service_instance_id, service_name, service_version, transport |
| jaeger_build_info | build_date, revision, version | target_info | service_instance_id, service_name, service_version |
File: cmd/jaeger/docs/migration/opensearch-metrics.md
OPENSEARCH METRICS
Combined Metrics
| V1 Metric | V1 Parameters | V2 Metric | V2 Parameters |
|---|---|---|---|
| jaeger_bulk_index_attempts_total | N/A | jaeger_bulk_index_attempts_total | N/A |
| jaeger_bulk_index_errors_total | N/A | jaeger_bulk_index_errors_total | N/A |
| jaeger_bulk_index_inserts_total | N/A | jaeger_bulk_index_inserts_total | N/A |
| jaeger_bulk_index_latency_err | N/A | jaeger_bulk_index_latency_err | N/A |
| jaeger_bulk_index_latency_ok | N/A | jaeger_bulk_index_latency_ok | N/A |
| jaeger_index_create_attempts_total | N/A | jaeger_index_create_attempts_total | N/A |
| jaeger_index_create_errors_total | N/A | jaeger_index_create_errors_total | N/A |
| jaeger_index_create_inserts_total | N/A | jaeger_index_create_inserts_total | N/A |
| jaeger_index_create_latency_err | N/A | jaeger_index_create_latency_err | N/A |
| jaeger_index_create_latency_ok | N/A | jaeger_index_create_latency_ok | N/A |
Equivalent Metrics
| V1 Metric | V1 Parameters | V2 Metric | V2 Parameters |
|---|---|---|---|
| jaeger_collector_spans_rejected_total | debug, format, svc, transport | receiver_refused_spans | receiver, service_instance_id, service_name, service_version, transport |
| jaeger_build_info | build_date, revision, version | target_info | service_instance_id, service_name, service_version |
File: cmd/jaeger/internal/exporters/storageexporter/README.md
jaeger_storage_exporter
This module implements exporter.Traces and writes spans into Jaeger native spanstore.SpanWriter, that it obtains from the jaeger_storage extension. This is primarily needed to wire a memory storage into the exporter pipeline (used for all-in-one), but the design of the exporter is such that it can do this for any V1 storage implementation.
Configuration
Basic Configuration
exporters:
jaeger_storage_exporter:
trace_storage: memstore
extensions:
jaeger_storage:
memory:
memstore:
max_traces: 100000Retry Configuration
The exporter supports configurable retry behavior for failed exports. By default, retry is disabled. When enabled, the following default settings are used:
enabled: false (disabled by default)initial_interval: 5srandomization_factor: 0.5multiplier: 1.5max_interval: 30smax_elapsed_time: 5m
To enable and customize the retry behavior:
exporters:
jaeger_storage_exporter:
trace_storage: memstore
retry_on_failure:
enabled: true # Explicitly enable retries
initial_interval: 10s
max_interval: 1m
max_elapsed_time: 10m
queue:
enabled: true
num_consumers: 10
queue_size: 1000File: cmd/jaeger/internal/extension/remotestorage/README.md
Remote Storage Backend Extension
The Remote Storage Backend Extension exposes any Jaeger-supported storage backend through a gRPC API by
implementing the gRPC Storage API. The gRPC API currently consists of the following services:
Overview
This extension allows you to make Jaeger storage backends accessible remotely over gRPC.
For example, you can expose the in-memory storage backend like this:
extensions:
jaeger_storage:
backends:
memory-storage:
memory:
max_traces: 100000
remote_storage:
endpoint: localhost:17271
storage: memory-storageFile: cmd/jaeger/internal/extension/remotesampling/README.md
Remote Sampling
Placeholder
/* Detailed source-code truncated for AI context efficiency. */2. Official Technical Reference & Guides (jaegertracing/documentation)
File: README.md
Jaeger website
This repo houses all the assets used to build the Jaeger website, available at https://jaegertracing.io.
The site is built with Hugo and hosted by Netlify.
Contributing to the site
We strongly encourage you to contribute to this site! For more information, see the contributing guide.
Publishing the site
The site is published automatically by Netlify whenever changes are merged to the main branch. The site cannot be published in an ad-hoc way (e.g. through a make command or script in the repo).
Publishing new Jaeger version
Please refer to RELEASE.md for instructions on how to release new version of documentation.
License
File: content/announcements/_index.md
title: Announcements
toc_hide: true
cascade:
type: docs
params:
hide_feedback: true
redirects: [{ from: '*', to: '?' }]
File: content/announcements/kubecon-na.md
title: KubeCon North America 2025 date: 2025-10-01 expiryDate: 2025-11-13
Join us in Atlanta, Georgia for KubeCon +
CloudNativeCon North America 2025, November 10 - 13, 2025
File: content/announcements/ukraine.md
title: We stand with Ukraine weight: -1 cSpell:ignore: ukraine body_class: ukraine-banner
We stand with our friends and colleagues in Ukraine. To assist
in their time of need, visit Support Ukraine.
File: content/docs/v1/1.76/architecture/_index.md
title: Architecture
weight: 3
children:
- title: APIs
url: apis - title: Sampling
url: sampling
Terminology
Jaeger represents tracing data in a data model inspired by the OpenTracing Specification. The data model is logically very similar to OpenTelemetry Traces, with some naming differences:
| Jaeger | OpenTelemetry | Notes |
|---|---|---|
| Tags | Attributes | Both support typed values, but nested tags are not supported in Jaeger. |
| Span Logs | Span Events | Point-in-time events on the span recorded in a structured form. |
| Span References | Span Links | Jaeger's Span References have a required type (child-of or follows-from) and always refer to predecessor spans; OpenTelemetry's Span Links have no type, but allow attributes. |
| Process | Resource | A struct describing the entity that produces the telemetry. |
Span
A span represents a logical unit of work that has an operation name, the start time of the operation, and the duration. Spans may be nested and ordered to model causal relationships.
Trace
A trace represents the data or execution path through the system. It can be thought of as a directed acyclic graph of spans.
Baggage
Baggage is arbitrary user-defined metadata (key-value pairs) that can be attached to distributed context and propagated by the tracing SDKs. See W3C Baggage for more information.
Architecture
Jaeger can be deployed either as an all-in-one binary, where all Jaeger backend components
run in a single process, or as a scalable distributed system. There are two main deployment options discussed below.
Direct to storage
In this deployment the collectors receive the data from traced applications and write it directly to storage. The storage must be able to handle both average and peak traffic. Collectors use an in-memory queue to smooth short-term traffic peaks, but a sustained traffic spike may result in dropped data if the storage is not able to keep up.
Collectors are able to centrally serve sampling configuration to the SDKs, known as remote sampling mode. They can also enable automatic sampling configuration calculation, known as adaptive sampling.
Via Kafka
To prevent data loss between collectors and storage, Kafka can be used as an intermediary, persistent queue. An additional component, jaeger-ingester, needs to be deployed to read data from Kafka and save to the database. Multiple jaeger-ingesters can be deployed to scale up ingestion; they will automatically partition the load across them.
With OpenTelemetry Collector
You do not need to use OpenTelemetry Collector, because jaeger-collector can receive OpenTelemetry data directly from the OpenTelemetry SDKs (using OTLP exporters). However, if you already use the OpenTelemetry Collectors, such as for gathering other types of telemetry or for pre-processing / enriching the tracing data, it can be placed between the SDKs and jaeger-collector's. The OpenTelemetry Collectors can be run as an application sidecar, as a host agent / daemon, or as a central cluster.
The OpenTelemetry Collector supports Jaeger's Remote Sampling protocol and can either serve static configurations from config files directly, or proxy the requests to the Jaeger backend (e.g., when using adaptive sampling).
OpenTelemetry Collector as a sidecar / host agent
Benefits:
- The SDK configuration is simplified as both trace export endpoint and sampling config endpoint can point to a local host and not worry about discovering where those services run remotely.
- Collector may provide data enrichment by adding environment information, like k8s pod name.
- Resource usage for data enrichment can be distributed across all application hosts.
Downsides:
- An extra layer of marshaling/unmarshaling the data.
OpenTelemetry Collector as a remote cluster
Benefits:
- Sharding capabilities, e.g., when using tail-based sampling.
Downsides:
- An extra layer of marshaling/unmarshaling the data.
Components
This section details the constituent parts of Jaeger and how they relate to each other. It is arranged by the order in which spans from your application interact with them.
Tracing SDKs
In order to generate tracing data, the applications must be instrumented with tracing SDK such as OpenTelemetry SDKs. An instrumented application creates spans when receiving new requests and attaches context information (trace id, span id, and baggage) to outgoing requests. Only the ids and baggage are propagated with requests; all other profiling data, like operation name, timing, tags and logs, is not propagated. Instead, it is exported out of process to the Jaeger backend asynchronously, in the background.
There are many ways to instrument an application:
- manually, using the tracing APIs directly,
- relying on instrumentation already created for a variety of existing open source frameworks,
- automatically, via byte code manipulation, monkey-patching, eBPF, and similar techniques.
Instrumentation typically should not depend on specific tracing SDKs, but only on abstract tracing APIs like the OpenTelemetry API. The tracing SDKs implement the tracing APIs and take care of data export.
The instrumentation is designed to be always on in production. To minimize overhead, the SDKs employ various sampling strategies. When a trace is sampled, the profiling span data is captured and transmitted to the Jaeger backend. When a trace is not sampled, no profiling data is collected at all, and the calls to the tracing API are short-circuited to incur a minimal amount of overhead. For more information, please refer to the Sampling page.
Collector
jaeger-collector receives traces, runs them through a processing pipeline for validation and clean-up/enrichment, and stores them in a storage backend. Jaeger comes with built-in support for several storage backends (see Deployment), as well as extensible plugin framework for implementing custom storage plugins.
Query
jaeger-query is a service that exposes the APIs for retrieving traces from storage and hosts a Web UI for searching and analyzing traces.
Ingester
jaeger-ingester is a service that reads traces from Kafka and writes them to a storage backend. Effectively, it is a stripped-down version of the Jaeger collector that supports Kafka as the only input protocol.
File: content/docs/v1/1.76/architecture/apis.md
title: APIs aliases: [../apis] hasparent: true
Jaeger components implement various APIs for saving or retrieving trace data.
The following labels are used to describe API compatibility guarantees.
- stable - the API guarantees backwards compatibility. If breaking changes are going to be made in the future, they will result in a new API version, e.g.
/api/v2URL prefix or a different namespace in the IDL. - internal - the APIs are intended for internal communications between Jaeger components and are not recommended for use by external components.
- deprecated - the APIs that are only maintained for legacy reasons and will be phased out in the future.
Since Jaeger v1.32, jaeger-collector and jaeger-query Service ports that serve gRPC endpoints enable gRPC reflection. Unfortunately, the internally used gogo/protobuf has a compatibility issue with the official golang/protobuf, and as a result only the list reflection command is currently working properly.
Span reporting APIs
jaeger-collector is the component of the Jaeger backend that can receive spans. At this time it supports two sets of non-overlapping APIs.
OpenTelemetry Protocol (stable)
Since v1.35, the Jaeger backend can receive trace data from the OpenTelemetry SDKs in their native OpenTelemetry Protocol (OTLP). It is no longer necessary to configure the OpenTelemetry SDKs with Jaeger exporters, nor deploy the OpenTelemetry Collector between the OpenTelemetry SDKs and the Jaeger backend.
The OTLP data is accepted in these formats: (1) binary gRPC, (2) Protobuf over HTTP, (3) JSON over HTTP. For more details on the OTLP receiver see the official documentation. Note that not all configuration options are supported in jaeger-collector (see --collector.otlp.* CLI Flags), and only tracing data is accepted, since Jaeger does not store other telemetry types.
| Port | Protocol | Endpoint | Format |
|---|---|---|---|
| 4317 | gRPC | n/a | Protobuf |
| 4318 | HTTP | /v1/traces |
Protobuf or JSON |
Protobuf via gRPC (stable)
Deprecated: we recommend the OpenTelemetry protocol.
Since Jaeger v1.11, the official protocol between user applications and jaeger-collectors is jaeger.api_v2.CollectorService gRPC endpoint defined in collector.proto IDL file. The same endpoint can be used to submit trace data from SDKs directly to jaeger-collector.
Thrift over HTTP (stable)
Deprecated: we recommend the OpenTelemetry protocol.
The payload in jaeger.thrift format can be submitted in an HTTP POST request to the /api/traces endpoint, for example, https://jaeger-collector:14268/api/traces. The Batch struct needs to be encoded using Thrift's binary encoding, and the HTTP request should specify the content type header:
Content-Type: application/vnd.apache.thrift.binaryJSON over HTTP (n/a)
There is no official Jaeger JSON format that can be accepted by jaeger-collector.
Jaeger does accept the OpenTelemetry protocol via JSON (see above).
Zipkin Formats (stable)
jaeger-collector can also accept spans in several Zipkin data formats, namely JSON v1/v2 and Thrift. jaeger-collector needs to be configured to enable Zipkin HTTP server, e.g. on port 9411 used by Zipkin collectors. The server enables two endpoints that expect POST requests:
/api/v1/spansfor submitting spans in Zipkin JSON v1 or Zipkin Thrift format./api/v2/spansfor submitting spans in Zipkin JSON v2.
Trace retrieval APIs
Traces saved in the storage can be retrieved by calling jaeger-query Service.
gRPC/Protobuf (stable)
The recommended way for programmatically retrieving traces and other data is via the jaeger.api_v2.QueryService gRPC endpoint defined in query.proto IDL file. In the default configuration this endpoint is accessible from jaeger-query:16685.
HTTP JSON (internal)
Jaeger UI communicates with jaeger-query Service via JSON API. For example, a trace can be retrieved via a GET request to https://jaeger-query:16686/api/traces/{trace-id-hex-string}. This JSON API is intentionally undocumented and subject to change.
Remote Storage API (stable)
When using the grpc storage type (a.k.a. remote storage), Jaeger components can use custom storage backends as long as those backends implement the gRPC Remote Storage API.
Remote Sampling Configuration (stable)
This API supports Jaeger's Remote Sampling protocol, defined in the sampling.proto IDL file.
jaeger-collector implements this API. See Remote Sampling for details on how to configure the Collector with sampling strategies.
The following table lists different endpoints and formats that can be used to query for sampling strategies. The official HTTP/JSON endpoints use standard Protobuf-to-JSON mapping.
| Component | Port | Endpoint | Format | Notes |
|---|---|---|---|---|
| Collector | 14268 | /api/sampling |
HTTP/JSON | Recommended for most SDKs |
| Collector | 14250 | sampling.proto | gRPC | For SDKs that want to use gRPC (e.g. OpenTelemetry Java SDK) |
Examples
Run all-in-one in one terminal:
$ go run ./cmd/all-in-one \
--sampling.strategies-file=cmd/all-in-one/sampling_strategies.jsonQuery the endpoint in another terminal:
$ curl "http://localhost:14268/api/sampling?service=foo"
{"strategyType":"PROBABILISTIC","probabilisticSampling":{"samplingRate":1}}Service dependencies graph (internal)
Can be retrieved fromjaeger-query Service at /api/dependencies endpoint. The GET request expects two parameters:
endTs(number of milliseconds since epoch) - the end of the time intervallookback(in milliseconds) - the length the time interval (i.e. start-time + lookback = end-time).
The returned JSON is a list of edges represented as tuples (caller, callee, count).
For programmatic access to the service graph, the recommended API is gRPC/Protobuf described above.
Service Performance Monitoring (internal)
Please refer to the SPM Documentation
File: content/docs/v1/1.76/architecture/sampling.md
title: Sampling aliases: [../sampling] hasparent: true
Jaeger libraries implement consistent upfront (or head-based) sampling. For example, assume we have a simple call graph where service A calls service B, and B calls service C: A -> B -> C. When service A receives a request that contains no tracing information, Jaeger tracer will start a new trace, assign it a random trace ID, and make a sampling decision based on the currently installed sampling strategy. The sampling decision will be propagated with the requests to B and to C, so those services will not be making the sampling decision again but instead will respect the decision made by the top service A. This approach guarantees that if a trace is sampled, all its spans will be recorded in the backend. If each service was making its own sampling decision we would rarely get complete traces in the backend.
Client Sampling Configuration
{{< warning >}}
This section only applies to classic Jaeger SDKs, which are now deprecated.
We recommend using the OpenTelemetry SDKs.
{{< /warning >}}
When using configuration object to instantiate the tracer, the type of sampling can be selected via sampler.type and sampler.param properties. Jaeger libraries support the following samplers:
- Constant (
sampler.type=const) sampler always makes the same decision for all traces. It either samples all traces (sampler.param=1) or none of them (sampler.param=0). - Probabilistic (
sampler.type=probabilistic) sampler makes a random sampling decision with the probability of sampling equal to the value ofsampler.paramproperty. For example, withsampler.param=0.1approximately 1 in 10 traces will be sampled. - Rate Limiting (
sampler.type=ratelimiting) sampler uses a leaky bucket rate limiter to ensure that traces are sampled with a certain constant rate. For example, whensampler.param=2.0it will sample requests with the rate of 2 traces per second. - Remote (
sampler.type=remote, which is also the default) sampler consults jaeger-collector for the appropriate sampling strategy to use in the current service. This allows controlling the sampling strategies in the services from a central configuration in Jaeger backend (see Remote Sampling), or even dynamically (see Adaptive Sampling).
Remote Sampling
If your client SDKs are configured to use remote sampling configuration (see Remote Sampling API) then sampling rates can be centrally controlled via jaeger-collectors. In this setup a sampling strategy configuration is served to the client SDK that describes endpoints and their sampling probabilities. This configuration can be generated by jaeger-collector in two different ways: periodically loaded from a file or dynamically calculated based on traffic. The method of generation is controlled by the environment variable SAMPLING_CONFIG_TYPE which can be set to either file (default) or adaptive.
File-based Sampling Configuration
jaeger-collectors can be instantiated with the --sampling.strategies-file option that points to a file containing sampling strategies to be served to Jaeger clients. The option's value can contain a path to a JSON file, which will be automatically reloaded if its contents change, or an HTTP URL from where the file will be periodically retrieved, with reload frequency controlled by the --sampling.strategies-reload-interval option.
If no configuration is provided, jaeger-collectors will return the default probabilistic sampling policy with probability 0.001 (0.1%) for all services.
Example strategies.json:
{
"service_strategies": [
{
"service": "foo",
"type": "probabilistic",
"param": 0.8,
"operation_strategies": [
{
"operation": "op1",
"type": "probabilistic",
"param": 0.2
},
{
"operation": "op2",
"type": "probabilistic",
"param": 0.4
}
]
},
{
"service": "bar",
"type": "ratelimiting",
"param": 5
}
],
"default_strategy": {
"type": "probabilistic",
"param": 0.5,
"operation_strategies": [
{
"operation": "/health",
"type": "probabilistic",
"param": 0.0
},
{
"operation": "/metrics",
"type": "probabilistic",
"param": 0.0
}
]
}
}service_strategies element defines service specific sampling strategies and operation_strategies defines operation specific sampling strategies. There are 2 types of strategies possible: probabilistic and ratelimiting which are described above (NOTE: ratelimiting is not supported for operation_strategies). default_strategy defines the catch-all sampling strategy that is propagated if the service is not included as part of service_strategies.
In the above example:
- All operations of service
fooare sampled with probability 0.8 except for operationsop1andop2which are probabilistically sampled with probabilities 0.2 and 0.4 respectively. - All operations for service
barare rate-limited at 5 traces per second. - Any other service will be sampled with probability 0.5 defined by the
default_strategy. - The
default_strategyalso includes shared per-operation strategies. In this example we disable tracing on/healthand/metricsendpoints for all services by using probability 0. These per-operation strategies will apply to any new service not listed in the config, as well as to thefooandbarservices unless they define their own strategies for these two operations.
Adaptive Sampling
Since Jaeger v1.27.
Adaptive sampling works in jaeger-collector by observing the spans received from services and recalculating sampling probabilities for each service/endpoint combination to ensure that the volume of collected traces matches --sampling.target-samples-per-second. When a new service or endpoint is detected, it is initially sampled with --sampling.initial-sampling-probability until enough data is collected to calculate the rate appropriate for the traffic going through the endpoint.
Adaptive sampling requires a storage backend to store the observed traffic data and computed probabilities. At the moment memory (for all-in-one deployment), cassandra, badger, elasticsearch and opensearch are supported as sampling storage backends.
By default adaptive sampling will attempt to use the backend specified by SPAN_STORAGE_TYPE to store data. However, a second type of backend can also be specified by using SAMPLING_STORAGE_TYPE. For instance, SPAN_STORAGE_TYPE=elasticsearch SAMPLING_STORAGE_TYPE=cassandra ./jaeger-collector will run jaeger-collector in a mode where it attempts to store its span data in the configured elasticsearch cluster and its adaptive sampling data in the configured cassandra cluster. Note that this feature can not be used to store span and adaptive sampling data in two different backends of the same type.
Read this blog post for more details on adaptive sampling engine.
File: content/docs/v1/1.76/deployment/_index.md
title: Deployment
weight: 4
children:
- title: Operator for Kubernetes
navtitle: Kubernetes
url: operator - title: Frontend/UI
url: frontend-ui - title: CLI Flags
url: cli - title: Security
url: security - title: On Windows
url: windows - title: Service Performance Monitoring (SPM)
navtitle: SPM
url: spm
The main Jaeger backend components are released as Docker images on Docker Hub and Quay:
| Component | Docker Hub | Quay |
|---|---|---|
| jaeger-all-in-one | hub.docker.com/r/jaegertracing/all-in-one/ | quay.io/repository/jaegertracing/all-in-one |
| jaeger-collector | hub.docker.com/r/jaegertracing/jaeger-collector/ | quay.io/repository/jaegertracing/jaeger-collector |
| jaeger-query | hub.docker.com/r/jaegertracing/jaeger-query/ | quay.io/repository/jaegertracing/jaeger-query |
| jaeger-ingester | hub.docker.com/r/jaegertracing/jaeger-ingester/ | quay.io/repository/jaegertracing/jaeger-ingester |
| jaeger-remote-storage | hub.docker.com/r/jaegertracing/jaeger-remote-storage/ | quay.io/repository/jaegertracing/jaeger-remote-storage |
The images listed above are the primary release versions. Most components have additional images published:
${component}-debugimages include Delve debugger${component}-snapshotimages are published from the tip of the main branch for every commit, allowing testing of unreleased versions${component}-debug-snapshotsnapshot images that include the Delve debugger
There are orchestration templates for running Jaeger with:
- Kubernetes: github.com/jaegertracing/jaeger-kubernetes,
- OpenShift: github.com/jaegertracing/jaeger-openshift.
Configuration Options
Jaeger binaries can be configured in a number of ways (in the order of decreasing priority):
- command line arguments,
- environment variables,
- configuration files in JSON, TOML, YAML, HCL, or Java properties formats.
To see the complete list of options, run the binary with the help command or refer to the CLI Flags page for more information. Options that are specific to a certain storage backend are only listed if the storage type is selected. For example, to see all available options in the Collector with Cassandra storage:
$ docker run --rm \
-e SPAN_STORAGE_TYPE=cassandra \
jaegertracing/jaeger-collector:{{< currentVersion >}} \
helpIn order to provide configuration parameters via environment variables, find the respective command line option and convert its name to UPPER_SNAKE_CASE, for example:
| Command line option | Environment variable |
|---|---|
--cassandra.connections-per-host |
CASSANDRA_CONNECTIONS_PER_HOST |
--metrics-backend |
METRICS_BACKEND |
All-in-one
Jaeger all-in-one is a special distribution that combines three Jaeger components, collector, and query service/UI, in a single binary or container image. It is useful for single-node deployments where your trace volume is light enough to be handled by a single instance. By default, all-in-one starts with memory storage, meaning it will lose all data upon restart. All other span storage backends can also be used with all-in-one, but memory and badger are exclusive to all-in-one because they cannot be shared between instances.
All-in-one listens to the same ports as the components it contains (described below), with the exception of the admin port.
| Port | Protocol | Function |
|---|---|---|
| 14269 | HTTP | admin port: health check at / and metrics at /metrics |
## make sure to expose only the ports you use in your deployment scenario!
docker run -d --name jaeger \
-e COLLECTOR_OTLP_ENABLED=true \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-p 5775:5775/udp \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 14250:14250 \
-p 14268:14268 \
-p 14269:14269 \
-p 4317:4317 \
-p 4318:4318 \
-p 9411:9411 \
jaegertracing/all-in-one:{{< currentVersion >}}You can navigate to http://localhost:16686 to access the Jaeger UI.
Collector
jaeger-collectors are stateless and thus many instances of jaeger-collector can be run in parallel.
jaeger-collectors require almost no configuration, except for storage location, such as--cassandra.keyspace and --cassandra.servers options, or the location of Elasticsearch cluster,
via --es.server-urls, depending on which storage is specified. See the CLI Flags for all
command line options.
At default settings jaeger-collector exposes the following ports:
| Port | Protocol | Endpoint | Function |
|---|---|---|---|
| 4317 | gRPC | n/a | Accepts traces in OpenTelemetry OTLP format (Protobuf). |
| 4318 | HTTP | /v1/traces |
Accepts traces in OpenTelemetry OTLP format (Protobuf and JSON). |
| 14268 | HTTP | /api/sampling |
Serves sampling policies (see Remote Sampling). |
/api/traces |
Accepts spans in jaeger.thrift format with binary thrift protocol (POST). |
||
| 14269 | HTTP | / |
Admin port: health check (GET). |
/metrics |
Prometheus-style metrics (GET). |
||
| 9411 | HTTP | /api/v1/spans and /api/v2/spans |
Accepts Zipkin spans in Thrift, JSON and Proto (disabled by default). |
| 14250 | gRPC | n/a | Accepts spans in model.proto Protobuf format. |
Ingester
jaeger-ingester is a service which reads span data from Kafka topic and writes it to another storage backend (Elasticsearch or Cassandra).
| Port | Protocol | Function |
|---|---|---|
| 14270 | HTTP | admin port: health check at / and metrics at /metrics |
To view all exposed configuration options run the following command:
docker run \
-e SPAN_STORAGE_TYPE=cassandra \
jaegertracing/jaeger-ingester:{{< currentVersion >}}
--helpQuery Service & UI
jaeger-query serves the API endpoints and a React/Javascript UI.
The service is stateless and is typically run behind a load balancer, such as NGINX.
At default settings the jaeger-query service exposes the following port(s):
| Port | Protocol | Function |
|---|---|---|
| 16685 | gRPC | Protobuf/gRPC QueryService |
| 16686 | HTTP | /api/* endpoints and Jaeger UI at / |
| 16687 | HTTP | admin port: health check at / and metrics at /metrics |
Minimal deployment example (Elasticsearch backend):
docker run -d --rm \
-p 16685:16685 \
-p 16686:16686 \
-p 16687:16687 \
-e SPAN_STORAGE_TYPE=elasticsearch \
-e ES_SERVER_URLS=http://<ES_SERVER_IP>:<ES_SERVER_PORT> \
jaegertracing/jaeger-query:{{< currentVersion >}}Clock Skew Adjustment
Jaeger backend combines trace data from applications that are usually running on different hosts. The hardware clocks on the hosts often experience relative drift, known as the clock skew effect. Clock skew can make it difficult to reason about traces, for example, when a server span may appear to start earlier than the client span, which should not be possible. jaeger-query service implements a clock skew adjustment algorithm (code) to correct for clock drift, using the knowledge about causal relationships between spans. All adjusted spans have a warning displayed in the UI that provides the exact clock skew delta applied to their timestamps.
Sometimes these adjustments themselves make the trace hard to understand. For example, when repositioning the server span within the bounds of its parent span, Jaeger does not know the exact relationship between the request and response latencies, so it assumes they are equal and places the child span in the middle of the parent span (see issue #961).
jaeger-query service supports a configuration flag --query.max-clock-skew-adjustment that controls how much clock skew adjustment should be allowed. Setting this parameter to zero (0s) disables clock skew adjustment completely. This setting applies to all traces retrieved from the given query service. There is an open ticket #197 to support toggling the adjustment on and off directly in the UI.
UI Base Path
The base path for all jaeger-query HTTP routes can be set to a non-root value, e.g. /jaeger would cause all UI URLs to start with /jaeger. This can be useful when running jaeger-query behind a reverse proxy.
The base path can be configured via the --query.base-path command line parameter or the QUERY_BASE_PATH environment variable.
UI Customization and Embedding
Please refer to the dedicated Frontend/UI page.
Remote Storage (component)
jaeger-remote-storage implements the Remote Storage gRPC API and proxies it into one of the regular Jaeger backends. It can be useful in the situation when we want to run a full deployment of Jaeger components, e.g., separate collector and query services, but use a single-node storage backend like the memory store or Badger. Without the remote storage, the single-node backends can only be used with all-in-one since they cannot be shared between multiple processes.
At default settings the service listens on the following port(s):
| Port | Protocol | Function |
|---|---|---|
| 17271 | gRPC | Remote Storage API |
| 17270 | HTTP | admin port: health check at / and metrics at /metrics |
Span Storage Backends
Jaeger requires a persistent storage backend. Cassandra and Elasticsearch/OpenSearch are the primary supported distributed storage backends. Additional backends are discussed here.
The storage type can be passed via SPAN_STORAGE_TYPE environment variable. Valid values are cassandra, elasticsearch, kafka (only as a buffer), badger and memory.
As of version 1.6.0, it's possible to use multiple storage types at the same time by providing a comma-separated list of valid types to the SPAN_STORAGE_TYPE environment variable. It's important to note that all listed storage types are used for writing, but only the first type in the list will be used for reading and archiving.
For large scale production deployment the Jaeger team recommends OpenSearch backend over Cassandra.
Memory
The in-memory storage is not intended for production workloads. It's intended as a simple solution to get started quickly and
data will be lost once the process exits.
By default, there's no limit in the amount of traces stored in memory but a limit can be established by passing an
integer value via --memory.max-traces.
Badger - local storage
- Since Jaeger v1.9
Badger is an embedded local storage, only available
with all-in-one distribution. By default, it acts as ephemeral storage using a temporary file system.
This can be overridden by using the --badger.ephemeral=false option.
docker run \
-e SPAN_STORAGE_TYPE=badger \
-e BADGER_EPHEMERAL=false \
-e BADGER_DIRECTORY_VALUE=/badger/data \
-e BADGER_DIRECTORY_KEY=/badger/key \
-v <storage_dir_on_host>:/badger \
-p 16686:16686 \
jaegertracing/all-in-one:{{< currentVersion >}}Cassandra
- Supported versions: 4.x, 5.x
Deploying Cassandra itself is out of scope for our documentation. One good
source of documentation is the Apache Cassandra Docs.
Configuration
Minimal
docker run \
-e SPAN_STORAGE_TYPE=cassandra \
-e CASSANDRA_SERVERS=<...> \
jaegertracing/jaeger-collector:{{< currentVersion >}}Note: White space characters are allowed in CASSANDRA_SERVERS. For Example: Servers can be passed as `CASSANDRA_SERVERS="1.2.3.4, 5.6.7.8" for better readability.
All options
To view the full list of configuration options, you can run the following command:
docker run \
-e SPAN_STORAGE_TYPE=cassandra \
jaegertracing/jaeger-collector:{{< currentVersion >}} \
--helpSchema script
A script is provided to initialize Cassandra keyspace and schema
using Cassandra's interactive shell cqlsh:
MODE=test sh ./internal/storage/v1/cassandra/schema/create.sh | cqlshOr using the published Docker image (make sure to provide the right IP address):
docker run \
-e CQLSH_HOST={server IP address} \
jaegertracing/jaeger-cassandra-schema:{{< currentVersion >}}For production deployment, pass MODE=prod DATACENTER={datacenter} arguments to the script,
where {datacenter} is the name used in the Cassandra configuration / network topology.
The script also allows overriding TTL, keyspace name, replication factor, etc.
Run the script without arguments to see the full list of recognized parameters.
Note: See README for more details on Cassandra schema management.
TLS support
Jaeger supports TLS client to node connections as long as you've configured
your Cassandra cluster correctly. After verifying with e.g. cqlsh, you can
configure the collector and query like this:
docker run \
-e CASSANDRA_SERVERS=<...> \
-e CASSANDRA_TLS=true \
-e CASSANDRA_TLS_SERVER_NAME="CN-in-certificate" \
-e CASSANDRA_TLS_KEY= \
-e CASSANDRA_TLS_CERT= \
-e CASSANDRA_TLS_CA= \
jaegertracing/jaeger-collector:{{< currentVersion >}}The schema tool also supports TLS. You need to make a custom cqlshrc file like
so:
# Creating schema in a cassandra cluster requiring client TLS certificates.
#
# Create a volume for the schema docker container containing four files:
# cqlshrc: this file
# ca-cert: the cert authority for your keys
# client-key: the keyfile for your client
# client-cert: the cert file matching client-key
#
# if there is any sort of DNS mismatch and you want to ignore server validation
# issues, then uncomment validate = false below.
#
# When running the container, map this volume to /root/.cassandra and set the
# environment variable CQLSH_SSL=--ssl
[ssl]
certfile = ~/.cassandra/ca-cert
userkey = ~/.cassandra/client-key
usercert = ~/.cassandra/client-cert
# validate = falseCompatible Backends
- ScyllaDB can be used as a drop-in replacement for Cassandra since it uses the same data model and query language.
Elasticsearch
- Supported since Jaeger v0.6.0
- Supported ES versions: 7.x, 8.x (since Jaeger v1.52.0)
Elasticsearch version is automatically retrieved from root/ping endpoint.
Based on this version Jaeger uses compatible index mappings and Elasticsearch REST API.
The version can be explicitly provided via --es.version= flag.
Elasticsearch does not require initialization other than
installing and running Elasticsearch.
Once it is running, pass the correct configuration values to jaeger-collector and jaeger-query.
Configuration
Minimal
docker run \
-e SPAN_STORAGE_TYPE=elasticsearch \
-e ES_SERVER_URLS=<...> \
jaegertracing/jaeger-collector:{{< currentVersion >}}All options
To view the full list of configuration options, you can run the following command:
docker run \
-e SPAN_STORAGE_TYPE=elasticsearch \
jaegertracing/jaeger-collector:{{< currentVersion >}} \
--helpShards and Replicas for Elasticsearch indices
Shards and replicas are some configuration values to take special attention to, because this is decided upon
index creation. This article goes into
more information about choosing how many shards should be chosen for optimization.
Elasticsearch Rollover
Elasticsearch rollover is an index management strategy that optimizes use of resources allocated to indices.
For example, indices that do not contain any data still allocate shards, and conversely, a single index might contain significantly more data than the others.
Jaeger by default stores data in daily indices which might not optimally utilize resources. Rollover feature can be enabled by --es.use-aliases=true.
Rollover lets you configure when to roll over to a new index based on one or more of the following criteria:
max_age- the maximum age of the index. It uses time units:d,h,m.max_docs- the maximum documents in the index.max_size- the maximum estimated size of primary shards (since Elasticsearch 6.x). It uses byte size unitstb,gb,mb.
Rollover index management strategy is more complex than using the default daily indices and it requires an initialization job to prepare the storage and two cron jobs to manage indices.
To learn more about rollover index management in Jaeger refer to this
article.
For automated rollover, please refer to Elasticsearch ILM support.
Initialize
The following command prepares Elasticsearch for rollover deployment by creating index aliases, indices, and index templates:
docker run -it --rm --net=host jaegertracing/jaeger-es-rollover:latest init http://localhost:9200 # <1>If you need to initialize archive storage, add -e ARCHIVE=true.
After the initialization Jaeger can be deployed with --es.use-aliases=true.
Rolling over to a new index
The next step is to periodically execute the rollover API which rolls the write alias to a new index based on supplied conditions. The command also adds a new index to the read alias to make new data available for search.
docker run -it --rm --net=host -e CONDITIONS='{"max_age": "2d"}' jaegertracing/jaeger-es-rollover:latest rollover http://localhost:9200 # <1><1> The command rolls the alias over to a new index if the age of the current write index is older than 2 days. For more conditions see Elasticsearch docs.
The next step is to remove old indices from read aliases. It means that old data will not be available for search. This imitates the behavior of --es.max-span-age flag used in the default index-per-day deployment. This step could be optional and old indices could be simply removed by index cleaner in the next step.
docker run -it --rm --net=host -e UNIT=days -e UNIT_COUNT=7 jaegertracing/jaeger-es-rollover:latest lookback http://localhost:9200 # <1><1> Removes indices older than 7 days from read alias.
Remove old data
The historical data can be removed with the jaeger-es-index-cleaner that is also used for daily indices.
docker run -it --rm --net=host -e ROLLOVER=true jaegertracing/jaeger-es-index-cleaner:latest 14 http://localhost:9200 # <1><1> Remove indices older than 14 days.
Elasticsearch ILM support
{{< warning >}}
Experimental feature added in release v1.22.0.
Supported Elasticsearch versions: 7.x
{{< /warning >}}
Elasticsearch ILM automatically manages indices according to performance, resiliency, and retention requirements.
For example:
- Rollover to a new index by size (bytes or number of documents) or age, archiving previous indices
- Delete stale indices to enforce data retention standards
Enabling ILM support
Create an ILM policy in elasticsearch named jaeger-ilm-policy.
For example, the following policy will rollover the "active" index when it is
older than 1m and delete indices that are older than 2m.shellcurl -X PUT http://localhost:9200/_ilm/policy/jaeger-ilm-policy \ -H 'Content-Type: application/json; charset=utf-8' \ --data-binary @- << EOF { "policy": { "phases": { "hot": { "min_age": "0ms", "actions": { "rollover": { "max_age": "1m" }, "set_priority": { "priority": 100 } } }, "delete": { "min_age": "2m", "actions": { "delete": {} } } } } } EOFRun elasticsearch initializer with
ES_USE_ILM=true:shelldocker run -it --rm --net=host -e ES_USE_ILM=true jaegertracing/jaeger-es-rollover:latest init http://localhost:9200 # <1><1> If you need to initialize archive storage, add
-e ARCHIVE=true.{{< info >}}
While initializing with ILM support, make sure that an ILM policy namedjaeger-ilm-policyis created in Elasticsearch beforehand (see the previous step), otherwise the following error message will be shown:"ILM policy jaeger-ilm-policy doesn't exist in Elasticsearch. Please create it and rerun init"
{{< /info >}}After the initialization, deploy Jaeger with
--es.use-ilm=trueand--es.use-aliases=true.
Upgrade Elasticsearch version
Elasticsearch defines wire and index compatibility versions. The index compatibility defines
the minimal version a node can read data from. For example Elasticsearch 8 can read indices
created by Elasticsearch 7, however it cannot read indices created by Elasticsearch 6 even
though they use the same index mappings. Therefore upgrade from Elasticsearch 7 to 8 does not require any
data migration. However, upgrade from Elasticsearch 6 to 8 has to be done through Elasticsearch 7 and wait
until indices created by ES 6.x are removed or explicitly reindexed.
Refer to the Elasticsearch documentation
for wire and index compatibility versions. Generally this information can be retrieved from root/ping REST endpoint.
Reindex
Manual reindexing can be used when upgrading from Elasticsearch 6 to 8 (through Elasticsearch 7)
without waiting until indices created by Elasticsearch 6 are removed.
Reindex all span indices to new indices with suffix
-1:bashcurl -ivX POST -H "Content-Type: application/json" http://localhost:9200/_reindex -d @reindex.json { "source": { "index": "jaeger-span-*" }, "dest": { "index": "jaeger-span" }, "script": { "lang": "painless", "source": "ctx._index = 'jaeger-span-' + (ctx._index.substring('jaeger-span-'.length(), ctx._index.length())) + '-1'" } }Delete indices with old mapping:
bashcurl -ivX DELETE -H "Content-Type: application/json" http://localhost:9200/jaeger-span-\*,-\*-1Create indices without
-1suffix:bashcurl -ivX POST -H "Content-Type: application/json" http://localhost:9200/_reindex -d @reindex.json { "source": { "index": "jaeger-span-*" }, "dest": { "index": "jaeger-span" }, "script": { "lang": "painless", "source": "ctx._index = 'jaeger-span-' + (ctx._index.substring('jaeger-span-'.length(), ctx._index.length() - 2))" } }Remove suffixed indices:
bashcurl -ivX DELETE -H "Content-Type: application/json" http://localhost:9200/jaeger-span-\*-1
Run the commands analogically for other Jaeger indices.
There might exist more effective migration procedure. Please share with the community any findings.
Kafka
- Supported in Jaeger since 1.6.0
- Supported Kafka versions: 0.9+
Kafka can be used as an intermediary buffer between collector and an actual storage.
jaeger-collector is configured with SPAN_STORAGE_TYPE=kafka that makes it write all received spans
into a Kafka topic. jaeger-ingester is used to read from
Kafka and store spans in another storage backend (Elasticsearch or Cassandra).
Writing to Kafka is particularly useful for building post-processing data pipelines.
Configuration
Minimal
docker run \
-e SPAN_STORAGE_TYPE=kafka \
-e KAFKA_PRODUCER_BROKERS=<...> \
-e KAFKA_TOPIC=<...> \
jaegertracing/jaeger-collector:{{< currentVersion >}}All options
To view the full list of configuration options, you can run the following command:
docker run \
-e SPAN_STORAGE_TYPE=kafka \
jaegertracing/jaeger-collector:{{< currentVersion >}} \
--helpTopic & partitions
Unless your Kafka cluster is configured to automatically create topics, you will need to create it ahead of time. You can refer to the Kafka quickstart documentation to learn how.
You can find more information about topics and partitions in general in the official documentation. This article provide more details about how to choose the number of partitions.
Remote Storage
Jaeger supports a gRPC-based Remote Storage API that allows extending the Jaeger ecosystem with custom storage backends, not directly supported by the project. These storage backends can be deployed as a remote gRPC server (since Jaeger v1.30). Older deployment mode as sidecar plugin will not be supported starting from v1.58.
To use a remote storage as Jaeger storage backend, use grpc as the storage type and specify the remote gRPC server address. For more information, please refer to internal/storage/v1/grpc.
Example:
docker run \
-e SPAN_STORAGE_TYPE=grpc \
-e GRPC_STORAGE_SERVER=<...> \
jaegertracing/all-in-one:{{< currentVersion >}}Known remote storage backends:
Metrics Storage Backends
Jaeger Query is capable of querying aggregated R.E.D metrics from a storage backend,
visualizing them on the Monitor tab. It should be emphasized that the
configured metrics storage type is for reading only and therefore, only applies
to the Jaeger Query component (and All In One, which contains Jaeger Query).
The storage type can be passed via METRICS_STORAGE_TYPE environment variable.
Valid values are: prometheus.
Prometheus
Any PromQL-compatible backend is supported by Jaeger Query. A list of these have
been compiled by Julius Volz in:
https://promlabs.com/blog/2020/11/26/an-update-on-promql-compatibility-across-vendors
Configuration
Minimal
docker run \
-e METRICS_STORAGE_TYPE=prometheus \
jaegertracing/jaeger-query:{{< currentVersion >}}All options
To view the full list of configuration options, you can run the following command:
docker run \
-e METRICS_STORAGE_TYPE=prometheus \
jaegertracing/jaeger-query:{{< currentVersion >}} \
--helpTLS support
Jaeger supports TLS client to Prometheus server connections as long as you've configured
your Prometheus server correctly. You can
configure jaeger-query like so:
docker run \
-e METRICS_STORAGE_TYPE=prometheus \
-e PROMETHEUS_SERVER_URL=<...> \
-e PROMETHEUS_TLS_ENABLED=true \
-e PROMETHEUS_TLS_CA= \
jaegertracing/jaeger-query:{{< currentVersion >}}Aggregation Jobs for Service Dependencies
Production deployments need an external process that aggregates data and creates dependency links between services. Project spark-dependencies is a Spark job which derives dependency links and writes them directly to the storage.
File: content/docs/v1/1.76/deployment/cli.md
title: CLI flags aliases: [../cli] widescreen: true hasparent: true
This is auto-generated documentation for CLI flags supported by Jaeger binaries.
- CLI flags for some binaries change depending on the
SPAN_STORAGE_TYPEenvironment variable. Relevant variations are included below. - Some binaries support commands (mostly informational), such as
env,docs,version, andstatus. These commands are not included here. - All parameters can be provided via environment variables, by changing all letters to upper-case and replacing all punctuation characters with the underscore
_. For example, the value for the flag--cassandra.connections-per-hostcan be provided via theCASSANDRA_CONNECTIONS_PER_HOSTenvironment variable.
{{< cli/tools-list >}}
File: content/docs/v1/1.76/deployment/frontend-ui.md
title: Frontend/UI Configuration navtitle: Frontend/UI aliases: [../frontend-ui] hasparent: true weight: 7
Configuration
Several aspects of the UI can be configured:
- The Dependencies section can be enabled / configured
- The Monitor tab (aka: Service Performance Monitoring) can be enabled / configured
- App analytics tracking can be enabled / configured (via Google Analytics or custom plugin)
- Additional menu options can be added to the global nav
- Search input limits can be configured
These options can be configured by a JSON configuration file. The --query.ui-config command line parameter of the query service must then be set to the path to the JSON file when the query service is started.
An example configuration file (see complete schema here):
{
"dependencies": {
"dagMaxNumServices": 200,
"menuEnabled": true
},
"monitor": {
"menuEnabled": true
},
"archiveEnabled": true,
"tracking": {
"gaID": "UA-000000-2",
"trackErrors": true
},
"menu": [
{
"label": "About Jaeger",
"items": [
{
"label": "GitHub",
"url": "https://github.com/jaegertracing/jaeger"
},
{
"label": "Docs",
"url": "https://www.jaegertracing.io/docs/latest/"
}
]
}
],
"search": {
"maxLookback": {
"label": "2 Days",
"value": "2d"
},
"maxLimit": 1500
},
"linkPatterns": [{
"type": "process",
"key": "jaeger.version",
"url": "https://github.com/jaegertracing/jaeger-client-java/releases/tag/#{jaeger.version}",
"text": "Information about Jaeger release #{jaeger.version}"
},
{
"type": "tags",
"key": "uniqueId",
"url": "https://mykibana.com/uniqueId=#{uniqueId}&traceId=#{trace.traceID}",
"text": "Redirect to kibana to view log"
},
{
"type": "traces",
"url": "https://my-logs.server?from=#{startTime | add -60000000 | epoch_micros_to_date_iso}&to=#{endTime | add 60000000 | epoch_micros_to_date_iso}'",
"text": "Redirect to kibana to view log with formatted dates"
}]
}Dependencies
dependencies.dagMaxNumServices defines the maximum number of services allowed before the DAG dependency view is disabled. Default: 200.
dependencies.menuEnabled enables (true) or disables (false) the dependencies menu button. Default: true.
Monitor
monitor.menuEnabled enables (true) or disables (false) the Monitor menu button. Default: false.
Archive Support
archiveEnabled enables (true) or disables (false) the archive traces button. Default: false. It requires a configuration of an archive storage in Query service. Archived traces are only accessible directly by ID, they are not searchable.
App Analytics Tracking
tracking.gaID defines the Google Analytics tracking ID. This is required for Google Analytics tracking, and setting it to a non-null value enables Google Analytics tracking. Default: null.
tracking.customWebAnalytics defines a factory function for a custom tracking plugin (only when using Javascript-form of UI configuration).
tracking.trackErrors enables (true) or disables (false) error tracking. Errors can only be tracked if a valid analytics tracker is configured. Default: true.
For additional details on app analytics see the tracking README in the UI repo.
Custom Menu Items
menu allows additional links to be added to the global nav. The additional links are right-aligned.
In the sample JSON config above, the configured menu will have a dropdown labeled "About Jaeger" with sub-options for "GitHub" and "Docs". The format for a link in the top right menu is as follows:
{
"label": "Some text here",
"url": "https://example.com"
}Links can either be members of the menu Array, directly, or they can be grouped into a dropdown menu option. The format for a group of links is:
{
"label": "Dropdown button",
"items": [ ]
}The items Array should contain one or more link configurations.
Search Input Limit
The search.maxLimit configures the maximum results that the input let you search.
The search.maxLookback configures the maximum time before the present users can query for traces. The options in the Lookback dropdown greater than this value will not be shown.
| Field | Description |
|---|---|
| label | The text displayed in the search form dropdown |
| value | The value submitted in the search query if the label is selected |
Link Patterns
The linkPatterns node can be used to create links from fields displayed in the Jaeger UI.
| Field | Description |
|---|---|
| type | The metadata section in which your link will be added: process, tags, logs, traces |
| key | The name of tag/process/log attribute which value will be displayed as a link, this field is not necessary for type traces. |
| url | The URL where the link should point to, it can be an external site or relative path in Jaeger UI |
| text | The text displayed in the tooltip for the link |
Both url and text can be defined as templates (i.e. using #{field-name}) where Jaeger UI will dynamically substitute values based on tags/logs/traces data.
For traces, the supported template fields are: duration, endTime, startTime, traceName and traceID.
Further, the trace template fields are available for substitution in process/logs/tags type when the trace template fields are prefixed with trace.. For example: trace.traceID, trace.startTime.
Formatting
In addition to interpolating fields into links, formatting functions can be used. The syntax is #{field | function} (eg #{endTime | epoch_micros_to_date_iso}'). Formatting functions can be chained together (eg #{startTime | add 60000000 | epoch_micros_to_date_iso}).
The available formatting functions and a description of their behavior are:
`epoch_micros_to_date_iso`
Format a date in microseconds since epoch to an ISO date time.
Example:#{endTime | epoch_micros_to_date_iso}
`pad_start`
Pad the start of a string with a given character until the resulting string reaches the given length. Behavior is implemented by and thus matches javascript's String.padStart
Arguments:
targetLength(integer) - Desired length of the string after paddingpadCharacter(string) - String to pad the start of the input string with
Example: #{traceID | pad_start 32 0}
`add`
Add a value to another number. Can be positive or negative.
Arguments:
offset(integer) - Value to add to the input number
Example: #{startTime | add 1000000}
Embedded Mode
Starting with version 1.9, Jaeger UI provides an "embedded" layout mode which is intended to support integrating Jaeger UI into other applications. Currently (as of v0), the approach taken is to remove various UI elements from the page to make the UI better suited for space-constrained layouts.
The embedded mode is induced and configured via URL query parameters.
To enter embedded mode, the uiEmbed=v0 query parameter and value must be added to the URL. For example, the following URL will show the trace with ID abc123 in embedded mode:
http://localhost:16686/trace/abc123?uiEmbed=v0uiEmbed=v0 is required.
Further, for each supported page a button {{< rawhtml >}}{{< /rawhtml >}} is added that will open the non-embedded page in a new tab.
The following pages support embedded mode:
- Search Page
- Trace Page
Search Page
To integrate the Search Trace Page to our application we have to indicate to the Jaeger UI that we want to use the embed mode with uiEmbed=v0.
For example:
http://localhost:16686/search?
service=my-service&
start=1543917759557000&
end=1543921359557000&
limit=20&
lookback=1h&
maxDuration&
minDuration&
uiEmbed=v0Configuration options
The following query parameter can be used to configure the layout of the search page :
uiSearchHideGraph=1- disables the display of the scatter plot above the search results
http://localhost:16686/search?
service=my-service&
start=1543917759557000&
end=1543921359557000&
limit=20&
lookback=1h&
maxDuration&
minDuration&
uiEmbed=v0&
uiSearchHideGraph=1Trace Page
To integrate the Trace Page to our application we have to indicate to the Jaeger UI that we want to use the embed mode with uiEmbed=v0.
For example:
http://localhost:16686/trace/{trace-id}?uiEmbed=v0If we have navigated to this view from the search traces page we'll have a button to go back to the results page.
Configuration options
The following query parameters can be used to configure the layout of the trace page :
uiTimelineCollapseTitle=1causes the trace header to start out collapsed, which hides the summary and the minimap.
http://localhost:16686/trace/{trace-id}?
uiEmbed=v0&
uiTimelineCollapseTitle=1uiTimelineHideMinimap=1removes the minimap, entirely, regardless of whether the trace header is expanded or not.
http://localhost:16686/trace/{trace-id}?
uiEmbed=v0&
uiTimelineHideMinimap=1uiTimelineHideSummary=1- removes the trace summary information (number of services, etc.) entirely, regardless of whether the trace header is expanded or not.
http://localhost:16686/trace/{trace-id}?
uiEmbed=v0&
uiTimelineHideSummary=1We can also combine the options:
http://localhost:16686/trace/{trace-id}?
uiEmbed=v0&
uiTimelineHideMinimap=1&
uiTimelineHideSummary=1