# journalctl: фильтрация и форматирование логов systemd

Индекс LLMS: [llms.txt](/llms.txt)

---

Логи пропали. Сервер перезагрузили — и привычный `less /var/log/syslog` молчит. В современных дистрибутивах с systemd логи собирает journald, а читает их `journalctl`. Если не знать его фильтры, работа с системой превращается в гадание.

## Почему логи исчезают после перезагрузки

По умолчанию journal хранит данные в `/run/log/journal/` — это tmpfs, сбрасывается при ребуте. Чтобы логи переживали перезагрузку, создайте директорию:

```bash
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
```

После этого перезапустите systemd-journald:

```bash
sudo systemctl restart systemd-journald
```

Проверить текущее расположение и объём:

```bash
journalctl --disk-usage
```

> [!NOTE]
> На свежих CentOS/RHEL 8+ и Fedora директория `/var/log/journal` создаётся автоматически. На Debian/Ubuntu — обычно нет.

## Фильтрация по юниту и диапазону времени

Самый частый кейс — логи конкретного сервиса:

```bash
journalctl -u nginx.service
journalctl -u postgresql@main.service
```

Комбинируйте несколько юнитов через повтор флага:

```bash
journalctl -u nginx.service -u php-fpm.service
```

Временные фильтры — для отладки инцидентов:

```bash
# Последний час
journalctl --since "1 hour ago"

# Конкретный день
journalctl --since "2025-01-15" --until "2025-01-15 23:59:59"

# За последние сутки
journalctl --since "yesterday"

# С 08:00 до 09:00
journalctl --since "today 08:00" --until "today 09:00"
```

Столкнулись с падением ночью — смотрите логи за тот период, а не весь буфер.

> [!WARNING]
> Если временной фильтр возвращает пустой вывод — проверьте часовой пояс. journalctl хранит метки в UTC, а `--since` интерпретирует локальное время.

## Фильтрация по приоритету

Уровни логов соответствуют syslog:

| Уровень | Число | Описание |
|---------|-------|----------|
| emerg   | 0     | Система неработоспособна |
| alert   | 1     | Требуется немедленное действие |
| crit    | 2     | Критическая ошибка |
| err     | 3     | Ошибка |
| warning | 4     | Предупреждение |
| notice  | 5     | Заметное событие |
| info    | 6     | Информационное |
| debug   | 7     | Отладочное |

```bash
# Только ошибки и критические
journalctl -p err -l

# Ошибки и предупреждения
journalctl -p warning..err

# Все уровни от notice и выше
journalctl -p notice
```

Флаг `-l` показывает полные hostname вместо сокращённых.

## Просмотр логов ядра и загрузки

Ядро шлёт свои сообщения отдельно. Флаг `-k` заменяет `dmesg`:

```bash
# Ядро за текущую загрузку
journalctl -k

# Ядро за предыдущую загрузку
journalctl -k -b -1
```

Список всех загрузок:

```bash
journalctl --list-boots
```

Вывод:

```
-2 5d3c1a9... Mon 2025-01-13 08:00:00 — Mon 2025-01-13 18:00:00
-1 a7b2d8f... Mon 2025-01-13 18:05:00 — Tue 2025-01-14 08:00:00
 0 c9e1f3a... Tue 2025-01-14 08:05:00 — currently running
```

Выбрать конкретную загрузку:

```bash
journalctl -b 5d3c1a9...
```

Для анализа загрузки используйте `systemd-analyze`:

```bash
systemd-analyze blame | head -20
systemd-analyze critical-chain nginx.service
```

## Поиск по регулярному выражению

Грепать вывод journalctl бессмысленно — теряете метаданные. Вместо этого `-g` (--grep):

```bash
# Искать ошибки подключения к БД
journalctl -g "connection.*failed" -u myapp.service

# Ошибки аутентификации
journalctl -g "auth.*fail" -p err
```

`-g` поддерживает базовые регулярки. Для сложных условий комбинируйте с `--since`:

