Script Python para Rotação de Logs no Ubuntu

10 min de leitura Automação

A gestão eficiente de logs é um pilar fundamental da administração de sistemas modernos. Em ambientes Ubuntu, onde a geração de dados de auditoria, erros e aplicações ocorre em tempo real, o acúmulo descontrolado de arquivos pode levar à saturação do disco, degradação de performance e dificuldades na análise forense. Embora ferramentas tradicionais como o logrotate sejam padrão no ecossistema Linux, a necessidade de lógica personalizada, integração com APIs externas ou formatação complexa frequentemente exige uma abordagem mais flexível.

Neste tutorial técnico, demonstraremos como criar e implementar um script Python robusto para automação da rotação de logs. Utilizaremos bibliotecas nativas do sistema para garantir leveza e segurança, focando em boas práticas de sysadmin, tratamento de exceções e escalabilidade. O objetivo é fornecer uma solução pronta para produção que substitua ou complemente configurações estáticas.

1. Preparação do Ambiente e Dependências

Antes de escrever o código, é essencial garantir que o ambiente Ubuntu esteja preparado. O Python 3 é padrão na maioria das distribuições modernas, mas a biblioteca logging e manipulação de arquivos (os, shutil) já vem incluída no interpretador, eliminando a necessidade de instalação de pacotes externos via pip.

No entanto, para garantir que o script tenha permissões adequadas e seja executado com segurança, vamos estruturar o diretório de trabalho. Recomenda-se criar um diretório específico para scripts de administração.

  1. Crie o diretório do projeto:
sudo mkdir -p /opt/scripts/log-rotation
  1. Navegue até o diretório criado:
cd /opt/scripts/log-rotation
  1. Crie um arquivo de log fictício para testes, simulando uma aplicação real:
sudo touch /var/log/app-simulada.log
sudo chmod 640 /var/log/app-simulada.log

Esta estrutura inicial permite que o script seja executado em um ambiente isolado, facilitando a depuração antes da implantação em produção.

2. Estruturação do Script Python

O coração da solução reside no script Python. A lógica deve seguir três etapas principais: identificação dos arquivos antigos, renomeação/arquivamento com carimbo de data/hora e compressão opcional para economia de espaço. Utilizaremos o módulo time para gerar timestamps únicos e o módulo os para manipulação do sistema de arquivos.

Crie o arquivo rotate_logs.py utilizando seu editor de texto preferido:

sudo nano /opt/scripts/log-rotation/rotate_logs.py

Insira o seguinte código base. Este script utiliza classes para manter o estado e facilitar a manutenção futura.

#!/usr/bin/env python3
import os
import time
import shutil
import logging
from datetime import datetime

class LogRotator:
    def __init__(self, log_path, max_size_bytes=10485760, backup_count=5):
        """
        Inicializa o rotador de logs.
        
        :param log_path: Caminho absoluto para o arquivo de log.
        :param max_size_bytes: Tamanho máximo em bytes antes da rotação (padrão 10MB).
        :param backup_count: Número de backups a reter.
        """
        self.log_path = log_path
        self.max_size = max_size_bytes
        self.backup_count = backup_count
        
        # Configuração básica de logging para o próprio script
        logging.basicConfig(
            filename='/var/log/script-rotation.log',
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s'
        )

    def should_rotate(self):
        """Verifica se o arquivo de log atingiu o tamanho máximo."""
        if not os.path.exists(self.log_path):
            return False
        
        file_size = os.path.getsize(self.log_path)
        return file_size >= self.max_size

    def rotate(self):
        """Executa a rotação dos arquivos de log."""
        if not self.should_rotate():
            logging.info(f"Arquivo {self.log_path} não precisa de rotação.")
            return

        timestamp = datetime.now().strftime('%Y%m%d-%H%M%S')
        base_name = self.log_path
        
        # Renomear o arquivo atual para .old ou similar
        rotated_name = f"{base_name}.{timestamp}"
        
        try:
            shutil.copy2(self.log_path, rotated_name)
            # Trunca o arquivo original (mantém o inode, importante para processos que mantêm o handle aberto)
            open(self.log_path, 'w').close()
            logging.info(f"Log rotacionado com sucesso: {rotated_name}")
            
            self.cleanup_old_logs(base_name)
            
        except Exception as e:
            logging.error(f"Erro ao rotacionar log: {str(e)}")

    def cleanup_old_logs(self, base_name):
        """Remove backups antigos que excedem o limite configurado."""
        logs = [f for f in os.listdir('.') if f.startswith(base_name) and f != os.path.basename(self.log_path)]
        logs.sort()
        
        # Mantém apenas os últimos N arquivos
        if len(logs) > self.backup_count:
            logs_to_delete = logs[:len(logs) - self.backup_count]
            for old_log in logs_to_delete:
                try:
                    os.remove(old_log)
                    logging.info(f"Backup antigo removido: {old_log}")
                except OSError as e:
                    logging.error(f"Erro ao remover {old_log}: {e}")

if __name__ == "__main__":
    # Configuração para execução manual ou via cron
    LOG_FILE = "/var/log/app-simulada.log"
    rotator = LogRotator(LOG_FILE, max_size_bytes=10485760, backup_count=3)
    rotator.rotate()

Este código implementa a lógica de cópia e truncamento. O uso de open(path, 'w').close() é crucial em sistemas Linux porque muitos serviços (como Nginx ou Java Apps) mantêm o descritor de arquivo aberto mesmo após a renomeação do arquivo físico. Se você apenas mover o arquivo, o serviço continuará escrevendo no arquivo antigo renomeado, criando um novo arquivo vazio.

