import os import psutil import time import json import httpx import subprocess from dotenv import load_dotenv load_dotenv() TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") CHAT_ID = os.getenv("TELEGRAM_CHAT_ID") # Configurações do Watchdog CPU_THRESHOLD = 90.0 CPU_STREAK_LIMIT = 6 # 6 * 10s = 60s CHECK_INTERVAL = 10 # segundos class Watchdog: def __init__(self): self.cpu_streak = 0 self.last_alert_time = 0 self.alert_cooldown = 300 # 5 minutos entre alertas do mesmo tipo self.previous_status = {} # Guarda o último estado conhecido de cada processo async def send_telegram_message(self, message: str): if not TOKEN or not CHAT_ID: print("[WATCHDOG] Erro: TOKEN ou CHAT_ID não configurados.") return url = f"https://api.telegram.org/bot{TOKEN}/sendMessage" payload = { "chat_id": CHAT_ID, "text": f"🚨 **[WATCHDOG VPS]**\n\n{message}", "parse_mode": "Markdown" } try: async with httpx.AsyncClient() as client: await client.post(url, json=payload) except Exception as e: print(f"[WATCHDOG] Erro ao enviar Telegram: {e}") def monitor_pm2(self): try: result = subprocess.run(["pm2", "jlist"], capture_output=True, text=True) if result.returncode == 0: data = json.loads(result.stdout) alerts = [] for proc in data: name = proc['name'] current_status = proc['pm2_env']['status'] prev_status = self.previous_status.get(name) # Detecta Queda (Transição de online para qualquer outra coisa) if current_status != 'online' and prev_status == 'online': alerts.append(f"🔴 App '{name}' ACABOU DE CAIR! (Status: {current_status})") # Detecta Recuperação (Transição de offline para online) elif current_status == 'online' and prev_status is not None and prev_status != 'online': alerts.append(f"🟢 App '{name}' ESTÁ ONLINE NOVAMENTE! 🚀") # Atualiza memória de estado self.previous_status[name] = current_status return alerts except Exception as e: print(f"[WATCHDOG] Erro PM2: {e}") return [] async def run(self): print("[WATCHDOG] Iniciado. Vigilância ativa (Ciclagem Online/Offline)...") while True: try: # 1. Monitoramento de CPU cpu_usage = psutil.cpu_percent(interval=1) if cpu_usage > CPU_THRESHOLD: self.cpu_streak += 1 else: self.cpu_streak = 0 if self.cpu_streak >= CPU_STREAK_LIMIT: if time.time() - self.last_alert_time > self.alert_cooldown: await self.send_telegram_message( f"CPU em nível crítico: {cpu_usage}% por mais de 1 minuto!" ) self.last_alert_time = time.time() # 2. Monitoramento de PM2 (Alertas de mudança de estado) pm2_alerts = self.monitor_pm2() if pm2_alerts: await self.send_telegram_message("\n".join(pm2_alerts)) # 3. Monitoramento de Espaço em Disco disk = psutil.disk_usage('/') if disk.percent > 95: if time.time() - self.last_alert_time > self.alert_cooldown: await self.send_telegram_message(f"Espaço em disco crítico: {disk.percent}% ocupado!") self.last_alert_time = time.time() await asyncio.sleep(CHECK_INTERVAL) except Exception as e: print(f"[WATCHDOG] Erro no loop: {e}") await asyncio.sleep(CHECK_INTERVAL) if __name__ == "__main__": import asyncio dog = Watchdog() asyncio.run(dog.run())