Script Python para Monitorar Serviços Linux (Código Pronto)

11 min de leitura Automação
Script Python para Monitorar Serviços Linux (Código Pronto)

Introdução à Automação de Monitoramento no Linux

No ambiente de infraestrutura de TI moderna, a estabilidade dos serviços é crítica. Para sysadmins e desenvolvedores que gerenciam servidores Linux, confiar apenas em monitoramentos externos ou verificar manualmente o status de cada daemon via terminal não é escalável. A automação permite a detecção proativa de falhas antes que elas impactem os usuários finais.

O objetivo deste tutorial é fornecer um script Python robusto e didático para verificar o status dos serviços gerenciados pelo systemd. Utilizaremos a biblioteca padrão do Python, garantindo que o código funcione em praticamente qualquer distribuição Linux moderna sem a necessidade de instalar dependências externas complexas. Este é um exemplo prático de como aplicar conceitos de automação, scripting e monitoramento no dia a dia de um profissional de TI.

Por que usar Python para Gerenciar Serviços?

Embora comandos como systemctl status sejam essenciais, eles são projetados para interação humana. Para scripts e automação, precisamos de saída estruturada (JSON, CSV ou logs formatados). O Python oferece uma interface limpa para interagir com o sistema operacional através do módulo subprocess ou bibliotecas como psutil.

Neste tutorial, optaremos por uma abordagem híbrida: utilizaremos o comando systemctl list-units via subprocesso para obter a lista oficial de unidades carregadas e seus estados. Isso garante precisão absoluta, pois estamos consultando diretamente o gerenciador de inicialização do Linux, evitando inconsistências que podem ocorrer ao verificar apenas processos em execução.

Preparação do Ambiente

Antes de escrever o código, é fundamental garantir que seu ambiente esteja preparado. Você precisará de:

  • Um servidor Linux com systemd instalado (a maioria das distribuições modernas: Ubuntu, CentOS, Debian, RHEL).
  • Permissões de root ou acesso ao grupo systemd-journal/wheel, pois a consulta de status de todos os serviços geralmente requer privilégios elevados.
  • Python 3.6 ou superior instalado na máquina.

Comece verificando sua versão do Python:

python3 --version

Se o comando retornar uma versão inferior a 3.6, considere atualizar ou usar um ambiente virtual para isolar suas ferramentas de automação.

Estrutura do Script Python

O script será dividido em três partes lógicas:

  1. Configuração e Importações: Definição de constantes e importação de módulos necessários.
  2. Lógica de Consulta: Função que executa o comando systemctl e parseia a saída.
  3. Análise e Relatório: Processamento dos dados para identificar serviços em estado crítico (failed) ou inativos.

Passo 1: O Código Base

Crie um arquivo chamado check_services.py. Vamos começar definindo a estrutura básica e a função principal que interage com o sistema.

#!/usr/bin/env python3
"""
Script para verificação de status de serviços Linux via systemd.
Autor: Toda Solução - Automação & Infraestrutura
Descrição: Verifica o estado dos serviços ativos no servidor.
"""

import subprocess
import sys
import json
from datetime import datetime

class ServiceMonitor:
    def __init__(self):
        self.services = []
        self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    def get_service_list(self):
        """
        Executa o comando systemctl para listar unidades carregadas.
        Retorna uma lista de dicionários com nome e estado do serviço.
        """
        # Comando base: list-units --type=service --no-pager --no-legend
        cmd = [
            'systemctl', 
            'list-units', 
            '--type=service', 
            '--state=active', 
            '--state=failed', 
            '--no-pager', 
            '--no-legend',
            '--output=json'
        ]
        
        try:
            # Executa o comando e captura a saída padrão (stdout)
            result = subprocess.run(
                cmd, 
                capture_output=True, 
                text=True, 
                check=True
            )
            
            # Tenta parsear o JSON retornado pelo systemctl
            # Nota: O formato JSON do systemctl pode variar ligeiramente entre versões.
            # Abaixo usamos uma abordagem robusta de parsing manual se o JSON falhar.
            try:
                data = json.loads(result.stdout)
                return self.parse_json_output(data)
            except json.JSONDecodeError:
                print("Erro ao parsear JSON. Retornando para parser baseado em texto.")
                return self.parse_text_output(result.stdout)

        except subprocess.CalledProcessError as e:
            print(f"Erro ao executar systemctl: {e}", file=sys.stderr)
            return []
        except Exception as e:
            print(f"Erro inesperado: {e}", file=sys.stderr)
            return []

