Настройка корреляции логов с метриками и трейсами

Когда метрики сигналят об аномалии, логи захлебываются тысячами строк, а трейсы теряются в глубине, диагностика инцидента превращается в ручной поиск иголки в стоге сена. Мы настраиваем сквозную корреляцию логов, метрик и трейсов, чтобы вы в один клик переходили от графика к конкретному запросу и его логам. Наша команда реализует проект под ключ — от аудита текущего стека до внедрения и последующей поддержки, обеспечивая надёжную работу системы.
Часто задаваемые вопросы

Как настроить сквозную корреляцию логов, метрик и трейсов?

Разбираешь инцидент: метрики показывают резкий рост 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. Аудит текущего стека (1–2 дня).
  2. Внедрение OpenTelemetry SDK во всех сервисах (3–10 дней).
  3. Настройка Collector и Grafana (1–2 дня).
  4. Тестирование и документирование (1–2 дня).

Наши инженеры имеют 5+ лет опыта в observability, сертифицированы по OpenTelemetry и Kubernetes. За 5 лет выполнили более 50 проектов по настройке observability. Проект окупается за 2–3 месяца за счёт сокращения времени диагностики инцидентов. Свяжитесь с нами для оценки вашего проекта — закажите внедрение под ключ.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    815
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139