journalctl: шпаргалка по логам systemd на Ubuntu
Все логи сервера на Ubuntu собирает systemd-journald, и достать из них нужное — задача одной команды с правильными фильтрами. Собрали рабочую шпаргалку: логи конкретного сервиса, за период, по уровню ошибки, с предыдущей загрузки, а также настройку размера журнала, чтобы он не съел диск.
На современной Ubuntu логи почти всех сервисов лежат не в текстовых файлах, а в бинарном журнале systemd. Это меняет привычки: вместо tail -f /var/log/... и grep работает journalctl с фильтрами. Ниже — набор команд, который закрывает подавляющее большинство задач диагностики.
Что такое journald
systemd-journald — служба, которая собирает сообщения от ядра, initrd, стандартных потоков всех сервисов и от syslog в единый индексированный журнал. Каждая запись хранится со структурированными полями: юнит, PID, UID, приоритет, время, идентификатор загрузки.
Отсюда главное отличие от текстовых логов: фильтровать нужно не grep-ом по строкам, а по полям — быстрее и точнее.
Часть сервисов по-прежнему пишет и в /var/log: nginx ведёт свои access.log и error.log, PostgreSQL — свой лог. А вот systemd-юниты, у которых вывод идёт в stdout, попадают именно в журнал.
Проверить, работает ли журнал и сколько занимает:
systemctl status systemd-journald
journalctl --disk-usage
Базовый просмотр
journalctl # весь журнал с начала, в пейджере
journalctl -e # сразу перейти в конец
journalctl -r # в обратном порядке, новые сверху
journalctl -n 50 # последние 50 строк
journalctl -f # следить в реальном времени, как tail -f
journalctl --no-pager # без пейджера, удобно для скриптов
Комбинация -f с фильтром по сервису — самая частая команда при отладке:
journalctl -u nginx -f
Логи конкретного сервиса
journalctl -u nginx # весь журнал юнита
journalctl -u nginx -n 100 --no-pager # последние 100 строк
journalctl -u nginx --since today # за сегодня
journalctl -u nginx -u php8.3-fpm # сразу два юнита
journalctl -u 'nginx*' # по шаблону
Суффикс .service можно опускать. Для таймеров и сокетов он обязателен: journalctl -u certbot.timer.
Посмотреть, какие юниты вообще писали в журнал:
journalctl --field _SYSTEMD_UNIT | sort | head -50
Про сами юниты и управление ими — в статье про systemd и systemctl enable.
Фильтр по времени
journalctl --since "2026-08-12 09:00" --until "2026-08-12 10:30"
journalctl --since today
journalctl --since yesterday
journalctl --since "1 hour ago"
journalctl --since "30 min ago"
journalctl --since "2 days ago" --until "1 day ago"
Формат времени понимает и абсолютные значения (ГГГГ-ММ-ДД ЧЧ:ММ:СС), и относительные фразы на английском. Это, пожалуй, самый полезный фильтр: инцидент почти всегда привязан ко времени.
Связка «сервис плюс период» отвечает на вопрос «что происходило перед падением»:
journalctl -u myapp --since "2026-08-12 03:00" --until "2026-08-12 03:15"
Фильтр по уровню важности
journalctl -p err # только ошибки и хуже
journalctl -p warning # предупреждения и хуже
journalctl -p err..alert # диапазон
journalctl -p err -b # ошибки с текущей загрузки
Уровни соответствуют syslog:
| Код | Имя | Смысл |
|---|---|---|
| 0 | emerg | Система неработоспособна |
| 1 | alert | Требуется немедленное вмешательство |
| 2 | crit | Критическая ошибка |
| 3 | err | Ошибка |
| 4 | warning | Предупреждение |
| 5 | notice | Заметное, но нормальное событие |
| 6 | info | Информационное сообщение |
| 7 | debug | Отладка |
Указание уровня всегда включает все, что выше по важности: -p warning покажет и err, и crit.
Первая команда при разборе «что не так с сервером»:
journalctl -p err -b --no-pager
Логи загрузки и ядра
journalctl -b # с текущей загрузки
journalctl -b -1 # с предыдущей
journalctl -b -2 # с позапрошлой
journalctl --list-boots # список всех загрузок с датами
journalctl -k # только сообщения ядра (аналог dmesg)
journalctl -k -b -1 # сообщения ядра с прошлой загрузки
journalctl -b -1 -p err — то, с чего начинают разбор внезапной перезагрузки: показывает ошибки, записанные до того, как сервер ушёл в ребут.
Если --list-boots показывает только текущую загрузку, значит журнал не сохраняется между перезагрузками — как это исправить, ниже.
Поиск по тексту
Встроенный поиск по регулярному выражению:
journalctl -g "connection refused"
journalctl -u nginx -g "50[0-9]" --since today
journalctl -g "timeout" --case-sensitive=false
Флаг -g (--grep) работает быстрее внешнего grep, потому что фильтрация идёт на уровне журнала. Классический конвейер тоже никто не отменял — например, чтобы посчитать частоту:
journalctl -u myapp --since today --no-pager \
| grep -oE 'code=[0-9]+' | sort | uniq -c | sort -rn
Разбор таких конвейеров — в статьях про grep и awk.
Фильтр по процессу и пользователю
journalctl _PID=1234
journalctl _UID=1000
journalctl _COMM=sshd # по имени исполняемого файла
journalctl /usr/sbin/sshd # то же, но путём
journalctl --user-unit=myapp # пользовательский юнит
journalctl _SYSTEMD_UNIT=ssh.service _PID=987 # несколько полей = И
Список доступных полей у конкретной записи показывает подробный формат:
journalctl -u ssh -n 1 -o verbose
Оттуда удобно брать точные имена полей для последующей фильтрации.
Форматы вывода
journalctl -u nginx -o short-iso # время в ISO-8601, удобно для отчётов
journalctl -u nginx -o cat # только текст сообщения, без метаданных
journalctl -u nginx -o json-pretty # структура со всеми полями
journalctl -u nginx -o verbose # все поля в читаемом виде
journalctl -u nginx -o short-precise # время с микросекундами
Формат cat удобен, когда нужно скормить лог другой утилите, а json — для машинной обработки:
journalctl -u myapp --since today -o json --no-pager \
| jq -r 'select(.PRIORITY <= "3") | .MESSAGE'
Отключить сокращение длинных строк:
journalctl -u myapp --no-hostname -a
Размер журнала и очистка
Журнал не растёт бесконечно, но настройки по умолчанию щедрые: до 10% от размера раздела /var.
journalctl --disk-usage
Ручная очистка:
sudo journalctl --vacuum-size=500M # оставить не больше 500 МБ
sudo journalctl --vacuum-time=14d # оставить только за 14 дней
sudo journalctl --vacuum-files=5 # оставить 5 файлов журнала
Постоянные лимиты задаются в /etc/systemd/journald.conf:
[Journal]
Storage=persistent
SystemMaxUse=1G
SystemMaxFileSize=100M
MaxRetentionSec=1month
sudo systemctl restart systemd-journald
SystemMaxUse — общий потолок, MaxRetentionSec — предельный возраст записей. Ставить оба разумно: первый защищает диск, второй ограничивает глубину истории.
Если место на разделе кончилось внезапно, проверьте журнал в первую очередь — вместе с du -sh /var/log/journal. Про случай, когда место не освобождается после удаления файлов, написано в статье про удаление файлов и каталогов, а посмотреть разделы поможет lsblk.
Журнал не сохраняется после перезагрузки
Если journalctl -b -1 отвечает Specified boot ID does not exist, журнал хранится только в памяти и очищается при каждой перезагрузке. На сервере это неприемлемо — именно логи до ребута обычно и нужны.
Проверяем настройку:
grep -E "^#?Storage" /etc/systemd/journald.conf
ls -ld /var/log/journal
Значение Storage=auto (по умолчанию) означает: хранить на диске, если существует каталог /var/log/journal, иначе — только в памяти. В штатной установке Ubuntu каталог есть, но в контейнерах и на урезанных образах его часто нет.
Включаем постоянное хранение:
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
journalctl --list-boots
После этого в списке начнут накапливаться загрузки.
Практические рецепты
Всё, что сломалось с момента загрузки:
journalctl -p err -b --no-pager
Почему упал сервис:
journalctl -u myapp -n 100 --no-pager
systemctl status myapp
Кто и когда перезагрузил сервер:
journalctl -u systemd-logind --since "1 day ago" | grep -i "power\|reboot"
last -x | head -20
Сработал ли OOM killer:
journalctl -k --since "1 day ago" -g "Out of memory|oom_kill"
Неудачные попытки входа по SSH:
journalctl -u ssh --since today -g "Failed password" --no-pager | tail -30
Если таких строк много, значит сервер перебирают — как это лечится, разобрано в статье про fail2ban.
Что делал cron прошлой ночью:
journalctl -u cron --since "yesterday 23:00" --until "today 06:00"
Логи 404-х у своего приложения:
journalctl -u myapp --since "7 days ago" --no-pager \
| grep -oE 'GET [^ ]+ responded 404' | awk '{print $2}' \
| sort | uniq -c | sort -rn | head -20
Экспорт для передачи коллеге:
journalctl -u myapp --since "2026-08-12" --no-pager -o short-iso > myapp.log
Шпаргалка
journalctl -u nginx -f следить за сервисом
journalctl -u nginx -n 100 последние 100 строк
journalctl -p err -b ошибки с текущей загрузки
journalctl --since "1 hour ago" за последний час
journalctl -b -1 с предыдущей загрузки
journalctl -k сообщения ядра
journalctl -g "текст" поиск по регулярке
journalctl -o cat только сообщения, без метаданных
journalctl --disk-usage размер журнала
sudo journalctl --vacuum-time=14d почистить старше 14 дней
Частые вопросы
Где хранятся логи systemd в Ubuntu?
В бинарных файлах каталога /var/log/journal/<machine-id>/, если включено постоянное хранение, либо в /run/log/journal/ — тогда журнал живёт только до перезагрузки.
Читать эти файлы напрямую нельзя, для доступа используется journalctl. Часть сервисов дополнительно ведёт собственные текстовые логи в /var/log.
Как посмотреть логи конкретного сервиса?
journalctl -u имя_сервиса. Например, journalctl -u nginx -n 100 --no-pager покажет последние сто строк без пейджера, а journalctl -u nginx -f будет следить за новыми записями.
Суффикс .service можно опускать, но для таймеров и сокетов его нужно указывать явно.
Как очистить журнал, если он занял всё место?
sudo journalctl --vacuum-size=500M оставит не больше 500 МБ, sudo journalctl --vacuum-time=7d — только записи за последнюю неделю.
Чтобы ситуация не повторилась, задайте SystemMaxUse в /etc/systemd/journald.conf и перезапустите systemd-journald.
Почему journalctl -b -1 пишет, что загрузки не существует?
Журнал хранится в памяти и стирается при перезагрузке. Так бывает, когда отсутствует каталог /var/log/journal — при Storage=auto это переключает journald в режим временного хранения.
Создайте каталог, выполните sudo systemd-tmpfiles --create --prefix /var/log/journal и перезапустите службу — после этого история загрузок начнёт сохраняться.
Чем journalctl -k отличается от dmesg?
Оба показывают сообщения ядра, но dmesg читает кольцевой буфер ядра, который очищается при перезагрузке и перезаписывается по кругу. journalctl -k берёт те же сообщения из журнала, поэтому умеет показывать их за прошлые загрузки (journalctl -k -b -1) и фильтровать по времени.
Для разбора инцидента, который случился вчера, подходит только journalctl.
Что запомнить
journalctl -u сервис -f— постоянная команда при отладке;-n 100 --no-pager— быстрый взгляд на последние строки.- Фильтры комбинируются и работают как «И»:
journalctl -u nginx -p err --since today. -b -1показывает логи предыдущей загрузки — с этого начинается разбор внезапной перезагрузки.- Журнал занимает до 10% от
/varпо умолчанию: задайтеSystemMaxUseвjournald.conf, чтобы не упереться в диск. - Нет каталога
/var/log/journal— журнал живёт только в памяти и исчезает при перезагрузке.