Наблюдаемость (logs/metrics/traces): как не гадать в продакшене

Чтобы перестать "гадать" в продакшене, выстройте наблюдаемость как связку логов, метрик и трейсов: структурированные события объясняют контекст, метрики показывают масштаб и динамику, а distributed tracing раскладывает путь запроса по сервисам. Дальше закрепите это в алертах и рутине расследований, используя одну observability платформа для корреляции данных.

Краткая карта наблюдаемости: что важно в продакшене

  • Единый корреляционный ключ: trace_id/span_id + request_id в логах, метках метрик и заголовках запросов.
  • Мониторинг логов и метрик строится от пользовательских SLI: ошибки, латентность, насыщение ресурсов, пропускная способность.
  • Трейсы включайте на входе в систему и на всех сетевых границах; без этого "дыры" в цепочке неизбежны.
  • Sampling и ограничение кардинальности меток - главный рычаг контроля стоимости и overhead.
  • Алерты по симптомам (SLO/SLI), диагностика - по деталям (логи/трейсы/профили), иначе будет шум.
  • Инцидент-рутина: от симптома → сегментации → локализации сервиса → поиска изменения → подтверждения корня.

Что логировать и как структурировать события для быстрых выводов

Кому подходит: командам с микросервисами и очередями, API с несколькими зависимостями, системам с частыми релизами, где APM мониторинг без логов не отвечает на вопрос "почему".

Когда НЕ стоит делать подробно: в системах с высокими требованиями к приватности/регуляторике без готовой политики редактирования (redaction), и в горячих путях, где синхронный вывод логов заметно бьёт по латентности - там начинайте с метрик и выборочных событий.

Минимальный формат события (схема, которую реально искать)

  • timestamp (в UTC), level, service, env, version.
  • message - коротко, без "романов".
  • trace_id, span_id, request_id - для склейки с distributed tracing и запросами.
  • event_name (например, payment.authorize) и outcome (success/fail/timeout).
  • http.method, http.route (шаблон), http.status_code - без сырого URL с параметрами.
  • user_id_hash/tenant_id (если есть мультиарендность) - только в безопасном виде.

Проблема → действие → пример

  • Проблема: невозможно отличить бизнес-ошибку от падения зависимости.
    Действие: разделите ошибки на классы (validation/timeout/dependency/auth) и логируйте error.kind и dependency.name.
    Пример: при таймауте в БД пишите error.kind=timeout, dependency.name=postgres, retry.count.
  • Проблема: логи "шумят" и дорого хранятся.
    Действие: оставьте INFO только для ключевых бизнес-событий и границ, DEBUG - под флаг/выборочно по trace_id.
    Пример: включайте расширенные логи для 1% запросов или для проблемного клиента по tenant_id.

Выбор метрик: SLI/SLO, латентность, пропускная способность и ошибки

Перед тем как настраивать мониторинг логов и метрик, подготовьте базовые условия: единые имена сервисов, теги окружения (prod/stage), доступ к метрикам на уровне инфраструктуры и приложений, а также договорённость, где живут SLO (в репозитории/в observability платформа) и кто их утверждает.

Что понадобится (минимум, без которого будет "разрыв картины")

  • Инструменты: метрики приложения (Prometheus/OpenTelemetry metrics/встроенные агенты APM), сбор инфраструктурных метрик, централизованный лог-стор и трейс-бэкенд.
  • Доступы: просмотр дашбордов, чтение логов, просмотр трейсов, доступ к конфигам алертов; возможность добавить/изменить теги и поля логов.
  • Стандарты именования: единый service.name, deployment.environment, service.version; одинаковые названия роутов/операций.
  • Ограничения кардинальности: правила, какие метки запрещены (user_id, order_id, email и т. п.).

Практический набор SLI для старта

  • Ошибки: доля 5xx, доля отказов бизнес-операции (например, payment.authorize.fail).
  • Латентность: p95/p99 по http.route и по бизнес-операции; отдельно - внешние зависимости (БД/кэш/внешние API).
  • Пропускная способность: RPS/ops/sec по роутам и очередям; скорость потребления/публикации сообщений.
  • Насыщение: CPU throttling, memory pressure/GC, пул соединений, очередь запросов, thread/worker pool saturation.

