Логи systemd через journalctl: где искать причину

Рейтинг: 67.6% · 8 голосов
Подробный курс по диагностике и производительности Linux для админов и DevOps: с чего начать, методология USE, логи (journalctl, dmesg), процессы, CPU, память и OOM, диск и IO (iostat), сеть (ss, tcpdump), системные вызовы и strace, ltrace, perf, флеймграфы, ftrace, eBPF и bpftrace, lsof, мониторинг. Разбор каждого инструмента с чтением вывода.
Ответить
Аватара пользователя
Dmitry_SRE
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Логи systemd через journalctl: где искать причину

Сообщение Dmitry_SRE »

Оглавление курса (47)
  1. С чего начать диагностику Linux: методология вместо паники
  2. Первые 60 секунд: экспресс-диагностика нагруженного сервера
  3. Методологии диагностики: USE, RED и здравый смысл
  4. Логи systemd через journalctl: где искать причину (вы здесь)
  5. Где лежат логи Linux: /var/log, dmesg и rsyslog
  6. Источники правды: load average, /proc и /sys
  7. Процессы Linux: ps, pstree и состояния процессов
  8. Интерактивный мониторинг: top и htop
  9. Метрики процессов во времени: pidstat
  10. Приоритеты и ограничения: nice, ionice, cgroups
  11. Сигналы и зависшие процессы: kill, и что делать с D-state
  12. Загрузка CPU: user, system, iowait, steal и контекст-свитчи
  13. Диагностика CPU по ядрам: vmstat и mpstat
  14. Профилирование CPU: perf top и поиск пожирателя
  15. Частоты, троттлинг и NUMA: turbostat и numastat
  16. Память Linux: RSS, VSZ, page cache и миф о нехватке памяти
  17. Сколько памяти занято: free, /proc/meminfo и vmstat
  18. Поиск утечек и пожирателей памяти: smem, pmap, smaps
  19. Swap и подкачка: swapon, swappiness, когда своп - это боль
  20. OOM killer: кто и за что убил процесс
  21. Память ядра и slab: slabtop и куда уходит RAM
  22. Подсистема ввода-вывода: путь запроса от приложения до диска
  23. Диагностика диска: iostat и чтение await, %util
  24. Кто грузит диск: iotop и атрибуция io процессам
  25. Файловые системы: df, du, иноды и куда делось место
  26. Глубокая диагностика блочного слоя: blktrace и biolatency
  27. Кеш страниц и грязные данные: dirty pages, fsync, drop_caches
  28. Сетевой стек Linux: путь пакета и где возникают задержки
  29. Сокеты и соединения: ss и netstat
  30. Захват трафика: tcpdump для диагностики сети
  31. Задержки и потери в сети: ping, mtr, диагностика латентности
  32. Сеть как источник проблем: nftables, conntrack, дропы
  33. Что такое системный вызов и зачем его трассировать
  34. strace: трассировка системных вызовов на практике
  35. strace в бою: почему программа висит, падает или тормозит
  36. ltrace: трассировка вызовов библиотек
  37. Накладные расходы трассировки и безопасные альтернативы
  38. perf: универсальный профайлер Linux
  39. Флеймграфы: визуализация профиля производительности
  40. Трассировка ядра: ftrace и trace-cmd
  41. eBPF: революция в наблюдаемости Linux
  42. Инструменты eBPF на практике: BCC и bpftrace
  43. lsof: открытые файлы, дескрипторы, кто держит файл и порт
  44. Разбор кейса: приложение тормозит - пошаговая диагностика
  45. Непрерывный мониторинг: sar, node_exporter, Grafana, Zabbix
  46. Диагностика в контейнерах: cgroups, лимиты, Docker и Kubernetes
  47. Карта инструментов и сквозной разбор инцидента производительности
