journalctl: как выжимать максимум из системных логов в продакшене

Системные логи — это не просто набор строк, которые кто-то когда-то решил сохранить. Это источник данных, который может рассказать о проблеме задолго до того, как она проявится в метриках или алертах. В Linux журнал системных событий (journald) и его основной клиент journalctl становятся критически важными инструментами, когда система выходит из-под контроля, а стандартные лог-файлы в /var/log/ перестают давать полную картину.

Проблема в том, что многие администраторы и разработчики используют journalctl как "последнюю инстанцию" — когда уже всё рушится. На самом деле, это инструмент для проактивного мониторинга, быстрой диагностики и оптимизации производительности. Но чтобы им пользоваться эффективно, нужно знать не только базовые команды, но и как настраивать journald, как фильтровать данные и как избежать типичных ошибок.


Когда journalctl становится незаменим

Представьте сценарий:

  • Сервис падает в продакшене, но в /var/log/syslog нет нужной информации.
  • Новый микросервис не запускается, а в консоли — только "command not found".
  • Система загружена до 90% CPU, но top и htop не показывают явных виновников.
  • Нужно проанализировать поведение системы за последние 30 дней, но ротация логов стирает данные.

В таких случаях journalctl становится ключевым источником истины. Он собирает:

  • Логи от системных сервисов (systemd, kernel, пользовательские сервисы).
  • Метрики производительности (CPU, memory, disk I/O).
  • Сообщения об ошибках и предупреждения.
  • Журналы ядра (если настроен правильно).

Но чтобы получить из этого что-то полезное, нужно знать, как искать, как фильтровать и как настраивать.


Практика: как не тонуть в потоке логов

1. Базовые команды, которые спасают время

Не все знают, что journalctl — это не просто cat /var/log/messages. Вот что действительно работает:

# Посмотреть последние 10 строк логов (по умолчанию — все)
journalctl -n 10

# Отфильтровать по сервису (например, nginx)
journalctl -u nginx --no-pager

# Показать только ошибки (priority 3 и выше)
journalctl -p err

# Логи за последние 5 минут
journalctl --since "5 minutes ago"

# Логи за конкретный период (например, вчера)
journalctl --since "2024-05-20 00:00:00" --until "2024-05-20 23:59:59"

# Логи от конкретного процесса (по PID)
journalctl _PID=1234

# Логи с определенным ключевым словом (например, "failed")
journalctl -g "failed"

# Показать только текущий бут (последний запуск системы)
journalctl -b

# Логи за предыдущий бут (если был)
journalctl -b -1

Лайфхак: Добавьте --no-pager к любой команде, если хотите сразу получить результат в терминале без пагинации.


2. Как настроить journald для своих нужд

По умолчанию journald хранит логи в бинарном формате и ротирует их. Но можно изменить поведение под свои задачи.

Пример конфигурации /etc/systemd/journald.conf:

[Journal]
# Увеличиваем максимальный размер логов до 500Мб
Storage=persistent
MaxFileSize=50M
MaxFiles=10

# Включаем сохранение логов в /var/log/journal/ (для долгого хранения)
SystemMaxUse=500M

# Сохраняем логи ядра (если нужно)
ForwardToSyslog=yes

Важно:

  • После изменения конфига обязательно перезапустите journald:
    sudo systemctl restart systemd-journald
    
  • Если используете systemd на файловой системе без поддержки xattr (например, tmpfs), логи не сохранятся при перезагрузке. В этом случае используйте Storage=persistent и убедитесь, что /var/log/journal/ существует и имеет правильные права.

3. Как вытаскивать данные для анализа

Иногда нужно не просто посмотреть логи, а экспортировать их для дальнейшего анализа. Вот как это сделать:

Экспорт в JSON для парсинга:

journalctl -u nginx --no-pager -o json > nginx_logs.json

Экспорт в CSV для анализа в Excel:

journalctl -u nginx --no-pager -o short -a | awk '{print $1, $2, $3, $4}' > nginx_logs.csv

Поиск по регулярным выражениям (например, найти все ошибки подключения к базе):

journalctl -u app-service --no-pager | grep -E "connection.*failed|timeout|error"

Пример реального кейса: В одном проекте сервис падало раз в неделю без явной причины. После анализа логов с помощью:

journalctl -u app-service --since "1 week ago" | grep -i "error\|fail\|crash"

Оказалось, что проблема была в недостаточном пуле соединений к базе данных. Логи показывали таймауты, но они "прятались" в общем шуме.


