open atlas
↑ К треку
Linux: операционная система LIN · 10 · 01

journald и journalctl

journald — структурированное бинарное хранилище логов systemd. journalctl запрашивает его по юниту (-u), приоритету (-p), загрузке (-b) и отслеживает вживую с -f. Поля _SYSTEMD_UNIT, PRIORITY и _PID делают фильтрацию точной — как текстовые логи никогда не позволяли.

LIN Junior ◷ 20 min
Уровень
ОсновыJuniorMiddleSenior

Сервис упал. Ты запускаешь systemctl status nginx и видишь четыре строки, заканчивающиеся «failed.» Этого недостаточно — нужны 30 секунд до падения. На системе с текстовыми логами ты бы сделал tail -f /var/log/nginx/error.log и надеялся, что приложение что-то записало. На современном Linux-сервере эти логи находятся в journald — бинарном структурированном индексированном хранилище, которое пишет каждый байт от каждого systemd-юнита с момента загрузки. journalctl — инструмент запросов, и когда знаешь четыре флага, можно вытащить именно нужное окно — отфильтрованное по юниту, приоритету или времени — за десять секунд.

Цель

После этого урока ты сможешь запрашивать systemd journal через journalctl, фильтровать по сервисному юниту (-u), приоритету (-p) и загрузке (-b), отслеживать вывод вживую (-f) и понимать, что такое структурированные поля _SYSTEMD_UNIT, PRIORITY и _PID и почему они важны.

1

journald захватывает всё, что пишут systemd-юниты в stdout/stderr.

Когда сервис запускается под systemd, stdout и stderr юнита передаются напрямую в journald. Не нужно настраивать путь лог-файла — журнал формируется автоматически.

# Показать последние 50 строк всего журнала (новые внизу):
journalctl -n 50

# Показать логи конкретного юнита (самый важный флаг):
journalctl -u nginx.service

# Логи юнита только с текущей загрузки:
journalctl -u nginx.service -b

# Комбинированно: последние 100 строк nginx, текущая загрузка:
journalctl -u nginx.service -b -n 100

Флаг -u — рабочая лошадка. Без него получаешь весь системный журнал — сотни строк в секунду на нагруженном сервере. С ним — ровно один сервис.

2

Фильтрация по приоритету для снижения шума.

journald отображает уровни серьёзности syslog на числа 0–7. -p фильтрует до этого уровня и выше (меньшее число = более серьёзный).

# Уровни приоритета (число = серьёзность syslog):
# 0 emerg   1 alert   2 crit   3 err
# 4 warning  5 notice  6 info  7 debug

# Только ошибки и хуже для nginx с последней загрузки:
journalctl -u nginx.service -b -p err

# Предупреждения и хуже, все юниты:
journalctl -b -p warning

# Всё включая debug (очень подробно):
journalctl -u myapp.service -p debug

# Диапазон (например, от warning до err):
journalctl -u myapp.service -p warning..err

На практике -p err — первое, что запускаешь при сбое сервиса. Убирает шум info и notice, оставляя только произошедшее.

3

Временные фильтры: --since и --until.

Граница загрузки (-b) удобна, но иногда нужно конкретное окно — например, 5 минут до срабатывания алерта.

# С конкретного времени:
journalctl -u postgres.service --since "2024-03-15 14:00:00"

# Временной диапазон:
journalctl -u postgres.service \
  --since "2024-03-15 14:00:00" \
  --until "2024-03-15 14:10:00"

# Относительное время (последние 30 минут):
journalctl -u postgres.service --since "30 min ago"

# Смещения загрузок: -b 0 = текущая, -b -1 = предыдущая, -b -2 = две назад:
journalctl -u postgres.service -b -1

# Список доступных загрузок:
journalctl --list-boots

--list-boots недооценён. Показывает каждую запись загрузки с индексом — после краша и перезагрузки можно заглянуть в -b -1 и прочитать последние моменты предыдущей сессии.

4

Отслеживание вживую с -f.

-f следит за журналом в реальном времени — как tail -f, но для структурированных логов.

# Следить за всеми новыми записями:
journalctl -f

# Следить только за конкретным юнитом (то, что реально нужно):
journalctl -u nginx.service -f

# Следить + фильтр приоритета (только ошибки):
journalctl -u myapp.service -f -p err

# Комбинированно: ошибки от двух юнитов одновременно:
journalctl -u nginx.service -u php-fpm.service -f -p err

-f можно комбинировать со всеми флагами. -f -p err во время деплоя даёт живой поток только фатальных событий без шума.

5

Структурированные поля: чем journald отличается от текстовых логов.

Каждая запись журнала — это набор ключ-значение, а не строка текста. Бинарный формат хранит типизированные поля вместе с сообщением. Можно запрашивать по любому полю.

