Загрузить файлы в «alert-processor/app/notifications»

This commit is contained in:
2026-08-06 18:36:17 +03:00
parent b13d89fb17
commit f3f5898b4d
3 changed files with 308 additions and 0 deletions
@@ -0,0 +1,192 @@
from __future__ import annotations
from app.config import settings
from app.models import NotificationDecision, ProcessorForwardEnvelope
class NotificationFormatter:
@staticmethod
def format_matrix_message(
envelope: ProcessorForwardEnvelope,
decision: NotificationDecision,
) -> str:
e = envelope.event
ctx = e.zabbix_context or {}
lines = [
f"[{decision.severity or 'UNKNOWN'}] {decision.event_phase.upper()}",
f"Host: {e.host or 'unknown'}",
f"Service: {e.service or 'unknown'}",
f"Trigger: {e.trigger_name or 'unknown'}",
f"Reason: {decision.reason}",
f"Fingerprint: {decision.fingerprint or 'unknown'}",
f"Repeat count: {decision.repeat_count}",
]
if decision.triage_applied:
lines.append(
f"Triage: {decision.triage_verdict or 'unknown'}"
f" ({decision.triage_classification or 'unknown'}, source={decision.triage_source or 'unknown'})"
)
if decision.triage_reason:
lines.append(f"Triage reason: {decision.triage_reason}")
if decision.correlation_applied:
lines.append(
f"Correlation: role={decision.correlation_role or 'unknown'}"
f", kind={decision.correlation_kind or 'unknown'}"
)
if decision.root_cause_candidate:
lines.append(
f"RCA: root cause candidate (related alerts in window: {decision.correlated_event_count})"
)
if decision.parent_event_id:
lines.append(f"Parent event: {decision.parent_event_id}")
if decision.correlation_reason:
lines.append(f"Correlation reason: {decision.correlation_reason}")
if decision.recovered_from_severity:
lines.append(f"Recovered from severity: {decision.recovered_from_severity}")
if decision.flap_detected and decision.flap_reason:
lines.append(f"Flap: {decision.flap_reason}")
if decision.suppressed and decision.suppress_reason:
lines.append(f"Suppress: {decision.suppress_reason}")
if ctx.get("last_value"):
lines.append(f"Last value: {ctx['last_value']}")
if ctx.get("item_key"):
lines.append(f"Item key: {ctx['item_key']}")
if ctx.get("resolved_opdata"):
lines.append(f"OpData: {ctx['resolved_opdata']}")
if decision.remediation_summary:
lines.append(f"Remediation: {decision.remediation_summary}")
if decision.remediation_steps:
lines.append("Steps:")
for idx, step in enumerate(decision.remediation_steps, start=1):
lines.append(f"{idx}. {step}")
if decision.remediation_commands:
lines.append("Commands:")
for cmd in decision.remediation_commands:
lines.append(f"- {cmd}")
if e.event_url:
lines.append(f"Zabbix Event: {e.event_url}")
elif e.zabbix_url:
lines.append(f"Zabbix Event: {e.zabbix_url}")
if e.graph_url:
lines.append(f"Graph: {e.graph_url}")
return "\n".join(lines)
@staticmethod
def format_mail_subject(
envelope: ProcessorForwardEnvelope,
decision: NotificationDecision,
) -> str:
e = envelope.event
phase = decision.event_phase.upper()
severity = decision.severity or e.severity or "UNKNOWN"
host = e.host or "unknown-host"
trigger = e.trigger_name or "unknown-trigger"
return f"{settings.mail_subject_prefix} [{severity}] {phase} {host} :: {trigger}"
@staticmethod
def format_mail_body(
envelope: ProcessorForwardEnvelope,
decision: NotificationDecision,
) -> str:
e = envelope.event
ctx = e.zabbix_context or {}
lines = [
f"Severity: {decision.severity or e.severity or 'UNKNOWN'}",
f"Phase: {decision.event_phase}",
f"Host: {e.host or 'unknown'}",
f"Service: {e.service or 'unknown'}",
f"Trigger: {e.trigger_name or 'unknown'}",
f"Reason: {decision.reason}",
f"Fingerprint: {decision.fingerprint or 'unknown'}",
f"Repeat count: {decision.repeat_count}",
f"Correlation ID: {e.correlation_id}",
f"Event ID: {e.event_id or 'unknown'}",
]
if decision.triage_applied:
lines.append(
f"Triage: {decision.triage_verdict or 'unknown'}"
f" ({decision.triage_classification or 'unknown'}, source={decision.triage_source or 'unknown'})"
)
if decision.triage_reason:
lines.append(f"Triage reason: {decision.triage_reason}")
if decision.correlation_applied:
lines.append(
f"Correlation: role={decision.correlation_role or 'unknown'}"
f", kind={decision.correlation_kind or 'unknown'}"
)
if decision.root_cause_candidate:
lines.append(
f"RCA: root cause candidate (related alerts in window: {decision.correlated_event_count})"
)
if decision.parent_event_id:
lines.append(f"Parent event: {decision.parent_event_id}")
if decision.correlation_reason:
lines.append(f"Correlation reason: {decision.correlation_reason}")
if decision.recovered_from_severity:
lines.append(f"Recovered from severity: {decision.recovered_from_severity}")
if decision.flap_detected and decision.flap_reason:
lines.append(f"Flap reason: {decision.flap_reason}")
if decision.suppressed and decision.suppress_reason:
lines.append(f"Suppress reason: {decision.suppress_reason}")
if ctx.get("last_value"):
lines.append(f"Last value: {ctx['last_value']}")
if ctx.get("item_name"):
lines.append(f"Item name: {ctx['item_name']}")
if ctx.get("item_key"):
lines.append(f"Item key: {ctx['item_key']}")
if ctx.get("resolved_opdata"):
lines.append(f"OpData: {ctx['resolved_opdata']}")
if ctx.get("trigger_comments"):
lines.append(f"Trigger comments: {ctx['trigger_comments']}")
if decision.remediation_summary:
lines.append("")
lines.append(f"Remediation: {decision.remediation_summary}")
if decision.remediation_steps:
lines.append("Steps:")
for idx, step in enumerate(decision.remediation_steps, start=1):
lines.append(f"{idx}. {step}")
if decision.remediation_commands:
lines.append("Commands:")
for cmd in decision.remediation_commands:
lines.append(f"- {cmd}")
if decision.correlation_applied:
lines.append(
f"Correlation: role={decision.correlation_role or 'unknown'}"
f", kind={decision.correlation_kind or 'unknown'}"
f", source={decision.correlation_source or 'unknown'}"
f", confidence={decision.correlation_confidence or 'unknown'}"
)
if e.event_url:
lines.append(f"Zabbix Event URL: {e.event_url}")
elif e.zabbix_url:
lines.append(f"Zabbix Event URL: {e.zabbix_url}")
if e.graph_url:
lines.append(f"Graph URL: {e.graph_url}")
return "\n".join(lines)