Как настроить сквозную корреляцию логов, метрик и трейсов?
Разбираешь инцидент: метрики показывают резкий рост latency в 03:47, но в Grafana нет аннотации, Loki выдаёт тысячи строк логов за ту минуту, а в Jaeger трейсы есть, но непонятно, какой span «лёг» первым. Три системы, три интерфейса, ноль связи между ними — и вы тратите час на ручную сверку timestamp'ов. Мы сталкивались с этим десятки раз. Наш подход — настроить сквозную корреляцию за 5–10 рабочих дней, сократить MTTR на 60% и избавить команду от рутины.
Корреляция логов, метрик и трейсов — это возможность в одном клике перейти от аномалии на графике к конкретному трейсу, а из трейса — к строке лога с полным контекстом ошибки. Без неё диагностика распределённых систем превращается в детектив с лупой. Получите консультацию по настройке корреляции для вашего проекта.
Как OpenTelemetry обеспечивает единый слой?
Современный стек для корреляции — это OpenTelemetry Collector, который получает данные от всех трёх сигналов и пробрасывает их в соответствующие бэкенды. Типовая конфигурация:
# otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
prometheus:
config:
scrape_configs:
- job_name: 'app'
static_configs:
- targets: ['app:8080']
processors:
batch:
timeout: 10s
resource:
attributes:
- key: deployment.environment
value: production
action: upsert
exporters:
otlp/jaeger:
endpoint: jaeger:4317
tls:
insecure: true
loki:
endpoint: http://loki:3100/loki/api/v1/push
labels:
resource:
service.name: "service_name"
deployment.environment: "env"
prometheus:
endpoint: 0.0.0.0:8889
namespace: otel
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch, resource]
exporters: [otlp/jaeger]
metrics:
receivers: [otlp, prometheus]
processors: [batch]
exporters: [prometheus]
logs:
receivers: [otlp]
processors: [batch, resource]
exporters: [loki]Ключевой момент: все три пайплайна работают через один Collector, который обеспечивает единый resource. В соответствии со спецификацией OpenTelemetry, trace_id должен быть 128-битным hex.
Exemplars: связь метрик с трейсами
Prometheus начиная с версии 2.29 поддерживает exemplars — это точки на гистограмме, к которым прикреплён trace_id. Чтобы это работало, нужно два условия:
# prometheus.yml global: scrape_interval: 15s storage: exemplars: max_exemplars: 100000 И в самом приложении (пример для Go с prometheus/client_golang):
histogram.With(prometheus.Labels{"handler": "/api/users"}).
ObserveWithExemplar(duration, prometheus.Labels{"traceID": span.SpanContext().TraceID().String()})В Grafana при включённом режиме exemplars на графике появляются маленькие ромбики — клик переносит прямо в Jaeger/Tempo на конкретный трейс. Наш опыт показывает, что exemplars сокращают время поиска первопричины с 40 минут до 5.
Прокидывание trace_id в логи
Приложение должно при каждом запросе извлекать trace_id из активного span'а и добавлять его в лог-запись. В Node.js с winston это выглядит так:
const { trace } = require('@opentelemetry/api');
const addTraceInfo = winston.format((info) => {
const span = trace.getActiveSpan();
if (span) {
const ctx = span.spanContext();
info.trace_id = ctx.traceId;
info.span_id = ctx.spanId;
}
return info;
});
После этого Loki получает логи с полем trace_id, и Grafana строит ссылку из лога прямо в Tempo/Jaeger через derivedFields в datasource.
Почему correlation_id недостаточен?
Многие останавливаются на уровне X-Request-ID в заголовках и correlation_id в JSON-логах. Это необходимо, но недостаточно. Проблемы начинаются там, где сервис на Go логирует в stdout без структуры, Logstash парсит через grok с регулярками, которые не захватывают trace_id, а Prometheus собирает метрики без label'а trace_id — и не может, это принципиально другой тип данных. Трейсы в Jaeger хранят span_id и trace_id, но логи сервиса их не содержат, потому что разработчик не прокинул контекст через context.Context.
Настоящая корреляция строится на трёх вещах: единый формат времени (UTC, миллисекунды), propagation контекста трейса в логи и exemplars в метриках для связи с трейсами. Без exemplars корреляция будет неполной.
Как Grafana объединяет все три источника?
Grafana 10+ умеет «склеивать» все три источника через Explore. Один запрос в Loki — и рядом кнопка «View in Tempo». Из Tempo — кнопка «Logs for this span». Это работает только если настроены correlations между datasource'ами. На практике настройка correlations через UI Grafana хрупкая — лучше описывать её в provisioning/datasources/.
Сравним три метода корреляции.
| Метод | Требования | Преимущества | Недостатки |
|---|---|---|---|
| correlation_id | Прокидывание заголовка | Простота реализации | Нет связи с трейсами и метриками |
| OpenTelemetry + exemplars | OpenTelemetry SDK, exemplars в метриках | Полная сквозная корреляция | Требует изменений в коде |
| Ручной парсинг логов | Только логи | Не требует изменений | Медленный, ненадёжный |
Типичные проблемы при внедрении
- Разные форматы trace_id. Jaeger использует 128-bit hex, Zipkin — 64-bit. Если в системе есть legacy-сервис с Zipkin, trace_id в логах будет в разных форматах — correlate не сработает. Решение: OpenTelemetry Collector с
zipkinreceiverи конвертацией. - Асинхронные задачи теряют контекст. Celery-воркер, обрабатывающий задачу из Redis-очереди, не знает trace_id HTTP-запроса. Надо явно передавать контекст трейса в payload и восстанавливать его через
propagate.extract(). - Логи без структуры. Если приложение пишет
ERROR: connection refusedв stdout, вытащить trace_id невозможно без grok-парсинга. Иногда проще добавить JSON-форматтер.
Что входит в работу
- Аудит текущего стека: инвентаризация сервисов, языков, форматов логов и наличия tracing instrumentation.
- Внедрение OpenTelemetry SDK или auto-instrumentation через otel-operator для Kubernetes.
- Разворачивание OpenTelemetry Collector с тремя пайплайнами и настройка exporters.
- Настройка exemplars в Prometheus и correlations в Grafana через provisioning.
- Прокидывание trace_id в логи во всех сервисах.
- Тестирование сквозной корреляции: генерация трафика, проверка trace_id от HTTP до БД.
- Документация: описание архитектуры корреляции, инструкция для разработчиков.
- Обучение команды (2-часовой вебинар).
- Поддержка 2 недели после внедрения.
Как мы это делаем: пошагово
- Аудит текущего стека (1–2 дня).
- Внедрение OpenTelemetry SDK во всех сервисах (3–10 дней).
- Настройка Collector и Grafana (1–2 дня).
- Тестирование и документирование (1–2 дня).
Наши инженеры имеют 5+ лет опыта в observability, сертифицированы по OpenTelemetry и Kubernetes. За 5 лет выполнили более 50 проектов по настройке observability. Проект окупается за 2–3 месяца за счёт сокращения времени диагностики инцидентов. Свяжитесь с нами для оценки вашего проекта — закажите внедрение под ключ.







