Link Search Menu Expand Document Documentation Menu

Analyzing Jaeger trace data

Introduced 2.5

If you use OpenSearch as the storage backend for Jaeger, you can analyze Jaeger trace data using trace analytics in OpenSearch Dashboards. Trace analytics shows the error rates and latency of your services and operations. You can filter traces and examine the spans of an individual trace to locate service issues.

Trace analytics supports two data sources. Select Data Prepper to analyze trace data that OpenSearch Data Prepper ingested into OpenSearch. Select Jaeger to analyze trace data that Jaeger stored in OpenSearch.

Jaeger indexes

Jaeger and Data Prepper store trace data in different indexes. Data Prepper writes to indexes named otel-v1-apm-span-* and otel-v1-apm-service-map*. Jaeger writes to indexes named jaeger-span-* and jaeger-service-*. By default, Jaeger creates a new span index and a new service index each day.

Error data requirements

Trace analytics identifies spans that contain errors using the tag.error field. Jaeger v2 always stores the error tag as a field in the span document, so error data is available without additional configuration.

Earlier Jaeger collectors store tags in a nested array by default. If you use one of these collectors, set the ES_TAGS_AS_FIELDS_ALL environment variable to true. Otherwise, error data is not available in trace analytics.

Setting up OpenSearch to use Jaeger data

The following example uses Docker Compose to run a single-node OpenSearch cluster, OpenSearch Dashboards, Jaeger, and the Jaeger HotROD sample application. HotROD sends trace data to Jaeger using the OpenTelemetry Protocol (OTLP), and Jaeger stores the data in OpenSearch.

Step 1: Set the admin password

OpenSearch requires a custom password for the admin user. In an empty directory, create a file named .env containing the following line, replacing <custom-admin-password> with a strong password:

OPENSEARCH_INITIAL_ADMIN_PASSWORD=<custom-admin-password>

Docker Compose reads this file and passes the password to both OpenSearch and Jaeger. For more information, see Admin password requirements.

Step 2: Configure Jaeger

In the same directory, create a file named jaeger-config.yaml containing the following configuration. It configures Jaeger to receive OTLP data and store it in OpenSearch:

service:
  extensions: [jaeger_storage, jaeger_query]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [jaeger_storage_exporter]

extensions:
  jaeger_query:
    storage:
      traces: opensearch_storage

  jaeger_storage:
    backends:
      opensearch_storage:
        opensearch:
          server_urls:
            - https://opensearch:9200
          tls:
            insecure_skip_verify: true # The demo security configuration uses self-signed certificates
          auth:
            basic:
              username: admin
              password: ${env:OPENSEARCH_PASSWORD}

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: opensearch_storage

Step 3: Create the Docker Compose file

In the same directory, create a file named docker-compose.yml containing the following configuration:

services:
  opensearch:
    image: opensearchproject/opensearch:latest
    environment:
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
      - OPENSEARCH_INITIAL_ADMIN_PASSWORD=${OPENSEARCH_INITIAL_ADMIN_PASSWORD}
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - opensearch-data:/usr/share/opensearch/data
    ports:
      - "9200:9200"
    healthcheck: # Jaeger starts only after the cluster is available
      test: ["CMD-SHELL", "curl -sk -u admin:$$OPENSEARCH_INITIAL_ADMIN_PASSWORD https://localhost:9200/_cluster/health | grep -qE '\"status\":\"(green|yellow)\"'"]
      interval: 10s
      timeout: 5s
      retries: 30
    networks:
      - opensearch-net

  opensearch-dashboards:
    image: opensearchproject/opensearch-dashboards:latest
    ports:
      - "5601:5601"
    environment:
      OPENSEARCH_HOSTS: '["https://opensearch:9200"]'
    networks:
      - opensearch-net
    depends_on:
      - opensearch

  jaeger:
    image: jaegertracing/jaeger:latest
    command: ["--config", "/etc/jaeger/config.yaml"]
    environment:
      - OPENSEARCH_PASSWORD=${OPENSEARCH_INITIAL_ADMIN_PASSWORD}
    volumes:
      - ./jaeger-config.yaml:/etc/jaeger/config.yaml:ro
    ports:
      - "16686:16686" # Jaeger UI
      - "4317:4317" # OTLP over gRPC
      - "4318:4318" # OTLP over HTTP
    networks:
      - opensearch-net
    depends_on:
      opensearch:
        condition: service_healthy

  hotrod:
    image: jaegertracing/example-hotrod:latest
    command: ["all"]
    environment:
      - OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4318
    ports:
      - "8080:8080"
    networks:
      - opensearch-net
    depends_on:
      - jaeger

volumes:
  opensearch-data:

networks:
  opensearch-net:

Step 4: Start the containers

To start the containers, run the following command:

docker compose up -d

Jaeger and HotROD start after the OpenSearch cluster reports a green or yellow health status, which can take a minute or longer.

To stop the containers and delete their data, run the following command:

docker compose down -v

Step 5: Generate sample data

To open the HotROD sample application, go to http://localhost:8080. Each time you select a customer, HotROD generates a trace. Some of the traces contain errors, so the error views in trace analytics display data.

HotROD sample application

To confirm that Jaeger stored the trace data in OpenSearch, list the Jaeger indexes:

curl -sk -u admin:<custom-admin-password> "https://localhost:9200/_cat/indices/jaeger-*?v"

The response contains a jaeger-span-* index and a jaeger-service-* index for the current day.

Step 6: View trace data in OpenSearch Dashboards

Go to http://localhost:5601 and log in as the admin user with the password you set in Step 1. On the top menu, go to Observability > Traces.

Selecting the data source

To analyze Jaeger data, select Jaeger from the data source selector at the top of the Trace analytics page.

Selecting Jaeger as the trace analytics data source

Trace analytics displays data only for the selected time range. The default time range is the last 5 minutes. If no traces appear, generate new data in the sample application or select a longer time range.

Traces

The Traces page lists the traces in the selected time range. For each trace, the list shows the trace ID, latency, whether the trace contains errors, and the time it was last updated.

Jaeger traces list

Error rate

To view error data, expand Service and Operations below the traces list and select Errors. The chart shows the trace error rate over time. The Top 5 Service and Operation Errors table lists the service and operation combinations that have the highest error rates.

Trace error rate over time

Request rate

To view throughput, select Request rate. The chart shows the number of traces over time. The Top 5 Service and Operation Latency table lists the service and operation combinations that have the highest latency.

Traces over time and the operations that have the highest latency

In either table, select a service and operation name to filter the traces list by that service and operation.

Trace details

To view the details of a trace, select its trace ID. The trace details page shows the time spent by each service and the spans of the trace as a timeline, a list, or a tree. The Payload section shows the span documents in JSON format.

Jaeger trace details

Services

To view the average duration, error rate, request rate, and number of traces for each service, select Services.

Jaeger services list