Сервис упал, сайт отдает 502, или машина после ребута ведет себя странно - и первый вопрос новичка обычно один и тот же: а где вообще логи в Linux, куда смотреть? Раньше ответ был "лезь в /var/log и читай текстовые файлы". На современном Linux с systemd главный вход в логи - это journalctl, утилита для чтения журнала systemd. Это не еще одна экзотика, это инструмент номер один: запрос "journalctl" - один из самых частых среди админов, и не зря. Освоишь его - и в большинстве случаев найдешь причину проблемы за пару минут, не открывая десяток файлов вручную.

В этом уроке разберем journalctl с нуля и до боевого применения: как просто посмотреть логи Linux, как фильтровать по сервису, по времени и по ошибкам, как читать вывод и понимать, что в нем норма, а что тревога, как раскрутить причину сбоя по цепочке. В конце - шпаргалка частых команд, мини-лаба и контрольные вопросы. Все актуально на 2026 год: systemd сейчас стоит почти везде (systemd 256/257 в свежих дистрибутивах), и на отечественных Astra Linux и RED OS под капотом тот же systemd-journald.

Что такое журнал systemd и чем он отличается от обычных логов linux

В классической схеме каждый демон писал свой текстовый файл: /var/log/syslog, /var/log/auth.log, /var/log/nginx/error.log и так далее. Это работает, но неудобно: чтобы соединить события по времени из разных файлов, приходится прыгать туда-сюда и руками сводить таймстемпы.

Systemd собирает все в один структурированный двоичный журнал. Демон systemd-journald ловит сообщения от ядра, от сервисов (их stdout/stderr), от системного лога (syslog), от библиотеки журналирования и складывает их вместе с метаданными. И это ключевое отличие: каждая запись - это не строка текста, а набор полей "ключ=значение". Кроме самого сообщения MESSAGE там лежат PRIORITY (уровень важности), _SYSTEMD_UNIT (какой юнит написал), _PID, _UID, _COMM (имя бинарника), _HOSTNAME, _BOOT_ID (идентификатор загрузки) и десятки других. Полный набор полей описан в man systemd.journal-fields.

Двоичный структурированный формат - это не каприз: благодаря ему ты можешь мгновенно фильтровать миллионы строк по полю, например "покажи только сообщения от юнита nginx с уровнем error за последний час". Текстовым grep так быстро и точно не сделаешь. Чтобы увидеть все поля записи целиком, добавь -o verbose:

Код: Выделить всё

journalctl -u ssh -n 1 -o verbose
Важная аналогия для новичка: journalctl - это не сам лог, а "окно" в базу журнала. Ты не читаешь файл напрямую, ты делаешь запрос к journald, и он отдает строки. Поэтому почти все сводится к тому, чтобы правильно задать фильтр. Запомни эту мысль - она объясняет всю логику команды.

Изображение

Базовый просмотр: листаем, следим, читаем с конца

Самая простая команда - без аргументов:

Код: Выделить всё

journalctl
Она открывает весь журнал в пейджере (less), от самых старых записей к новым, и сразу прыгает в конец (это поведение по умолчанию начиная с современных версий). Строка выглядит так:

Код: Выделить всё

Jun 15 10:42:13 web01 sshd[1287]: Accepted password for deploy from 10.0.0.5 port 51234 ssh2
Разберем по полям, это пригодится везде:
  • Jun 15 10:42:13 - время события. Хочешь точные таймстемпы с годом и часовым поясом - добавь -o short-iso или -o short-precise (будет видна и доля секунды, что важно при анализе всплесков).
  • web01 - имя хоста.
  • sshd - имя процесса (_COMM), который написал строку. Внимание: это имя бинарника, а не обязательно имя юнита. Юнит лежит в поле _SYSTEMD_UNIT и может называться иначе (например ssh.service против бинарника sshd).
  • 1287 - PID, номер процесса. По нему потом можно отфильтровать.
  • дальше - само сообщение (MESSAGE).
На живой системе записей тысячи, листать с начала бессмысленно. Поэтому запоминай связку коротких флагов:

Код: Выделить всё

