# logrotate для своих демонов

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

---

Логи демона разрастаются, а ротации нет — файл достигает десятков гигабайт, диск забивается, мониторинг ругается. systemd-journald и syslog-ng умеют вращать сами, но если у тебя свой демон пишет напрямую в файл, ротацию несёт logrotate. Вот как его настроить под конкретный сервис.

## Зачем писать свой конфиг logrotate

Пакеты из репозитория обычно ставят конфиг в `/etc/logrotate.d/`, но для自建 демонов или собранных из исходников его нет. Без конфига файл растёт бесконтрольно. logrotate запускается через systemd-таймер (`logrotate.timer`) или cron и читает все файлы из `/etc/logrotate.d/`. Достаточно создать один файл — и цикл ротации заработает.

> [!NOTE]
> Проверь, установлен ли пакет `logrotate` и активен ли таймер: `systemctl status logrotate.timer`. В большинстве дистрибутивов он включён по умолчанию.

## copytruncate vs create — когда что использовать

Это два принципиально разных подхода к переименованию и созданию нового файла.

| | `copytruncate` | `create` |
|---|---|---|
| **Механизм** | Копирует текущий файл, обрезает оригинал на месте | Переименовывает старый, создаёт новый с нужными правами |
| **Приложение** | Не нужно перезапускать | Нужно уметь открывать новый файл (обычно через SIGHUP или `copytruncate` не нужен) |
| **Риск потери строк** | Да — между копированием и обрезкой новые записи могут попасть в «дыру» | Минимальный — атомарное переименование |
| **Когда использовать** | Демон не умеет переоткрывать файл (например, написан на Go без сигналов) | Демон поддерживает SIGHUP или `systemd-notify` |

> [!WARNING]
> `copytruncate` — это компромисс. Строки, записанные между `cp` и `truncate`, теряются. Для высоконагруженных сервисов это может означать сотни потерянных строк в секунду.

Если демон умеет получать сигнал — используй `create` и перезапускай через `postrotate`.

## delaycompress и как он влияет на цепочку архивов

По умолчанию logrotate сжимает ротированный файл сразу в тот же цикл. Проблема: если демон ещё пишет в старый файл (или ещё не переоткрыл новый), сжатие ломает всё.

`delaycompress` откладывает сжатие на один цикл. Цепочка выглядит так:

```
app.log          ← текущий
app.log.1        ← ротированный, ещё не сжат
app.log.2.gz     ← сжатый, два цикла назад
app.log.3.gz     ← сжатый, три цикла назад
```

Без `delaycompress` переход выглядит жёстче: `app.log` сразу становится `app.log.1.gz`, и если демон ещё пишет в `app.log` через дескриптор, данные идут в сжатый архив — или теряются.

> [!TIP]
> `delaycompress` имеет смысл только вместе с `create` и `compress`. С `copytruncate` он работает, но теряет смысл — ведь файл обрезается на месте, и сжатие можно делать сразу.

## Интеграция с systemd notify

Если демон поддерживает `sd_notify(3)`, можно не полагаться на `postrotate` с ручным перезапуском. systemd умеет перезапускать сервис по сигналу от logrotate.

В конфиге logrotate указываешь:

```
postrotate
    systemctl kill -s HUP my-daemon.service
endscript
```

Или, если демон слушает `NOTIFY_SOCKET`:

```
postrotate
    systemctl notify-reload my-daemon.service
endscript
```

> [!NOTE]
> `systemctl notify-reload` доступен начиная с systemd 231. Отправляет `RELOADING=1`, а затем `READY=1` — это стандартный механизм уведомления о перезагрузке конфигурации.

Для `copytruncate` `postrotate` обычно не нужен — обрезка файла на месте не требует участия демона.

## Пример рабочего конфига

Допустим, демон `my-app` пишет в `/var/log/my-app/app.log`, поддерживает SIGHUP и `sd_notify`.

```
/var/log/my-app/app.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 myapp myapp
    postrotate
        systemctl notify-reload my-app.service >/dev/null 2>&1 || true
    endscript
}
```

Ключи:

| Флаг | Что делает |
|---|---|
| `daily` | Ротация каждый день |
| `rotate 14` | Хранить 14 архивов |
| `compress` | gzip-сжатие |
| `delaycompress` | Сжатие с задержкой на один цикл |
| `missingok` | Не ругаться, если файла нет |
| `notifempty` | Не ротировать пустой файл |
| `create 0640 myapp myapp` | Создать новый файл с нужными правами и владельцем |
| `postrotate` | Уведомить systemd о перезагрузке |

Для теста без реального вращения:

```
logrotate -d /etc/logrotate.d/my-app
```

Флаг `-d` запускает в debug-режиме — покажет, что будет сделано, без изменений файлов.

> [!WARNING]
> После создания конфига первый запуск происходит только на следующий запуск таймера. Чтобы принудительно проверить — `logrotate -f /etc/logrotate.d/my-app`. Это немедленно ротирует файл, так что используй осторожно на проде.
