Наблюдаемость в продакшене: минимум логов, метрик, трасс
Наблюдаемость в продакшене: минимальные логи, метрики и трейсы на первый день, плюс понятный поток триажа для жалоб "у нас медленно".

Зачем нужна минимальная наблюдаемость с первого дня
Когда новая версия попадает в продакшен, проблемы почти всегда звучат одинаково: «у нас медленно», «не открывается», «иногда падает». Без базовых сигналов поиск причин превращается в угадайку и споры про «то ли сеть, то ли база, то ли фронт».
Минимальная наблюдаемость нужна не ради красивых графиков. Она нужна, чтобы за 5 минут ответить на главные вопросы и решить, что делать дальше: откатывать релиз, выключать фичу, расширять лимиты или искать конкретный баг.
Продакшен должен быстро отвечать на четыре вопроса:
- Что именно сломалось: ошибки, таймауты, деградация скорости, рост очередей.
- Где сломалось: клиент, API, фоновые задачи, база данных, внешняя интеграция.
- Кого задело: всех или часть пользователей (регион, тариф, конкретный endpoint).
- Когда началось и что изменилось: релиз, конфиг, нагрузка, зависимость.
Без этого один и тот же симптом выглядит одинаково, хотя причины разные. Например, запросы к API стали в 2 раза медленнее. Это может быть переставший использоваться индекс, рост ретраев к внешнему сервису или новый код, который делает лишние запросы. Если есть только «пользователи жалуются», вы начинаете с конца.
Минимум обычно состоит из трех типов сигналов и одной связки между ними:
-
Логи: редкие, но информативные события с контекстом.
-
Метрики: числа, которые показывают тенденции.
-
Трейсы: цепочка вызовов, где видно, на чем тратится время.
-
Корреляция: общий
request_idилиtrace_id, чтобы из метрики перейти к трейсу, а из трейса - к логам.
Важно не пытаться «собрать все» в первый день. Лучше меньше сигналов, но стабильных: одинаковые поля в логах, одинаковые метки у метрик, один способ прокидывать идентификатор запроса. Тогда при первой же аварии вы не будете чинить наблюдаемость вместо продукта.
Сначала договоритесь, что значит «нормально»
Наблюдаемость часто ломается об одно: команда не знает, как выглядит нормальная работа. В итоге любой график можно трактовать по-разному, а фраза «стало медленно» превращается в спор вместо действий.
Начните с 2-3 ключевых пользовательских действий. Это не список всех API и не карта микросервисов. Это то, ради чего люди вообще открывают продукт: например, вход в аккаунт, поиск, оформление заказа.
Дальше задайте две цели, которые легко проверить: доступность и время ответа. Для времени ответа берите перцентиль, обычно P95 (95% запросов быстрее этого значения). Среднее время часто маскирует проблемы.
Пример: вы договорились, что «поиск» в норме отвечает за 1,2 секунды по P95, а доступность 99,9%. Этого уже достаточно, чтобы отличать обычные колебания от реальной деградации.
Теперь зафиксируйте, что вы называете инцидентом. Важно указать не только порог, но и длительность, иначе будете реагировать на каждую минутную яму. Удобная формула: «если хуже порога дольше N минут». Например:
- P95 выше 2 секунд дольше 10 минут
- доля ошибок 5xx выше 1% дольше 10 минут
И отдельно разведите три класса проблем, потому что расследуются они по-разному:
- «Не работает»: запросы не проходят, много 5xx, таймауты, резкий рост отказов.
- «Иногда ошибается»: сбой у части пользователей, часто завязан на сценарий, данные или регион.
- «Медленно»: ошибок может не быть, но растет P95, увеличивается очередь, база отвечает дольше или подвисают внешние интеграции.
Если это записано одной страничкой (хоть в заметках), дальше проще: вы знаете, какие метрики строить, какие логи искать и что проверять первым, когда приходит «у нас медленно».
Логи: минимальный набор и понятная структура
Если метрики отвечают на вопрос «когда стало хуже», то логи помогают понять «почему». В продакшене важнее не количество строк, а то, насколько быстро вы находите нужную запись и связываете ее с конкретным запросом.
Структура: один формат для всех
С первого дня договоритесь о структурированных логах (обычно JSON). Так их проще искать, фильтровать и сопоставлять между сервисами.
Минимальные поля, которые стоит писать в каждую запись:
time(единая зона для всех)level(info,warn,error)service(имя сервиса или компонента)env(prod,stage)request_id(илиtrace_id, если используете трассировку)
request_id должен приходить с входящим запросом или генерироваться на границе системы и прокидываться дальше: в вызовы сервисов, в задачи очереди, во внешние API.
Какие события логировать всегда
Не пытайтесь логировать все подряд. Логи должны фиксировать ключевые точки, где запрос может «сломаться» или стать медленным: начало обработки, внешние вызовы, ретраи, таймауты, ошибки. В info пишите только то, что реально помогает разбирать инциденты, иначе полезные записи утонут.
Когда логируете ошибку, добавляйте контекст, который помогает действовать:
- код и короткое сообщение
- тип ошибки и стек (если есть)
- что делали в момент сбоя (коротко: «вызов платежного API», «чтение из БД»)
- ключевые параметры в безопасном виде (например,
user_idкак число)
warn оставляйте для деградации, когда система еще работает, но уже «плохо»: ретрай с 3 попытки, внешний сервис отвечает дольше порога, очередь растет. error используйте для явных отказов.
Отдельно зафиксируйте правила безопасности. Не пишите пароли, токены, ключи, полные персональные данные и большие тела запросов. Если нужен фрагмент, сохраняйте «срез»: длину, тип, несколько первых символов, хеш или маску.
Пример: пользователь жалуется «оформление заказа тормозит». По request_id вы находите старт запроса (info), затем внешний вызов (warn: 2.4s), ретрай (warn), потом таймаут (error). Уже понятно, где копать дальше.
Метрики: что измерять, чтобы видеть деградацию
Метрики нужны, чтобы быстро понять: проблема в росте нагрузки, в ошибках или в том, что сервис уперся в ресурс. Для минимума достаточно договориться о нескольких показателях и считать их одинаково во всех сервисах.
4 золотых сигнала
Latency (задержка), Traffic (трафик), Errors (ошибки), Saturation (насыщение по ресурсам или очередям). Смотрите не только среднее, а перцентили.
Минимум метрик на день один
Начните с метрик уровня запроса, одинаковых для API, фоновых задач и ключевых операций:
- количество запросов (RPS) по маршруту/методу и по коду ответа
- задержка P50/P95/P99
- доля 5xx и доля 4xx, плюс таймауты
- ретраи (количество и доля запросов, ушедших в ретрай)
- размеры очередей и время ожидания (если есть воркеры)
Дальше добавьте метрики зависимостей. Они часто объясняют «почему стало медленно», даже если ваш код не менялся. Для PostgreSQL полезны время запросов, количество активных соединений, занятость пула, блокировки. Для кэша - hit rate и время ответа. Для внешних API - время ответа, ошибки, таймауты и ретраи. Если бэкенд на Go, отдельно следите за количеством горутин и паузами GC.
Базовые алерты без лишнего шума
Алерты должны ловить деградацию, а не «каждый чих». Держите их простыми и привязанными к пользовательскому эффекту:
- ошибки выше порога и держатся несколько минут
- рост P95/P99 относительно «нормы» (только на маршрутах с трафиком)
- отсутствие трафика там, где он обязан быть
- ресурсы: CPU, память, диск, длины очередей
- для БД: исчерпан пул соединений или резко выросло время запросов
Полезная привычка: разделяйте алерты на «срочно разбудить» и «посмотреть утром».
Трейсы: где нужны и как их разметить
Трейсы полезны там, где по логам и метрикам видно только симптом («медленно»), но непонятно, где теряется время. Максимум отдачи они дают в микросервисах, при работе с очередями, при вызовах внешних API и в местах со сложными запросами к базе.
Идея простая: у каждого входящего запроса есть trace_id и внутри него цепочка span-ов. trace_id живет до конца обработки и прокидывается дальше: в БД, во внешние сервисы, в сообщения очередей. Тогда жалоба «страница открывается 8 секунд» превращается в картинку: 200 мс на обработчик, 6.5 с на внешний сервис, 1.1 с на БД.
Что размечать span-ами
Начните с самых дорогих и частых операций:
- входящий HTTP handler (или gRPC метод) как корневой span
- запросы к базе (каждый запрос отдельным span-ом)
- вызовы внешних API (платежи, SMS, авторизация)
- публикация и обработка сообщений очереди
Какие атрибуты добавлять и как выбрать семплинг
Чтобы трейсы можно было фильтровать и сравнивать, добавляйте понятные атрибуты: route (шаблон пути), status_code, метод, имя сервиса, технический контекст клиента (например, tenant_id, тариф/план без персональных данных). Для ошибок полезны тип и короткое сообщение.
Практичный старт по семплингу: 100% для ошибок и медленных запросов и небольшой процент для успешных (часто 1-10% в зависимости от нагрузки). Если есть возможность, сохраняйте больше трейсинга для важных маршрутов вроде логина и оплаты.
Связность сигналов: чтобы логи, метрики и трейсы находились вместе
Наблюдаемость начинает работать по-настоящему, когда можно быстро ответить на вопрос: «Эта ошибка и этот всплеск задержек - про один и тот же запрос или про разные вещи?». Для этого логи, метрики и трейсы нужно склеить общими идентификаторами и одинаковыми именами.
Первый кирпич - единый идентификатор запроса. Для HTTP это обычно request_id и/или trace_id. Важно, чтобы он:
- попадал в каждый лог внутри обработки запроса
- возвращался клиенту в заголовке ответа
- передавался дальше во все вызовы между сервисами
Второй кирпич - перенос контекста между компонентами, включая фоновые задачи. Частая ловушка: в HTTP все хорошо, а как только запрос положили в очередь или запустили джобу, идентификатор теряется. Договоритесь, что минимум (trace_id, request_id, account_id/user_id, job_id) хранится в сообщении очереди или параметрах задания и снова попадает в логи и трейсы при обработке.
Третий кирпич - одинаковые имена. Один и тот же endpoint не должен называться по-разному в трех местах. Выберите формат и придерживайтесь его в метриках, в спанах и в логах.
И держите простую «карту сервисов»: компоненты и зависимости (сервисы, PostgreSQL/кэш, очереди, внешние API, точки входа web/mobile). На старте этого достаточно, чтобы быстрее находить первопричину.
Пошагово: как добавить минимум наблюдаемости за один день
За один день реально поставить базу, если ограничиться минимумом и сразу договориться о корреляции между логами, метриками и трейсами.
План на 1 день
-
Выберите 3 главных пользовательских сценария. Для каждого определите по 3 метрики: доля ошибок, P95 задержки и объем (RPS/количество операций).
-
Добавьте структурированные логи в точки входа (HTTP handler, очередь, cron) и в обработку ошибок. В каждом логе держите одинаковые поля:
request_id/trace_id,endpoint/operation, статус (ok/error),latency_msи краткую причину ошибки. Чтобы не утонуть в шуме, пишите логи ровно в двух местах: на входе и при ошибке. -
Подключите базовые метрики HTTP и инфраструктуры: количество запросов, доли 5xx/4xx, распределение задержки (P50/P95), плюс CPU, память, диск, пул соединений к БД. Первые алерты делайте грубыми: рост 5xx и P95 выше нормы в течение 5-10 минут.
-
Добавьте трейсы там, где чаще всего пропадает время: внешние HTTP вызовы и запросы к базе данных. Включите захват ошибок в трейс и прокиньте
trace_idв логи. -
Прогоните тестовый трафик и убедитесь, что по одному
request_idвиден весь путь: входной запрос -> ключевые шаги -> БД/внешние вызовы -> итоговый статус.
Триаж жалобы «у нас медленно»: простой поток действий
Когда кто-то пишет «все тормозит», важно быстро сузить круг причин.
Сначала зафиксируйте симптомы так, чтобы их можно было проверить: кто жалуется (один клиент или многие), что именно медленно, с какого времени, как часто, есть ли точные примеры (время запроса, аккаунт, регион, устройство).
Дальше двигайтесь по шагам:
-
Проверьте доступность и явные ошибки за нужный период. 5xx, таймауты, рост отказов, заполнение очередей, перезапуски.
-
Подтвердите деградацию по задержке. Сравните P95/P99 с «обычным» уровнем и найдите самый проблемный endpoint или экран.
-
Откройте трейсы для медленных запросов. Найдите самый длинный span: БД, внешнее API, кэш, очередь, тяжелая бизнес-операция.
-
Перейдите из трейса в логи по
trace_id. Проверьте ретраи, лимиты, ожидание блокировок, переполнение пула соединений, долгие SQL, повторные вызовы. -
Примите временное решение и зафиксируйте его. Откат/отключение фичи, временное увеличение ресурсов, деградация при сбое внешнего сервиса (кеш, заглушка, таймауты, снижение частоты).
Простой пример: пользователи мобильного приложения жалуются, что «оплата» стала открываться 15 секунд. Метрики показывают рост P95 только у одного endpoint. В трейсе самый длинный span - запрос в PostgreSQL. По trace_id в логах видно: после вчерашнего изменения включился ретрай, а запрос держит блокировку. Временное решение: откатить фичу или убрать ретрай, затем исправить запрос и добавить индекс.
Частые ошибки, из-за которых наблюдаемость не помогает
Наблюдаемость часто «не работает» не потому, что инструменты плохие, а потому что сигналы собраны без правил.
Ошибка 1: логов слишком много, а смысла мало
Когда пишут «все подряд», поиск превращается в гадание. Договоритесь, какие события важны: вход запроса, ключевые шаги, ошибки, ретраи, внешние вызовы.
Ошибка 2: нет корреляции между логами, метриками и трассами
График показывает деградацию, но по логам нельзя найти конкретные запросы, а трейсы живут отдельно. Решает простое правило: у каждого запроса должен быть один и тот же request_id или trace_id везде.
Ошибка 3: алерт на каждый чих
Шумные алерты приучают игнорировать уведомления. Оставьте только те сигналы, которые требуют действия прямо сейчас, и привяжите их к понятным порогам и окнам времени.
Пять типичных промахов, которые стоит исправить в первую очередь:
- debug-логи в продакшене постоянно (оставьте debug по флажку и на короткое время)
- нет общего идентификатора (
trace_id/request_id) в логах, метриках и трейсе - алерты настроены на «пик» в 1 минуту (используйте 5-10 минут)
- в логах есть персональные данные или секреты
- трейсы есть, но без атрибутов (
route,method,status,db.system,peer.service)
Быстрый чеклист и следующие шаги
Чтобы наблюдаемость работала, нужна простая привычка: перед релизом проверить минимум, а при инциденте собирать одни и те же факты.
Чеклист перед выпуском
- В каждом запросе есть
request_idи/илиtrace_id, и они попадают в логи. - Есть базовые метрики: RPS, ошибки (4xx/5xx), задержки (P50 и P95), загрузка ключевых ресурсов.
- Логи ошибок пишутся с контекстом:
endpoint, код ответа, время, краткая причина. - Настроены 2-3 алерта: всплеск 5xx, рост P95, падение успешных запросов по ключевому сценарию.
- Понятно, где смотреть: один дашборд или один «главный экран» для ответа «все ок или нет».
Чеклист на инцидент «у нас медленно»
- Время начала: когда заметили, и с какого момента видно ухудшение по графикам.
- Затронутые сценарии: что именно медленно, один регион или все.
- Ошибки и задержки: текущие значения и отклонение от обычного, особенно P95.
- Топ проблемных endpoint-ов: где хуже всего задержка при достаточном трафике.
- Подозрительные изменения: релиз, миграция, конфиг, рост трафика.
Чтобы инциденты не повторялись, заведите два артефакта: короткий шаблон отчета (что случилось, как нашли, как починили, почему произошло, что делаем дальше) и список принятых действий (например, «добавили индекс», «ограничили таймаут», «поставили алерт на рост очереди»).
Если вы делаете приложение в TakProsto (takprosto.ai), удобно заранее фиксировать SLO в planning mode, а для безопасных выкладок использовать snapshots и rollback. Это помогает не спорить «на глаз», а опираться на договоренности и данные.
FAQ
Зачем вообще нужна минимальная наблюдаемость с первого дня?
Минимум нужен, чтобы за несколько минут ответить на четыре вопроса: что сломалось, где, кого задело и когда началось/что изменилось. Это помогает быстро выбрать действие (откат, отключение фичи, увеличение лимитов, поиск конкретного бага), а не спорить «то ли сеть, то ли база».
С чего начать, если команда не понимает, что значит «нормально»?
Выберите 2–3 ключевых пользовательских сценария (например, логин, поиск, оплата) и зафиксируйте для них:
- доступность (например, 99,9%)
- время ответа по P95 (например, 1,2 с)
Дальше определите, что считается инцидентом: «хуже порога дольше N минут», чтобы не реагировать на минутные провалы.
Какие поля должны быть в логах «по умолчанию»?
Пишите структурированные логи (обычно JSON) и держите один формат во всех сервисах. Минимальные поля:
time(единая зона)level(info/warn/error)serviceenv(prod/stage)request_idилиtrace_id
Главное — чтобы идентификатор запроса прокидывался дальше по цепочке вызовов.
Что логировать всегда, чтобы потом не гадать причину?
Логируйте то, что помогает разбирать инциденты, а не «все подряд»:
- вход в обработку запроса/задачи (кратко)
- внешние вызовы (время, факт ретрая, таймаут)
- ошибки с контекстом (что делали, код/тип ошибки)
Практичное правило: в info — только полезные точки, warn — деградация (ретраи, медленные зависимости), error — явный отказ.
Как не утечь с персональными данными и секретами в логах?
Не пишите в логи:
- пароли, токены, ключи
- полные персональные данные
- большие тела запросов/ответов
Если нужен контекст — сохраняйте безопасный «срез»: длину, тип, первые символы в маске, хеш, user_id как число без лишних данных.
Какие метрики реально нужны в первый день?
Минимальный набор для уровня запросов:
- RPS/количество операций по маршруту и коду ответа
- задержка P50/P95/P99
- доля 5xx и 4xx, отдельно таймауты
- ретраи (количество/доля)
- длина очередей и время ожидания (если есть воркеры)
Этого хватает, чтобы увидеть «не работает», «иногда ошибается» и «медленно».
Как настроить алерты, чтобы они не были шумными?
Ставьте простые алерты, привязанные к пользовательскому эффекту и с окном 5–10 минут:
- 5xx выше порога и держится несколько минут
- P95/P99 выше «нормы» на маршрутах с трафиком
- пропал трафик там, где он должен быть
- ресурсы: CPU/память/диск, очереди
- для БД: исчерпан пул соединений или резко выросло время запросов
Разделяйте «срочно разбудить» и «посмотреть утром», иначе алерты начнут игнорировать.
Где трассировка дает максимум пользы и что размечать span-ами?
Трейсы нужны, когда по метрикам видно «медленно», но непонятно, где теряется время. Стартовая разметка:
- входящий HTTP/gRPC как корневой span
- каждый запрос к БД отдельным span
- внешние API вызовы
- публикация/обработка сообщений очереди
Обязательно прокидывайте trace_id дальше, чтобы цепочка не обрывалась.
Как связать логи, метрики и трейсы, чтобы они «находились вместе»?
Сделайте единый идентификатор (request_id/trace_id) обязательным:
- он есть в каждом логе внутри обработки
- он возвращается клиенту в заголовке ответа
- он передается между сервисами и в фоновые задачи/сообщения очереди
Так вы можете перейти от всплеска на графике к конкретному трейсу и дальше к нужным логам без ручного «сведения» событий.
Что делать по шагам, когда пришла жалоба «у нас медленно»?
Держите простой поток:
- Проверьте ошибки/таймауты/перезапуски и очереди за нужный период.
- Подтвердите деградацию по P95/P99 и найдите самый проблемный endpoint.
- Откройте трейсы медленных запросов и найдите самый длинный span.
- Перейдите из трейса в логи по
trace_id: ретраи, лимиты, блокировки, пул соединений, долгие SQL. - Примите временное решение (откат/фича-флаг/ресурсы/таймауты) и зафиксируйте, что сделали.
Цель — быстро сузить круг причин и не тратить время на догадки.