Learning Platform
Глоссарий Troubleshooting
Урок 16.03 · 22 мин
Начальный
journalctljournaldlogsloggingdebugging
Мониторинг через /proc — метрики ядра под journald

Зачем единый журнал

До systemd каждый сервис писал логи по-своему: nginx в /var/log/nginx/access.log, postgres в /var/log/postgresql/postgresql-16-main.log, ssh в /var/log/auth.log через syslog, своё приложение — куда придумал автор. Чтобы понять «что произошло на сервере за последний час», нужно было tail десяток файлов с разным форматом.

systemd-journald решает это, собирая логи всех units (и не только) в structured journal с metadata. Команда journalctl — это твоё окно в этот журнал.

Структурированность важна: каждая запись имеет fields (UNIT=nginx.service, _PID=12347, PRIORITY=3, _UID=33, MESSAGE=...). Это позволяет фильтровать «все ошибки от nginx с PID 12347 между 14:00 и 14:15» одной командой.

journalctl без аргументов: «весь журнал»

$ journalctl
-- Logs begin at Mon 2026-05-12 03:00:00 UTC, end at Wed 2026-05-13 11:45:31 UTC. --
May 12 03:00:01 prod-vm systemd[1]: Started Daily apt download.
May 12 03:00:01 prod-vm CRON[12345]: pam_unix(cron:session): session opened for user root
May 12 03:00:02 prod-vm postfix/master[12347]: starting Postfix mail system
...

По умолчанию open pager (less). Выход — q. Внутри: / поиск, g/G начало/конец, n/N next match.

Без sudo ты увидишь логи своего user и общие. С sudo — логи всех users и системных units (в большинстве случаев). Точные права зависят от группы systemd-journal — если ты в ней, читаешь всё без sudo.

$ groups
levo sudo docker systemd-journal

$ journalctl   # читает всё без sudo

journalctl -u SERVICE: один сервис

Самая частая команда:

$ journalctl -u nginx
May 13 08:42:11 prod-vm systemd[1]: Starting nginx.service - A high performance web server...
May 13 08:42:11 prod-vm nginx[12346]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
May 13 08:42:11 prod-vm nginx[12346]: nginx: configuration file /etc/nginx/nginx.conf test is successful
May 13 08:42:11 prod-vm systemd[1]: Started nginx.service - A high performance web server...

Все логи только от nginx.service. Можно несколько unit-ов через несколько -u:

$ journalctl -u airflow-scheduler -u airflow-celery-worker

Это даст merged-feed обоих сервисов — полезно для дебага, когда ошибка касается нескольких компонентов.

-n N: last N lines

$ journalctl -u nginx -n 50

Последние 50 строк. По умолчанию -n без числа = 10. Аналог tail -n.

-f: follow live

$ journalctl -u nginx -f

Стримит логи в реальном времени, как tail -f. Останов: Ctrl+C. Можно совместить с -u, -p, и т.д.

Самый частый workflow дебага:

# Терминал 1: live-tail
$ journalctl -u my-etl -f

# Терминал 2: запустить ETL и смотреть в первом терминале как идёт
$ sudo systemctl restart my-etl

—since и —until: по времени

$ journalctl -u nginx --since today
$ journalctl -u nginx --since "1 hour ago"
$ journalctl -u nginx --since "2026-05-13 09:00"
$ journalctl -u nginx --since "2026-05-13 09:00" --until "2026-05-13 10:00"
$ journalctl -u nginx --since yesterday --until "yesterday 23:59"

Форматы времени:

  • today, yesterday, now — относительно.
  • "1 hour ago", "30 min ago", "2 days ago" — relative.
  • "YYYY-MM-DD" — конкретная дата (всё за этот день).
  • "YYYY-MM-DD HH:MM:SS" — момент.
# Что было между деплоем и падением:
$ journalctl --since "2026-05-13 09:30:00" --until "2026-05-13 09:45:00"

-p priority: severity filter

systemd использует syslog-уровни:

0 emerg     — система не работает
1 alert     — требуется немедленное действие
2 crit      — критическая ошибка
3 err       — ошибки
4 warning   — предупреждения
5 notice    — нормальные, но значимые
6 info      — общая информация
7 debug     — отладочный шум
# Только error и хуже (priority <= 3):
$ journalctl -u airflow-scheduler -p err

# Между err и emerg (включая):
$ journalctl -p err..emerg

# Только warning (одна priority):
$ journalctl -p warning..warning