3. Configuração de Permissões e Executabilidade

Para que o script funcione corretamente, ele precisa ter permissão de leitura no diretório de logs e permissão de escrita para criar os arquivos de backup. Além disso, o arquivo deve ser executável.

sudo chmod +x /opt/scripts/log-rotation/rotate_logs.py

É recomendável criar um usuário dedicado ou garantir que o script seja executado pelo usuário root ou por um usuário com privilégios específicos de sudo, dependendo da sensibilidade dos logs. Para este exemplo, assumiremos execução via sudo.

4. Integração com Cron para Automação Contínua

A verdadeira automação ocorre quando o script é agendado. O gerenciador de tarefas cron no Ubuntu permite executar scripts a cada minuto, hora ou dia. Para rotação baseada em tamanho (como implementado acima), a execução frequente é necessária.

  1. Edite o crontab do usuário root:
sudo crontab -e
  1. Adicione a seguinte linha ao final do arquivo. Esta configuração executa o script a cada 5 minutos:
/5 * * * * /usr/bin/python3 /opt/scripts/log-rotation/rotate_logs.py >> /var/log/cron-rotation.log 2>&1

A flag >> redireciona o stdout para um log de auditoria do próprio cron, permitindo que você monitore se o script está sendo executado e se houve erros. A flag 2>&1 captura também os erros padrão.

5. Testes e Validação da Implementação

Antes de confiar na automação, realize testes manuais para validar a lógica. Utilize o comando dd para gerar dados rapidamente no arquivo de log simulado e forçar a condição de rotação.

# Gera 15MB de dados aleatórios no log
sudo dd if=/dev/urandom of=/var/log/app-simulada.log bs=1M count=15

Agora, execute o script manualmente para verificar o comportamento:

sudo python3 /opt/scripts/log-rotation/rotate_logs.py

Verifique os resultados:

  1. Confirme que o arquivo /var/log/app-simulada.log está vazio (0 bytes):
ls -lh /var/log/app-simulada.log
  1. Verifique se um novo arquivo com timestamp foi criado no diretório do script:
ls -lh /opt/scripts/log-rotation/

Você deve ver um arquivo como /var/log/app-simulada.log.20231027-143022. Se a configuração de backup estiver ativa, tente rodar o script várias vezes até atingir o limite de backups definidos (ex: 3) e confirme que os arquivos mais antigos são removidos automaticamente.

6. Considerações Avançadas para Produção

Embora o script acima seja funcional para cenários básicos, ambientes corporativos exigem camadas adicionais de robustez. Ao adaptar este código para sua infraestrutura, considere as seguintes melhorias:

Compressão Gzip: Para economizar espaço em disco, após copiar o log, comprima-o imediatamente usando o módulo gzip. Isso reduz significativamente o custo de armazenamento de logs históricos.

import gzip
import shutil

# Exemplo simplificado de compressão pós-cópia
shutil.copy2(self.log_path, rotated_name)
with open(rotated_name, 'rb') as f_in:
    with gzip.open(f"{rotated_name}.gz", 'wb') as f_out:
        shutil.copyfileobj(f_in, f_out)
os.remove(rotated_name)

Rotação Baseada em Tempo: Além do tamanho, muitas políticas de compliance exigem rotação diária ou semanal, independentemente do volume. Isso requer a verificação da data de modificação do arquivo versus a data atual.

Sinalização SIGHUP: Em vez de truncar o arquivo (que pode causar perda de buffer em alguns buffers de E/S), é uma prática avançada enviar o sinal SIGHUP para o PID da aplicação. Isso instrui a aplicação a fechar e reabrir seus próprios arquivos de log, garantindo que o novo arquivo seja criado limpo pelo próprio processo.

7. Troubleshooting Comum

Durante a implementação, você pode encontrar erros frequentes:

  • Permission Denied: Certifique-se de que o usuário executando o script tem permissão de escrita no diretório de logs e permissão de execução no script.
  • Arquivo não truncado: Se o arquivo continuar crescendo sem rotação, verifique se a lógica should_rotate está calculando o tamanho corretamente. Lembre-se que o tamanho é verificado no momento da chamada do script.
  • Cron não executa: O ambiente do cron é minimalista. Sempre defina o caminho absoluto para o interpretador Python (/usr/bin/python3) e para os arquivos envolvidos.

Conclusão

A automação da rotação de logs via Python oferece flexibilidade superior às ferramentas padrão quando as necessidades vão além do simples corte por tempo. Ao implementar este script no Ubuntu, você ganha controle granular sobre políticas de retenção, compressão e limpeza de disco.

Este tutorial cobriu desde a preparação do ambiente até a integração com o cron, fornecendo uma base sólida para gerenciamento de arquivos em servidores Linux. Lembre-se de monitorar os logs gerados pelo próprio script (/var/log/script-rotation.log) para garantir que a saúde da sua infraestrutura permaneça estável.

Para otimizações futuras, considere containerizar este script ou integrá-lo a ferramentas de orquestração como Ansible, garantindo que a política de rotação seja consistente em todos os nós do seu cluster.

Esse tutorial foi útil?

Comentários (0)

Seja o primeiro a comentar.

Deixe seu comentário

Seu comentário será analisado antes de ser publicado.

0/2000
WhatsApp