Типичные ошибки и как их избежать

  1. Игнорирование ротации логов

    • Проблема: Если не настроена ротация, /var/log/journal/ может разрастись до гигабайт и заполнить диск.
    • Решение: Установите MaxFileSize и SystemMaxUse в конфиге journald.conf и следите за использованием диска.
  2. Поиск по неточным ключевым словам

    • Проблема: Команда journalctl -g "error" может вернуть сотни строк, среди которых нужная информация "затеряется".
    • Решение: Уточняйте поиск:
      journalctl -u nginx -g "50[0-9]*"  # Искать ошибки 500-599
      
  3. Забывание о фильтрации по времени

    • Проблема: journalctl по умолчанию показывает все логи, что может занять минуты и забить терминал.
    • Решение: Всегда ограничивайте временной диапазон:
      journalctl --since "1 hour ago" -u critical-service
      
  4. Неправильная настройка хранения логов

    • Проблема: Если Storage=volatile, все логи сбрасываются при перезагрузке.
    • Решение: Для долгого хранения используйте Storage=persistent и убедитесь, что /var/log/journal/ существует.
  5. Отсутствие мониторинга заполнения логов

    • Проблема: Если логи не ротируются, система может разогнаться до OOM-киллера.
    • Решение: Добавьте в cron проверку:
      #!/bin/bash
      LOG_DIR="/var/log/journal/"
      if [ $(du -sh $LOG_DIR | cut -f1) -gt "200M" ]; then
        journalctl --vacuum-size=150M
      fi
      

Когда journalctl не поможет (и что делать дальше)

Есть случаи, когда journalctl не даст нужной информации:

  • Логи не записываются: Проверьте права доступа и конфиг journald.conf.
  • Сервис не использует systemd: В этом случае логи могут лежать в /var/log/<service>.log или /dev/null.
  • Проблема в аппаратном обеспечении: Если виноват диск или RAM, то и journalctl не спасет — нужны dmesg, smartctl и физическая диагностика.

В таких случаях комбинируйте journalctl с другими инструментами:

# Логи ядра (если проблема на уровне hardware/driver)
dmesg | tail -n 50

# Мониторинг дисков
iostat -x 1

# Проверка памяти
free -h
vmstat 1

Практический вывод: как интегрировать journalctl в рабочий процесс

  1. Настройте journald под свои задачи

    • Определите, какие сервисы критически важны, и настройте для них отдельные правила хранения.
    • Пример: Для базы данных (postgresql) можно увеличить MaxFileSize, а для временных сервисов — уменьшить.
  2. Автоматизируйте экспорт логов

    • Настройте cron-задачу для экспорта важных логов в JSON/CSV раз в сутки:
      0 3 * * * journalctl -u critical-service --since "1 day ago" -o json > /backups/journal_logs_$(date +\%Y\%m\%d).json
      
  3. Используйте journalctl для проактивного мониторинга

    • Пишите скрипты, которые парсят логи и отправляют алерты при определенных событиях:
      # Пример: алерт, если в логах nginx появляется слово "502"
      journalctl -u nginx --no-pager | grep "502" && curl -X POST -d "alert" http://monitoring-service/alert
      
  4. Обучайте команду

    • Многие инциденты происходят из-за того, что разработчики не знают, как искать логи. Добавьте в онбординг инструкцию по journalctl с 3-5 ключевыми командами.
  5. Комбинируйте с другими инструментами

    • journalctl — это не панацея. Умело сочетайте его с:
      • strace (для отладки процессов).
      • tcpdump (для сетевых проблем).
      • perf (для анализа производительности).

Заключение: journalctl — это не просто утилита, а часть инфраструктуры

Если вы работаете с Linux-системами, journalctl должен быть в вашем арсенале не как инструмент для экстренных случаев, а как часть ежедневного мониторинга. Он помогает:

  • Быстрее находить корень проблем.
  • Автоматизировать сбор метрик.
  • Сохранять историю событий для постмортема.

Главный совет: Начните с базовых команд, затем настройте journald под свои нужды, и наконец — автоматизируйте работу с логами. Это сэкономит часы в будущем, когда система начнет "вести себя странно", а вам нужно будет найти источник проблемы за 5 минут, а не за 5 часов.

А теперь — практика. Попробуйте сами:

  1. Запустите journalctl -u <ваш_сервис> и посмотрите, какие логи приходят.
  2. Настройте ротацию для одного из сервисов.
  3. Напишите скрипт, который раз в день архивирует логи для критически важных сервисов.

Если вы сделаете это, то уже через неделю заметите, как сильно упростится жизнь в поддержке.