logrotate
Ротация логов — переименовать, сжать, удалить старые и дать службе начать новый файл
logrotate не работает постоянно: его запускают по расписанию (cron или таймер systemd, обычно раз в сутки). При каждом запуске он читает конфиги, решает, какие логи пора «повернуть», и делает это: app.log → app.log.1 → app.log.2.gz…, лишние старые копии удаляет, а для службы создаёт новый пустой файл.
Синтаксис
logrotate [опции] конфиг
Главный конфиг — /etc/logrotate.conf: в нём глобальные настройки и строка include /etc/logrotate.d. Правила для отдельных программ лежат в /etc/logrotate.d/<имя>. Ежедневный запуск — /etc/cron.daily/logrotate (на системах с systemd — logrotate.timer).
Формат правила:
/var/log/myapp/*.log {
daily
rotate 7
compress
missingok
notifempty
}
Сначала один или несколько путей (можно шаблоны), затем в фигурных скобках директивы — по одной на строку. Директивы вне скобок задают значения по умолчанию для правил ниже.
Опции командной строки
| Опция | Что делает |
|---|---|
-d | отладка: ничего не делает, только печатает, что было бы сделано (включает -v) |
-v | подробно печатать, что происходит |
-f | ротировать принудительно, даже если по расписанию ещё рано |
-s файл | свой файл состояния вместо /var/lib/logrotate/status |
-l файл | писать лог работы в файл (или syslog) |
-m команда | чем отправлять почту (для mail) |
Когда ротировать
| Директива | Что значит |
|---|---|
daily / weekly / monthly / yearly | по времени с прошлой ротации |
hourly | раз в час — только если сам logrotate запускается каждый час |
size 100M | когда файл больше размера (время не учитывается); единицы k, M, G |
minsize 1M | по времени, но только если файл не меньше размера |
maxsize 500M | по времени или раньше, если файл больше размера |
notifempty / ifempty | не трогать / трогать пустой файл |
missingok | нет файла — не ошибка |
Сколько хранить и куда
| Директива | Что значит |
|---|---|
rotate 7 | хранить 7 старых копий; rotate 0 — старые сразу удалять |
maxage 30 | удалять копии старше 30 дней |
olddir каталог | складывать копии в другой каталог (на той же ФС) |
dateext | суффикс с датой (app.log-20250115) вместо номера |
dateformat -%Y%m%d-%s | формат даты для dateext |
extension .log | сохранить расширение в конце: app-20250115.log |
start 0 | с какого номера начинать (по умолчанию 1) |
Сжатие
| Директива | Что значит |
|---|---|
compress / nocompress | сжимать старые копии (по умолчанию gzip) |
delaycompress | сжимать со следующего раза: .1 остаётся несжатым, его может дописывать служба |
compresscmd, compressext, compressoptions | другой архиватор: compresscmd /usr/bin/xz, compressext .xz |
Как получить новый файл
| Директива | Что значит |
|---|---|
create 0640 user group | после переименования создать новый файл с правами и владельцем |
nocreate | не создавать новый файл |
copytruncate | скопировать лог и обнулить оригинал — для программ, которые не умеют переоткрывать файл |
copy | только скопировать, оригинал не трогать |
su user group | ротировать от имени пользователя — нужно, если каталог лога принадлежит не root |
Скрипты
| Директива | Когда выполняется |
|---|---|
prerotate … endscript | перед ротацией |
postrotate … endscript | после ротации — обычно здесь сигнал службе переоткрыть лог |
firstaction / lastaction … endscript | один раз до / после обработки всех файлов правила |
sharedscripts | pre/postrotate — один раз на всё правило, а не на каждый файл шаблона |
Скрипты выполняются через /bin/sh.
Примеры
# что будет сделано — без изменений
logrotate -d /etc/logrotate.d/nginx
# проверить свой конфиг принудительно и подробно
logrotate -f -v /etc/logrotate.d/myapp
# прогнать всё, как это делает cron
logrotate /etc/logrotate.conf
# свой конфиг со своим файлом состояния — не трогая системный
logrotate -s /tmp/lr.state /path/to/test.conf
# когда что ротировалось в последний раз
cat /var/lib/logrotate/status
Пример правила для программы, которая по HUP переоткрывает логи:
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 root adm
sharedscripts
postrotate
kill -HUP "$(cat /run/myapp.pid)" 2>/dev/null || true
endscript
}
Подводные камни
- Первый запуск ничего не ротирует. Если лога нет в файле состояния,
logrotateзаписывает «ротирован сейчас» и ждёт следующего периода. Для проверки используй-f. -dничего не делает — это только репетиция. Чтобы увидеть результат, нужен-f(и-v).- Без
postrotateилиcopytruncateслужба пишет в старый файл. Переименование не меняет открытый дескриптор: процесс продолжит писать вapp.log.1, а новыйapp.logостанется пустым. copytruncateможет потерять строки, записанные между копированием и обнулением. Если служба умеет переоткрывать логи — лучшеcreate+postrotate.notifemptyпобеждает даже-f: пустой лог не ротируется.- Шаблон
*захватит уже ротированные копии./var/log/app/*превратитapp.log.1вapp.log.1.1. Пиши*.log. - Конфиг, доступный на запись группе или всем, игнорируется («writable by group or others»). Права —
644, владелец — root. - Каталог лога, доступный на запись не-root, тоже пропускается: нужна директива
su. - Отдельный конфиг не наследует
/etc/logrotate.conf. При запускеlogrotate мой.confглобальныеcreate,weeklyи прочее не действуют — пиши всё нужное в правиле. - Размер пишется без
B:size 10M, а не10MB— иначе ошибка «unknown unit». - В контейнере сам по себе он не запустится: ежедневный вызов идёт из cron, а cron надо запустить (
service cron start).