·4 мин чтения

Как читать чужие логи и не утонуть

Типичное обращение выглядит так: «у нас ничего не работает, посмотрите». Ни времени, ни запроса, ни описания — только эмоция. Дальше всё зависит от того, в каком порядке ты будешь сужать.

Ниже — порядок, к которому я пришёл. Он скучный, но экономит часы.

Сначала время, потом всё остальное

Первый вопрос всегда один: когда. Не «что случилось», а «во сколько».

Без временного окна поиск по логам превращается в чтение всего подряд. С окном в пять минут — в просмотр сотни строк.

Если пользователь не помнит — привязывайся к косвенным признакам: время последнего успешного действия, время скриншота, время письма. Годится любая точка отсчёта.

Связка идентификаторов

Дальше ищем request_id. В нормально устроенном сервисе он есть в ответе — в заголовке или в теле ошибки:

HTTP/1.1 500 Internal Server Error
content-type: application/json
x-request-id: 7f3a91c4-2b08-4e1d-9a55-c0de12345678

{
  "error": {
    "code": "internal_error",
    "message": "Что-то пошло не так",
    "request_id": "7f3a91c4-2b08-4e1d-9a55-c0de12345678"
  }
}

Этот идентификатор — вход в лог. По нему находится строка, которая породила ответ:

2026-08-14T09:14:22.881Z  ERROR  billing-api  host=billing-api-04
  request_id=7f3a91c4-2b08-4e1d-9a55-c0de12345678
  trace_id=b19d0c77aa5e4f02
  method=POST path=/v1/orders status=500 duration_ms=8412
  msg="upstream timeout" upstream=inventory-service

Здесь есть всё, что нужно для следующего шага:

Поле Что говорит
status=500 Ошибка на нашей стороне, не у клиента
duration_ms=8412 Восемь секунд — почти наверняка таймаут, а не логическая ошибка
upstream=inventory-service Виноваты не мы, а сервис ниже по цепочке
trace_id Ключ, по которому видно всю цепочку вызовов

request_id и trace_id — не одно и то же

Это различие стоит держать в голове, потому что путаница здесь стоит дороже всего.

request_id живёт внутри одного сервиса. Он отвечает на вопрос «что произошло здесь».

trace_id сквозной: он одинаковый у всех сервисов, которые участвовали в обработке. Он отвечает на вопрос «что произошло по всей цепочке».

Поиск по request_id покажет одну строку. Поиск по trace_id — весь путь:

09:14:14.402  INFO   api-gateway        trace_id=b19d0c77aa5e4f02  POST /v1/orders           status=-
09:14:14.418  INFO   billing-api        trace_id=b19d0c77aa5e4f02  -> inventory-service/reserve
09:14:14.503  INFO   inventory-service  trace_id=b19d0c77aa5e4f02  acquiring lock sku=A-1187
09:14:22.874  ERROR  inventory-service  trace_id=b19d0c77aa5e4f02  lock wait timeout after 8000ms
09:14:22.881  ERROR  billing-api        trace_id=b19d0c77aa5e4f02  upstream timeout status=500

И вот тут картина собирается: дело не в биллинге, который вернул 500. Дело в блокировке на конкретной позиции склада, которую кто-то держал восемь секунд.

Биллинг — жертва, а не причина. Если бы я остановился на первой строке с ERROR, я бы завёл задачу не на ту команду.

Порядок, который работает

  1. Время. Окно в 5–10 минут вокруг события.
  2. Идентификатор. request_id из ответа или из скриншота.
  3. Цепочка. trace_id — весь путь запроса.
  4. Первая ошибка по времени, а не первая, которую увидел. Они редко совпадают.
  5. Сравнение с нормой. Найди такой же успешный запрос рядом по времени и посмотри, чем он отличался.

Пятый шаг пропускают чаще всего, а он самый полезный. Ошибка сама по себе говорит мало. Ошибка рядом с успехом говорит почти всё.

Три ошибки, которые я делал сам

Смотрел на последнюю ошибку вместо первой. В логах ошибки размножаются: одна причина порождает десяток следствий, и следствия часто заметнее. Сортируй по времени по возрастанию.

Верил уровню логирования. ERROR в одном сервисе может быть штатной ситуацией, а WARN в другом — настоящей проблемой. Уровень расставлял человек, у него было своё представление о важности.

Искал по тексту ошибки. «Timeout» найдётся в тысяче строк. Идентификатор — в одной. Всегда, когда есть идентификатор, ищи по нему.

Что делать, если request_id нет

Бывает и так. Тогда сужение идёт по косвенным признакам: аккаунт, эндпоинт, код ответа, время. Это дольше, но работает.

И отдельным пунктом — заводи задачу на то, чтобы идентификатор появился в ответе. Один раз потратить время на это дешевле, чем каждый раз искать вслепую.

Что проверить дальше

Если картина не сошлась:

  • посмотри логи балансировщика — часть запросов может не доходить до приложения вообще;
  • сравни время на серверах: расхождение в пару минут превращает разбор в гадание;
  • проверь, не совпало ли событие с деплоем или миграцией;
  • глянь соседние экземпляры сервиса: если ошибка только на одном хосте, причина в нём, а не в коде.

Обновлено 22 августа 2026