Setup Jaeger sampling strategies for high-volume production tracing

Advanced 45 min Jun 11, 2026 500 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Configure advanced Jaeger sampling strategies to efficiently capture traces in high-traffic production environments while controlling storage costs and maintaining observability.

Prerequisites

  • Existing Jaeger installation
  • Prometheus for metrics
  • Root or sudo access
  • Basic understanding of distributed tracing

What this solves

In high-volume production environments, tracing every request creates overwhelming data volumes and storage costs. Jaeger sampling strategies help you capture meaningful traces while controlling resource usage. This tutorial shows you how to implement adaptive sampling, per-service policies, and remote sampling configuration for production-scale distributed tracing.

Prerequisites

You need a running Jaeger deployment with Elasticsearch or another storage backend. If you don't have this yet, follow our Jaeger Kubernetes deployment guide.

Understanding sampling strategies

Jaeger supports several sampling strategies that determine which traces to collect:

Strategy TypeUse CaseConfiguration
ConstFixed percentage samplingAlways sample X% of traces
ProbabilisticRandom samplingSample based on trace ID
RateLimitingMaximum traces per secondCap at N traces/second
AdaptiveDynamic adjustmentAdjust based on traffic patterns
PerServiceService-specific rulesDifferent rates per service

Step-by-step configuration

Create sampling strategies configuration

Create a JSON configuration file that defines your sampling strategies. This file tells Jaeger how to sample traces for different services and operations.

{
  "default_strategy": {
    "type": "probabilistic",
    "param": 0.1
  },
  "per_service_strategies": [
    {
      "service": "frontend-service",
      "type": "probabilistic",
      "param": 0.5,
      "max_traces_per_second": 100
    },
    {
      "service": "payment-service",
      "type": "probabilistic",
      "param": 1.0,
      "max_traces_per_second": 50
    },
    {
      "service": "logging-service",
      "type": "probabilistic",
      "param": 0.01,
      "max_traces_per_second": 10
    },
    {
      "service": "health-check",
      "type": "probabilistic",
      "param": 0.001
    }
  ],
  "per_operation_strategies": [
    {
      "service": "frontend-service",
      "operation": "GET /health",
      "type": "probabilistic",
      "param": 0.001
    },
    {
      "service": "api-gateway",
      "operation": "POST /api/orders",
      "type": "probabilistic",
      "param": 0.8,
      "max_traces_per_second": 200
    }
  ]
}

Configure Jaeger Collector with sampling strategies

Update your Jaeger Collector configuration to use the sampling strategies file. This enables remote sampling where the collector serves sampling decisions to clients.

sampling:
  strategies-file: /etc/jaeger/sampling_strategies.json
  strategies-reload-interval: 30s

http-server:
  host-port: :14268

grpc-server:
  host-port: :14250

processors:
  batch:
    timeout: 1s
    send-batch-size: 1024
    send-batch-max-size: 2048

Setup adaptive sampling with volume control

Create an advanced configuration that adapts sampling rates based on traffic volume and service importance.

{
  "default_strategy": {
    "type": "adaptive",
    "max_traces_per_second": 500,
    "param": 0.1
  },
  "per_service_strategies": [
    {
      "service": "user-service",
      "type": "adaptive",
      "param": 0.3,
      "max_traces_per_second": 100,
      "operation_strategies": [
        {
          "operation": "login",
          "type": "probabilistic",
          "param": 0.8
        },
        {
          "operation": "register",
          "type": "probabilistic",
          "param": 1.0
        }
      ]
    },
    {
      "service": "database-service",
      "type": "rate_limiting",
      "param": 50
    },
    {
      "service": "cache-service",
      "type": "probabilistic",
      "param": 0.05,
      "max_traces_per_second": 20
    }
  ]
}

Configure environment-specific sampling

Create different sampling configurations for development, staging, and production environments.

