Log rotation e cleanup automatizado
1. Fundamentos do Log Rotation
Log rotation é o processo de gerenciar arquivos de log que crescem continuamente, dividindo-os em arquivos menores e removendo versões antigas. Sem rotação, um único arquivo de log pode consumir gigabytes de espaço em disco e degradar a performance de I/O do sistema.
A estrutura de nomes típica inclui timestamp (meuapp.log.2025-03-28), sequência numérica (meuapp.log.1, meuapp.log.2) ou compressão automática (meuapp.log.2025-03-28.gz). A compressão com gzip ou bzip2 reduz o tamanho dos logs antigos em 80-90%.
É crucial distinguir rotation de truncation. Rotation move o arquivo atual para um novo nome e cria um arquivo vazio para continuar logging. Truncation simplesmente esvazia o arquivo existente, o que pode causar perda de dados se o processo gravador não for notificado. Sempre prefira rotation com sinalização adequada aos processos.
2. Implementação com logrotate via Shell
O logrotate é a ferramenta padrão no Linux. Sua configuração global fica em /etc/logrotate.conf, e configurações específicas em /etc/logrotate.d/.
Exemplo de configuração para logs do nginx em /etc/logrotate.d/nginx:
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 nginx adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
Para forçar rotação manual e testar configurações:
# Forçar rotação imediata
sudo logrotate -f /etc/logrotate.d/nginx
# Modo debug: mostra o que seria feito sem executar
sudo logrotate -d /etc/logrotate.d/nginx
# Verificar última execução
cat /var/lib/logrotate/status
3. Script Customizado de Rotation com Bash
Quando o logrotate não atende necessidades específicas, um script Bash oferece controle total. Exemplo funcional:
#!/bin/bash
LOG_DIR="/var/log/meuapp"
LOG_FILE="meuapp.log"
MAX_SIZE=10485760 # 10MB em bytes
RETENTION_DAYS=30
LOCK_FILE="/tmp/rotate_meuapp.lock"
# Evitar execução concorrente
exec 200>"$LOCK_FILE"
flock -n 200 || { echo "Rotação já em execução"; exit 1; }
# Detectar se o log está ativo (evitar conflito de escrita)
if lsof "$LOG_DIR/$LOG_FILE" > /dev/null 2>&1; then
echo "AVISO: Log está sendo escrito no momento"
fi
# Verificar tamanho atual
CURRENT_SIZE=$(stat -c%s "$LOG_DIR/$LOG_FILE" 2>/dev/null || echo 0)
if [ "$CURRENT_SIZE" -ge "$MAX_SIZE" ]; then
TIMESTAMP=$(date +%Y-%m-%d_%H%M%S)
# Mover e comprimir
mv "$LOG_DIR/$LOG_FILE" "$LOG_DIR/${LOG_FILE}.${TIMESTAMP}"
gzip "$LOG_DIR/${LOG_FILE}.${TIMESTAMP}"
# Criar novo arquivo vazio com permissões corretas
touch "$LOG_DIR/$LOG_FILE"
chmod 640 "$LOG_DIR/$LOG_FILE"
echo "Log rotacionado: ${LOG_FILE}.${TIMESTAMP}.gz"
fi
# Cleanup de logs antigos
find "$LOG_DIR" -name "${LOG_FILE}.*.gz" -mtime +$RETENTION_DAYS -delete
flock -u 200
4. Políticas de Cleanup e Retenção
Definir políticas claras evita surpresas. Duas abordagens comuns:
Retenção por tempo (mais comum):
# Remover logs com mais de 30 dias
find /var/log/meuapp -name "*.gz" -mtime +30 -delete
# Ou mover para archive antes de deletar
find /var/log/meuapp -name "*.gz" -mtime +30 -exec mv {} /archive/ \;
Retenção por quantidade (útil quando o volume diário varia):
#!/bin/bash
LOG_DIR="/var/log/meuapp"
MAX_FILES=14
# Contar arquivos de log compactados
FILE_COUNT=$(ls -1 "$LOG_DIR"/*.gz 2>/dev/null | wc -l)
if [ "$FILE_COUNT" -gt "$MAX_FILES" ]; then
# Remover os mais antigos até atingir o limite
TO_REMOVE=$((FILE_COUNT - MAX_FILES))
ls -1t "$LOG_DIR"/*.gz | tail -n "$TO_REMOVE" | xargs rm -f
echo "Removidos $TO_REMOVE arquivos antigos"
fi
Cleanup condicional preserva os últimos N arquivos mesmo se antigos:
# Preservar sempre os 7 arquivos mais recentes, depois limpar por idade
ls -1t /var/log/meuapp/*.gz | tail -n +8 | xargs rm -f 2>/dev/null
find /var/log/meuapp -name "*.gz" -mtime +60 -delete
5. Tratamento de Logs de Aplicações Específicas
Nginx/Apache: usar kill -USR1 ou kill -HUP para recarregar sem perder conexões.
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
Docker: logs JSON podem crescer rapidamente. Limpeza segura:
# Limitar logs do container a 10MB e 3 arquivos
docker run --log-opt max-size=10m --log-opt max-file=3 meuapp
# Limpeza manual de logs parados
docker container prune --force
docker system prune --volumes --force
# Verificar tamanho dos logs
du -sh /var/lib/docker/containers/*/*-json.log
Logs do sistema (/var/log/syslog, auth.log): usar logrotate padrão do sistema, nunca manipular manualmente sem entender as permissões e processos envolvidos.
# Configuração segura para syslog
/var/log/syslog
/var/log/auth.log {
rotate 7
daily
missingok
notifempty
delaycompress
compress
postrotate
systemctl restart rsyslog > /dev/null 2>&1 || true
endscript
}
6. Automação com Cron e Systemd Timers
Cron job para execução diária às 3h da manhã:
# Editar crontab: crontab -e
0 3 * * * /usr/local/bin/rotate_logs.sh >> /var/log/rotation.log 2>&1
Systemd timer (mais moderno e confiável):
# /etc/systemd/system/rotate-logs.service
[Unit]
Description=Rotation de logs do sistema
[Service]
Type=oneshot
ExecStart=/usr/local/bin/rotate_logs.sh
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/rotate-logs.timer
[Unit]
Description=Timer para rotação diária de logs
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
Ativar o timer:
sudo systemctl daemon-reload
sudo systemctl enable rotate-logs.timer
sudo systemctl start rotate-logs.timer
Importante: o script de rotation deve logar suas próprias ações em um arquivo separado para evitar loops infinitos:
ROTATION_LOG="/var/log/rotation_audit.log"
echo "$(date): Rotação executada, $(ls /var/log/meuapp/*.gz | wc -l) arquivos" >> "$ROTATION_LOG"
7. Monitoramento e Alertas
Verificação de espaço e notificação em caso de falha:
#!/bin/bash
LOG_DIR="/var/log/meuapp"
THRESHOLD=80 # Percentual de uso do disco
ALERT_EMAIL="admin@exemplo.com"
# Verificar espaço antes da rotação
DISK_USAGE=$(df /var/log | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -gt "$THRESHOLD" ]; then
echo "ALERTA: Disco em /var/log está com ${DISK_USAGE}% de uso"
fi
# Executar rotação
/usr/local/bin/rotate_logs.sh
ROTATION_EXIT=$?
# Verificar espaço depois
NEW_DISK_USAGE=$(df /var/log | awk 'NR==2 {print $5}' | sed 's/%//')
SPACE_FREED=$((DISK_USAGE - NEW_DISK_USAGE))
# Relatório
REPORT="Rotação executada em $(date)
Exit code: $ROTATION_EXIT
Espaço antes: ${DISK_USAGE}%
Espaço depois: ${NEW_DISK_USAGE}%
Espaço liberado: ${SPACE_FREED}%
Logs rotacionados: $(ls -1 $LOG_DIR/*.gz 2>/dev/null | wc -l)"
echo "$REPORT"
# Notificar em caso de erro
if [ "$ROTATION_EXIT" -ne 0 ]; then
echo "$REPORT" | mail -s "Falha na rotação de logs" "$ALERT_EMAIL"
curl -X POST -H "Content-Type: application/json" \
-d "{\"text\":\"Falha na rotação de logs em $(hostname)\"}" \
https://hooks.slack.com/services/SEU/WEBHOOK
fi
8. Boas Práticas e Armadilhas Comuns
Sempre usar flock para evitar execução concorrente:
LOCK_FILE="/tmp/rotate_logs.lock"
exec 200>"$LOCK_FILE"
flock -n 200 || { echo "Já está rodando"; exit 1; }
# ... rotação ...
flock -u 200
Cuidado com links simbólicos: nunca rotacionar o link em si, mas o arquivo alvo:
# Verificar se é link simbólico antes de rotacionar
if [ -L "$LOG_DIR/$LOG_FILE" ]; then
echo "ERRO: $LOG_DIR/$LOG_FILE é um link simbólico"
exit 1
fi
Testar em staging antes de produção:
# Criar ambiente de teste
mkdir -p /tmp/test_logs
cp /var/log/meuapp.log /tmp/test_logs/
./rotate_logs.sh --dry-run --log-dir /tmp/test_logs
Outras armadilhas comuns:
- Não esquecer de recarregar o processo após rotação
- Verificar permissões do novo arquivo (muitas vezes o processo não consegue escrever)
- Não usar rm -f sem antes verificar se o arquivo não está sendo usado
- Configurar rotação antes do disco encher completamente (monitore com df -h)
Referências
- logrotate(8) - Linux man page — Documentação oficial completa do logrotate com todas as diretivas e opções
- How To Manage Logfiles with Logrotate on Ubuntu — Tutorial prático da DigitalOcean cobrindo configuração, compressão e notificações
- Bash Scripting: Log Rotation and Cleanup — Artigo técnico no Baeldung com exemplos de scripts customizados e tratamento de concorrência
- Systemd Timers vs Cron: A Practical Guide — Guia da Red Hat comparando cron e systemd timers para automação de tarefas
- Docker Logging: Best Practices and Configuration — Documentação oficial do Docker sobre gerenciamento de logs de containers
- Advanced Log Rotation Techniques with Bash — Tutorial avançado com funções Bash para compressão seletiva e políticas de retenção