Логи системы: journalctl, rsyslog, logrotate
Где на самом деле лежат логи современного Linux, как искать в бинарном журнале systemd и как не дать логам забить диск.
journald — компонент systemd, который собирает структурированные логи всех служб в бинарный журнал; читают его командой
journalctl, а неcat.
Зачем это на практике
«Сервис не работает» — и первое, что делает админ, открывает логи. На systemd-системах журнал у каждой службы общий и индексированный: можно фильтровать по юниту, времени, приоритету и даже по PID — без grep по гигабайтам. Параллельно существует классический rsyslog с текстовыми файлами в /var/log, и оба надо уметь читать. А logrotate спасает диск от переполнения.
journalctl: основные фильтры
Без аргументов journalctl вываливает весь журнал от старта системы. На практике всегда фильтруют:
journalctl -u nginx.service # только логи юнита nginx
journalctl -u nginx -f # следить в реальном времени (как tail -f)
journalctl -u nginx --since "10 min ago"
journalctl --since "2024-01-01" --until "2024-01-02 12:00"
journalctl -b # логи только текущей загрузки
journalctl -b -1 # предыдущей загрузки (искать причину падения)
journalctl -k # сообщения ядра (= dmesg)Флаг -u (unit) — самый частый. -f (follow) и -b (boot) экономят часы.
Приоритеты (severity)
Каждая запись имеет уровень от 0 (emerg) до 7 (debug). Фильтр -p показывает выбранный уровень и важнее:
| Код | Уровень | Когда |
| 0–3 | emerg/alert/crit/err | что-то сломалось |
| 4 | warning | подозрительно |
| 6 | info | обычные события |
| 7 | debug | детальная отладка |
journalctl -p err -b # только ошибки и хуже за эту загрузку
journalctl -u myapp -p warning --since today
journalctl -u myapp -o json-pretty # структурированный вывод со всеми полямиПостоянный журнал
По умолчанию во многих дистрибутивах журнал хранится в /run/log/journal — это tmpfs в памяти, и после перезагрузки он исчезает. Чтобы журнал переживал ребут (критично для разбора падений), его делают постоянным:
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
# или явно в конфиге:
# /etc/systemd/journald.conf -> [Journal]\nStorage=persistent
sudo systemctl restart systemd-journald
journalctl --disk-usage # сколько занимает журнал
sudo journalctl --vacuum-size=500M # обрезать до 500 МБ
sudo journalctl --vacuum-time=2weeks # удалить старше 2 недель/var/log и rsyslog
Даже с journald многие демоны и сам rsyslog пишут текстовые файлы в /var/log. Знать их наизусть полезно:
/var/log/syslog или /var/log/messages | общесистемные сообщения |
/var/log/auth.log или /var/log/secure | аутентификация, sudo, ssh-входы |
/var/log/kern.log | сообщения ядра |
/var/log/nginx/, /var/log/dpkg.log | логи конкретных служб/пакетов |
rsyslog принимает сообщения и раскладывает по файлам согласно правилам facility.priority. Конфиг — /etc/rsyslog.conf и /etc/rsyslog.d/*.conf:
# /etc/rsyslog.d/50-myapp.conf — все сообщения от local0 в отдельный файл
local0.* /var/log/myapp.log
# проверить конфиг и перезапустить
sudo rsyslogd -N1
sudo systemctl restart rsyslog
# отправить тестовую запись
logger -p local0.info "проверка связи"Ротация: logrotate
Текстовые логи растут бесконечно и забивают диск. logrotate по расписанию (обычно через systemd-timer или cron) переименовывает, сжимает и удаляет старые файлы. Правила — в /etc/logrotate.d/:
# /etc/logrotate.d/myapp
/var/log/myapp.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
}Что значат ключи: daily — раз в сутки; rotate 14 — хранить 14 архивов; compress — gzip старых; missingok — не ругаться, если файла нет; copytruncate — копировать и обнулить файл (для демонов, которые держат файл открытым и не умеют переоткрывать его по сигналу).
sudo logrotate -d /etc/logrotate.d/myapp # -d = dry-run, ничего не меняет, показывает план
sudo logrotate -f /etc/logrotate.d/myapp # -f = принудительно прокрутить сейчасКак это работает под капотом
journald получает логи несколькими путями: stdout/stderr каждой службы перехватывается systemd и пишется в журнал автоматически (поэтому print() в вашем приложении сразу виден в journalctl -u); плюс есть нативный сокет и приём от syslog(). Журнал хранится в индексированных бинарных файлах .journal с полями-ключами (_SYSTEMD_UNIT, _PID, PRIORITY), поэтому фильтрация по юниту/времени — это поиск по индексу, а не перебор строк. Записи криптографически последовательны, и journald отслеживает повреждение файлов. rsyslog и journald часто работают вместе: journald — первичный приёмник, а rsyslog читает из него и пишет привычные текстовые файлы для совместимости и пересылки на удалённый лог-сервер.
Частые ошибки
- Ищут логи службы в
/var/log/myapp.log, а она пишет в stdout → всё вjournalctl -u myapp, файл пуст. - Журнал не постоянный: после ребута логи падения исчезли, потому что
Storageостался в памяти. - Диск забился логами журнала — забыли про
SystemMaxUseвjournald.confили про--vacuum. - logrotate с обычным переименованием для демона, который держит дескриптор открытым: служба продолжает писать в «старый» файл. Решение —
copytruncateили сигнал на переоткрытие черезpostrotate. - Забыли
journalctl -b -1при разборе внезапной перезагрузки и смотрят только текущую загрузку, где причины уже нет.
Итоги
journalctl -u ИМЯ -fи-p err— рабочие лошадки разбора инцидентов.-b/-b -1переключают между текущей и прошлой загрузкой.- Постоянный журнал (
/var/log/journal) нужен, чтобы логи переживали перезагрузку. /var/log/auth.log,syslog,kern.log— классические текстовые логи rsyslog.logrotateне даёт логам забить диск:rotate,compress,copytruncate.