Passo 2: Implementando o Parseador de Dados

O systemctl pode retornar dados em formato JSON (se compilado com suporte) ou texto. Para garantir compatibilidade máxima, vamos implementar um parser que tente ler o JSON primeiro e, se falhar, utilize expressão regular ou split simples para textos.

    def parse_json_output(self, data):
        """
        Processa a saída JSON do systemctl.
        Estrutura típica: [{'id': 'nginx.service', 'load-state': 'loaded', ...}]
        """
        services = []
        
        # O formato pode ser uma lista direta ou um dicionário com chaves específicas
        if isinstance(data, list):
            units = data
        elif isinstance(data, dict) and 'units' in data:
            units = data['units']
        else:
            units = []

        for unit in units:
            service_info = {
                'name': unit.get('id', 'unknown'),
                'state': unit.get('sub-state', 'unknown'),
                'load_state': unit.get('load-state', 'unknown')
            }
            services.append(service_info)
            
        return services

    def parse_text_output(self, text):
        """
        Parser de fallback para saída textual do systemctl.
        Formato típico: 
        UNIT              LOAD   ACTIVE SUB     DESCRIPTION
        nginx.service     loaded active running The NGINX HTTP and reverse proxy server
        """
        services = []
        lines = text.strip().split('\n')
        
        for line in lines:
            if not line.strip():
                continue
            
            # Dividir por múltiplos espaços
            parts = line.split()
            if len(parts) >= 3:
                name = parts[0]
                load_state = parts[1]
                active_state = parts[2]
                
                # Normalizar o estado para um formato consistente
                full_state = f"{load_state}/{active_state}"
                
                services.append({
                    'name': name,
                    'state': full_state,
                    'load_state': load_state
                })
                
        return services

Passo 3: Lógica de Análise e Alerta

Agora que temos os dados, precisamos analisá-los. Um sysadmin quer saber imediatamente se algum serviço está com o estado failed. Vamos criar uma função que filtra e gera um relatório.

    def analyze_services(self):
        """
        Analisa a lista de serviços e identifica anomalias.
        Retorna estatísticas e lista de serviços problemáticos.
        """
        total = len(self.services)
        active_count = 0
        failed_count = 0
        failed_services = []

        for svc in self.services:
            state = svc['state'].lower()
            
            # Verifica se o serviço está ativo e funcionando
            if 'active' in state or 'running' in state:
                active_count += 1
            elif 'failed' in state or 'inactive' in state:
                failed_count += 1
                failed_services.append(svc)

        report = {
            'timestamp': self.timestamp,
            'total_services_scanned': total,
            'active_services': active_count,
            'failed_services': failed_count,
            'problematic_services': failed_services
        }
        
        return report

Passo 4: Formatação de Saída e Execução Principal

Finalmente, implementamos a função que imprime os resultados no terminal de forma legível e define o bloco principal do script.

    def print_report(self, report):
        """
        Imprime o relatório formatado no terminal.
        """
        print("=" * 60)
        print(f"RELATÓRIO DE STATUS DE SERVIÇOS - {report['timestamp']}")
        print("=" * 60)
        
        print(f"Total de Serviços Verificados: {report['total_services_scanned']}")
        print(f"Serviços Ativos:               {report['active_services']}")
        print(f"Serviços com Problemas:        {report['failed_services']}")
        print("-" * 60)

        if report['problematic_services']:
            print("\n[ATENÇÃO] Serviços com falha detectados:")
            for svc in report['problematic_services']:
                print(f"  - Nome: {svc['name']} | Estado: {svc['state']}")
        else:
            print("\n[TUDO OK] Todos os serviços monitorados estão operacionais.")

        print("=" * 60)

    def run(self):
        """
        Método principal que orquestra a execução.
        """
        print("Iniciando verificação de serviços...")
        
        # 1. Obter lista de serviços
        self.services = self.get_service_list()
        
        if not self.services:
            print("Nenhum serviço encontrado ou erro na coleta de dados.")
            sys.exit(1)

        # 2. Analisar dados
        report = self.analyze_services()
        
        # 3. Imprimir resultado
        self.print_report(report)
        
        # Retornar código de saída baseado na presença de falhas
        if report['failed_services'] > 0:
            return 1
        return 0

