Лучшие правила полезного логирования
Логи пишут все, а пользуются ими единицы — потому что в момент аварии в них невозможно ничего найти. Семь правил, после которых разбор инцидента занимает пять минут, а не полночи.
Зачем логи, если есть отладчик
Отладчик работает там, где вы можете воспроизвести проблему. На боевом сервере вы не можете: ошибка случилась ночью, у одного пользователя из тысячи, при стечении обстоятельств, которое вы не повторите. Всё, что от неё осталось, — то, что программа успела записать.
Отсюда простой критерий качества: лог хорош, если по нему можно восстановить, что происходило, не имея доступа к машине и не воспроизводя ситуацию. Всё остальное — детали.
Обратная сторона. Логи стоят денег: место на диске, трафик, хранилище, время на разбор. Писать всё подряд так же плохо, как не писать ничего, — только дороже. В логе на десять гигабайт в сутки нужную строку не найдёт никто.
И ещё одно. Логи — это данные, которые вы вынесли за пределы приложения. К ним имеют доступ администраторы, служба поддержки, внешний сервис сбора. Всё, что туда попало, считайте наполовину опубликованным.

Топ 7 правил
Контекст вместо «произошла ошибка»
разница между пятиминутным разбором и бесполезной строкой
Запись «ошибка при обработке заказа» не стоит ничего. Какого заказа, какого пользователя, на каком шаге, что именно не получилось — ничего из этого в ней нет, и найти по ней конкретный случай невозможно.
Минимальный набор. Идентификатор сущности, с которой работали. Идентификатор пользователя — именно идентификатор, а не имя и не почта. Шаг или операция. Причина отказа, а не только факт. И сквозной идентификатор запроса, о котором ниже.
Сквозной идентификатор. На входе каждому запросу присваивается случайный номер, который дальше передаётся во все вызовы и попадает в каждую строку лога. Тогда по одному номеру собирается вся история: что пришло, куда сходили, что ответили. Без этого в логе нагруженного сервиса строки от разных пользователей перемешаны, и распутать их нельзя.
Приятный бонус. Тот же номер можно показывать пользователю на странице ошибки. Человек называет его в поддержке — и вы находите его случай мгновенно, вместо разговора «а во сколько это было примерно».
- Превращает лог из ленты сообщений в средство расследования
- Один номер связывает все компоненты системы
- Резко ускоряет работу поддержки
- Передачу номера нужно организовать через весь код и все вызовы
- Легко случайно записать в контекст лишнее — например, всё тело запроса
главное правило · оценка 9,5
Уровни — по требуемой реакции
не «насколько это важно», а «что мне с этим делать»
Уровни превращаются в бесполезную декорацию, когда каждый выбирает их на глаз. Работающий критерий — не важность, а действие, которого запись требует.
Ошибка — сломалось то, что должно было работать, и кто-то должен вмешаться. По этому уровню настраивают оповещения, поэтому в него нельзя класть ожидаемые ситуации.
Предупреждение — всё работает, но происходит что-то ненормальное: сработал повтор, кончается место, чужой сервис отвечает медленно. Смотреть не срочно, но регулярно.
Информация — значимые события бизнес-логики: заказ создан, платёж подтверждён, задача выполнена. То, по чему потом восстанавливают ход событий.
Отладка — подробности для разбора, обычно выключены в проде и включаются на время.
Самая частая порча. Ошибками помечают то, что ошибкой не является: пользователь ввёл неверный пароль, чужой сервис вернул ожидаемый отказ, запись не найдена. Через месяц таких записей тысячи, на оповещения перестают смотреть, и настоящая авария теряется в шуме. Если реакции не требуется — это не ошибка.
- Позволяет фильтровать и настраивать оповещения осмысленно
- Уровень отладки можно включать на живой системе точечно
- Правило простое и не требует обсуждений
- Требует общей договорённости, иначе каждый ставит по-своему
- Границу между предупреждением и ошибкой всё равно приходится обсуждать
база · оценка 9,4
Ни секретов, ни персональных данных
лог — это данные, вынесенные наружу
В логи регулярно утекает то, чего там быть не должно: пароли из тела запроса, токены доступа, ключи к чужим сервисам, номера карт, паспортные данные, полные адреса и телефоны. Чаще всего не намеренно, а одной строкой «записать весь запрос целиком, чтобы было понятнее».
Почему это серьёзно. Логи хранятся дольше всего остального, лежат в отдельном хранилище, часто у стороннего сервиса, и доступ к ним обычно шире, чем к базе. Утечка через логи — типовой сценарий, а не экзотика.
Как правильно. Заранее составьте список полей, которые вырезаются или заменяются на маску, и обрабатывайте его централизованно, на уровне библиотеки логирования. Полагаться на внимательность каждого разработчика в каждой строке не выйдет.
Вместо значения — ссылка. Пишите идентификатор пользователя, а не его почту. Идентификатор карты в платёжной системе, а не номер. Признак «телефон указан», а не сам телефон. Для разбора этого достаточно, а для утечки — уже нет.
Проверяйте на входе. Простой поиск по логам своих же тестовых данных — фамилии, номера, слова вроде «пароль» и «токен» — обычно находит что-нибудь в первый же раз. Про общие правила обращения с чувствительными данными у нас есть отдельный материал.
- Закрывает целый класс утечек одним централизованным фильтром
- Ничего не стоит, если сделано с самого начала
- Упрощает жизнь при проверках и разборе инцидентов
- Вычистить то, что уже записано, почти невозможно
- Слишком агрессивная маскировка мешает разбирать проблемы
критично · оценка 9,3
Структурные логи вместо склеенных строк
чтобы искать по полям, а не выковыривать регулярными выражениями
Сообщение, собранное склейкой текста и значений, читается человеком и не читается машиной. Как только вам понадобится «все ошибки этого пользователя за час» или «сколько раз сработал повтор», начнётся разбор строк регулярными выражениями — занятие, которое ломается при первой же смене формулировки.
Как правильно. Сообщение — постоянный текст, всё переменное — отдельными полями. Тогда запись превращается в структуру, по которой можно фильтровать, группировать и считать. Большинство библиотек логирования умеют это из коробки, включается настройкой формата.
Компромисс для локальной разработки. В машиночитаемом формате читать логи глазами тяжело. Обычная схема: в проде — структурный вывод, локально — человекочитаемый. Это одна настройка, зависящая от окружения.
Одинаковые имена полей. Если в одном сервисе поле называется одним именем, а в другом иным, сквозной поиск не работает. Договоритесь о наборе базовых имён: идентификатор запроса, пользователь, операция, длительность, код результата.
- Поиск и подсчёт по полям вместо разбора текста
- Легко строить сводки и оповещения
- Формат не ломается при изменении формулировок
- Читать глазами без инструмента неудобно
- Записи занимают заметно больше места
- Требует договорённости об именах полей между сервисами
важно · оценка 9,2
Один поток вывода и сбор в одном месте
искать по десяти машинам вручную — не вариант
Приложение должно писать в стандартный вывод, а не заботиться о файлах, каталогах и правах. Дальше уже среда решает, куда это девать: на локальной машине — на экран, в контейнере — в журнал движка, на сервере — в систему сбора. Так проще всего, и так одинаково работает везде.
Зачем централизованный сбор. Как только сервисов больше одного, а машин больше одной, ручной поиск по файлам перестаёт работать. Нужна одна точка, где лежат логи всех компонентов, с поиском по полям и по времени. Тогда сквозной идентификатор запроса наконец начинает окупаться.
Время — в UTC и с одинаковым форматом. Иначе записи с разных машин не выстраиваются в одну ленту, и в момент разбора аварии приходится пересчитывать смещения в уме. Это ровно тот случай, когда экономия пяти минут при настройке стоит часа в неподходящий момент.
Реалистичная оговорка. Для одного маленького сервиса на одной машине полноценная система сбора избыточна: обычные файлы плюс просмотр в терминале закрывают вопрос. Порог — примерно два сервиса или две машины.
- Одна точка поиска вместо обхода серверов
- Приложению не нужно ничего знать про файлы и ротацию
- Логи не теряются вместе с пересозданным контейнером
- Система сбора — ещё один компонент, который нужно обслуживать
- Готовые сервисы стоят денег, и цена растёт с объёмом
- Отставание доставки мешает в момент горячего разбора
от двух сервисов · оценка 9,1
Сообщение отвечает на вопрос «что и дальше что»
текст пишется для человека, который увидит его ночью
Хорошая запись говорит, что именно произошло и, если это ошибка, что с этим делать. «Ошибка сохранения» — плохо. «Не удалось сохранить заказ: база отклонила запись из-за нарушения уникальности номера» — хорошо: понятно и что случилось, и куда смотреть.
Ошибку записывайте один раз. Типовая беда — исключение перехватили, записали, пробросили выше, там записали снова, и так три раза. В логе три записи об одном событии, и кажется, что проблем больше, чем есть. Правило: пишет тот, кто обработал; кто пробрасывает — не пишет.
Со стеком вызовов. Для настоящих ошибок стек обязателен — без него запись почти бесполезна. А вот для ожидаемых ситуаций он не нужен и только раздувает объём.
Границы операций. Полезно писать начало и конец значимой операции с длительностью и результатом. Это даёт понимание, где именно всё встало, без всякого профилировщика.
Чего не писать. «Вошли в функцию» и «вышли из функции», содержимое циклов построчно, повторяющиеся сообщения без новой информации. Это не логи, а шум, в котором тонет полезное.
- Разбор ускоряется без всяких инструментов
- Меньше объём: шума нет, полезное остаётся
- Помогает не только автору кода, но и дежурному
- Требует привычки, а не настройки — внедряется медленно
- Формулировки со временем расходятся между разработчиками
на разработчике · оценка 9,0
Ротация и срок хранения
забитый логами диск — классическая ночная авария
Лог растёт всегда. Без ограничений он однажды займёт весь диск, и сервис ляжет не из-за ошибки в коде, а из-за того, что некуда записать. Это одна из самых частых причин инцидентов на маленьких проектах.
Что настроить. Ротацию по размеру или по времени, сжатие старых файлов, ограничение общего количества и автоматическое удаление. На большинстве систем всё это делает штатный механизм, и настройка занимает несколько минут.
Срок хранения — осознанное решение. Оперативные логи нужны днями и неделями, а не годами. Отдельно стоит выделить записи о значимых действиях с данными: их иногда требуется хранить дольше, но и требования к их защите выше. Хранить всё вечно «на всякий случай» — дорого и рискованно: чем дольше лежат данные, тем больше шансов, что они утекут.
Проверьте, что оно работает. Настроенная, но не проверенная ротация — то же самое, что ненастроенная. Посмотрите каталог с логами через неделю: если старые файлы на месте и не сжаты, значит, настройка не подхватилась.
- Убирает целый класс аварий с местом на диске
- Настраивается штатными средствами за минуты
- Сокращает объём хранимых персональных данных
- Слишком короткий срок — и данных для разбора уже нет
- Требования к хранению иногда диктуются не вами
- Про проверку настройки все забывают
гигиена · оценка 8,8