{
  "default_strategy": {
    "type": "probabilistic",
    "param": 0.01
  },
  "per_service_strategies": [
    {
      "service": "critical-payment-service",
      "type": "probabilistic",
      "param": 0.5,
      "max_traces_per_second": 1000
    },
    {
      "service": "user-analytics",
      "type": "probabilistic",
      "param": 0.001,
      "max_traces_per_second": 10
    }
  ]
}
{
  "default_strategy": {
    "type": "probabilistic",
    "param": 1.0
  },
  "per_service_strategies": [
    {
      "service": "test-service",
      "type": "probabilistic",
      "param": 1.0
    }
  ]
}

Enable remote sampling in Jaeger Collector

Configure the Jaeger Collector to serve sampling strategies to client applications over HTTP.

sudo systemctl stop jaeger-collector
[Unit]
Description=Jaeger Collector
After=network.target

[Service]
Type=simple
User=jaeger
Group=jaeger
ExecStart=/usr/local/bin/jaeger-collector \
  --config-file=/etc/jaeger/collector.yaml \
  --sampling.strategies-file=/etc/jaeger/production_sampling.json \
  --sampling.strategies-reload-interval=60s \
  --collector.http-server.host-port=:14268 \
  --collector.grpc-server.host-port=:14250
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl start jaeger-collector
sudo systemctl status jaeger-collector

Configure client applications for remote sampling

Update your application configuration to fetch sampling strategies from the Jaeger Collector instead of using local configuration.

package main

import (
    "github.com/uber/jaeger-client-go/config"
    "github.com/uber/jaeger-client-go"
)

func initJaeger() {
    cfg := config.Configuration{
        ServiceName: "my-service",
        Sampler: &config.SamplerConfig{
            Type: jaeger.SamplerTypeRemote,
            Param: 0.1, // fallback sampling rate
            SamplingServerURL: "http://jaeger-collector:14268/api/sampling",
            SamplingRefreshInterval: 60,
        },
        Reporter: &config.ReporterConfig{
            LocalAgentHostPort: "jaeger-agent:6831",
        },
    }
    
    tracer, closer, err := cfg.NewTracer()
    if err != nil {
        panic(err)
    }
    defer closer.Close()
}

Setup sampling strategy monitoring

Create a monitoring script to track sampling effectiveness and adjust strategies based on metrics.

#!/bin/bash

# Get sampling stats from Jaeger
SAMPLING_URL="http://localhost:14268/api/sampling"
METRICS_URL="http://localhost:14269/metrics"

# Check current sampling strategies
echo "Current sampling strategies:"
curl -s $SAMPLING_URL | jq .

# Get trace volume metrics
echo "\nTrace volume metrics:"
curl -s $METRICS_URL | grep jaeger_collector_traces_received_total

# Check storage usage
echo "\nStorage usage:"
curl -s $METRICS_URL | grep jaeger_collector_spans_saved_total

# Calculate sampling efficiency
RECEIVED=$(curl -s $METRICS_URL | grep jaeger_collector_traces_received_total | tail -1 | awk '{print $2}')
SAVED=$(curl -s $METRICS_URL | grep jaeger_collector_spans_saved_total | tail -1 | awk '{print $2}')

if [ "$RECEIVED" -gt 0 ]; then
    EFFICIENCY=$(echo "scale=2; $SAVED / $RECEIVED * 100" | bc)
    echo "\nSampling efficiency: $EFFICIENCY%"
fi
sudo chmod +x /usr/local/bin/monitor-sampling.sh

Create automated sampling adjustment script

Implement a script that automatically adjusts sampling rates based on system load and storage capacity.

#!/usr/bin/env python3
import json
import requests
import time
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class SamplingAdjuster:
    def __init__(self, collector_url, strategies_file):
        self.collector_url = collector_url
        self.strategies_file = strategies_file
        
    def get_current_load(self):
        """Get current trace volume from metrics"""
        try:
            response = requests.get(f"{self.collector_url}/metrics")
            metrics = response.text
            
            # Extract trace rate (traces per second)
            for line in metrics.split('\n'):
                if 'jaeger_collector_traces_received_total' in line:
                    return float(line.split()[-1])
        except Exception as e:
            logger.error(f"Failed to get metrics: {e}")
        return 0
        
    def adjust_sampling_rate(self, current_load):
        """Adjust sampling based on load"""
        with open(self.strategies_file, 'r') as f:
            strategies = json.load(f)
            
        # Adjust default strategy based on load
        if current_load > 10000:  # High load
            strategies['default_strategy']['param'] = 0.01
        elif current_load > 1000:  # Medium load  
            strategies['default_strategy']['param'] = 0.05
        else:  # Low load
            strategies['default_strategy']['param'] = 0.1
            
        # Write updated strategies
        with open(self.strategies_file, 'w') as f:
            json.dump(strategies, f, indent=2)
            
        logger.info(f"Adjusted sampling for load: {current_load}")
        