Это сильно сокращает шум. На production «дай мне все error за сегодня»:

$ journalctl --since today -p err

—grep PATTERN: regex по сообщениям

$ journalctl -u airflow-scheduler --grep "ModuleNotFoundError"
$ journalctl --grep -i "timeout"   # -i = case-insensitive

Regex компилируется в journalctl напрямую — быстрее, чем journalctl ... | grep ..., потому что фильтрация идёт на уровне журнала, без полного materializа.

-k: kernel messages

$ journalctl -k
$ journalctl -k --since today

Эквивалент dmesg. Hardware errors, OOM killer, network device up/down, кернел-warnings.

Если у тебя процесс был убит OOM-killer:

$ journalctl -k | grep -i 'killed process'
May 13 09:14:33 prod-vm kernel: Out of memory: Killed process 5432 (airflow), UID 1001, total-vm:8128MB

—output: формат вывода

# Default: short
$ journalctl -u nginx -n 1
May 13 08:42:11 prod-vm systemd[1]: Started nginx.service.

# Verbose: все fields структуры
$ journalctl -u nginx -n 1 -o verbose
Wed 2026-05-13 08:42:11.234567 UTC [s=abc123;i=4567;b=def...]
    _BOOT_ID=...
    _MACHINE_ID=...
    _HOSTNAME=prod-vm
    _SYSTEMD_UNIT=nginx.service
    _PID=1
    _UID=0
    _GID=0
    MESSAGE=Started nginx.service.
    SYSLOG_IDENTIFIER=systemd
    SYSLOG_FACILITY=3
    PRIORITY=6

# JSON: для парсинга в jq / Python
$ journalctl -u nginx -n 1 -o json | jq
{
  "_BOOT_ID": "...",
  "_HOSTNAME": "prod-vm",
  "_SYSTEMD_UNIT": "nginx.service",
  "MESSAGE": "Started nginx.service.",
  "PRIORITY": "6",
  ...
}

# JSON-pretty:
$ journalctl -u nginx -n 5 -o json-pretty

# Cat — только MESSAGE без metadata:
$ journalctl -u nginx -n 5 -o cat
Started nginx.service.
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
...

JSON-output — основа для интеграции journal с внешними мониторингами (Loki, Datadog).

Где живут журналы

$ ls /var/log/journal
4e3a1234567890abcdef.../

Каждая папка — machine-id. Внутри — бинарные .journal файлы. Размер обычно 50-200 МБ каждый, новые создаются по rotation policy.

Если /var/log/journal/ нет — журнал volatile (только в /run/log/journal/), теряется при reboot. Это типичная ситуация на минимальных Docker-образах. Чтобы сделать persistent:

$ sudo mkdir -p /var/log/journal
$ sudo systemd-tmpfiles --create --prefix /var/log/journal
$ sudo systemctl restart systemd-journald

Cleanup: —vacuum

Journal без retention может разрастись до десятков ГБ. Команды очистки:

# Сколько занимает:
$ journalctl --disk-usage
Archived and active journals take up 14.3G in the file system.

# Удалить старше 7 дней:
$ sudo journalctl --vacuum-time=7d

# Оставить не больше 2 ГБ:
$ sudo journalctl --vacuum-size=2G

# Оставить максимум 50 файлов:
$ sudo journalctl --vacuum-files=50

Постоянная политика — в /etc/systemd/journald.conf:

[Journal]
Storage=persistent
Compress=yes
SystemMaxUse=2G
SystemMaxFileSize=128M
MaxRetentionSec=2week

После правки:

$ sudo systemctl restart systemd-journald
journald retention опции

Лимиты можно ставить независимо. journald применит самый строгий из активных.

SystemMaxUse=2Gобщий лимит
SystemMaxFileSize=128Mразмер одного файла
MaxRetentionSec=2weekмакс возраст
Compress=yeszstd сжатие
ForwardToSyslog=yesпараллельно в /var/log/syslog

/var/log/syslog vs journal

На Debian/Ubuntu обычно установлен rsyslog, и journald forwards в него. Так получается, что одни и те же сообщения попадают и в structured journal, и в текстовый /var/log/syslog.

$ ls /var/log/
auth.log     daemon.log    journal/    nginx/      syslog

Старые log-shippers (logrotate, fluent-bit для текстовых логов, custom grep-скрипты) работают с /var/log/syslog. Современные читают journald напрямую (через journalctl --output=json --follow или libsystemd API).