journalctl -e    # сразу прыгнуть в КОНЕЦ журнала (самое свежее)
journalctl -f    # следить за новыми строками в реальном времени, как tail -f
journalctl -r    # вывести в ОБРАТНОМ порядке, новые сверху
-f (follow) - твой лучший друг при отладке "вживую": запускаешь его, в другом окне дергаешь приложение и смотришь, что прилетает в лог прямо сейчас. Останавливается по Ctrl+C. -e хорош, когда нужно начать с конца уже в пейджере. -r удобен, когда хочешь увидеть последние ошибки первыми без пейджера.

Чтобы не утонуть в пейджере, ограничивай число строк, а для скриптов отключай пейджер:

Код: Выделить всё

journalctl -n 50            # последние 50 строк
journalctl -u nginx -n 100
journalctl -u nginx --no-pager # без less, удобно в скриптах и пайпах
Фильтры: journalctl service, journalctl error и поиск по времени

Вся сила journalctl - в фильтрах. Их можно комбинировать, и тогда выборка становится точечной.

По сервису (юниту). Это первое, что делаешь, когда знаешь, какой компонент сломан. Связка journalctl service - самый ходовой сценарий:

Код: Выделить всё

journalctl -u nginx.service
journalctl -u ssh -f            # следим за логами SSH вживую
journalctl -u nginx -u php8.3-fpm  # сразу несколько юнитов (логика ИЛИ)
Суффикс .service можно опускать. Несколько -u объединяются по ИЛИ: покажет записи любого из перечисленных юнитов в общем потоке по времени - удобно, когда сбой ходит между nginx и php-fpm. Если не помнишь точное имя юнита, подсмотри: systemctl list-units --type=service или journalctl -F _SYSTEMD_UNIT (флаг -F выводит все значения поля). А свои пользовательские сервисы (запущенные через systemctl --user) смотри так:

Код: Выделить всё

journalctl --user -u myapp.service
По приоритету (уровню важности). Когда нужно отделить ошибки от шума, фильтруй по приоритету. Это запрос вида journalctl error - показать только важное:

Код: Выделить всё

journalctl -p err            # ошибки и хуже
journalctl -p warning -b      # предупреждения и выше за текущую загрузку
journalctl -u nginx -p err    # только ошибки конкретного сервиса
journalctl -p 0..3            # диапазон: от emerg до err
Уровни идут от 0 (самый критичный) к 7 (самый болтливый), и -p показывает указанный уровень И ВСЕ, что серьезнее:
  • 0 emerg, 1 alert, 2 crit - система реально в беде.
  • 3 err - ошибки. С этого уровня обычно и начинают расследование.
  • 4 warning - предупреждения, часто безобидные, но иногда подсказка.
  • 5 notice, 6 info, 7 debug - обычная болтовня и отладка.
Можно задать и диапазон через FROM..TO, как в примере выше. Практическое правило новичка: сломалось - начни с journalctl -p err -b. Если там пусто, поднимись до warning. Важная ловушка: приложение ставит приоритет само. Многие пишут все подряд с уровнем info, и реальная ошибка может прятаться там, а не в err. Поэтому если -p err молчит, а проблема есть - читай и info по нужному юниту.

По времени. Чтобы не искать иголку в стоге, ограничивай период. Запрос journalctl since закрывает большинство случаев:

Код: Выделить всё

journalctl --since "2026-06-15 10:00:00"
journalctl --since "1 hour ago"
journalctl --since today
journalctl --since "09:00" --until "10:30"
journalctl -u nginx --since "30 min ago" -p err
journald понимает человеческие формулировки: "today", "yesterday", "1 hour ago", "10 min ago". Последняя команда в примере - типичный рабочий запрос: ошибки nginx за последние полчаса. Именно так выглядит реальная диагностика. Нюанс: по умолчанию время в журнале показывается в локальном часовом поясе машины, а вот --since тоже считается в локальном времени. Если сервер в UTC, а ты думаешь в Москве - это частый источник промахов на 3 часа. Для однозначности используй -o short-iso (покажет смещение) или задавай метку с зоной.