def main():
    adjuster = SamplingAdjuster(
        collector_url="http://localhost:14268",
        strategies_file="/etc/jaeger/production_sampling.json"
    )
    
    while True:
        load = adjuster.get_current_load()
        adjuster.adjust_sampling_rate(load)
        time.sleep(300)  # Check every 5 minutes
        
if __name__ == "__main__":
    main()
sudo chmod +x /usr/local/bin/adjust-sampling.py

Setup sampling strategy validation

Create a validation script to ensure sampling configurations are working correctly.

#!/bin/bash

JAEGER_COLLECTOR="http://localhost:14268"
JAEGER_QUERY="http://localhost:16686"

echo "Validating Jaeger sampling configuration..."

# Test sampling endpoint
echo "1. Testing sampling endpoint:"
SAMPLING_RESPONSE=$(curl -s -w "%{http_code}" $JAEGER_COLLECTOR/api/sampling)
HTTP_CODE=${SAMPLING_RESPONSE: -3}

if [ "$HTTP_CODE" = "200" ]; then
    echo "✓ Sampling endpoint accessible"
else
    echo "✗ Sampling endpoint failed (HTTP $HTTP_CODE)"
    exit 1
fi

# Validate JSON structure
echo "\n2. Validating sampling strategy JSON:"
SAMPLING_JSON=$(curl -s $JAEGER_COLLECTOR/api/sampling)
echo $SAMPLING_JSON | jq . > /dev/null 2>&1
if [ $? -eq 0 ]; then
    echo "✓ Valid JSON structure"
else
    echo "✗ Invalid JSON structure"
    exit 1
fi

# Check for required fields
echo "\n3. Checking required fields:"
HAS_DEFAULT=$(echo $SAMPLING_JSON | jq -r '.default_strategy.type')
if [ "$HAS_DEFAULT" != "null" ] && [ "$HAS_DEFAULT" != "" ]; then
    echo "✓ Default strategy configured"
else
    echo "✗ Missing default strategy"
fi

# Test trace collection
echo "\n4. Testing trace collection:"
TRACE_COUNT=$(curl -s "$JAEGER_QUERY/api/traces?limit=1" | jq -r '.data | length')
if [ "$TRACE_COUNT" -gt 0 ]; then
    echo "✓ Traces are being collected"
else
    echo "! No recent traces found (this may be normal)"
fi

echo "\nSampling validation complete."
sudo chmod +x /usr/local/bin/validate-sampling.sh

Configure per-service sampling policies

Create service-tier based sampling

Implement different sampling rates based on service criticality and business importance.

{
  "default_strategy": {
    "type": "probabilistic",
    "param": 0.1
  },
  "per_service_strategies": [
    {
      "service": "tier1-payment-gateway",
      "type": "probabilistic",
      "param": 0.8,
      "max_traces_per_second": 500,
      "operation_strategies": [
        {
          "operation": "process_payment",
          "type": "probabilistic",
          "param": 1.0
        },
        {
          "operation": "refund_payment",
          "type": "probabilistic",
          "param": 1.0
        }
      ]
    },
    {
      "service": "tier2-user-service",
      "type": "probabilistic",
      "param": 0.3,
      "max_traces_per_second": 200
    },
    {
      "service": "tier3-analytics",
      "type": "probabilistic",
      "param": 0.05,
      "max_traces_per_second": 50
    },
    {
      "service": "tier4-background-jobs",
      "type": "probabilistic",
      "param": 0.01,
      "max_traces_per_second": 10
    }
  ]
}