Сравнение по главному
| Правило | Зачем | Цена пропуска | Внедрить |
|---|---|---|---|
| Контекст и сквозной номер | поиск по инциденту | высокая | день |
| Уровни по реакции | фильтрация и оповещения | средняя | сразу |
| Без секретов и личных данных | безопасность | критичная | сразу |
| Структурные логи | поиск и подсчёт | средняя | день |
| Сбор в одном месте | одна лента событий | высокая | день |
| Понятные сообщения | скорость разбора | средняя | привычка |
| Ротация и срок хранения | место на диске | высокая | минуты |

Что писать в лог, а что нет
Обязательно. Старт и остановка приложения с версией и ключевыми настройками. Входящие запросы: метод, адрес, код ответа, длительность, номер запроса. Обращения к чужим сервисам: адрес, результат, длительность, факт повтора. Фоновые задачи: запуск, итог, число обработанных элементов. Значимые действия с данными: кто, что и когда изменил.
Полезно. Решения бизнес-логики, которые потом придётся объяснять: почему заказ отклонён, по какому правилу выбрана цена, почему сработало ограничение. Именно эти записи спасают в спорах с пользователями и с коллегами.
Не нужно. Вход и выход из каждой функции. Содержимое коллекций построчно. Дублирование одной ошибки на нескольких уровнях. Сообщения без единого идентификатора внутри.
Как читать в терминале. Просмотр в реальном времени с фильтром по уровню закрывает большую часть повседневных задач. Базовых команд для этого нужно всего несколько — они разобраны в материале про команды терминала.
Проверка на практике. Возьмите вчерашнюю ошибку и попробуйте восстановить по логам, что произошло, не открывая код. Если не получилось — вы точно знаете, чего в них не хватает.
Частые вопросы
Сколько логов — это много?
Ориентир не в объёме, а в пользе: если в потоке невозможно найти нужное без сложных фильтров, записей слишком много. Первым делом убирают повторы и отладочные записи, оставшиеся с этапа разработки. Для очень частых однотипных событий применяют выборочную запись — сохраняют часть, а не каждое.
Логи, метрики или трассировка?
Это разные инструменты. Метрики отвечают на вопрос «сколько и как часто» и дешевле в хранении. Логи — на вопрос «что именно случилось в этом конкретном случае». Трассировка показывает путь одного запроса через несколько сервисов. Считать что-то массовое логами дорого и неудобно — для этого есть счётчики.
Что делать, если для разбора нужны личные данные?
Записывать идентификатор, а не значение: по нему в момент разбора можно поднять нужное из базы, имея на это право. Если без значения совсем никак — маскированный вид, короткий срок хранения и ограниченный доступ. И обязательно фиксируйте, кто и зачем смотрел: это защищает в первую очередь вас.
Нужен ли централизованный сбор маленькому проекту?
Пока сервис один и живёт на одной машине — нет, файлов и терминала достаточно. Порог — второй сервис, вторая машина или контейнеры, которые пересоздаются вместе со своими логами. Начать разумно с самого простого варианта: важнее не выбор инструмента, а то, что все логи оказываются в одном месте и по ним работает поиск.
Итог
Начните с двух вещей: сквозного идентификатора запроса и честных уровней. Первое превращает разрозненные строки в историю, второе возвращает смысл оповещениям. Это работа на день, а эффект виден при первом же инциденте.
Дальше — фильтр секретов и личных данных на уровне библиотеки и настроенная ротация. Обе вещи делаются один раз и защищают от двух самых неприятных сценариев: утечки через логи и упавшего из-за забитого диска сервиса.
Комментарии
0Будьте первым, кто ответит автору.