Когда что-то ломается ночью, администратор не гадает - он идет в логи. Эта глава про то, как Linux собирает сообщения о событиях: классический демон rsyslog с его системой facility/priority, бинарный журнал journald от systemd и ротацию logrotate, чтобы диски не переполнялись. Разберем, где физически лежат логи, как их читать и почему на современной системе одно и то же сообщение часто попадает сразу в два места.

Как это работает
Идея syslog родилась еще в 80-х: любая программа отправляет короткое сообщение демону логирования, а тот сам решает, куда его записать. Чтобы демон мог сортировать поток, у каждого сообщения есть два атрибута. Facility - это категория источника: kern (ядро), auth и authpriv (вход в систему, sudo), mail, cron, daemon, и восемь свободных local0-local7 для своих приложений. Priority (он же severity) - это важность: от debug (самое мелкое) через info, notice, warning, err, crit, alert до emerg (система умирает). Связка facility.priority и есть язык, на котором пишутся правила маршрутизации.
В rsyslog правило выглядит как selector + action. Селектор mail.err означает категорию mail и приоритет err И ВЫШЕ. Действие - чаще всего путь к файлу. То есть строка mail.err /var/log/mail.err читается как все письма уровня err и серьезнее пиши в этот файл. Важно понимать накопительную логику: указав err, вы поймаете также crit, alert, emerg. Чтобы взять ровно один уровень, ставят знак равенства: mail.=info.
journald - это другой подход. Демон systemd-journald пишет не в текст, а в структурированный бинарный журнал. Каждая запись несет десятки полей: какой юнит ее породил, PID, UID, имя загрузки (boot ID), точное время. Поэтому фильтровать можно не грепом, а по полям. Минус бинарного формата - его не прочитать обычным cat, нужен journalctl. Плюс - надежность, индексация и связь сообщения с конкретным сервисом systemd.
На современной системе работают оба механизма сразу. journald получает сообщения первым (от ядра, от сервисов, из сокета /dev/log), а потом может переслать их дальше в rsyslog через сокет /run/systemd/journal/syslog. Так получается, что вы видите событие и в journalctl, и в текстовом /var/log/syslog. Это не баг, а штатная связка для совместимости со старыми инструментами разбора логов.
Команды и примеры
Маршрутизация в rsyslog задается в /etc/rsyslog.conf и подключаемых файлах из /etc/rsyslog.d/. Несколько типовых правил:
Код: Выделить всё
# все ошибки уровня err и выше - в один файл
*.err /var/log/errors.log
# только аутентификация (вход, sudo, su)
auth,authpriv.* /var/log/auth.log
# ровно info из cron, ни выше ни ниже
cron.=info /var/log/cron-info.log
# исключить debug из общего потока
*.*;mail.none;authpriv.none /var/log/messages
# отправка на удаленный сервер по TCP
*.* @@logserver.local:514
Код: Выделить всё
logger -p auth.warning "тестовая запись от админа"
Код: Выделить всё
journalctl -u sshd.service # только юнит sshd
journalctl -b # с текущей загрузки
journalctl -b -1 # с предыдущей загрузки
journalctl -p err # приоритет err и выше
journalctl -f # хвост в реальном времени (как tail -f)
journalctl --since "2026-06-13 09:00" --until "10:00"
journalctl -k # только сообщения ядра (dmesg)
journalctl -u nginx -p warning --since today
Код: Выделить всё
mkdir -p /var/log/journal
systemctl restart systemd-journald
journalctl --disk-usage # сколько занято
journalctl --vacuum-time=2weeks # удалить старше двух недель
Код: Выделить всё
/var/log/myapp/*.log {
weekly
rotate 8
compress
delaycompress
missingok
notifempty
create 0640 myapp myapp
postrotate
systemctl reload myapp >/dev/null 2>&1 || true
endscript
}
Код: Выделить всё
logrotate -d /etc/logrotate.conf # debug, ничего не меняет
logrotate -f /etc/logrotate.d/myapp # форсировать ротацию
Частые грабли
- Забыли, что priority накопительный: написали warning, а удивляетесь записям уровня crit. Для точного уровня нужен знак равенства.
- Журнал journald непостоянный: после reboot пропали логи аварии. Каталог /var/log/journal не создан или Storage=volatile в /etc/systemd/journald.conf.
- logrotate ротирует, но демон продолжает писать в старый inode и новый файл пустой. Решение - copytruncate или сигнал/reload в postrotate.
- Запутались в дублях: одно сообщение в journalctl и в /var/log/syslog. Это связка journald to rsyslog через ForwardToSyslog, а не ошибка.
- Правка rsyslog.conf без перезапуска демона - изменения не подхватываются, нужен systemctl restart rsyslog.
- journalctl показывает старое локальное время после смены таймзоны - журнал хранит UTC, отображение зависит от настроек системы.
- Сделайте journald персистентным: создайте /var/log/journal, перезапустите systemd-journald, перезагрузите стенд и проверьте journalctl -b -1.
- Сгенерируйте сообщение: logger -p local0.info "lab test" и найдите его через journalctl и в текстовом логе.
- Создайте /etc/rsyslog.d/90-lab.conf с правилом local0.* /var/log/lab.log, перезапустите rsyslog, повторите logger и убедитесь, что файл появился.
- Найдите все сообщения уровня err и выше за сегодня: journalctl -p err --since today.
- Напишите правило logrotate для /var/log/lab.log (rotate 3, daily, compress) и форсируйте ротацию ключом -f, посмотрите на результат в каталоге.
- Ограничьте размер журнала: journalctl --vacuum-size=50M и сверьте journalctl --disk-usage.
- Чем отличается селектор mail.info от mail.=info в rsyslog?
- Какой ключ journalctl покажет сообщения только от предыдущей загрузки системы и какой - только от ядра?
- Что физически нужно сделать, чтобы журнал journald пережил перезагрузку?
- Зачем в правиле logrotate директива delaycompress и в каком случае нужен copytruncate?
- Через какой механизм сообщение попадает одновременно в journald и в /var/log/syslog?
- Перечислите приоритеты syslog от самого низкого до самого высокого.