Setup error-based sampling boost

Configure higher sampling rates for services experiencing errors to improve debugging.

{
  "default_strategy": {
    "type": "probabilistic",
    "param": 0.1
  },
  "per_service_strategies": [
    {
      "service": "error-prone-service",
      "type": "probabilistic",
      "param": 0.5,
      "max_traces_per_second": 100,
      "operation_strategies": [
        {
          "operation": "failing_endpoint",
          "type": "probabilistic",
          "param": 1.0
        }
      ]
    }
  ],
  "per_operation_strategies": [
    {
      "service": "*",
      "operation": "*error*",
      "type": "probabilistic",
      "param": 0.8
    },
    {
      "service": "*", 
      "operation": "*exception*",
      "type": "probabilistic",
      "param": 0.8
    }
  ]
}

Setup remote sampling with Jaeger Collector

Configure collector for high availability

Setup multiple Jaeger Collectors with load balancing for sampling strategy distribution.

sampling:
  strategies-file: /etc/jaeger/production_sampling.json
  strategies-reload-interval: 30s

http-server:
  host-port: 0.0.0.0:14268

grpc-server: 
  host-port: 0.0.0.0:14250

span-storage:
  type: elasticsearch
  
elasticsearch:
  server-urls: http://elasticsearch-1:9200,http://elasticsearch-2:9200
  index-prefix: jaeger
  
processors:
  batch:
    timeout: 1s
    send-batch-size: 2048
    send-batch-max-size: 4096

metrics-storage:
  type: prometheus

Create sampling strategy hot reload

Implement a system to update sampling strategies without restarting the collector.

#!/bin/bash

STRATEGIES_FILE="/etc/jaeger/production_sampling.json"
COLLECTOR_PID_FILE="/var/run/jaeger-collector.pid"
BACKUP_DIR="/var/backups/jaeger"

# Create backup
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
sudo mkdir -p $BACKUP_DIR
sudo cp $STRATEGIES_FILE "$BACKUP_DIR/sampling_strategies_$TIMESTAMP.json"

# Validate new configuration
echo "Validating new sampling configuration..."
if ! jq . "$STRATEGIES_FILE" > /dev/null 2>&1; then
    echo "Error: Invalid JSON in strategies file"
    exit 1
fi

# Send SIGHUP to collector for hot reload
if [ -f "$COLLECTOR_PID_FILE" ]; then
    PID=$(cat $COLLECTOR_PID_FILE)
    if kill -0 $PID 2>/dev/null; then
        echo "Reloading sampling strategies..."
        kill -HUP $PID
        echo "Sampling strategies reloaded successfully"
    else
        echo "Collector process not found, restarting service..."
        sudo systemctl restart jaeger-collector
    fi
else
    echo "PID file not found, restarting service..."
    sudo systemctl restart jaeger-collector
fi

# Verify reload
sleep 2
echo "Verifying configuration reload..."
curl -s http://localhost:14268/api/sampling | jq . > /dev/null
if [ $? -eq 0 ]; then
    echo "✓ Sampling strategies successfully reloaded"
else
    echo "✗ Failed to reload sampling strategies"
    exit 1
fi
sudo chmod +x /usr/local/bin/reload-sampling.sh

Monitor and optimize sampling performance

Setup Prometheus metrics collection

Configure Prometheus to scrape Jaeger metrics for sampling analysis. This helps you monitor sampling effectiveness and storage impact.

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'jaeger-collector'
    static_configs:
      - targets: ['localhost:14269']
    scrape_interval: 10s
    metrics_path: /metrics
    
  - job_name: 'jaeger-agent'
    static_configs:
      - targets: ['localhost:14271']
    scrape_interval: 30s
    
  - job_name: 'jaeger-query'
    static_configs:
      - targets: ['localhost:16687']
    scrape_interval: 30s

Create sampling performance dashboard

Setup Grafana dashboard to visualize sampling metrics and trace volumes.

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. Fully managed, with one fixed contact who knows your setup.

You get one fixed contact who knows your setup

Rotterdam 06:20 · reachable in a message, no ticket form