Налаштування кореляції логів з метриками та трейсами

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

Налаштування наскрізної кореляції логів, метрик і трейсів?

Розбираєш інцидент: метрики показують різке зростання latency о 03:47, але в Grafana немає анотації, Loki видає тисячі рядків логів за ту хвилину, а в Jaeger трейси є, але незрозуміло, який span «ліг» першим. Три системи, три інтерфейси, нуль зв'язку між ними — і ви витрачаєте годину на ручне звірення timestamp'ів. Ми стикалися з цим десятки разів. Наш підхід — налаштувати наскрізну кореляцію за 5–10 робочих днів, скоротити MTTR на 60% (економія від $5000/міс) і позбавити команду рутини. Налаштування через OpenTelemetry в 3 рази швидше за ручний парсинг логів.

Кореляція логів, метрик і трейсів — це можливість в один клік перейти від аномалії на графіку до конкретного трейсу, а з трейсу — до рядка лога з повним контекстом помилки. Без неї діагностика розподілених систем перетворюється на детектив з лупою. Отримайте консультацію з налаштування кореляції для вашого проекту.

Як OpenTelemetry забезпечує єдиний шар?

Сучасний стек для кореляції — це OpenTelemetry Collector, який отримує дані від усіх трьох сигналів і пробрасовує їх у відповідні бекенди. Типова конфігурація:

Конфігурація 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 (https://opentelemetry.io/docs/specs/otel/trace/), 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