Трассировка в распределённых системах: где открывать span и какие теги нужны

  1. Определите границы трассировки. Трейс должен начинаться на входном edge (API gateway/ingress) или в consumer очереди и продолжаться через все сетевые вызовы. Так вы получите непрерывную картину вместо "кусочков" APM мониторинг.

    • HTTP: start span на сервере при приёме запроса и propagate context дальше.
    • MQ: start span при обработке сообщения; при публикации - span producer.
  2. Включите контекст и пропагацию. Настройте передачу trace context в заголовках HTTP и метаданных сообщений (W3C Trace Context или формат вашего стека). Проверьте, что trace_id попадает и в логи.
  3. Откройте спаны на сетевых вызовах и критичных участках. Оборачивайте клиентские вызовы БД/кэша/HTTP/GRPC, а также очереди и файловые/облачные хранилища. Не пытайтесь "спанить" каждый метод - начинайте с границ и горячих точек.

    • Отдельные спаны: db, http.client, rpc, messaging.
    • Внутри сервиса: спаны вокруг сериализации, тяжёлых вычислений, вызовов внешних SDK.
  4. Добавьте обязательные атрибуты (теги) для поиска. Минимум: service.name, deployment.environment, service.version, http.route (шаблон), http.method, http.status_code, error.type/error.message (без секретов), dependency.name. Эти поля должны совпадать по смыслу с логами и метриками.
  5. Свяжите логи и трейсы. В каждый лог из контекста запроса добавляйте trace_id/span_id. В трейсах добавляйте ссылки на ключевые события (например, order_id в безопасном виде или внутренний correlation key).
  6. Настройте sampling осознанно. Для высоких нагрузок используйте head-based sampling (процент) + tail-based (по ошибкам/медленным запросам), чтобы сохранять проблемные трейсы. Зафиксируйте правила, чтобы команда понимала, почему "трейса нет".

Быстрый режим

  1. Сделайте пропагацию trace context везде (HTTP + очереди) и добавьте trace_id/span_id в логи.
  2. Оберните спанами все внешние зависимости (БД/кэш/HTTP) и входные обработчики.
  3. Стандартизируйте теги: service.name, env, version, http.route, dependency.name.
  4. Включите sampling: сохраняйте 100% ошибок и медленных запросов, остальное - процентом.

Инструментация и сбор данных: библиотеки, sampling и overhead в реале

Для практичной наблюдаемости выбирайте один путь инструментации: либо OpenTelemetry SDK/auto-instrumentation, либо агент конкретной APM/observability платформа. Смешивание подходов допустимо, но только если вы понимаете, кто создаёт спаны/метрики и не дублируете данные.

Проверка результата (чек-лист перед включением на весь прод)

  • В логах по одному запросу видны trace_id и span_id, а по trace_id находится соответствующий трейс.
  • В трейсе нет "провалов" на сетевых границах (клиентский и серверный спаны связаны).
  • Метрики по http.route не раздуваются из-за кардинальности (нет меток со значениями типа user_id, order_id, полный URL).
  • Sampling действительно сохраняет проблемные случаи: есть трейсы по 5xx, таймаутам и медленным запросам.
  • Overhead контролируем: нет всплеска p95/p99 после включения, нет деградации CPU/памяти от экспортёров.
  • Буферы/очереди экспортёра не переполняются при пиках (данные не "теряются молча").
  • Тайм-ауты и ретраи экспортёра настроены так, чтобы не блокировать обработку запросов.
  • Политика безопасности соблюдена: в логах/тегах нет секретов, токенов, персональных данных.
  • Версии сервисов размечены (service.version), чтобы находить регресс после релиза.

Алертинг и эскалации: как настраивать пороги, чтобы уменьшить шум