По загрузке системы. Каждая загрузка (boot) имеет свой _BOOT_ID. Это спасает после ребута:

Код: Выделить всё

journalctl -b        # логи ТЕКУЩЕЙ загрузки
journalctl -b -1     # логи ПРЕДЫДУЩЕЙ загрузки (что было до ребута)
journalctl --list-boots  # список всех загрузок со смещениями
Если сервер внезапно перезагрузился и ты хочешь понять почему - смотри хвост предыдущей загрузки: journalctl -b -1 -e -p warning. Часто там видно либо OOM-киллер, либо паника ядра, либо штатное завершение по reboot/poweroff (тогда причина не в самой машине).

Только ядро. Сообщения ядра (аналог dmesg), сюда падают проблемы с железом, диском, сетью на низком уровне, OOM-киллер:

Код: Выделить всё

journalctl -k            # ядро за текущую загрузку
journalctl -k -p err -b   # ошибки ядра
journalctl -k -g -i "killed process"  # ловим жертв OOM-киллера
По процессу и поиск текста. Можно фильтровать по любому полю и грепать вывод:

Код: Выделить всё

journalctl _PID=1287
journalctl _SYSTEMD_UNIT=nginx.service _UID=33   # несколько полей = логика И
journalctl -u nginx | grep -i timeout
journalctl -g "out of memory"   # встроенный grep по шаблону
journalctl -g "timeout" -i      # -i делает поиск регистронезависимым
Флаг -g (или --grep) - это встроенный поиск прямо внутри journalctl. Важная деталь на 2026: шаблон трактуется как PCRE (Perl-совместимая регулярка), а не как простой grep, и по умолчанию поиск чувствителен к регистру - добавляй -i, если нужно игнорировать регистр. Когда фильтруешь по полям (например _SYSTEMD_UNIT=... _UID=...), несколько разных полей объединяются по И, а повтор одного поля - по ИЛИ. Это и есть тот самый "запрос к базе", о котором мы говорили в начале.

Объяснение ошибок. Флаг -x подмешивает к известным сообщениям подсказку из каталога (что это значит и куда копать). Подсказки есть не для всех записей, но для системных событий часто выручают:

Код: Выделить всё

journalctl -xe   # хвост журнала с пояснениями к ошибкам
Машинно-читаемый вывод и интеграция (актуально на 2026)

journalctl умеет отдавать структуру, а не только текст - это пригодится, когда логи уезжают в мониторинг:

Код: Выделить всё

journalctl -u nginx -o json-pretty   # все поля записи в JSON
journalctl -o json | jq .MESSAGE        # дальше парсим через jq
Что про современный стек: journald отлично работает локально, но в проде логи централизуют. На 2026 типовые связки - это journald как источник, а доставка через systemd-journal-upload, либо через агенты Vector, Grafana Alloy (пришел на смену Promtail) или Fluent Bit в стек Loki/Grafana или ELK/OpenSearch. journalctl остается твоим первым инструментом на самой машине: быстро локализовать проблему на узле, а уже потом смотреть агрегацию по флоту. Знание полей (_SYSTEMD_UNIT, PRIORITY, _BOOT_ID) тут окупается: по ним же ты будешь фильтровать и в Loki/Grafana.

Постоянное хранение и размер журнала

Тут кроется грабля, на которую напарывается почти каждый новичок. Параметр Storage в /etc/systemd/journald.conf по умолчанию равен auto, и ведет себя так: если каталог /var/log/journal существует - пишем на диск (persistent), если нет - держим журнал в /run/log/journal, то есть в оперативной памяти (volatile), и после перезагрузки он обнуляется. На многих установках Debian и Ubuntu каталог /var/log/journal по умолчанию не создается, поэтому де-факто журнал живет в RAM. Вот почему journalctl -b -1 нередко отвечает "нет данных" - логов прошлой загрузки просто не сохранилось. На RHEL/Fedora и ряде других каталог обычно уже есть, и хранение постоянное.

