Логи в Linux: journalctl, /var/log, rsyslog и logrotate
В современных дистрибутивах Linux логи собирает journald, а читают их командой journalctl: journalctl -u nginx покажет записи одного сервиса, -f — поток в реальном времени, --since и -p фильтруют по времени и важности. Текстовые логи лежат в /var/log, их пишет rsyslog или само приложение, а logrotate регулярно сжимает и удаляет старые файлы, чтобы диск не переполнился.
Когда сервис упал ночью, ответ почти всегда есть в логах — вопрос только в том, где их искать. В современных дистрибутивах (Ubuntu, Debian, RHEL, Fedora, Arch) события собирает служба journald, а читаются они командой journalctl. Параллельно многие программы пишут обычные текстовые файлы в /var/log, и за их размером следит logrotate. Ниже — как работать с journalctl логами Linux на практике, где лежат остальные журналы и как не потерять важное при ротации.
Где хранятся логи в Linux
Источников три, и полезно держать их в голове как карту:
- journald — бинарный журнал systemd. Принимает stdout и stderr всех сервисов, сообщения ядра и syslog. Хранится в
/var/log/journal/(постоянно) или/run/log/journal/(до перезагрузки). - /var/log — текстовые файлы. Их пишет
rsyslog(например,/var/log/syslog,/var/log/auth.log) или сами приложения: nginx, PostgreSQL, MySQL. - Кольцевой буфер ядра — сообщения драйверов и оборудования, их показывает
dmesgилиjournalctl -k.
| Файл | Что внутри |
|---|---|
/var/log/syslog (Debian/Ubuntu) | общий системный журнал |
/var/log/messages (RHEL/Fedora) | то же самое в семействе Red Hat |
/var/log/auth.log или /var/log/secure | входы, sudo, SSH |
/var/log/kern.log | сообщения ядра |
/var/log/dpkg.log, /var/log/apt/ | установка пакетов |
/var/log/nginx/ | access.log и error.log веб-сервера |
/var/log/wtmp, /var/log/btmp | бинарные журналы входов, читаются через last и lastb |
Большинство файлов в /var/log доступны только root или группе adm, поэтому команды чтения часто нужно запускать через sudo.
journalctl: базовые команды
Без аргументов journalctl выводит весь журнал от самых старых записей через пейджер less. Это редко нужно — обычно сразу сужают выборку.
journalctl # весь журнал, от старых к новым
journalctl -e # открыть сразу в конце
journalctl -n 50 # последние 50 строк
journalctl -r # в обратном порядке, новые сверху
journalctl --no-pager # без less, удобно для скриптов и grep
Внутри пейджера работают привычные клавиши less: / — поиск, G — в конец, q — выход. Длинные строки обрезаются по ширине экрана; стрелки влево и вправо прокручивают их.
Логи конкретного сервиса: journalctl -u
Самый частый сценарий — посмотреть, что писал один юнит systemd. Искать файл и грепать его не нужно:
$ sudo journalctl -u nginx -n 20
Oct 14 03:12:41 web1 systemd[1]: Starting nginx.service - A high performance web server...
Oct 14 03:12:41 web1 nginx[1834]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Oct 14 03:12:41 web1 systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Oct 14 03:12:41 web1 systemd[1]: nginx.service: Failed with result 'exit-code'.
Флаг -u можно повторять: journalctl -u nginx -u php8.2-fpm покажет оба сервиса вперемешку по времени, что удобно, когда ошибка возникает на стыке. Для пользовательских юнитов (systemctl --user) используйте journalctl --user -u имя.
Логи в реальном времени: journalctl -f
sudo journalctl -u nginx -f
Это аналог tail -f: команда выводит последние 10 записей и ждёт новых. Удобно держать её в отдельном терминале, пока вы перезапускаете сервис или воспроизводите ошибку. Выход — Ctrl+C.
Фильтры по времени и загрузке
Если вы знаете, когда случилась авария, выборку по времени задают флагами --since и --until. Они понимают и точные даты, и относительные значения:
journalctl --since "2026-10-14 02:50" --until "2026-10-14 03:30"
journalctl --since "1 hour ago"
journalctl --since yesterday --until today
journalctl -u nginx --since "10 min ago"
Второй полезный срез — по загрузкам системы. Если сервер сам перезагрузился, причину ищут в конце предыдущей сессии:
$ journalctl --list-boots
-2 8f1c... Sat 2026-10-12 09:01:12 UTC Sun 2026-10-13 22:47:03 UTC
-1 a7d2... Sun 2026-10-13 22:48:30 UTC Tue 2026-10-14 03:05:51 UTC
0 c3e9... Tue 2026-10-14 03:07:02 UTC Tue 2026-10-14 09:15:40 UTC
$ journalctl -b -1 -e # конец предыдущей загрузки
$ journalctl -b # только текущая загрузка
Список загрузок доступен, только если журнал хранится на диске. Как это включить — ниже, в разделе про настройку journald.
Фильтр по важности: journalctl -p
Каждая запись имеет приоритет syslog от 0 до 7. Флаг -p показывает указанный уровень и всё, что важнее:
| Код | Имя | Когда используется |
|---|---|---|
| 0 | emerg | система неработоспособна |
| 1 | alert | нужно немедленное вмешательство |
| 2 | crit | критическая ошибка |
| 3 | err | ошибка |
| 4 | warning | предупреждение |
| 5 | notice | значимое, но нормальное событие |
| 6 | info | информационное сообщение |
| 7 | debug | отладка |
journalctl -p err -b # все ошибки с начала загрузки
journalctl -p warning..err -u ssh # диапазон уровней для одного сервиса
Команда journalctl -p err -b — хорошая первая проверка после перезагрузки или обновления: она за секунды показывает, что пошло не так.
Поиск и другие фильтры
journald хранит у каждой записи структурированные поля, и по ним можно фильтровать без grep:
journalctl _PID=1834 # по номеру процесса
journalctl _COMM=sshd # по имени программы
journalctl _UID=1000 # по пользователю
journalctl /usr/sbin/sshd # по пути к исполняемому файлу
journalctl -k # только сообщения ядра (как dmesg)
journalctl -t CRON # по идентификатору syslog
journalctl -g "Out of memory" # поиск по тексту, регулярное выражение
Флаг -g (--grep) появился в systemd 237; на старых системах используйте обычный конвейер journalctl --no-pager | grep .... Фильтры по разным полям объединяются через «И», так что journalctl -u nginx -p err --since today вернёт только сегодняшние ошибки nginx.
Форматы вывода
Флаг -o меняет формат. Самые полезные варианты:
-o short-iso— время в ISO 8601, удобно сравнивать с логами приложения.-o verbose— все поля записи, включая_SYSTEMD_UNIT,_PID,_BOOT_ID.-o jsonилиjson-pretty— для обработки скриптом илиjq.-o cat— только текст сообщения, без даты и хоста.
journalctl -u myapp -o json --since today | jq -r '.MESSAGE'
Настройка journald: хранение и размер
Настройки лежат в /etc/systemd/journald.conf (переопределения удобнее класть в /etc/systemd/journald.conf.d/*.conf). Главный параметр — Storage:
persistent— журнал пишется на диск в/var/log/journalи переживает перезагрузку.volatile— только в памяти, в/run/log/journal.auto(по умолчанию) — на диск, если каталог/var/log/journalсуществует.
На некоторых минимальных образах каталога нет, и после перезагрузки история пропадает. Включить постоянное хранение:
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
Чтобы журнал не занимал весь диск, задайте лимиты:
# /etc/systemd/journald.conf.d/size.conf
[Journal]
Storage=persistent
SystemMaxUse=500M
MaxRetentionSec=1month
По умолчанию SystemMaxUse — 10% от размера файловой системы, но не больше 4 ГБ.
Как очистить журнал journalctl
$ journalctl --disk-usage
Archived and active journals take up 1.8G in the file system.
sudo journalctl --vacuum-size=300M # оставить не больше 300 МБ
sudo journalctl --vacuum-time=2weeks # удалить записи старше двух недель
sudo journalctl --rotate # закрыть активные файлы, чтобы их тоже можно было удалить
Удалять файлы из /var/log/journal через rm не стоит: vacuum делает то же аккуратно и не трогает активный файл.
rsyslog: классические текстовые логи
rsyslog — демон, который принимает сообщения syslog (в том числе пересланные из journald) и раскладывает их по файлам по правилам. Конфигурация — /etc/rsyslog.conf и /etc/rsyslog.d/*.conf. Правило состоит из селектора источник.уровень и действия:
# /etc/rsyslog.d/50-default.conf (фрагмент)
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
kern.* -/var/log/kern.log
Минус перед путём означает запись без синхронизации на диск после каждой строки — быстрее, но при аварии последние строки могут потеряться. После изменения конфигурации проверьте синтаксис и перезапустите службу:
sudo rsyslogd -N1
sudo systemctl restart rsyslog
Главное, ради чего rsyslog держат рядом с journald, — пересылка логов на центральный сервер. Одна строка отправит всё по TCP:
# /etc/rsyslog.d/90-remote.conf
*.* @@logs.example.com:514
Один символ @ означает UDP, два @@ — TCP. Если сервер умрёт целиком, копия логов останется на другой машине. Чтобы записать своё сообщение в системный журнал из скрипта, используйте logger:
logger -t backup -p user.err "Бэкап базы не удался"
journalctl -t backup -n 5
logrotate: ротация логов
Текстовые логи растут бесконечно, пока их кто-то не обрежет. Этим занимается logrotate: раз в сутки (через cron или таймер logrotate.timer) он переименовывает текущий файл, сжимает старые и удаляет самые давние. Общие настройки — /etc/logrotate.conf, правила для программ — /etc/logrotate.d/.
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 myapp adm
postrotate
systemctl reload myapp > /dev/null 2>&1 || true
endscript
}
| Директива | Смысл |
|---|---|
daily / weekly / size 100M | когда ротировать |
rotate 14 | сколько старых файлов хранить |
compress, delaycompress | сжимать gzip, но самый свежий архив оставить несжатым |
missingok, notifempty | не ругаться на отсутствие файла, не ротировать пустой |
create 0640 user group | с какими правами создать новый файл |
copytruncate | скопировать и обнулить файл — для программ, которые не умеют переоткрывать лог |
postrotate ... endscript | команда после ротации, обычно сигнал приложению переоткрыть файл |
Проверить правило без изменений и принудительно запустить ротацию:
sudo logrotate -d /etc/logrotate.d/myapp # сухой прогон с отладкой
sudo logrotate -f /etc/logrotate.d/myapp # ротировать прямо сейчас
Типичная ошибка — забыть postrotate или copytruncate. Тогда приложение продолжает писать в переименованный app.log.1 по старому дескриптору, а новый app.log остаётся пустым.
Чтение текстовых логов
Для файлов в /var/log хватает стандартных утилит:
sudo tail -n 100 /var/log/syslog # последние строки
sudo tail -F /var/log/nginx/error.log # следить, переживая ротацию
sudo less +G /var/log/auth.log # открыть в конце
sudo zgrep "Failed password" /var/log/auth.log.*.gz # поиск в сжатых архивах
sudo grep -c " 500 " /var/log/nginx/access.log # сколько ответов 500
Обратите внимание на tail -F с заглавной буквой: в отличие от -f, он заново открывает файл, когда logrotate его подменяет.
Пошаговый разбор аварии
Сценарий «сервис упал ночью» удобно разбирать по одному порядку:
systemctl status myapp— текущее состояние и последние строки журнала.journalctl -u myapp --since "03:00" --until "03:30"— что сервис писал в момент падения.journalctl -p err -b— нет ли других ошибок в системе в то же время.journalctl -k --since "03:00" -g "Out of memory|Killed process"— не убил ли процесс OOM killer ядра.- Логи самого приложения в
/var/log/myapp/, включая архивы.gz. - Если сервер перезагружался —
journalctl -b -1 -e.
Итог
Для повседневной работы с логами в Linux достаточно нескольких команд: journalctl -u для сервиса, -f для потока, --since и -p err для сужения выборки, -b -1 для разбора перезагрузки. Текстовые журналы лежат в /var/log, rsyslog раскладывает и пересылает их, а logrotate и journalctl --vacuum-* не дают логам съесть диск. Работа с journalctl, ротацией и диагностикой нагрузки разобрана на практике в лекции курса по Linux.
Частые вопросы
Почему journalctl показывает только записи с последней загрузки?
Журнал хранится в памяти (/run/log/journal). Создайте каталог /var/log/journal или задайте Storage=persistent в journald.conf и перезапустите systemd-journald.
Как дать обычному пользователю читать системный журнал без sudo?
Добавьте его в группу systemd-journal (или adm в Debian и Ubuntu): sudo usermod -aG systemd-journal имя, затем перелогиньтесь.
Можно ли посмотреть журнал другой системы, например с подключённого диска?
Да, укажите каталог журнала флагом -D: journalctl -D /mnt/var/log/journal. Флаг --file читает отдельный файл .journal.
Нужен ли rsyslog, если есть journald?
Не обязательно. Он полезен, если нужны текстовые файлы для старых инструментов или пересылка логов на центральный сервер; на многих минимальных образах его уже не ставят.
Как экспортировать логи сервиса в файл, чтобы отправить коллеге?
Выполните journalctl -u имя --since today --no-pager > service.log — получится обычный текстовый файл.
Эта тема подробно разобрана с практикой в курсе «Linux: с нуля до уверенного администрирования».
Перейти к курсу