Наблюдаемость (logs/metrics/traces): как не
  • Алертите на всё подряд (CPU, диски, любые 5xx) без связи с пользовательским влиянием - начните с SLI/SLO и симптомов деградации.
  • Пороги без окна и устойчивости: один всплеск → алерт. Добавьте окно оценки и условие "держится N минут" (по возможностям вашей системы алертинга).
  • Одинаковые пороги для всех сервисов - разные нагрузки и профили трафика требуют разных порогов и разных SLO.
  • Нет маршрутизации по владению: алерт падает "в общий чат". Настройте, кто дежурит за сервис/компонент, и укажите runbook-ссылку.
  • Нет разделения на симптом/причину: алерт на "БД медленная" и на "ошибки API" одновременно без приоритета. Симптом - основной, причины - диагностические.
  • Не учитываются деплои: алерты взрываются на раскатке. Введите корректное подавление/маркировку релизов и наблюдение за регрессом.
  • Слишком детальная разбивка (например, по customer_id) - кардинальность и шквал алертов. Держите агрегацию на уровне route/операции/сервиса.
  • Нет политики эскалаций: если не подтверждено за разумное время - кому и как повышаем приоритет, куда писать/звонить.

Пошаговое расследование инцидента: от симптома до корневой причины

Выберите маршрут расследования по тому, что у вас уже есть (метрики, логи, трейсы) и как быстро нужно локализовать проблему. Ниже - рабочие альтернативы, которые комбинируются в одной observability платформа.

Вариант 1: от SLO/SLI к сервису-источнику (когда есть качественные метрики)

  • Уместно, если вы доверяете SLI (ошибки/латентность/трафик) и видите, что "сломалось" в масштабе.
  • Ход: алерт по SLI → сегментация по route/региону/версии → переход к dependency метрикам → подтверждение в трейсе → точный лог по trace_id.

Вариант 2: от трейса к зависимости (когда деградация точечная и "прыгающая")

  • Уместно при росте p99 без явных 5xx, при таймаутах, "залипаниях" на отдельных клиентах.
  • Ход: найти медленные трейсы → увидеть самый длинный span → проверить теги dependency.name и error.type → открыть логи по trace_id → сопоставить с релизом/конфигом.

Вариант 3: от логов к воспроизведению (когда ошибка чётко проявляется сообщением/кодом)

  • Уместно, если в логах есть стабильный маркер (error.kind, исключение, код бизнес-ошибки) и хорошие поля корреляции.
  • Ход: фильтр по marker → группировка по version/route/dependency → взять один trace_id → пройтись по цепочке span'ов → сформулировать минимальный сценарий воспроизведения.

Решения для типичных проблем наблюдаемости

Почему трейс не находится по trace_id из логов?

Чаще всего не совпадает формат/пропагация контекста или трейс отсэмплирован. Проверьте, что trace_id пишется из активного span-контекста и что правила sampling сохраняют ошибки/медленные запросы.

Как быстро отличить регресс после релиза от внешней деградации зависимости?

Сегментируйте метрики и ошибки по service.version и сравните соседние версии. Если проблема привязана к одной версии - идите в diff конфигов/кода; если ко всем версиям - смотрите dependency метрики и трейсы на внешние вызовы.

Что делать, если мониторинг логов и метрик раздувается по стоимости?

Уберите высококардинальные метки и поля, ограничьте INFO-события до бизнес-границ, включите sampling для трейсов. Для логов применяйте редактирование чувствительных данных и выносите детали в DEBUG только по флагу.

Как настроить distributed tracing для очередей, чтобы не терялась связность?

Передавайте trace context в метаданных сообщения при публикации и создавайте span producer/consumer. В consumer начинайте новый span как дочерний к контексту сообщения и логируйте trace_id для каждого обработчика.

Почему APM мониторинг показывает "медленно", но непонятно где?

Наблюдаемость (logs/metrics/traces): как не

Обычно не хватает спанов на внешних зависимостях или отсутствуют корректные теги (dependency.name, http.route). Добавьте спаны на сетевые вызовы и убедитесь, что в трейсе видно время на БД/HTTP/кэше отдельными участками.

Как уменьшить шум от алертов, не потеряв реальные инциденты?

Оставьте алерты по симптомам (SLI/SLO) и добавьте устойчивость по времени, а причины перенесите в дашборды диагностики. Введите маршрутизацию по владению и runbook рядом с алертом, чтобы сокращать время реакции.

Прокрутить вверх