Files
LinuxAwesomeBot/alerter.py
T

85 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""后台高负载告警任务。"""
import asyncio
import logging
import time
import monitor
log = logging.getLogger("alerter")
class Alerter:
def __init__(self, ob, cfg: dict):
self.ob = ob
self.cfg = cfg
self.interval = cfg.get("interval", 10)
self.threshold = cfg.get("cpu_threshold", 85.0)
self.consecutive_need = cfg.get("consecutive", 2)
self.cooldown = cfg.get("cooldown", 600)
self.top_n = cfg.get("top_n", 5)
self.groups = cfg.get("groups", []) or []
self.friends = cfg.get("friends", []) or []
self._consecutive = 0
self._alerting = False # 当前是否处于高负载状态
self._last_alert_ts = 0.0
self._task = None
def start(self):
self._task = asyncio.get_running_loop().create_task(self._loop())
async def stop(self):
if self._task:
self._task.cancel()
async def _loop(self):
log.info("告警监控已启动: 阈值 %.0f%%, 连续 %d 次, 间隔 %ds, 冷却 %ds",
self.threshold, self.consecutive_need, self.interval, self.cooldown)
while True:
try:
await asyncio.sleep(self.interval)
if not self.ob.connected or (not self.groups and not self.friends):
continue
cpu = monitor.get_cpu()
await self._check(cpu["percent"])
except asyncio.CancelledError:
break
except Exception:
log.exception("告警循环出错")
async def _check(self, cpu_percent: float):
now = time.monotonic()
if cpu_percent >= self.threshold:
self._consecutive += 1
if (self._consecutive >= self.consecutive_need
and (not self._alerting or now - self._last_alert_ts >= self.cooldown)):
self._alerting = True
self._last_alert_ts = now
await self._send_alert(cpu_percent)
else:
self._consecutive = 0
if self._alerting:
self._alerting = False
msg = (f"✅ [恢复] 服务器 CPU 已回落到 {cpu_percent:.1f}%,"
f"负载恢复正常。")
log.info(msg)
await self.ob.broadcast(msg, self.groups, self.friends)
async def _send_alert(self, cpu_percent: float):
top = monitor.get_top_processes(self.top_n)
cpu = monitor.get_cpu()
load = cpu["load"]
lines = [
f"⚠️ [高负载告警] CPU 持续超过 {self.threshold:.0f}%,当前 {cpu_percent:.1f}%",
f"负载: {load[0]:.2f} / {load[1]:.2f} / {load[2]:.2f} 核心: {cpu['cores']}",
"",
f"TOP{self.top_n} 高负载进程:",
]
for i, p in enumerate(top, 1):
lines.append(
f"{i}. {p['name']} (PID {p['pid']}) CPU {p['cpu']}% 内存 {p['mem_mb']}MB"
)
msg = "\n".join(lines)
log.warning("触发高负载告警: %.1f%%", cpu_percent)
await self.ob.broadcast(msg, self.groups, self.friends)