Для DE: на современных дистрибутивах читай journal, на legacy CentOS 6/7 или минимальных Docker-образах — /var/log/syslog или /var/log/messages (RHEL-семейство). Команда tail -f /var/log/syslog всё ещё работает на 99% систем.

DE-сценарий: «расследуй, почему упал DAG»

Реальная отладочная сессия:

# 1) Symptom: alert от Airflow — DAG failed at 06:42 UTC.

# 2) Что было с airflow-scheduler в этот момент:
$ journalctl -u airflow-scheduler --since "2026-05-13 06:30" --until "2026-05-13 06:50"

# 3) Видим Python traceback и database-error. Что было с postgresql?
$ journalctl -u postgresql --since "2026-05-13 06:30" --until "2026-05-13 06:50"

# 4) Postgres логи: 'connection refused'. Был ли он жив?
$ journalctl -u postgresql -p err --since today

# 5) Видим: OOM-killer убил postgres. Подтверждаем в kernel-journal:
$ journalctl -k --since "2026-05-13 06:40" --until "2026-05-13 06:45" | grep -i kill

# May 13 06:42:18 prod-vm kernel: Out of memory: Killed process 8888 (postgres)
# May 13 06:42:18 prod-vm kernel:   memory.max=4G, memory.current=4G

# 6) Память исчерпана — потому что? Смотрим что съело RAM:
$ journalctl -k --since "2026-05-13 06:30" --until "2026-05-13 06:45" | grep -i 'memory'

# 7) Находим: spark-job писал в shared memory без лимитов.
# Решение: добавить MemoryMax= в spark.service unit-файл.

Без структурированного journal такой workflow занял бы час. С journalctl — 5 минут.

Когда journal не помогает

journald — для системных и сервисных логов. Не предназначен:

  • Application logs с массой данных (Apache access.log, Spark app logs). Эти приложения пишут в свои файлы — journald был бы слишком тяжёлым.
  • Audit logs с строгими требованиями (HIPAA, PCI). Для этого auditd с /var/log/audit/.
  • Network packet capture (tcpdump, wireshark). Это не текст.

Для каждого случая — свой инструмент. journal хорош для «что делает мой systemd-сервис прямо сейчас».

Полезный one-liner: топ failed-services с логами

# Какие сервисы упали и почему — одной командой:
$ systemctl --failed --no-legend | awk '{print $1}' | while read svc; do
    echo "=== $svc ==="
    journalctl -u "$svc" -n 5 -p err --no-pager
  done

Полезно при разборе утреннего alert-а: «что упало за ночь?».

Попробуй сам

  1. Последние 50 строк journal:
    journalctl -n 50
  2. Только error за сегодня:
    journalctl -p err --since today
  3. Logs ssh за час:
    journalctl -u ssh --since "1 hour ago"
  4. Сколько диска занимает journal:
    journalctl --disk-usage
  5. Live-tail systemd:
    journalctl -f
  6. Kernel за сегодня:
    journalctl -k --since today

macOS-различия

  • На macOS нет systemd -> нет journalctl. Логи через Apple Unified Logging: log show --predicate 'subsystem == "com.apple.something"' --last 1h, log stream.
  • Для Docker Desktop логи контейнеров — docker logs CONTAINER или colima logs (для colima). Внутри Linux VM — обычный journalctl, как на native Linux.

Главное

  • journalctl — единый журнал systemd. Structured (fields, metadata), фильтруемый.
  • journalctl -u SVC — логи одного сервиса. Самая частая команда.
  • -n N — последние N строк. -f — follow (live). -p err — только error+.
  • --since "1 hour ago" / --until — временной фильтр. Форматы: today, yesterday, “X ago”, “YYYY-MM-DD HH:MM”.
  • --grep PATTERN — regex по сообщениям.
  • -k — kernel messages (эквивалент dmesg). Полезно для OOM, hardware errors.
  • -o json — для парсинга в jq / Python. Основа интеграции с monitoring.
  • Persistent journal в /var/log/journal/. Если нет — volatile (/run/log/journal), теряется при reboot.
  • Cleanup: journalctl --vacuum-time=7d или --vacuum-size=2G. Постоянная политика в /etc/systemd/journald.conf.
  • /var/log/syslog (или /var/log/messages на RHEL) — параллельный текстовый log через rsyslog. Для legacy log-shippers.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. DAG упал в 06:42. Как посмотреть логи Airflow scheduler именно за этот период?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4