Уровень логирования задаёт приоритет сообщения и решает, попадёт ли запись в файл, увидит ли её дежурный и сработает ли алерт. Ошибка, записанная как INFO, теряется в потоке штатных событий. Та же ошибка с уровнем ERROR уходит в мониторинг и поднимает человека.
Дальше разбираем восемь уровней syslog, пять уровней Python logging и восемь приоритетов systemd-journald: где они совпадают, где расходятся и как перенести настройки между стеками. Внутри таблица соответствия, конфиги rsyslog и journald, команды проверки и разбор инцидента, который стоил трёх часов простоя.
Что такое уровни логирования и зачем они нужны в продакшене
Уровень логирования (severity, приоритет) - это числовая метка у каждого сообщения, которая отражает серьёзность события. Syslog задаёт шкалу из восьми значений с кодами от 0 (Emergency) до 7 (Debug). Python logging обходится пятью уровнями с шагом 10: DEBUG (10), INFO (20), WARNING (30), ERROR (40), CRITICAL (50). systemd-journald повторяет шкалу syslog и хранит её в поле PRIORITY.
Механика везде одна: библиотека сравнивает уровень записи с порогом и отбрасывает всё, что не проходит фильтр. В Python порог задают как level=logging.INFO, в syslog и journald - как условие severity <= 4. Разница в порядке сортировки: у Python большее число означает более серьёзное событие, у syslog и journald наоборот.
Без уровней лог превращается в один поток, где сообщение о падении базы тонет среди тысяч строк вида 'connection opened'. С уровнями вы держите в файлах то, что нужно для диагностики, а в алертинге только то, на что команда обязана реагировать.
Как уровни помогают фильтровать шум и не терять критичные события
Польза уровней видна на алертинге. Настройте правило на ERROR и CRITICAL, и дежурный получит уведомление только о сломанных операциях, а не о каждом запросе. DEBUG остаётся в коде и включается точечно, когда нужно разобрать конкретный сбой.
Обратная сторона проявляется при включённом DEBUG в продакшене. В разборе инцидента с переполнением диска (разбор на zrachok.com) автор описал, как детализированный debug-лог для одного сервиса начал генерировать сотни мегабайт логов в минуту.
Уровни управляют двумя вещами сразу: объёмом логов и приоритетом событий. Отключённый DEBUG уменьшает поток, корректно расставленные ERROR и CRITICAL гарантируют, что инцидент не потеряется.
Стандартные уровни логирования: от DEBUG до CRITICAL
В прикладном коде устоялся набор из пяти уровней. Его используют Python logging, log4j и logback, Go-пакет log/slog, большинство библиотек для Node.js и Java. Расширенный набор syslog добавляет к ним NOTICE, ALERT и EMERGENCY.
- DEBUG: подробности выполнения, значения переменных, тела запросов. В продакшене держите выключенным.
- INFO: штатные события. Старт и остановка сервиса, успешная транзакция, применённая миграция, вход пользователя.
- WARNING: работа идёт, но появился риск. Повторная попытка подключения, деградация ответа внешнего API, диск заполнен на 85%.
- ERROR: операция не выполнена. Не отправлено письмо, отклонён платёж, упал запрос к внешнему сервису.
- CRITICAL: сервис или данные недоступны. База переведена в read-only, потеряно соединение с брокером, процесс не стартует.
В продакшене включают INFO и выше, DEBUG оставляют для стенда или включают временно. Для высоконагруженных сервисов INFO тоже бывает избыточным: 2000 запросов в секунду и две INFO-строки на запрос дают 4000 записей в секунду, а за сутки это сотни миллионов строк. Если объём мешает, ограничьте набор событий до ключевых бизнес-операций.
DEBUG и INFO: когда детализация помогает, а когда вредит
DEBUG решает узкую задачу: показать, что происходит внутри. Включайте его на одном инстансе, на короткий срок и с понятным условием выключения. Ограничивайте область: пишите только нужный модуль через именованный логгер (logging.getLogger('payment.gateway')) и не отправляйте в лог тела запросов целиком.
INFO фиксирует бизнес-события. Ценность каждой записи проверяется вопросом: если я увижу эту строку, смогу ли понять, что произошло с заказом? Если ответ отрицательный, запись лишняя.
Оценить фактический объём помогают команды:
du -sh /var/log/* | sort -rh | head df -h df -i
Смотрите не только на байты, но и на inode: каталоги с большим числом мелких файлов расходуют их быстрее, чем ожидается, и df -i показывает остаток.
WARNING, ERROR, CRITICAL: как не пропустить инцидент
WARNING сигналит о проблеме, которая ещё не сломала работу. Пример из практики: мониторинг срабатывал при заполнении диска на 85%, предупреждения приходили, но правила на скорость роста не было, а алерт, который должен был поймать экспоненциальное заполнение, оказался выключен (как развивался инцидент).
ERROR фиксирует неудачную операцию при живом сервисе, CRITICAL - полный отказ или угрозу данным. Алертинг настраивайте на ERROR и CRITICAL, а WARNING отправляйте в отдельный канал или в дашборд: иначе дежурный привыкнет игнорировать уведомления. Ожидаемые ошибки (неверный пароль, 404 на статике, отменённый заказ) в ERROR не пишите.
Уровни логирования в syslog: соответствие и особенности
RFC 5424 фиксирует восемь уровней серьёзности. Чем меньше код, тем серьёзнее событие.
| Код | Имя | Когда использовать |
|---|---|---|
| 0 | emerg (Emergency) | Система неработоспособна, нужно немедленное вмешательство |
| 1 | alert (Alert) | Реакция требуется сейчас: отказ диска в массиве, недоступность БД |
| 2 | crit (Critical) | Критическая ошибка, сервис или данные под угрозой |
| 3 | err (Error) | Операция не выполнена |
| 4 | warning (Warning) | Предупреждение, работа продолжается |
| 5 | notice (Notice) | Значимое штатное событие: перезапуск сервиса, смена конфигурации |
| 6 | info (Informational) | Обычные информационные сообщения |
| 7 | debug (Debug) | Отладочная информация |
Приоритет сообщения кодируется формулой PRI = facility * 8 + severity, поэтому фильтровать можно и по источнику, и по уровню. Например, при facility = local0 (код 16) и PRI = 134 severity = 6, то есть информационный тип важности (пример расчёта PRI в документации Eltex). rsyslog принимает селекторы по имени (err, warning, debug) и условия по свойствам $syslogseverity и $syslogfacility.
Как настроить фильтрацию по уровням в rsyslog
Разведите сообщения по файлам: ошибки в отдельный журнал, предупреждения в свой, всё остальное в общий.
# /etc/rsyslog.d/10-levels.conf *.err /var/log/errors.log *.=warning /var/log/warnings.log *.info /var/log/app-info.log
Селектор *.err выбирает сообщения уровня err и серьёзнее, *.=warning - только warning, *.info - от info и серьёзнее. Селектор *.debug совпадает с любым уровнем, поэтому его применяют как catch-all. Если нужно точное условие, используйте свойства:
if $syslogseverity <= 3 then /var/log/errors.log if $syslogseverity == 4 then /var/log/warnings.log
Порядок правил важен: директива & stop останавливает дальнейший разбор сообщения. Проверьте конфигурацию и отправьте тестовое сообщение:
rsyslogd -N1 logger -p user.err 'Test error message' tail -n 5 /var/log/errors.log
DEBUG в проде отключайте на уровне приложения, а не только в конфиге rsyslog: запись всё равно сформируется и уйдёт в сокет, а фильтр лишь уберёт её из файла. Схему сбора, ротацию и отправку логов на центральный сервер разбираем в статье про системное логирование в Linux: journald, rsyslog и Grafana.
Уровни логирования в Python logging: настройка и соответствие
Числовые значения уровней позволяют сравнивать их напрямую: DEBUG (10), INFO (20), WARNING (30), ERROR (40), CRITICAL (50). Запись отбрасывается, если её уровень ниже порога логгера или порога хендлера.
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s %(name)s %(message)s',
)
log = logging.getLogger('billing')
log.debug('payload: %s', payload)
log.info('invoice %s created', invoice_id)
log.warning('retry %s for gateway', attempt)
log.error('payment failed for order %s', order_id)
log.critical('database is read-only, service stopped')Порог задаётся отдельно у логгера и у хендлера. Если у логгера стоит DEBUG, а у хендлера WARNING, в вывод попадут только warning и серьёзнее. Так удобно держать один хендлер для файла с полной детализацией и второй для stderr с высоким порогом.
На производительность влияет не только уровень, но и способ форматирования строк. Приёмы с ленивым форматированием, асинхронными хендлерами и буферизацией разобраны в статье как сохранить скорость приложения при логировании в Python.
Как сопоставить уровни Python logging и syslog
Стандартный SysLogHandler умеет отправлять записи в syslog, но точное сопоставление уровней Python и приоритетов syslog зависит от версии и конфигурации обработчика. В документации Python, доступной в рамках этого разбора, таблица соответствия CRITICAL → LOG_CRIT, ERROR → LOG_ERR, WARNING → LOG_WARNING, INFO → LOG_INFO, DEBUG → LOG_DEBUG не подтверждена, поэтому перед продакшеном проверьте фактический приоритет на своей версии Python: отправьте тестовое сообщение каждого уровня и посмотрите, с каким PRIORITY оно дошло до journald или файла rsyslog.
from logging.handlers import SysLogHandler
handler = SysLogHandler(address='/dev/log', facility=SysLogHandler.LOG_DAEMON)
handler.setFormatter(logging.Formatter('%(name)s: %(levelname)s %(message)s'))
log.addHandler(handler)По умолчанию SysLogHandler использует facility LOG_USER, для демонов указывайте LOG_DAEMON. Проверить доставку можно командой journalctl -t billing или через /var/log/syslog, если в системе работает rsyslog. Уровни NOTICE, ALERT и EMERGENCY в стандартной таблице Python отсутствуют: чтобы отправить их в syslog, задайте кастомный уровень числом больше 50 или формируйте приоритет явно. Настройка логгеров, хендлеров и форматов подробно разобрана в статье про настройку логирования в Python: от основ до промышленного развёртывания.
Уровни логирования в systemd-journald: приоритеты и фильтрация
journald использует ту же шкалу, что syslog: 0 emerg, 1 alert, 2 crit, 3 err, 4 warning, 5 notice, 6 info, 7 debug. Уровень хранится в поле PRIORITY, и по нему работает фильтр journalctl -p.
Практические команды journalctl для фильтрации по уровням
journalctl -p err -b journalctl -p warning -f journalctl -p crit..alert -b journalctl -u nginx -p err --since '1 hour ago' journalctl --disk-usage
Диапазоны записываются через две точки: -p crit..alert показывает сообщения от crit до alert включительно. Проверка фильтра занимает две команды:
logger -p user.err 'Test error message' journalctl -p err -n 1
Ограничьте объём журнала, иначе journald займёт раздел целиком. Минимальный набор параметров в /etc/systemd/journald.conf:
[Journal] Storage=persistent SystemMaxUse=2G SystemMaxFileSize=200M SystemMaxFiles=10 RateLimitIntervalSec=30s RateLimitBurst=10000
После правки выполните systemctl restart systemd-journald. Параметры RateLimitIntervalSec и RateLimitBurst задают порог подавления потока: при его превышении journald отбрасывает сообщения и помечает это записью о числе подавленных строк. Эти параметры настраиваются в /etc/systemd/journald.conf и связанных drop-in файлах, а в man-странице journald.conf(5) они присутствуют наряду с настройками, добавленными в версиях 190 и 246 (описание параметров в journald.conf, man-страница journald.conf(5)). Конкретные значения по умолчанию и их изменения между версиями systemd в доступных источниках не подтверждены, поэтому сверьтесь с man journald.conf на своих машинах. Фильтры по сервису, времени и PID, а также постоянное хранение и ротацию разбираем в статье про journalctl: фильтры, хранение и ротация логов.
Таблица соответствия уровней логирования в популярных системах
Сводная таблица для переноса настроек между syslog, Python logging и systemd-journald.
| syslog (код, имя) | Python logging | systemd-journald | Типовое применение |
|---|---|---|---|
| 0 emerg | CRITICAL (50) | 0 emerg | Система или данные недоступны |
| 1 alert | нет прямого аналога, ближайший CRITICAL (50) | 1 alert | Реакция нужна немедленно |
| 2 crit | CRITICAL (50) | 2 crit | Критическая ошибка |
| 3 err | ERROR (40) | 3 err | Операция не выполнена |
| 4 warning | WARNING (30) | 4 warning | Потенциальная проблема |
| 5 notice | нет прямого аналога, ближайший INFO (20) | 5 notice | Значимое штатное событие |
| 6 info | INFO (20) | 6 info | Информационное сообщение |
| 7 debug | DEBUG (10) | 7 debug | Отладочные детали |
Что учитывать при переносе: Python не различает notice, alert и emerg, поэтому сообщение с уровнем CRITICAL при отправке через SysLogHandler получит приоритет crit (2), а не alert или emerg. Обратное преобразование тоже неполное: прочитанный из syslog notice в Python отобразится как INFO. Если в вашем стеке важно различать эти события, заведите набор констант и маппинг в коде, а в конфиге отправки укажите приоритет явно.
Как выбрать уровень для конкретного сообщения: практические правила
Проходите четыре вопроса по порядку и останавливайтесь на первом подходящем.
- Сервис или данные недоступны, восстановления нет? CRITICAL.
- Операция не выполнена, но сервис работает? ERROR.
- Работа идёт, но появился риск или сработал защитный механизм? WARNING.
- Событие штатное и его стоит зафиксировать? INFO.
Пятый вопрос про детали: нужна ли запись, чтобы понять порядок вызовов или содержимое данных? Тогда DEBUG.
Уровень отражает последствия, а не источник сообщения. Таймаут внешнего API в пользовательском запросе и тот же таймаут в фоновом воркере с ретраями имеют разную цену, и уровень у них может отличаться.
Примеры выбора уровня для типовых событий в продакшене
- Запуск и остановка сервиса - INFO.
- Успешная транзакция или созданный заказ - INFO.
- Смена конфигурации - NOTICE в syslog, INFO в Python.
- Повторная попытка подключения к базе - WARNING.
- Ответ внешнего API медленнее обычного - WARNING.
- Диск заполнен на 85% - WARNING.
- Таймаут внешнего API, запрос пользователя не выполнен - ERROR.
- Не удалось записать файл или отправить письмо - ERROR.
- База переведена в read-only, сервис не принимает запросы - CRITICAL.
- Подозрительная активность (серия неудачных входов, обращение к закрытому пути) - WARNING, если действие заблокировано, и ERROR, если нет.
Ожидаемые ошибки не поднимайте до ERROR: неверный пароль пользователя, 404 на статике, отменённый заказ - это INFO или WARNING плюс метрика. Иначе алертинг теряет сигнал. Если сомневаетесь между INFO и WARNING, выбирайте WARNING. Если между ERROR и CRITICAL, проверьте, есть ли у сервиса запасной путь: пока запросы обслуживает хотя бы один инстанс, это ERROR. Критерии того, что вообще стоит записывать в лог, разобраны в статье что логировать, а что нет: критерии для мониторинга.
Типичные ошибки при настройке уровней и как их избежать
Пять ошибок закрывают большинство проблем с логированием в продакшене. Каждая приводит либо к потере события, либо к переполнению диска.
Кейс: как debug-логи и отсутствие алертов привели к трёхчасовому простою
Разбор инцидента (полный разбор инцидента) показывает цепочку целиком. Детализированный debug-лог включили для одного сервиса в проде. Накопление логов пошло со скоростью 300-400 МБ в минуту, за 15 минут это дало до 6 ГБ.
Диск на 500 ГБ был заполнен на 460 ГБ, и потерянных 40 ГБ хватило, чтобы WAL Postgres перестал писать и СУБД перевела базу в режим read-only. Сервис обработки писем и платежей упал. Мониторинг срабатывал при 85% заполнения, но правила на скорость роста не было, а алерт на экспоненциальное заполнение был выключен.
Хронология: 11:10 предупреждение о 85%, 11:40 - 95%, 12:05 диск заполнен почти полностью, 12:12 база ушла в read-only. Около 14:30 инженер откатил часть логов вручную, к 15:00 сервис вернулся в работу. Итог: примерно 3 часа простоя, 1.2k задач в очередях на отправку писем и около 300 платёжных транзакций в состоянии retry.
После инцидента добавили алерт на скорость заполнения: рост за 15 минут и порог более 1 ГБ за 15 минут. Ротацию тоже пересмотрели: logrotate был настроен только по размеру, без ограничения суммарного объёма и числа файлов, а медленное сжатие оставляло временные .gz.tmp файлы, которые занимали место.
- DEBUG в продакшене без ограничения объёма. Поток растёт до сотен мегабайт в минуту. Держите INFO как минимальный уровень, а DEBUG включайте на одном инстансе и на короткий срок.
- ERROR для ожидаемых ошибок. Неверный пароль, 404 на статике, отменённый заказ зашумляют алертинг. Переведите их в WARNING или INFO.
- Нет алерта на скорость роста. Порог по абсолютному значению (85% диска) не ловит экспоненту. Добавьте правило вида 'более 1 ГБ за 15 минут'.
- Ротация только по размеру. Без rotate и лимита на общий объём архивы копятся, а сжатие оставляет .gz.tmp. Задайте maxsize, rotate и delaycompress.
- journald без лимитов. Журнал растёт и забивает раздел. Установите SystemMaxUse и SystemMaxFileSize.
Как выстроить единые правила логирования для команды
Политика логирования занимает одну-две страницы и отвечает на пять вопросов: какой минимальный уровень в продакшене, какие события относятся к каждому уровню, в каком формате пишутся логи, какие данные запрещено логировать, как включается DEBUG.
Формат: структурированный вывод (JSON или logfmt) с обязательными полями timestamp, level, service, message и trace_id. Одинаковые поля позволяют фильтровать по уровню в Loki, Elasticsearch или Grafana без регулярных выражений. Запрет на пароли, токены, номера карт и персональные данные закрепите отдельным пунктом и вынесите в чек-лист код-ревью.
Правило по умолчанию для новых сервисов: INFO на старте, ERROR для сломанных операций, CRITICAL для отказов. Уровень DEBUG включается переменной окружения или конфигом, а не правкой кода.
Чек-лист для настройки уровней логирования в продакшене
- Убедитесь, что DEBUG отключён и включается только по флагу.
- Оцените скорость роста логов: du -sh /var/log и приращение за сутки.
- Настройте алертинг на ERROR и CRITICAL.
- Добавьте алерт на скорость роста, например больше 1 ГБ за 15 минут.
- Проверьте свободное место и inode: df -h и df -i.
- Проверьте ротацию: maxsize, rotate по числу файлов, сжатие с delaycompress.
- Для journald задайте SystemMaxUse и SystemMaxFileSize.
- Проверьте фильтры: journalctl -p err -b и содержимое errors.log.
- Отправьте тестовые сообщения всех уровней через logger и убедитесь, что они попали в нужные файлы и каналы.
- Проведите ревью нового сервиса: уровни, формат, обязательные поля, отсутствие секретов.
Проверка и отладка настроек логирования: команды и примеры
du -sh /var/log/* | sort -rh | head df -h df -i find /var/log -type f -mtime +30 -printf '%s %p\n' | sort -rn | head journalctl --disk-usage rsyslogd -N1 logrotate -d /etc/logrotate.conf
logrotate -d показывает, что утилита сделает с каждым файлом, и не трогает сами логи. Пример конфигурации с ограничением объёма и числа файлов:
/var/log/app/*.log {
daily
rotate 14
maxsize 500M
compress
delaycompress
missingok
notifempty
}rotate 14 ограничивает число архивных файлов, maxsize запускает ротацию раньше суточного срока при превышении размера, delaycompress откладывает сжатие на один цикл и снижает нагрузку на диск. Для Python проверьте, что уровень действительно отсекает записи: временно поставьте DEBUG у логгера, посмотрите объём за минуту, верните INFO и сравните.
Заключение: ключевые принципы работы с уровнями логирования
- Уровень отражает серьёзность последствий, а не источник сообщения.
- В продакшене минимальный уровень - INFO, DEBUG включается точечно и временно.
- Алертинг строят на ERROR и CRITICAL плюс на скорости роста логов.
- Таблица соответствия из этой статьи переносит настройки между syslog, Python и journald за пару минут.
- Единое правило в команде дешевле любого инцидента: формат, уровни и запрет на секреты фиксируются в документе и проверяются на код-ревью.
Начните с двух действий: проверьте скорость роста логов командой du -sh /var/log/* | sort -rh | head и посмотрите, есть ли у вас алерт на рост заполнения диска. Инцидент из разбора стоил трёх часов простоя и сотен задач в очередях, а начинался с одной включённой строки debug-лога.