Хочете перетворити живі журнали systemd у акуратні архіви per-service — для аудиту, дебагу чи відправки колегам? Зараз покажу простий, надійний і відтворюваний підхід на базі bash скриптів і systemd timers. Це чиста автоматизація задач без зайвої магії: зберігаємо log-файли Linux у текстовому форматі, стискаємо, чистимо старі — і все це працює самостійно щодня 🔧.

Що ми побудуємо

Ми створимо: - Bash-скрипт, який експортує журнали конкретного сервісу з journalctl, стискає їх і видаляє застарілі архіви. - Шаблонні systemd units (@-service і @-timer), щоб легко підключати будь-який юніт: nginx.service, ssh.service, docker.service тощо. - Альтернативу через cron, якщо вам так зручніше. Це ідеально для сценаріїв на кшталт «експортуйте вчорашні логи певного сервісу щодня о 00:05» 🚀. У тексті я природно вживатиму теги: bash скрипти, cron та systemd timers, автоматизація задач, log-файли Linux — бо саме про це наш гайд.

Основний How-to: експорт і таймери

1) Підготуйте директорії

sudo mkdir -p /var/log/exported-journals
sudo chmod 755 /var/log/exported-journals

Рекомендовано мати persistent-журнали для systemd (щоб логи не зникали після перезавантаження):

sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald

2) Створіть bash-скрипт експорту

Збережіть як export-unit-logs.sh, потім встановіть у /usr/local/bin.

#!/usr/bin/env bash
set -euo pipefail

UNIT="${1:-}"
RETENTION_DAYS="${2:-30}"
SINCE="${3:-yesterday}"

if [[ -z "$UNIT" ]]; then
  echo "Usage: $0  [retention_days] [since]" >&2
  exit 1
fi

if ! systemctl status "$UNIT" &>/dev/null; then
  echo "Unit '$UNIT' not found" >&2
  exit 2
fi

DEST_BASE="/var/log/exported-journals"
DEST_DIR="$DEST_BASE/$UNIT"
sudo mkdir -p "$DEST_DIR"
STAMP="$(date +%F)"
OUT="$DEST_DIR/${UNIT}-${STAMP}.log"

# Експорт у текст із часовими мітками ISO
journalctl -u "$UNIT" --since "$SINCE" --output=short-iso --no-pager > "$OUT"

gzip -f -9 "$OUT"

# Прибирання старих архівів
find "$DEST_DIR" -type f -name "${UNIT}-*.log.gz" -mtime +"$RETENTION_DAYS" -print -delete || true

echo "Saved: ${OUT}.gz"
sudo install -m 0755 export-unit-logs.sh /usr/local/bin/export-unit-logs.sh

Перша перевірка (разово):

sudo /usr/local/bin/export-unit-logs.sh nginx.service 14 yesterday
ls -l /var/log/exported-journals/nginx.service

3) Шаблонні systemd service і timer

Створіть файл /etc/systemd/system/export-unit-logs@.service:

sudo tee /etc/systemd/system/export-unit-logs@.service >/dev/null <<'EOF'
[Unit]
Description=Export systemd logs for %i
Documentation=man:journalctl(1)

[Service]
Type=oneshot
ExecStart=/usr/local/bin/export-unit-logs.sh %i.service
EOF

І таймер /etc/systemd/system/export-unit-logs@.timer (щодня о 00:05 з невеликою рандомною затримкою):

sudo tee /etc/systemd/system/export-unit-logs@.timer >/dev/null <<'EOF'
[Unit]
Description=Daily export of systemd logs for %i

[Timer]
OnCalendar=*-*-* 00:05:00
RandomizedDelaySec=5min
Persistent=true
Unit=export-unit-logs@%i.service

[Install]
WantedBy=timers.target
EOF

Активуйте для потрібних сервісів. Зверніть увагу на точну назву юніта: на Debian/Ubuntu це ssh.service, на RHEL-подібних часто sshd.service. Перевірте назву:

