Fix: Mail-Alerts per Fingerprint deduplizieren — jede Mail nur einmal melden, nie wiederholen

This commit is contained in:
root 2026-03-09 18:20:12 +07:00
parent 7454db1bc6
commit f7417f6517

View file

@ -11,13 +11,12 @@ sys.path.insert(0, os.path.dirname(__file__))
from core import config, loki_client, proxmox_client, mail_client from core import config, loki_client, proxmox_client, mail_client
ALERT_STATE_FILE = os.path.join(os.path.dirname(__file__), ".alert_state.json") ALERT_STATE_FILE = os.path.join(os.path.dirname(__file__), ".alert_state.json")
ALERT_COOLDOWN_MINUTES = { ALERT_COOLDOWN_SECONDS = {
"mail": 120, "container": 1800,
"container": 30, "ram": 1800,
"ram": 30, "panic": 3600,
"panic": 60, "silence": 3600,
"silence": 60, "default": 3600,
"default": 60,
} }
@ -94,8 +93,26 @@ def check_all() -> list[str]:
mail_client.init(cfg) mail_client.init(cfg)
important = mail_client.get_important_mails(hours=1) important = mail_client.get_important_mails(hours=1)
if important and "error" not in important[0]: if important and "error" not in important[0]:
senders = [m["from"][:30] for m in important] state = _load_alert_state()
alerts.append(f"📧 {len(important)} wichtige Mail(s) (letzte Stunde): {', '.join(senders)}") seen = state.get("seen_mails", {})
now = datetime.now(timezone.utc).timestamp()
new_mails = []
for m in important:
fp = hashlib.md5(
f"{m.get('date_str','')}|{m.get('from','')}|{m.get('subject','')}".encode()
).hexdigest()
if fp not in seen:
new_mails.append(m)
seen[fp] = now
seen = {k: v for k, v in seen.items() if now - v < 172800}
state["seen_mails"] = seen
_save_alert_state(state)
if new_mails:
senders = [m["from"][:30] for m in new_mails]
alerts.append(f"📧 {len(new_mails)} neue wichtige Mail(s): {', '.join(senders)}")
except Exception: except Exception:
pass pass
@ -160,8 +177,6 @@ def _alert_key(alert_text: str) -> str:
def _alert_category(alert_text: str) -> str: def _alert_category(alert_text: str) -> str:
if "📧" in alert_text or "Mail" in alert_text:
return "mail"
if "CT " in alert_text and "ist " in alert_text: if "CT " in alert_text and "ist " in alert_text:
return "container" return "container"
if "RAM " in alert_text: if "RAM " in alert_text:
@ -174,24 +189,26 @@ def _alert_category(alert_text: str) -> str:
def _filter_new_alerts(alerts: list[str]) -> list[str]: def _filter_new_alerts(alerts: list[str]) -> list[str]:
"""Filtert bereits gemeldete Alerts. Gibt nur neue/fällige zurück.""" """Filtert bereits gemeldete Infra-Alerts per Cooldown. Mails werden separat in check_all() dedupliziert."""
state = _load_alert_state() state = _load_alert_state()
now = datetime.now(timezone.utc).timestamp() now = datetime.now(timezone.utc).timestamp()
cooldowns = state.get("alert_cooldowns", {})
new_alerts = [] new_alerts = []
for alert in alerts: for alert in alerts:
key = _alert_key(alert) key = _alert_key(alert)
cat = _alert_category(alert) cat = _alert_category(alert)
cooldown = ALERT_COOLDOWN_MINUTES.get(cat, 60) * 60 cooldown = ALERT_COOLDOWN_SECONDS.get(cat, 3600)
last_sent = state.get(key, {}).get("ts", 0) last_sent = cooldowns.get(key, {}).get("ts", 0)
if now - last_sent > cooldown: if now - last_sent > cooldown:
new_alerts.append(alert) new_alerts.append(alert)
state[key] = {"ts": now, "text": alert[:80], "cat": cat} cooldowns[key] = {"ts": now, "text": alert[:80], "cat": cat}
cutoff = now - 86400 cutoff = now - 86400
state = {k: v for k, v in state.items() if v.get("ts", 0) > cutoff} cooldowns = {k: v for k, v in cooldowns.items() if v.get("ts", 0) > cutoff}
state["alert_cooldowns"] = cooldowns
_save_alert_state(state) _save_alert_state(state)
return new_alerts return new_alerts