# Подробный вывод со всеми полями юнита:
journalctl -u nginx.service -o verbose | head -40
# В выводе:
#   _SYSTEMD_UNIT=nginx.service
#   PRIORITY=3
#   _PID=1234
#   _UID=0
#   _COMM=nginx
#   MESSAGE=connect() failed (111: Connection refused)...

# Запрос по конкретному значению поля (например, только от PID 1234):
journalctl _PID=1234

# Все записи от пользователя www-data:
journalctl _UID=33

# Несколько фильтров по полям (AND):
journalctl _SYSTEMD_UNIT=nginx.service _PID=1234

# Форматы вывода: short (по умолчанию), json, cat (только MESSAGE):
journalctl -u nginx.service -b -p err -o json | head -5
journalctl -u nginx.service -b -o cat

Ключевые структурированные поля: _SYSTEMD_UNIT (какой юнит), PRIORITY (0–7), _PID (ID процесса), _UID (ID пользователя), _COMM (имя команды), MESSAGE (сама строка лога). Фильтрация по _PID — то, что буквально невозможно сделать через grep в смешанном лог-файле.

Разбор примера

Поиск причины сбоя nginx после изменения конфига.

Ты отредактировал /etc/nginx/sites-enabled/myapp.conf и перезагрузил nginx. Теперь он в состоянии failed.

# Шаг 1: проверить статус для краткого снипета
systemctl status nginx.service
# ● nginx.service - A high performance web server
#    Active: failed (Result: exit-code)
#  Main PID: 5821 (code=exited, status=1/FAILURE)
#    ...последние 10 строк журнала...

# Шаг 2: получить полную картину из journald — текущая загрузка, только ошибки
journalctl -u nginx.service -b -p err
# Mar 15 15:32:11 host nginx[5821]: nginx: [emerg] unknown directive "proxy_cache_pat"
# Mar 15 15:32:11 host nginx[5821]: nginx: configuration file test failed

# Найдена опечатка: "proxy_cache_pat" вместо "proxy_cache_path"

# Шаг 3: проверить info-уровень для полного вывода теста конфига:
journalctl -u nginx.service -b -p info -n 30
# Mar 15 15:32:11 host nginx[5821]: nginx: [emerg] unknown directive "proxy_cache_pat"
# Mar 15 15:32:11 host nginx[5821]:   /etc/nginx/sites-enabled/myapp.conf:8
# Показан файл и строка — точное местоположение

# Шаг 4: исправить и перезапустить, затем следить для подтверждения чистого старта:
# (отредактировать конфиг, затем:)
sudo systemctl restart nginx && journalctl -u nginx.service -f -n 5
# Mar 15 15:35:02 host nginx[5890]: start worker processes
# Mar 15 15:35:02 host systemd[1]: Started A high performance web server.
Почему это работает

Почему бинарный + структурированный лучше текстового. Текстовые лог-файлы требуют знать, куда пишет приложение, парсить временные метки через grep и надеяться на единообразный формат. journald хранит каждую запись с гарантированными типизированными полями (_PID, _UID, _SYSTEMD_UNIT, PRIORITY) независимо от того, что пишет приложение в сообщении. Можно фильтровать по любому полю без grep. Бинарный формат также обеспечивает быстрый индексированный поиск — --since "5 min ago" — это бинарный поиск, а не полное сканирование файла. Компромисс: нельзя cat журнал, нужен journalctl или journal API для чтения.

Частая ошибка

На macOS нет journald. macOS использует Unified Logging (log show, log stream, log collect). log show --predicate 'process == "nginx"' --last 5m — грубый аналог journalctl -u nginx -p err --since "5 min ago". Концепции (структурированные поля, бинарное хранилище, индексированные запросы) переносятся напрямую, но команды полностью разные. Не жди journalctl на macOS — его там нет.

Проверь себя
Викторина

Нужно видеть только сообщения уровня error и выше от сервиса sshd с последней перезагрузки и отслеживать их вживую по мере появления. Какой вызов journalctl верный?

Итог

journald — структурированное бинарное хранилище логов systemd. stdout/stderr каждого systemd-юнита захватывается автоматически — без настройки пути лог-файла. journalctl -u <unit> фильтрует по одному сервису. -b ограничивает текущей загрузкой; -b -1 — предыдущей (полезно после краша и перезагрузки). -p err показывает только ошибки и хуже, срезая шум. -f следит вживую. -o verbose открывает типизированные структурированные поля: _SYSTEMD_UNIT, PRIORITY, _PID, _UID, MESSAGE — они позволяют точную фильтрацию, невозможную через grep в текстовых логах. Бинарный формат — причина, по которой нельзя cat журнал, и причина, по которой --since — это быстрый индексированный поиск, а не сканирование файла.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 4 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

Примени это

Примени этот урок в реальном проекте.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources1
expand
  1. 01

Trademarks belong to their respective owners. Editorial reference only.