Чтобы гарантированно включить постоянное хранение, есть два пути. Простой - просто создать каталог (при Storage=auto этого достаточно). Явный и надежный - прописать persistent:

Код: Выделить всё

sudo mkdir -p /var/log/journal
# вариант с явной настройкой в /etc/systemd/journald.conf:
# [Journal]
# Storage=persistent
sudo systemctl restart systemd-journald
После этого логи лягут в /var/log/journal и будут жить между загрузками. Проверить, сколько они занимают:

Код: Выделить всё

journalctl --disk-usage
Вывод вида "Archived and active journals take up 1.2G in the file system" - это суммарный размер всех файлов журнала. Если он разрастается, чисти через vacuum:

Код: Выделить всё

sudo journalctl --vacuum-size=500M    # ужать до 500 МБ
sudo journalctl --vacuum-time=2weeks    # удалить старше 2 недель
sudo journalctl --vacuum-files=10       # оставить максимум 10 файлов журнала
Жесткий потолок задается в том же journald.conf параметром SystemMaxUse (по умолчанию около 10% от раздела с /var/log/journal, но не больше 4G). Например SystemMaxUse=2G ограничит журнал двумя гигабайтами. Полезно также проверить целостность файлов после сбоя диска: journalctl --verify. Все это одинаково работает на любом современном дистрибутиве с systemd: Ubuntu, Debian, RHEL/Fedora, а также на отечественных Astra Linux и RED OS - у них тот же systemd-journald, команды и параметры не меняются.

Типичные грабли и заблуждения
  • "journalctl -b -1 пустой - значит логов нет". Нет, скорее всего у тебя журнал в RAM (Storage=auto без каталога /var/log/journal). Настрой постоянное хранение заранее, ДО того как что-то сломается, иначе причину ночного ребута ты не увидишь.
  • "Логов нет вообще". Проверь права: обычный пользователь видит свой user-журнал, но не системный. Добавь себя в группу systemd-journal (или adm), перелогинься, либо запускай через sudo.
  • Путаница -e и -r. -e просто прыгает в конец (порядок прямой), -r переворачивает вывод (новые сверху). Это разные вещи.
  • Путаница _COMM и _SYSTEMD_UNIT. В строке видно имя бинарника (sshd), а -u ждет имя юнита (ssh.service). Если -u ничего не дал, проверь реальное имя через journalctl -F _SYSTEMD_UNIT.
  • "journalctl показывает не все, что писал сервис". Если приложение пишет в собственный файл (например nginx в /var/log/nginx/error.log напрямую), в журнал попадет только то, что ушло в stdout/stderr. Смотри и журнал, и файлы приложения.
  • Часовой пояс. --since считается в локальном времени машины. На сервере в UTC легко промахнуться на несколько часов - сверяйся через -o short-iso.
  • Забывают про -b. Без него фильтры по времени могут зацепить старые загрузки. Привыкай добавлять -b, когда расследуешь свежий инцидент.
Мини-лаба: повтори руками прямо сейчас
  • Выполни journalctl -n 20 и разбери одну строку по полям: время, хост, процесс, PID. Затем journalctl -n 1 -o verbose и найди в нем _SYSTEMD_UNIT и PRIORITY.
  • Запусти journalctl -f, в другом окне сделай sudo systemctl restart ssh и поймай событие в реальном времени.
  • Покажи только ошибки текущей загрузки: journalctl -p err -b. Пусто? Подними планку: journalctl -p warning -b. Есть ли что-то тревожное?
  • Посмотри логи одного сервиса за час: journalctl -u ssh --since "1 hour ago".
  • Найди жертв OOM, если они были: journalctl -k -g -i "killed process".
  • Проверь размер журнала: journalctl --disk-usage. Загляни в /etc/systemd/journald.conf, найди строку Storage и проверь, существует ли /var/log/journal.