if __name__ == "__main__":
    monitor = ServiceMonitor()
    exit_code = monitor.run()
    sys.exit(exit_code)

Como Executar o Script

Com o arquivo check_services.py criado, torne-o executável e execute-o. Lembre-se de que a consulta detalhada de serviços pode exigir privilégios elevados.

chmod +x check_services.py
sudo ./check_services.py

A saída esperada será algo similar a:

Iniciando verificação de serviços...
============================================================
RELATÓRIO DE STATUS DE SERVIÇOS - 2023-10-27 14:30:00
============================================================
Total de Serviços Verificados: 45
Serviços Ativos:               42
Serviços com Problemas:        3
------------------------------------------------------------

[ATENÇÃO] Serviços com falha detectados:
  - Nome: postgresql.service | Estado: loaded/failed
  - Nome: docker.service | Estado: loaded/inactive
============================================================

Integração com Ferramentas de Monitoramento

Um script isolado é útil, mas seu verdadeiro poder na automação emerge quando integrado a pipelines maiores. Aqui estão algumas sugestões de como evoluir este código:

  1. Logs Estruturados: Modifique a função print_report para escrever em um arquivo JSON ou syslog, facilitando o consumo por ferramentas como ELK Stack (Elasticsearch, Logstash, Kibana) ou Grafana Loki.
  2. Alertas via Webhook: Adicione uma condição no final do script que dispare uma requisição HTTP POST para o Slack, Discord ou Microsoft Teams se failed_count > 0.
  3. Cron Jobs: Configure um agendamento no crontab para rodar este script a cada 5 minutos, criando um histórico de estabilidade dos serviços.

Exemplo de entrada no crontab para execução a cada 10 minutos:

/10 * * * * /usr/bin/python3 /opt/scripts/check_services.py >> /var/log/service_monitor.log 2>&1

Boas Práticas e Considerações de Segurança

Ao implementar scripts de monitoramento no Linux, considere os seguintes pontos para manter a infraestrutura segura e eficiente:

  • Princípio do Menor Privilégio: Se possível, configure o sudoers para permitir que um usuário específico execute apenas o comando systemctl list-units, sem acesso root total. Isso reduz a superfície de ataque.
  • Tratamento de Erros: O script atual captura exceções básicas, mas em produção, adicione logs detalhados (usando o módulo logging do Python) para diagnosticar falhas na comunicação com o systemd.
  • Timeouts: Em servidores sob alta carga, o comando systemctl pode demorar para responder. Utilize a flag --no-legend e considere adicionar timeouts no subprocesso se a latência for um problema crítico.

Conclusão

Neste tutorial, desenvolvemos um script Python completo para verificar o status de serviços Linux. Utilizamos conceitos fundamentais de scripting, manipulação de subprocessos e parseamento de dados para criar uma ferramenta prática de monitoramento.

Este exemplo demonstra como um sysadmin pode sair da verificação manual reativa e adotar uma postura proativa, utilizando código para garantir a saúde contínua dos serviços. A lógica apresentada pode ser expandida para monitorar recursos de disco, memória ou até mesmo integrar-se com APIs de cloud providers.

Para aprofundar seus conhecimentos em automação de infraestrutura, explore o módulo subprocess da documentação oficial do Python e estude como os serviços systemd funcionam internamente. A combinação de conhecimento profundo do sistema operacional com habilidades de programação é o diferencial de um profissional de TI de alta performance.

Lembre-se: a automação não substitui o julgamento humano, mas libera seu tempo para resolver problemas complexos em vez de apenas monitorar gráficos. Copie, teste e adapte este script às necessidades específicas do seu ambiente Linux.

Compartilhar: Link copiado!
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