systemctl list-units --type=service | grep -E 'ssh|nginx'
sudo systemctl daemon-reload
sudo systemctl enable --now export-unit-logs@nginx.timer
sudo systemctl enable --now export-unit-logs@ssh.timer   # або @sshd.timer

Перевірка:

systemctl list-timers | grep export-unit-logs@
systemctl status export-unit-logs@nginx.service
ls -l /var/log/exported-journals/nginx.service

Альтернативні способи

Експорт «на льоту» однією командою

journalctl -u nginx.service -S "-1h" -o short-iso --no-pager | gzip -9 > nginx-last-hour-"$(date +%F-%H)".log.gz

Фільтрація за рівнями логів прямо в journalctl:

journalctl -u nginx.service -S yesterday -g "error|crit|alert" --no-pager > errors-yesterday.log

Через cron замість systemd timers

echo '5 0 * * * root /usr/local/bin/export-unit-logs.sh nginx.service 14 yesterday' | sudo tee /etc/cron.d/export-nginx-logs

Догляд за самими журналами systemd

Щоб обмежити розмір двійкових журналів:

sudo journalctl --vacuum-time=14d
sudo journalctl --vacuum-size=500M

GUI-спосіб (для разових експортів)

Для візуального перегляду підійде GNOME Logs або KSystemLog. Це не заміна автоматизації, але зручно для швидких вибірок.

# Приклад для Debian/Ubuntu
sudo apt update
sudo apt install gnome-logs

Запустіть «Logs», відфільтруйте повідомлення за назвою сервісу у пошуку (наприклад, Unit: nginx.service), виділіть записи та збережіть у файл. Для регулярних експортів все ж краще триматися systemd timers.

FAQ

Чому потрібні права root?
Журнали systemd часто вимагають підвищених прав. Запускайте скрипт і таймери через sudo або додайте користувача до групи systemd-journal (права доступу Linux важливі для цього кейсу).

Де лежать архіви?
У /var/log/exported-journals/<unit.service>/, файли виду <unit.service>-YYYY-MM-DD.log.gz.

Як змінити період експорту?
Третій аргумент скрипта — SINCE, за замовчуванням yesterday. Можна ставити -1h, today, або точну дату/час: "2026-02-01 00:00".

Таймер не спрацював, що робити?
Перевірте: systemctl list-timers, systemctl status export-unit-logs@nginx.service. Переконайтеся, що назва юніта правильна. Також гляньте логи самого таймера: journalctl -u export-unit-logs@nginx.service -S -1d.

Журнали зникають після перезавантаження
Увімкніть persistent-режим: створіть /var/log/journal і перезапустіть systemd-journald.

Чи не дублюються експорти?
Ми експортуємо за інтервал --since. Якщо ставите yesterday щодня — дублювань не буде. Для кастомних інтервалів подбайте, щоб вони не перетинались.

Як швидко переглянути останні рядки?
journalctl -u nginx.service -n 200 -f для live-перегляду (корисно для Linux моніторинг під час налагодження).

Як видалити старі архіви гнучкіше?
Підкоригуйте find у скрипті (наприклад, зберігайте не більше N файлів або за розміром каталогу).

Порада від Kernelka

Додайте до скрипта сервісні теги в іменах файлів, якщо збираєте з багатьох вузлів: наприклад, хостнейм і середовище (prod/stage). Так ви швидше знайдете потрібний архів. І ще: якщо полюєте за помилками — додавайте «швидкий» добір під час експорту, наприклад -g "error|warn", та зберігайте окремо. Маленький крок — велика економія часу.

Підсумок

  • Експортуємо журнали systemd для окремих сервісів у текстовий формат і стискаємо їх.
  • Використовуємо bash скрипти для керованості та прозорості.
  • Автоматизуємо через cron та systemd timers — простіше та надійніше для продакшену.
  • Тримаємо log-файли Linux у чистоті: retention + vacuum для журналів.
  • Перевіряємо права доступу і назви юнітів, щоб уникнути типових збоїв.

Готово! Тепер ваші логи — завжди під рукою та в порядку. 🙂