Шпаргалка journalctl, чтобы держать под рукой:

Код: Выделить всё

journalctl -e                 # в конец журнала
journalctl -f                 # следить вживую (tail -f)
journalctl -n 50              # последние 50 строк
journalctl -r                 # новые сверху
journalctl -u nginx           # логи сервиса
journalctl -u nginx -f        # следить за сервисом
journalctl --user -u myapp    # логи пользовательского сервиса
journalctl -p err -b          # ошибки текущей загрузки
journalctl -p 0..3            # диапазон приоритетов
journalctl --since "1 hour ago"   # за последний час
journalctl --since today --until "10:30"
journalctl -b                 # текущая загрузка
journalctl -b -1              # предыдущая загрузка
journalctl -k                 # сообщения ядра
journalctl _PID=1287          # по процессу
journalctl -g "out of memory" -i  # встроенный grep (PCRE), без регистра
journalctl -xe                # хвост с пояснениями к ошибкам
journalctl -o json-pretty     # все поля в JSON
journalctl --disk-usage       # размер журнала
sudo journalctl --vacuum-size=500M   # чистка
journalctl --verify           # проверка целостности
Контрольные вопросы
  • Чем отличаются флаги -e, -f и -r? Когда какой удобнее?
  • Как показать только ошибки конкретного сервиса за текущую загрузку? Напиши команду.
  • Почему journalctl -b -1 может вернуть пусто и как это исправить заранее (два способа)?
  • В чем разница между _COMM и _SYSTEMD_UNIT и почему -u иногда "ничего не находит"?
  • Какой командой узнать размер журнала и как ужать его до 1 ГБ?
Что запомнить

journalctl - это окно в журнал systemd, где каждая запись хранится как набор полей, а вся работа сводится к фильтрам. Базис: -e в конец, -f следить, -n ограничить. Расследование: -u сервис, -p err по ошибкам (помни, что приоритет ставит само приложение), --since по времени, -b по загрузке, -k по ядру, -g для поиска по PCRE, -x за пояснениями. Чтобы логи переживали ребут, проверь Storage и наличие /var/log/journal, а размер держи под контролем через --disk-usage и vacuum. Для централизации в 2026 отдавай -o json в Vector/Alloy/Fluent Bit и Loki или ELK. Освоив эту шпаргалку, ты сможешь посмотреть логи Linux и найти причину почти любого сбоя, не открывая руками ни одного файла.
👍1 ❤️2 🔥3 😄 🤔1
Аватара пользователя
jonh1201
Сообщения: 1
Зарегистрирован: 14 май 2026, 20:37

Re: Логи systemd через journalctl: где искать причину

Сообщение jonh1201 »

Спасибо, наконец дошло зачем -b -1. У меня сервер ребутнулся ночью, а логов прошлой загрузки не было - оказалось каталога /var/log/journal не существовало, Storage=auto держал все в RAM. Создал каталог, теперь буду готов.
👍 ❤️ 🔥 😄 🤔1
Аватара пользователя
martwall
Сообщения: 1
Зарегистрирован: 11 май 2026, 16:35

Re: Логи systemd через journalctl: где искать причину

Сообщение martwall »

Подскажите, journalctl -u nginx -f и tail -f /var/log/nginx/error.log это одно и то же? Кажется в файл nginx пишет больше деталей, а в журнал только часть. Или я что-то путаю с stdout?
👍1 ❤️1 🔥 😄 🤔
Ответить
← Предыдущая глава
Методологии диагностики: USE, RED и здравый смысл
Следующая глава →
Где лежат логи Linux: /var/log, dmesg и rsyslog

Все главы курса «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Поделиться темой: ✈ Telegram VK
Похожие запросы: strace почему программа висит и тормозитЛоги и диагностика macOSкак смотреть логи в linux и где они лежат

Вернуться в «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость