TGViewer
BashTex | Linux BashTex | Linux @bash_tex · 2.51K subscribers
Post #491 1.03K
Автоматическая ротация кастомных логов без logrotate

Не все логи живут в /var/log. Самописные сервисы часто пишут сюда:


/opt/app/logs/
/srv/project/log/
/data/custom/*.log


Реализуем для них контролируемую ротацию на bash.

💚 Задача

архивировать логи старше N дней;
удалять архивы старше M дней;
не ломать активный файл;
не удалять то, что еще пишется.

1️⃣ Поиск логов старше N дней


LOG_DIR="/opt/app/logs"
DAYS=7

find "$LOG_DIR" -type f -name "*.log" -mtime +$DAYS


-mtime +7 - старше 7 дней.

⚠️ mtime - это время последнего изменения.

2️⃣ Архивирование с датой. Добавим gzip и текущую дату:


ARCHIVE_DIR="/opt/app/archive"
mkdir -p "$ARCHIVE_DIR"

find "$LOG_DIR" -type f -name "*.log" -mtime +7 -print0 |
while IFS= read -r -d '' file; do
base=$(basename "$file")
gzip -c "$file" > "$ARCHIVE_DIR/${base}_$(date +%F).gz" && rm -f "$file"
done


Здесь важно:

-print0 + read -d '' - безопасно для пробелов
gzip -c - сначала создаем архив
&& rm - удаляем только если архив создан

Никаких rm до успешного gzip.

3️⃣ Защита от удаления активного лога. Если сервис продолжает писать в файл, удалять его напрямую нельзя. Проверка через lsof:


if lsof "$file" >/dev/null 2>&1; then
echo "Файл используется, пропускаем: $file"
continue
fi


Альтернатива: ротировать только логи, которые не менялись X часов:


-mmin +1440


4️⃣ Удаление старых архивов. Храним архивы 30 дней:


find "$ARCHIVE_DIR" -type f -name "*.gz" -mtime +30 -delete


Лучше сначала проверить:


find "$ARCHIVE_DIR" -type f -mtime +30 -print


Только потом добавлять -delete.

5️⃣ Безопасный вариант с flock (чтобы не запустить дважды)


(
flock -n 200 || exit 1

# код ротации здесь

) 200>/var/lock/custom-log-rotate.lock


Теперь крон не создаст гонку.

▪️ Пример запуска через cron


0 3 * * * /usr/local/bin/custom_rotate.sh


BashTex 📱 #bash #utils
  • 👍 8
More from @bash_tex
  1. Oct 7, 2026/dev/tcp - сетевое соединение средствами Bash В Bash есть малоизвестная возможность работа…
  2. Oct 6, 2026Ephemeral ports - почему заканчиваются исходящие TCP-порты Когда приложение устанавливает…
  3. Oct 5, 2026name_to_handle_at() - как получить файловый объект без обычного пути В Linux обычно обраща…
  4. Oct 2, 2026madvise() - как процесс подсказывает ядру, как он собирается использовать память Когда про…
  5. Oct 1, 2026flock vs fcntl - почему две блокировки одного файла могут вести себя совершенно по-разному…
  6. Sep 30, 2026DEBUG trap - как Bash выполняет код перед каждой командой В Bash есть специальный DEBUG tr…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →