matrix-alertbot/matrix_alertbot/alert.py

91 lines
2.6 KiB
Python

from __future__ import annotations
import logging
import re
from typing import Dict, Optional
from jinja2 import (
BaseLoader,
ChoiceLoader,
Environment,
FileSystemLoader,
PackageLoader,
)
logger = logging.getLogger(__name__)
class Alert:
EMOJIS = {"critical": "🔥", "warning": "⚠️", "resolved": "🥦"}
COLORS = {"critical": "dc3545", "warning": "ffc107", "resolved": "33cc33"}
def __init__(
self,
fingerprint: str,
url: str,
labels: Dict[str, str],
annotations: Dict[str, str],
firing: bool = True,
user_id: Optional[str] = None,
):
self.fingerprint = fingerprint
self.url = url
self.firing = firing
self.labels = labels
self.annotations = annotations
self.description = annotations["description"]
if self.firing:
self.status = self.labels.get("severity", "unknown_alert")
else:
self.status = "resolved"
self.user_id = user_id
@staticmethod
def from_dict(data: Dict) -> Alert:
return Alert(
fingerprint=data["fingerprint"],
url=data["generatorURL"],
firing=data["status"] == "firing",
labels=data["labels"],
annotations=data["annotations"],
)
@property
def emoji(self) -> str:
return self.EMOJIS.get(self.status, "❓️")
@property
def color(self) -> str:
return self.COLORS.get(self.status, "ffff0c")
def match_label(self, label_name: str, pattern: re.Pattern[str]) -> bool:
if label_name not in self.labels:
return False
return pattern.match(self.labels[label_name]) is not None
def match_all_labels(self, labels: Dict[str, re.Pattern[str]]) -> bool:
for label_name, pattern in labels.items():
if not self.match_label(label_name, pattern):
return False
return True
class AlertRenderer:
def __init__(self, template_dir: Optional[str] = None) -> None:
loader: BaseLoader = PackageLoader("matrix_alertbot", "resources/templates")
if template_dir is not None:
loader = ChoiceLoader([FileSystemLoader(template_dir), loader])
env = Environment(loader=loader, autoescape=True)
self.html_template = env.get_template("alert.html.j2")
self.text_template = env.get_template("alert.txt.j2")
def render(self, alert: Alert, html: bool = True) -> str:
if html:
template = self.html_template
else:
template = self.text_template
return template.render(vars(alert), color=alert.color, emoji=alert.emoji)