```bash
journalctl -u nginx.service --since "1 hour ago" | grep -E "(timeout|502|503)"
```

Так вы держите выборку по юниту и времени, а затем фильтруете по паттерну.

## Follow-режим (-f)

Аналог `tail -f` для journald. В отличие от слежения за файлом, follow работает с любым фильтром:

```bash
journalctl -u nginx.service -f
journalctl -f -p err
journalctl -u nginx.service -p err -f
```

В терминале Ctrl+C останавливает follow. Из скрипта — через `timeout` или сигнал.

> [!TIP]
> Запускайте `-f` в отдельном окне tmux/screen. Если окно закроется, логи продолжат писаться в journald — данные не потеряются.

Флаги комбинируются через AND: `-u nginx -p err` покажет ошибки только из nginx. Для OR по юнитам используйте поля journald:

```bash
journalctl --no-pager _SYSTEMD_UNIT=nginx.service OR _SYSTEMD_UNIT=php-fpm.service -p err
```

Другие полезные поля:

```bash
# По UID
journalctl --no-pager _UID=1000

# По executable
journalctl --no-pager _EXE=/usr/sbin/nginx

# Список значений поля
journalctl --no-pager -F _SYSTEMD_UNIT
```

## Форматы вывода

По умолчанию journalctl pager'ит вывод. Для скриптов и передачи в jq нужна машиночитаемая форма:

```bash
# JSON Lines (jq-friendly)
journalctl -u nginx -n 50 -o json

# JSON со структурой
journalctl -u nginx -n 50 -o json-pretty
```

| Флаг | Описание | Применение |
|------|----------|------------|
| `-o short` | Классический syslog | По умолчанию |
| `-o short-iso` | Время в ISO 8601 | Логирование в SIEM |
| `-o short-precise` | Миллисекунды | Точный тайминг |
| `-o verbose` | Все поля | Максимум деталей |
| `-o json` | JSON Lines | jq, Splunk, ELK |
| `-o cat` | Только MESSAGE | Минимализм |

```bash
# Только сообщения, без метаданных — аналог tail -f /var/log/app.log
journalctl -u myapp -f -o cat
```

> [!TIP]
> `-n 100` ограничивает вывод последними 100 строками. `--no-pager` отключает pager для скриптов.

## Очистка и управление размером журнала

journald ротирует логи по размеру и времени. Настраивается в `/etc/systemd/journald.conf`:

```ini
[Journal]
SystemMaxUse=500M
SystemMaxFileSize=50M
MaxRetentionSec=30day
```

Применить без рестарта:

```bash
sudo systemd-tmpfiles --create /etc/tmpfiles.d/journald.conf
sudo killall -USR1 systemd-journald
```

Очистить место вручную:

```bash
# Показать занимаемое место
journalctl --disk-usage

# Удалить логи старше N дней
sudo journalctl --vacuum-time=7days

# Удалить логи, оставив последние N мегабайт
sudo journalctl --vacuum-size=200M

# Удалить старые файлы журнала (не текущий)
sudo journalctl --vacuum-files=5
```

> [!WARNING]
> `--vacuum-*` удаляет только файлы, превышающие лимит. Чтобы освободить место наверняка, увеличьте `SystemMaxUse` и перезапустите journald.

## Типичные ошибки

**journalctl: cannot open files** — нет прав. Добавьте себя в группу `systemd-journal`:

```bash
sudo usermod -aG systemd-journal $USER
# перелогиниться
```

**Логи пустые после перезагрузки** — не настроено персистентное хранилище (первая секция).

**journalctl зависает** — огромный буфер. Начните с `-b` или ограничьте время `--since`.

**Нет логов юнита** — проверьте, что юнит вообще запускался:

```bash
systemctl status nginx
journalctl -u nginx --no-pager -n 20
```

journalctl заточен под быстрый поиск. Не читайте логи глазами — фильтруйте сразу.
