Overview

3 AM. Your phone buzzes. You get out of bed, open your laptop, SSH in, and find a service with CPU spiking. Kill the process, restart the service, 12 minutes done — but you’re wide awake now. 4:30 AM, another alert: disk usage exceeds 85%. Get up again, du -sh to locate, delete old logs, 15 minutes.

This is the daily reality for countless operations engineers. Monitoring is set up, alerts are configured, scripts are written — but the final step still relies on humans. And it always happens at 3 AM.

According to Google’s SRE Book, a typical SRE team receives 50-100 alerts per day, 80% of which are noise, and over 60% are known issues that have been handled before.

The goal of alert automation is not to eliminate alerts, but to transform human judgment and actions into automated system responses. This article systematically covers how to build an alert automation system across five dimensions: noise reduction, severity-based routing, Runbook automation, self-healing platform architecture, and AI-assisted governance.

The Alert Problem: Why Automation Is Needed

Root Causes of Alert Storms

Alert storms are usually not caused by insufficient monitoring, but by monitoring over-proliferation. Here are the most common alert problem patterns in production:

Problem PatternTypical SymptomsRoot Cause
Alert flooding100+ alerts/day, 80% require no actionOversensitive static thresholds, no aggregation/dedup
Alert fatigueEngineers ignore notifications, real incidents buriedLow signal-to-noise ratio, no priority classification
Duplicate alertsSame issue triggers multiple alerts from different monitorsNo alert correlation/aggregation mechanism
Response delay15-30 min average from alert to human actionNo automated response, manual intervention required
Repetitive labor60%+ of alerts follow identical handling proceduresKnown operations not codified as automated Runbooks

The Five Stages of Alert Lifecycle

A mature alert automation system should cover the complete alert lifecycle:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  1. Detect   │────▶│  2. Dedup   │────▶│  3. Route   │────▶│  4. Remediate│────▶│  5. Review  │
│  Detection  │     │  Dedup      │     │  Route     │     │  Remediate │     │  Review    │
└─────────────┘     └─────────────┘     └─────────────┘     └─────────────┘     └─────────────┘
     │                    │                   │                   │                   │
  Monitor           Dedup/Aggregate     Severity/Dispatch    AutoRunbook/Human    Archive/Improve
  1. Detection: Monitoring systems (Prometheus, Zabbix, Datadog, etc.) detect anomalies and generate raw alerts
  2. Noise Reduction: Deduplication, aggregation, and suppression compress alert storms into manageable events
  3. Routing: Distribute alerts to correct channels based on severity, service ownership, and on-call schedules
  4. Remediation: Automatically execute Runbooks or involve human intervention
  5. Review: Record handling process, measure effectiveness, continuously improve alert rules and automation scripts

Alert Noise Reduction: From Noise to Signal

Alert Deduplication and Aggregation

Alertmanager is the most commonly used alert management component in the Prometheus ecosystem, offering powerful noise reduction capabilities.

Grouping

Merging related alerts into a single notification to prevent alert storms:

# alertmanager.yml — Grouping configuration
route:
  group_by: ['alertname', 'cluster', 'service']
  group_wait: 30s        # Wait 30s after first alert, collecting same-group alerts
  group_interval: 5m     # Send interval for same-group alerts
  repeat_interval: 4h    # Repeat notification interval for unresolved alerts
  receiver: 'default'

receivers:
  - name: 'default'
    webhook_configs:
      - url: 'http://alert-router:8080/alert'

The key to grouping strategy is selecting the right group_by dimensions:

Scenariogroup_by ConfigurationEffect
Multi-instance service failure['alertname', 'cluster', 'service']Merge multi-instance alerts for same service
Infrastructure-level failure['alertname', 'cluster']Merge infrastructure alerts for same cluster
Single node failure['alertname', 'instance']Merge multi-dimensional alerts for same node
Global failure['alertname']Merge all alerts with same name

Inhibition

Automatically suppress lower-level alerts when higher-level alerts fire:

# alertmanager.yml — Inhibition rules
inhibit_rules:
  # When a node is down, suppress all service alerts for that node
  - source_match:
      alertname: 'NodeDown'
    target_match_re:
      alertname: '.*(Service|Pod|Container).*Down|CrashLoopBackOff'
    equal: ['instance']

  # When cluster is unavailable, suppress all alerts for that cluster
  - source_match:
      severity: 'critical'
      alertname: 'ClusterUnavailable'
    target_match_re:
      severity: 'warning|info'
    equal: ['cluster']

  # During MySQL master switch, suppress replica lag alerts
  - source_match:
      alertname: 'MySQLMasterSwitch'
    target_match:
      alertname: 'MySQLReplicationLag'
    equal: ['cluster', 'service']

Alert Fingerprint Deduplication

For alerts from multiple monitoring systems, fingerprint-based deduplication is needed at the alert routing layer:

#!/usr/bin/env python3
"""Alert fingerprint deduplication engine — generates unique fingerprints for cross-system dedup"""

import hashlib
import time
from dataclasses import dataclass, field
from typing import Optional

@dataclass
class Alert:
    """Alert data structure"""
    alertname: str
    severity: str
    service: str
    instance: str
    cluster: str
    message: str
    labels: dict = field(default_factory=dict)
    fingerprint: str = ""
    first_seen: float = 0
    last_seen: float = 0
    count: int = 0

    def compute_fingerprint(self) -> str:
        """Compute alert fingerprint (based on structural fields, ignoring timestamps and dynamic values)"""
        key_fields = f"{self.alertname}:{self.service}:{self.instance}:{self.cluster}:{self.severity}"
        return hashlib.md5(key_fields.encode()).hexdigest()[:16]

class AlertDeduplicator:
    """Alert deduplicator"""

    def __init__(self, dedup_window: int = 300):
        """
        Args:
            dedup_window: Dedup window (seconds), same fingerprint only kept once within window
        """
        self.dedup_window = dedup_window
        self.alert_store: dict[str, Alert] = {}  # fingerprint -> Alert

    def process(self, alert: Alert) -> Optional[Alert]:
        """
        Process alert, return alert to send (after dedup)
        Returns None if alert is duplicate and suppressed
        """
        alert.fingerprint = alert.compute_fingerprint()
        now = time.time()

        if alert.fingerprint in self.alert_store:
            existing = self.alert_store[alert.fingerprint]
            existing.last_seen = now
            existing.count += 1

            # Within dedup window, suppress duplicate
            if now - existing.first_seen < self.dedup_window:
                return None  # Suppress
            else:
                # Beyond dedup window, treat as new alert
                existing.first_seen = now
                existing.count = 1
                return existing
        else:
            alert.first_seen = now
            alert.last_seen = now
            alert.count = 1
            self.alert_store[alert.fingerprint] = alert
            return alert

    def get_active_alerts(self) -> list[Alert]:
        """Get currently active alert list"""
        now = time.time()
        return [
            a for a in self.alert_store.values()
            if now - a.last_seen < self.dedup_window * 2
        ]

    def cleanup(self, max_age: int = 3600):
        """Clean up expired alert records"""
        now = time.time()
        expired = [
            fp for fp, alert in self.alert_store.items()
            if now - alert.last_seen > max_age
        ]
        for fp in expired:
            del self.alert_store[fp]

if __name__ == "__main__":
    dedup = AlertDeduplicator(dedup_window=300)

    # Simulate alert storm
    alerts = [
        Alert("HighCPU", "warning", "api-gw", "10.0.1.1", "prod", "CPU 92%"),
        Alert("HighCPU", "warning", "api-gw", "10.0.1.1", "prod", "CPU 95%"),  # Duplicate
        Alert("HighCPU", "warning", "api-gw", "10.0.1.1", "prod", "CPU 98%"),  # Duplicate
        Alert("HighMemory", "critical", "api-gw", "10.0.1.1", "prod", "Memory 95%"),
        Alert("DiskFull", "critical", "db", "10.0.2.1", "prod", "Disk 85%"),
    ]

    for alert in alerts:
        result = dedup.process(alert)
        if result:
            print(f"[SEND] {alert.alertname} | {alert.service} | {alert.instance} | fp={alert.fingerprint}")
        else:
            print(f"[SUPPRESS] {alert.alertname} | {alert.service} | {alert.instance} | duplicate")

    print(f"\nActive alerts: {len(dedup.get_active_alerts())}")

Silence Management

Temporarily silence specific alerts during maintenance windows:

# alertmanager.yml — Silence rules (can also be created dynamically via API)
# Create silence via API
# curl -X POST http://alertmanager:9093/api/v2/silences \
#   -H "Content-Type: application/json" \
#   -d '{
#     "matchers": [
#       {"name": "service", "value": "payment-service", "isRegex": false}
#     ],
#     "startsAt": "2026-07-11T02:00:00+08:00",
#     "endsAt": "2026-07-11T04:00:00+08:00",
#     "createdBy": "ops-team",
#     "comment": "Database maintenance window"
#   }'

Automated silence management script:

#!/bin/bash
# schedule-silence.sh — Auto-create alert silence (for maintenance windows)

ALERTMANAGER="http://alertmanager:9093"
SERVICE="${1:-payment-service}"
DURATION="${2:-120}"  # minutes

START_TIME=$(date -u -d "+1 minute" '+%Y-%m-%dT%H:%M:%S.000Z')
END_TIME=$(date -u -d "+${DURATION} minutes" '+%Y-%m-%dT%H:%M:%S.000Z')

curl -s -X POST "${ALERTMANAGER}/api/v2/silences" \
  -H "Content-Type: application/json" \
  -d "{
    \"matchers\": [
      {\"name\": \"service\", \"value\": \"${SERVICE}\", \"isRegex\": false}
    ],
    \"startsAt\": \"${START_TIME}\",
    \"endsAt\": \"${END_TIME}\",
    \"createdBy\": \"automation\",
    \"comment\": \"Auto-silence: ${SERVICE} maintenance ${DURATION}min\"
  }"

echo "Created ${DURATION}min silence window for ${SERVICE}"

Multi-Dimensional Alert Correlation

When multiple monitoring systems (Prometheus, ELK, APM) produce alerts simultaneously, they need to be correlated into a single event:

#!/usr/bin/env python3
"""Multi-dimensional alert correlation engine — correlates alerts from different sources into events"""

import time
from dataclasses import dataclass, field
from typing import Optional
from collections import defaultdict

@dataclass
class AlertEvent:
    """Correlated alert event"""
    event_id: str
    service: str
    cluster: str
    severity: str  # Takes highest severity
    alerts: list = field(default_factory=list)
    first_seen: float = 0
    last_seen: float = 0
    status: str = "firing"  # firing / resolved

    def add_alert(self, alert: dict):
        self.alerts.append(alert)
        self.last_seen = time.time()
        severity_order = {"info": 0, "warning": 1, "critical": 2, "fatal": 3}
        if severity_order.get(alert.get("severity", "info"), 0) > \
           severity_order.get(self.severity, 0):
            self.severity = alert["severity"]

class AlertCorrelator:
    """Alert correlator — correlates alerts based on service, cluster, time window"""

    CORRELATION_WINDOW = 300  # 5-minute window

    def __init__(self):
        self.events: dict[str, AlertEvent] = {}  # correlation_key -> AlertEvent

    def _correlation_key(self, alert: dict) -> str:
        """Generate correlation key"""
        service = alert.get("labels", {}).get("service", "unknown")
        cluster = alert.get("labels", {}).get("cluster", "unknown")
        return f"{service}:{cluster}"

    def process(self, alert: dict) -> Optional[AlertEvent]:
        """Process alert, return correlated event"""
        key = self._correlation_key(alert)
        now = time.time()

        if key in self.events:
            event = self.events[key]
            # Check if within correlation window
            if now - event.last_seen <= self.CORRELATION_WINDOW:
                event.add_alert(alert)
                return event
            else:
                # Window expired, create new event
                event.status = "resolved"

        # Create new event
        event_id = f"EVT-{int(now)}-{key.replace(':', '-')}"
        event = AlertEvent(
            event_id=event_id,
            service=alert.get("labels", {}).get("service", "unknown"),
            cluster=alert.get("labels", {}).get("cluster", "unknown"),
            severity=alert.get("severity", "info"),
            first_seen=now,
            last_seen=now,
        )
        event.add_alert(alert)
        self.events[key] = event
        return event

if __name__ == "__main__":
    correlator = AlertCorrelator()

    # Simulate multi-source alerts
    raw_alerts = [
        {"alertname": "HighCPU", "severity": "warning",
         "labels": {"service": "api-gw", "cluster": "prod"}},
        {"alertname": "HighLatency", "severity": "critical",
         "labels": {"service": "api-gw", "cluster": "prod"}},  # Correlated
        {"alertname": "ErrorRateHigh", "severity": "critical",
         "labels": {"service": "api-gw", "cluster": "prod"}},  # Correlated
        {"alertname": "DiskFull", "severity": "critical",
         "labels": {"service": "db", "cluster": "prod"}},       # Different service
    ]

    for alert in raw_alerts:
        event = correlator.process(alert)
        print(f"Alert: {alert['alertname']:20s} → Event: {event.event_id} | "
              f"Severity: {event.severity:8s} | Correlated: {len(event.alerts)}")

Alert Severity Classification and Routing

Severity Classification Standards

Establishing unified alert severity standards is the prerequisite for automated routing:

LevelDefinitionResponse TimeExampleHandling
P0 - CriticalCore service unavailableImmediate (< 1 min)Production DB down, API fully unavailablePhone+SMS+IM, all-hands
P1 - HighCore service degradedWithin 5 minAPI error rate > 5%, P99 latency doubledSMS+IM, on-call engineer
P2 - MediumNon-core service abnormalWithin 30 minTest env service down, disk > 80%IM, handle during work hours
P3 - LowWarning informationWork hoursDisk > 70%, cert 30 days to expiryEmail/IM, create ticket

Alert Routing Rule Design

#!/usr/bin/env python3
"""Alert routing engine — rule-based alert classification and dispatch"""

import re
import json
from dataclasses import dataclass, field
from typing import Optional
from enum import Enum

class Severity(Enum):
    P0 = "critical"
    P1 = "high"
    P2 = "medium"
    P3 = "low"

@dataclass
class RouteRule:
    """Routing rule"""
    name: str
    match_labels: dict           # Labels to match
    match_severity: list[str]    # Severities to match
    receivers: list[str]         # Receiver list
    escalate_after: int = 0     # Escalation time if no response (seconds)
    escalate_to: list[str] = field(default_factory=list)  # Escalation receivers
    auto_remediation: str = ""   # Associated auto-remediation Runbook

class AlertRouter:
    """Alert router"""

    def __init__(self):
        self.rules: list[RouteRule] = []
        self.default_receivers = ["on-call-team"]

    def add_rule(self, rule: RouteRule):
        self.rules.append(rule)

    def route(self, alert: dict) -> dict:
        """Route alert to correct receivers and handling flow"""
        severity = alert.get("severity", "info")
        labels = alert.get("labels", {})

        for rule in self.rules:
            if self._match(alert, rule):
                return {
                    "alert": alert,
                    "severity": severity,
                    "receivers": rule.receivers,
                    "escalate_after": rule.escalate_after,
                    "escalate_to": rule.escalate_to,
                    "auto_remediation": rule.auto_remediation,
                    "routed_at": alert.get("startsAt", ""),
                }

        return {
            "alert": alert,
            "severity": severity,
            "receivers": self.default_receivers,
            "escalate_after": 0,
            "escalate_to": [],
            "auto_remediation": "",
            "routed_at": alert.get("startsAt", ""),
        }

    def _match(self, alert: dict, rule: RouteRule) -> bool:
        """Check if alert matches routing rule"""
        severity = alert.get("severity", "info")
        labels = alert.get("labels", {})

        if rule.match_severity and severity not in rule.match_severity:
            return False

        for key, value in rule.match_labels.items():
            if key not in labels:
                return False
            if isinstance(value, str) and value.startswith("~"):
                pattern = value[1:]
                if not re.match(pattern, str(labels.get(key, ""))):
                    return False
            elif str(labels.get(key, "")) != str(value):
                return False

        return True

if __name__ == "__main__":
    router = AlertRouter()

    # Define routing rules
    router.add_rule(RouteRule(
        name="Database P0",
        match_labels={"service": "mysql", "cluster": "prod"},
        match_severity=[Severity.P0.value],
        receivers=["on-call-dba", "on-call-sre", "tech-lead"],
        escalate_after=300,  # Escalate after 5 min no response
        escalate_to=["cto", "vp-engineering"],
        auto_remediation="runbook:mysql-failover",
    ))

    router.add_rule(RouteRule(
        name="API Service P1",
        match_labels={"service": "~api-.*", "cluster": "prod"},
        match_severity=[Severity.P1.value, Severity.P0.value],
        receivers=["on-call-sre"],
        escalate_after=600,
        escalate_to=["tech-lead"],
        auto_remediation="runbook:api-restart",
    ))

    router.add_rule(RouteRule(
        name="Disk Space Warning",
        match_labels={"alertname": "DiskSpaceWarning"},
        match_severity=[Severity.P2.value, Severity.P3.value],
        receivers=["ops-team-im"],
        escalate_after=0,
        auto_remediation="runbook:disk-cleanup",
    ))

    # Test routing
    test_alerts = [
        {"alertname": "MySQLDown", "severity": "critical",
         "labels": {"service": "mysql", "cluster": "prod"},
         "startsAt": "2026-07-11T02:25:59+08:00"},
        {"alertname": "HighErrorRate", "severity": "high",
         "labels": {"service": "api-gateway", "cluster": "prod"},
         "startsAt": "2026-07-11T02:25:59+08:00"},
        {"alertname": "DiskSpaceWarning", "severity": "medium",
         "labels": {"service": "web", "cluster": "prod", "instance": "10.0.1.5"},
         "startsAt": "2026-07-11T02:25:59+08:00"},
    ]

    for alert in test_alerts:
        result = router.route(alert)
        print(f"\nAlert: {alert['alertname']} ({alert['severity']})")
        print(f"  Receivers: {result['receivers']}")
        print(f"  Auto-remediation: {result['auto_remediation']}")
        print(f"  Escalation: {result['escalate_after']}s → {result['escalate_to']}")

Escalation Mechanism

Automatically escalate alerts when not acknowledged within specified time:

#!/usr/bin/env python3
"""Alert escalation manager — tracks alert response status, auto-escalates on timeout"""

import time
import threading
from dataclasses import dataclass, field

@dataclass
class EscalationPolicy:
    """Escalation policy"""
    initial_receivers: list[str]
    escalate_after: int           # seconds
    escalate_to: list[str]        # escalation receivers
    max_escalations: int = 3      # max escalation levels
    auto_resolve_on_action: bool = True  # stop escalation on acknowledgment

@dataclass
class AlertEscalation:
    """Alert escalation tracking"""
    alert_id: str
    policy: EscalationPolicy
    created_at: float
    acknowledged: bool = False
    current_level: int = 0
    escalation_history: list = field(default_factory=list)

    def acknowledge(self, user: str):
        self.acknowledged = True
        self.escalation_history.append({
            "action": "acknowledged",
            "user": user,
            "timestamp": time.time(),
        })

    def escalate(self) -> list[str]:
        """Execute escalation, return new receiver list"""
        if self.acknowledged:
            return []

        self.current_level += 1
        if self.current_level > self.policy.max_escalations:
            return ["final-escalation", "cto"]

        receivers = self.policy.escalate_to[:self.current_level]
        self.escalation_history.append({
            "action": "escalated",
            "level": self.current_level,
            "receivers": receivers,
            "timestamp": time.time(),
        })
        return receivers

class EscalationManager:
    """Alert escalation manager"""

    def __init__(self):
        self.tracked: dict[str, AlertEscalation] = {}
        self._timer: threading.Timer = None

    def track(self, alert_id: str, policy: EscalationPolicy):
        """Start tracking alert escalation"""
        escalation = AlertEscalation(
            alert_id=alert_id,
            policy=policy,
            created_at=time.time(),
        )
        self.tracked[alert_id] = escalation

        # Set escalation timer
        timer = threading.Timer(
            policy.escalate_after,
            self._check_escalation,
            args=[alert_id]
        )
        timer.daemon = True
        timer.start()

    def _check_escalation(self, alert_id: str):
        """Check if escalation is needed"""
        if alert_id not in self.tracked:
            return

        escalation = self.tracked[alert_id]
        if escalation.acknowledged:
            return

        new_receivers = escalation.escalate()
        if new_receivers:
            print(f"[ESCALATE] Alert {alert_id} → level {escalation.current_level}")
            print(f"  New receivers: {new_receivers}")
            # Trigger actual notification sending here

    def acknowledge(self, alert_id: str, user: str):
        """Acknowledge alert"""
        if alert_id in self.tracked:
            self.tracked[alert_id].acknowledge(user)
            print(f"[ACK] Alert {alert_id} acknowledged by {user}")

if __name__ == "__main__":
    manager = EscalationManager()

    policy = EscalationPolicy(
        initial_receivers=["on-call-sre"],
        escalate_after=5,  # 5 seconds (demo, should be 300-600 in production)
        escalate_to=["tech-lead", "vp-engineering", "cto"],
        max_escalations=3,
    )

    manager.track("EVT-001", policy)
    print("Alert tracked, awaiting response...")
    print("(Not acknowledged, auto-escalating in 5 seconds)")

    time.sleep(8)  # Wait for escalation trigger

    # Simulate acknowledgment
    # manager.acknowledge("EVT-001", "John")

Runbook Automation

Runbook Registry Design

Runbooks are the core of alert automation — encoding known fault handling procedures into automatically executable scripts:

#!/usr/bin/env python3
"""Runbook registry — manages and executes automated remediation scripts"""

import subprocess
import logging
import time
import json
import os
from dataclasses import dataclass, field
from typing import Optional, Callable
from enum import Enum

logger = logging.getLogger(__name__)

class RunbookStatus(Enum):
    SUCCESS = "success"
    FAILED = "failed"
    PARTIAL = "partial"
    SKIPPED = "skipped"

class RunbookRisk(Enum):
    SAFE = "safe"           # Safe operation, auto-execute
    CAUTION = "caution"     # Use with caution, recommend human confirmation
    DANGEROUS = "dangerous" # High risk, must confirm manually

@dataclass
class RunbookResult:
    """Runbook execution result"""
    runbook_name: str
    status: RunbookStatus
    message: str
    execution_time: float
    output: str = ""
    actions_taken: list = field(default_factory=list)

@dataclass
class Runbook:
    """Runbook definition"""
    name: str
    description: str
    risk_level: RunbookRisk
    match_conditions: dict       # Alert conditions to match
    handler: Callable            # Handler function
    max_retries: int = 1        # Max retry count
    timeout: int = 60           # Timeout (seconds)
    cooldown: int = 300         # Cooldown between executions (seconds)
    last_executed: float = 0    # Last execution timestamp

    def matches(self, alert: dict) -> bool:
        """Check if alert matches this Runbook"""
        labels = alert.get("labels", {})
        for key, value in self.match_conditions.items():
            if key not in labels:
                return False
            if str(labels[key]) != str(value):
                return False
        return True

    def can_execute(self) -> bool:
        """Check if can execute (cooldown check)"""
        if self.last_executed == 0:
            return True
        return time.time() - self.last_executed >= self.cooldown

    def execute(self, alert: dict) -> RunbookResult:
        """Execute the Runbook"""
        if not self.can_execute():
            return RunbookResult(
                runbook_name=self.name,
                status=RunbookStatus.SKIPPED,
                message=f"Runbook in cooldown ({self.cooldown}s)",
                execution_time=0,
            )

        self.last_executed = time.time()
        start = time.time()

        for attempt in range(self.max_retries + 1):
            try:
                result = self.handler(alert)
                elapsed = time.time() - start

                if result.get("success", False):
                    return RunbookResult(
                        runbook_name=self.name,
                        status=RunbookStatus.SUCCESS,
                        message=result.get("message", "Success"),
                        execution_time=elapsed,
                        output=result.get("output", ""),
                        actions_taken=result.get("actions", []),
                    )
                else:
                    if attempt < self.max_retries:
                        logger.warning(f"Runbook {self.name} attempt {attempt+1} failed, retrying...")
                        time.sleep(2 ** attempt)  # Exponential backoff
                    else:
                        return RunbookResult(
                            runbook_name=self.name,
                            status=RunbookStatus.FAILED,
                            message=result.get("message", "Failed"),
                            execution_time=elapsed,
                            output=result.get("output", ""),
                            actions_taken=result.get("actions", []),
                        )
            except Exception as e:
                elapsed = time.time() - start
                logger.error(f"Runbook {self.name} exception: {e}")
                if attempt >= self.max_retries:
                    return RunbookResult(
                        runbook_name=self.name,
                        status=RunbookStatus.FAILED,
                        message=f"Exception: {str(e)}",
                        execution_time=elapsed,
                    )
                time.sleep(2 ** attempt)

        return RunbookResult(
            runbook_name=self.name,
            status=RunbookStatus.FAILED,
            message="Retries exhausted",
            execution_time=time.time() - start,
        )

class RunbookRegistry:
    """Runbook registry"""

    def __init__(self):
        self.runbooks: list[Runbook] = []
        self.execution_history: list[dict] = []

    def register(self, runbook: Runbook):
        """Register a Runbook"""
        self.runbooks.append(runbook)
        logger.info(f"Registered Runbook: {runbook.name} (risk: {runbook.risk_level.value})")

    def find_and_execute(self, alert: dict, auto_execute: bool = True) -> Optional[RunbookResult]:
        """Find matching Runbook and execute"""
        for runbook in self.runbooks:
            if runbook.matches(alert):
                if not auto_execute and runbook.risk_level != RunbookRisk.SAFE:
                    logger.info(f"Runbook {runbook.name} risk level {runbook.risk_level.value}, needs confirmation")
                    return RunbookResult(
                        runbook_name=runbook.name,
                        status=RunbookStatus.SKIPPED,
                        message=f"Risk level {runbook.risk_level.value}, awaiting confirmation",
                        execution_time=0,
                    )

                logger.info(f"Executing Runbook: {runbook.name}")
                result = runbook.execute(alert)

                # Record execution history
                self.execution_history.append({
                    "timestamp": time.time(),
                    "runbook": runbook.name,
                    "alert": alert.get("alertname", ""),
                    "status": result.status.value,
                    "message": result.message,
                    "execution_time": result.execution_time,
                    "actions": result.actions_taken,
                })

                return result

        return None

# ====== Six Auto-Remediation Scenarios ======

def handle_high_cpu(alert: dict) -> dict:
    """Scenario 1: High CPU — restart process or scale"""
    instance = alert.get("labels", {}).get("instance", "")
    service = alert.get("labels", {}).get("service", "")

    actions = []

    # Step 1: Collect diagnostic info
    actions.append(f"Collecting top processes on {instance}")
    top_output = subprocess.run(
        ["ssh", instance, "top", "-b", "-n", "1"],
        capture_output=True, text=True, timeout=10
    ).stdout

    # Step 2: Identify high CPU process
    actions.append("Analyzing high CPU processes")
    if "runaway_worker" in top_output:
        # Step 3: Restart service
        actions.append(f"Restarting service {service} on {instance}")
        subprocess.run(
            ["ssh", instance, "systemctl", "restart", service],
            timeout=30
        )
        return {"success": True, "message": f"Restarted {service} on {instance}", "actions": actions}

    return {"success": False, "message": "No anomalous process identified, needs manual investigation", "actions": actions}

def handle_disk_full(alert: dict) -> dict:
    """Scenario 2: Disk full — clean expired logs and temp files"""
    instance = alert.get("labels", {}).get("instance", "")
    partition = alert.get("labels", {}).get("partition", "/")

    actions = []

    # Find large files
    actions.append(f"Scanning large files on {instance}:{partition}")
    du_output = subprocess.run(
        ["ssh", instance, "du", "-sh", f"{partition}/*"],
        capture_output=True, text=True, timeout=30
    ).stdout

    # Cleanup strategy
    cleanup_dirs = ["/var/log", "/tmp", "/var/cache/apt/archives"]
    total_cleaned = 0

    for dir_path in cleanup_dirs:
        if dir_path.startswith(partition):
            actions.append(f"Cleaning files older than 7 days in {dir_path}")
            result = subprocess.run(
                ["ssh", instance, "find", dir_path, "-type", "f", "-mtime", "+7", "-delete"],
                capture_output=True, text=True, timeout=60
            )
            actions.append(f"Cleaned {dir_path}")

    # Clean Docker unused images
    actions.append("Cleaning Docker unused images and containers")
    subprocess.run(
        ["ssh", instance, "docker", "system", "prune", "-f"],
        capture_output=True, text=True, timeout=60
    )

    # Verify disk space
    df_output = subprocess.run(
        ["ssh", instance, "df", "-h", partition],
        capture_output=True, text=True, timeout=10
    ).stdout

    return {
        "success": True,
        "message": f"Disk cleanup complete\n{df_output}",
        "actions": actions,
    }

def handle_memory_oom(alert: dict) -> dict:
    """Scenario 3: Memory OOM — restart OOM process and adjust limits"""
    instance = alert.get("labels", {}).get("instance", "")
    service = alert.get("labels", {}).get("service", "")

    actions = []

    # Check OOM records
    actions.append("Checking dmesg for OOM records")
    oom_log = subprocess.run(
        ["ssh", instance, "dmesg", "-T", "|", "grep", "-i", "oom"],
        capture_output=True, text=True, timeout=10, shell=True
    ).stdout

    if "Out of memory" in oom_log or "Killed process" in oom_log:
        actions.append(f"OOM Kill detected, restarting service {service}")
        subprocess.run(["ssh", instance, "systemctl", "restart", service], timeout=30)
        actions.append("Increasing cgroup memory limit")
        return {"success": True, "message": f"Handled OOM and restarted {service}", "actions": actions}

    return {"success": False, "message": "No OOM Kill record found", "actions": actions}

def handle_cert_expiry(alert: dict) -> dict:
    """Scenario 4: Certificate expiring — auto-renew"""
    instance = alert.get("labels", {}).get("instance", "")
    domain = alert.get("labels", {}).get("domain", "")

    actions = [f"Renewing certificate for {domain}"]

    # Renew with certbot
    result = subprocess.run(
        ["ssh", instance, "certbot", "renew", "--quiet", "--deploy-hook",
         "systemctl reload nginx"],
        capture_output=True, text=True, timeout=120
    )

    if result.returncode == 0:
        actions.append("Certificate renewed successfully, nginx reloaded")
        return {"success": True, "message": f"Certificate {domain} auto-renewed", "actions": actions}
    else:
        return {"success": False, "message": f"Certificate renewal failed: {result.stderr}", "actions": actions}

def handle_service_down(alert: dict) -> dict:
    """Scenario 5: Service down — attempt restart and health check"""
    instance = alert.get("labels", {}).get("instance", "")
    service = alert.get("labels", {}).get("service", "")

    actions = []

    # Attempt restart
    actions.append(f"Restarting service {service} on {instance}")
    subprocess.run(["ssh", instance, "systemctl", "restart", service], timeout=30)

    # Wait and check health
    time.sleep(10)
    health_check = subprocess.run(
        ["ssh", instance, "systemctl", "is-active", service],
        capture_output=True, text=True, timeout=10
    )

    if health_check.stdout.strip() == "active":
        actions.append("Service recovered")
        return {"success": True, "message": f"{service} restarted and recovered", "actions": actions}
    else:
        actions.append("Service still down after restart")
        return {"success": False, "message": f"{service} still down after restart, needs manual intervention",
                "actions": actions}

def handle_disk_io_high(alert: dict) -> dict:
    """Scenario 6: High disk IO — identify and throttle"""
    instance = alert.get("labels", {}).get("instance", "")

    actions = []

    # Identify high IO processes
    actions.append(f"Identifying high IO processes on {instance}")
    iotop_output = subprocess.run(
        ["ssh", instance, "iotop", "-b", "-n", "1", "-o"],
        capture_output=True, text=True, timeout=10
    ).stdout

    # Apply cgroup v2 IO limits
    actions.append("Applying cgroup limits to high IO processes")

    return {"success": True, "message": "Identified and throttled high IO processes", "actions": actions}

if __name__ == "__main__":
    registry = RunbookRegistry()

    # Register Runbooks
    registry.register(Runbook(
        name="auto-cpu-restart",
        description="Auto-restart service on high CPU",
        risk_level=RunbookRisk.CAUTION,
        match_conditions={"alertname": "HighCPU"},
        handler=handle_high_cpu,
        max_retries=1,
        timeout=60,
        cooldown=300,
    ))

    registry.register(Runbook(
        name="auto-disk-cleanup",
        description="Auto-cleanup on disk space warning",
        risk_level=RunbookRisk.SAFE,
        match_conditions={"alertname": "DiskSpaceWarning"},
        handler=handle_disk_full,
        max_retries=1,
        timeout=120,
        cooldown=600,
    ))

    registry.register(Runbook(
        name="auto-oom-restart",
        description="Auto-restart and adjust memory on OOM",
        risk_level=RunbookRisk.CAUTION,
        match_conditions={"alertname": "OOMKilled"},
        handler=handle_memory_oom,
        max_retries=1,
        timeout=30,
        cooldown=300,
    ))

    registry.register(Runbook(
        name="auto-cert-renew",
        description="Auto-renew expiring certificates",
        risk_level=RunbookRisk.SAFE,
        match_conditions={"alertname": "CertExpiringSoon"},
        handler=handle_cert_expiry,
        max_retries=1,
        timeout=120,
        cooldown=3600,
    ))

    registry.register(Runbook(
        name="auto-service-restart",
        description="Auto-restart on service down",
        risk_level=RunbookRisk.CAUTION,
        match_conditions={"alertname": "ServiceDown"},
        handler=handle_service_down,
        max_retries=2,
        timeout=30,
        cooldown=300,
    ))

    registry.register(Runbook(
        name="auto-io-throttle",
        description="Auto-throttle on high IO",
        risk_level=RunbookRisk.SAFE,
        match_conditions={"alertname": "HighDiskIO"},
        handler=handle_disk_io_high,
        max_retries=1,
        timeout=30,
        cooldown=300,
    ))

    # Simulate alert triggering Runbook
    test_alert = {
        "alertname": "DiskSpaceWarning",
        "severity": "medium",
        "labels": {
            "instance": "10.0.1.5",
            "service": "web-server",
            "partition": "/",
        },
    }

    print(f"Received alert: {test_alert['alertname']}")
    result = registry.find_and_execute(test_alert, auto_execute=True)
    if result:
        print(f"Runbook: {result.runbook_name}")
        print(f"Status: {result.status.value}")
        print(f"Message: {result.message}")
        print(f"Execution time: {result.execution_time:.2f}s")
        print(f"Actions: {result.actions_taken}")

Safety Mechanisms: Whitelists and Rate Limiting

Automated remediation must be safe. The following mechanisms ensure automation doesn’t cause bigger problems:

#!/usr/bin/env python3
"""Automated safety layer — whitelists, rate limiting, circuit breakers"""

import time
from collections import defaultdict
from dataclasses import dataclass, field
from threading import Lock

@dataclass
class CircuitBreaker:
    """Circuit breaker — trips on consecutive failures"""
    failure_threshold: int = 3      # Consecutive failure threshold
    recovery_timeout: int = 600     # Recovery time (seconds)
    failure_count: int = 0
    last_failure_time: float = 0
    state: str = "closed"           # closed / open / half-open
    lock: Lock = field(default_factory=Lock)

    def can_execute(self) -> bool:
        with self.lock:
            if self.state == "open":
                # Check if can enter half-open
                if time.time() - self.last_failure_time > self.recovery_timeout:
                    self.state = "half-open"
                    return True
                return False
            return True

    def record_success(self):
        with self.lock:
            self.failure_count = 0
            self.state = "closed"

    def record_failure(self):
        with self.lock:
            self.failure_count += 1
            self.last_failure_time = time.time()
            if self.failure_count >= self.failure_threshold:
                self.state = "open"
                print(f"[CIRCUIT BREAKER] {self.failure_count} consecutive failures, tripping for {self.recovery_timeout}s")

class RateLimiter:
    """Rate limiter — limits Runbook execution frequency"""

    def __init__(self):
        self.executions: dict[str, list[float]] = defaultdict(list)
        self.lock = Lock()

    def can_execute(self, runbook_name: str, max_per_hour: int = 5) -> bool:
        """Check if execution is allowed (max per hour)"""
        with self.lock:
            now = time.time()
            # Clean records older than 1 hour
            self.executions[runbook_name] = [
                t for t in self.executions[runbook_name]
                if now - t < 3600
            ]
            if len(self.executions[runbook_name]) >= max_per_hour:
                return False
            self.executions[runbook_name].append(now)
            return True

class SafeExecutor:
    """Safe executor — integrates whitelist, rate limiting, circuit breaker"""

    def __init__(self):
        self.circuit_breakers: dict[str, CircuitBreaker] = defaultdict(CircuitBreaker)
        self.rate_limiter = RateLimiter()
        # Whitelist: only auto-remediate specific services
        self.service_whitelist = {
            "nginx", "redis", "web-server", "api-gateway",
            "log-collector", "metric-exporter",
        }
        # Blacklist: never auto-remediate these services
        self.service_blacklist = {
            "mysql-master", "postgresql-primary", "etcd",
            "consul", "zookeeper",
        }

    def can_execute(self, runbook_name: str, alert: dict) -> tuple[bool, str]:
        """Check if safe to execute"""
        labels = alert.get("labels", {})
        service = labels.get("service", "")

        # Check blacklist
        if service in self.service_blacklist:
            return False, f"Service {service} is blacklisted, auto-remediation forbidden"

        # Check whitelist
        if service and service not in self.service_whitelist:
            return False, f"Service {service} not in whitelist, needs confirmation"

        # Check circuit breaker
        cb = self.circuit_breakers[runbook_name]
        if not cb.can_execute():
            return False, f"Runbook {runbook_name} circuit breaker tripped, awaiting recovery"

        # Check rate limit
        if not self.rate_limiter.can_execute(runbook_name, max_per_hour=5):
            return False, f"Runbook {runbook_name} reached hourly execution limit"

        return True, "Allowed"

    def record_result(self, runbook_name: str, success: bool):
        """Record execution result"""
        cb = self.circuit_breakers[runbook_name]
        if success:
            cb.record_success()
        else:
            cb.record_failure()

if __name__ == "__main__":
    executor = SafeExecutor()

    # Test whitelist checking
    alerts = [
        {"alertname": "HighCPU", "labels": {"service": "nginx"}},
        {"alertname": "HighCPU", "labels": {"service": "mysql-master"}},
        {"alertname": "HighCPU", "labels": {"service": "unknown-service"}},
    ]

    for alert in alerts:
        can_run, reason = executor.can_execute("auto-cpu-restart", alert)
        status = "ALLOW" if can_run else "DENY"
        print(f"[{status}] {alert['labels']['service']:20s} | {reason}")

Self-Healing Platform Architecture

Overall Architecture

┌──────────────────────────────────────────────────────────────────────────┐
│                    Self-Healing Platform Architecture                      │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │
│  │ Prometheus   │  │ ELK Stack   │  │ APM (Jaeger)│  │ Zabbix      │    │
│  │ (Metrics)    │  │ (Logs)      │  │ (Traces)    │  │ (Infra)     │    │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘    │
│         │                 │                 │                 │            │
│         ▼                 ▼                 ▼                 ▼            │
│  ┌──────────────────────────────────────────────────────────────────┐    │
│  │                   Alert Ingestion Layer                          │    │
│  │         Webhook Receiver | API Gateway | Message Queue           │    │
│  └──────────────────────────────┬───────────────────────────────────┘    │
│                                 │                                        │
│                                 ▼                                        │
│  ┌──────────────────────────────────────────────────────────────────┐    │
│  │                   Alert Processing Layer                         │    │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────┐    │    │
│  │  │ Dedup    │  │ Correlate│  │ Inhibit  │  │ Silence Mgmt │    │    │
│  │  └──────────┘  └──────────┘  └──────────┘  └──────────────┘    │    │
│  └──────────────────────────────┬───────────────────────────────────┘    │
│                                 │                                        │
│                                 ▼                                        │
│  ┌──────────────────────────────────────────────────────────────────┐    │
│  │               Routing & Dispatch Layer                          │    │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────┐    │    │
│  │  │ Severity │  │ Route    │  │ Escalate │  │ Notify       │    │    │
│  │  └──────────┘  └──────────┘  └──────────┘  └──────────────┘    │    │
│  └──────────────────────────────┬───────────────────────────────────┘    │
│                                 │                                        │
│                  ┌──────────────┴──────────────┐                        │
│                  ▼                              ▼                        │
│  ┌──────────────────────┐     ┌──────────────────────────────────┐     │
│  │  Auto-Remediation    │     │  Human Notification              │     │
│  │  ┌──────────────────┐│     │  ┌──────────────────────────┐    │     │
│  │  │ Runbook Registry ││     │  │ PagerDuty / Slack / SMS  │    │     │
│  │  │ (match+execute)   ││     │  └──────────────────────────┘    │     │
│  │  └────────┬─────────┘│     └──────────────────────────────────┘     │
│  │           │           │                                              │
│  │  ┌────────▼─────────┐ │                                              │
│  │  │ Safe Executor    │ │  (whitelist+rate limit+circuit breaker)    │
│  │  └────────┬─────────┘ │                                              │
│  │           │           │                                              │
│  │  ┌────────▼─────────┐ │                                              │
│  │  │ Action Executor  │ │  (SSH/API/K8s/Cloud)                        │
│  │  └────────┬─────────┘ │                                              │
│  └───────────┼──────────┘                                              │
│              │                                                           │
│              ▼                                                           │
│  ┌──────────────────────────────────────────────────────────────────┐    │
│  │               Verify & Feedback Layer                            │    │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────┐    │    │
│  │  │ Health   │  │ Verify   │  │ Rollback │  │ Event Archive│    │    │
│  │  └──────────┘  └──────────┘  └──────────┘  └──────────────┘    │    │
│  └──────────────────────────────────────────────────────────────────┘    │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘

Core Service Implementation

Here is the core service skeleton for the self-healing platform, implemented in Go (suitable for ops team deployment):

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"
)

// Alert structure
type Alert struct {
	ID        string            `json:"id"`
	AlertName string            `json:"alertname"`
	Severity  string            `json:"severity"`
	Labels    map[string]string `json:"labels"`
	Message   string            `json:"message"`
	StartsAt  time.Time         `json:"startsAt"`
}

// RemediationAction represents a remediation action
type RemediationAction struct {
	Name       string                 `json:"name"`
	Type       string                 `json:"type"` // ssh, api, k8s, cloud
	Params     map[string]interface{} `json:"params"`
	Result     string                 `json:"result"`
	ExecutedAt time.Time              `json:"executedAt"`
}

// RemediationResult represents the result of remediation
type RemediationResult struct {
	AlertID    string              `json:"alertId"`
	Success    bool                `json:"success"`
	Message    string              `json:"message"`
	Actions    []RemediationAction `json:"actions"`
	Duration   float64             `json:"duration"`
	Timestamp  time.Time           `json:"timestamp"`
}

// AutoRemediationPlatform is the core self-healing platform
type AutoRemediationPlatform struct {
	mu             sync.RWMutex
	deduplicator   *Deduplicator
	correlator     *Correlator
	router         *Router
	runbookReg     *RunbookRegistry
	safeExecutor   *SafeExecutor
	verifier       *HealthVerifier
	eventStore     []RemediationResult
}

// HandleAlert processes an alert through the complete pipeline
func (p *AutoRemediationPlatform) HandleAlert(alert Alert) (*RemediationResult, error) {
	start := time.Now()

	// 1. Dedup check
	if p.deduplicator.IsDuplicate(alert) {
		return &RemediationResult{
			AlertID:   alert.ID,
			Success:   true,
			Message:   "Alert deduplicated, no action needed",
			Timestamp: time.Now(),
		}, nil
	}

	// 2. Correlation check
	event := p.correlator.Correlate(alert)

	// 3. Routing decision
	route := p.router.Route(alert)

	// 4. Attempt auto-remediation
	var result *RemediationResult
	if route.AutoRemediation != "" {
		canExecute, reason := p.safeExecutor.Check(route.AutoRemediation, alert)
		if canExecute {
			result = p.runbookReg.Execute(route.AutoRemediation, alert)
			p.safeExecutor.RecordResult(route.AutoRemediation, result.Success)

			// 5. Verify remediation effectiveness
			if result.Success {
				verified := p.verifier.Verify(alert)
				if !verified {
					result.Success = false
					result.Message = "Remediation executed but verification failed, needs manual check"
				}
			}
		} else {
			log.Printf("[SAFETY] Runbook %s blocked: %s", route.AutoRemediation, reason)
		}
	}

	// 6. If auto-remediation failed or not configured, notify humans
	if result == nil || !result.Success {
		p.notifyHumans(route, alert)
	}

	// 7. Archive
	result.Duration = time.Since(start).Seconds()
	result.Timestamp = time.Now()
	p.storeEvent(*result)

	return result, nil
}

func (p *AutoRemediationPlatform) notifyHumans(route *RouteResult, alert Alert) {
	log.Printf("[HUMAN NOTIFY] Alert %s → %v (escalate: %ds → %v)",
		alert.AlertName, route.Receivers, route.EscalateAfter, route.EscalateTo)
}

func (p *AutoRemediationPlatform) storeEvent(result RemediationResult) {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.eventStore = append(p.eventStore, result)
}

// WebhookHandler receives Alertmanager webhooks
func (p *AutoRemediationPlatform) WebhookHandler(w http.ResponseWriter, r *http.Request) {
	var payload struct {
		Alerts []Alert `json:"alerts"`
	}

	if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	for _, alert := range payload.Alerts {
		go func(a Alert) {
			result, err := p.HandleAlert(a)
			if err != nil {
				log.Printf("[ERROR] Failed to handle alert %s: %v", a.AlertName, err)
			} else {
				log.Printf("[DONE] Alert %s → %s (%.2fs)",
					a.AlertName, result.Message, result.Duration)
			}
		}(alert)
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]string{"status": "received"})
}

func main() {
	platform := &AutoRemediationPlatform{
		deduplicator: NewDeduplicator(300),
		correlator:   NewCorrelator(),
		router:       NewRouter(),
		runbookReg:   NewRunbookRegistry(),
		safeExecutor: NewSafeExecutor(),
		verifier:     NewHealthVerifier(),
	}

	http.HandleFunc("/api/v1/alerts", platform.WebhookHandler)

	// Health check
	http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintln(w, "OK")
	})

	// Stats endpoint
	http.HandleFunc("/api/v1/stats", func(w http.ResponseWriter, r *http.Request) {
		platform.mu.RLock()
		defer platform.mu.RUnlock()

		total := len(platform.eventStore)
		success := 0
		for _, e := range platform.eventStore {
			if e.Success {
				success++
			}
		}

		json.NewEncoder(w).Encode(map[string]interface{}{
			"total_events":  total,
			"success_count": success,
			"success_rate": func() float64 {
				if total == 0 {
					return 0
				}
				return float64(success) / float64(total) * 100
			}(),
		})
	})

	log.Println("Self-healing platform starting on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

// Simplified component implementations (full implementations in production)

type Deduplicator struct{ window int }
type Correlator struct{}
type Router struct{}
type RouteResult struct {
	Receivers        []string
	EscalateAfter    int
	EscalateTo       []string
	AutoRemediation  string
}
type RunbookRegistry struct{}
type SafeExecutor struct{}
type HealthVerifier struct{}

func NewDeduplicator(w int) *Deduplicator { return &Deduplicator{window: w} }
func (d *Deduplicator) IsDuplicate(a Alert) bool { return false }
func NewCorrelator() *Correlator { return &Correlator{} }
func (c *Correlator) Correlate(a Alert) interface{} { return nil }
func NewRouter() *Router { return &Router{} }
func (r *Router) Route(a Alert) *RouteResult {
	return &RouteResult{Receivers: []string{"on-call"}, AutoRemediation: ""}
}
func NewRunbookRegistry() *RunbookRegistry { return &RunbookRegistry{} }
func (r *RunbookRegistry) Execute(name string, a Alert) *RemediationResult {
	return &RemediationResult{Success: false, Message: "no runbook matched"}
}
func NewSafeExecutor() *SafeExecutor { return &SafeExecutor{} }
func (s *SafeExecutor) Check(name string, a Alert) (bool, string) { return false, "safe check" }
func (s *SafeExecutor) RecordResult(name string, success bool) {}
func NewHealthVerifier() *HealthVerifier { return &HealthVerifier{} }
func (h *HealthVerifier) Verify(a Alert) bool { return true }

Docker One-Click Deployment

# docker-compose.yml — Self-healing platform deployment
version: '3.8'

services:
  remediation-platform:
    build: .
    container_name: auto-remediation
    ports:
      - "8080:8080"
    volumes:
      - ./config:/app/config
      - ./runbooks:/app/runbooks
      - ./logs:/app/logs
    environment:
      - LOG_LEVEL=info
      - ALERTMANAGER_URL=http://alertmanager:9093
      - PROMETHEUS_URL=http://prometheus:9090
      - GRAFANA_URL=http://grafana:3000
    networks:
      - monitoring
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 5s
      retries: 3

  alertmanager:
    image: prom/alertmanager:latest
    container_name: alertmanager
    ports:
      - "9093:9093"
    volumes:
      - ./config/alertmanager.yml:/etc/alertmanager/alertmanager.yml
    networks:
      - monitoring
    restart: unless-stopped

networks:
  monitoring:
    driver: bridge

AI-Assisted Alert Governance

From Rules to Intelligence

Traditional alert automation is based on static rules (if-then), while AI-assisted alert governance introduces dynamic learning and adaptive capabilities:

CapabilityRule-DrivenAI-Assisted
Anomaly detectionStatic thresholdsDynamic baselines + anomaly detection algorithms
Alert classificationManual rulesAuto-classification + semantic understanding
Root cause analysisPredefined correlation rulesCausal reasoning + topology analysis
Remediation suggestionsFixed RunbooksContext-aware generated repair strategies
Alert optimizationManual tuningAuto-tuning + feedback learning

LLM-Based Alert Diagnosis

#!/usr/bin/env python3
"""AI alert diagnostic engine — uses LLM to understand alert context and generate remediation suggestions"""

import json
import requests
from dataclasses import dataclass

@dataclass
class DiagnosticResult:
    """Diagnostic result"""
    root_cause: str          # Root cause analysis
    severity_assessment: str # Severity assessment
    impact_analysis: str    # Impact analysis
    remediation_plan: str    # Remediation suggestions
    confidence: float        # Confidence level

class AlertDiagnosticEngine:
    """Alert diagnostic engine"""

    def __init__(self, llm_api_url: str, llm_api_key: str):
        self.llm_api_url = llm_api_url
        self.llm_api_key = llm_api_key

    def diagnose(self, alert: dict, context: dict) -> DiagnosticResult:
        """
        Diagnose alert
        Args:
            alert: Alert information
            context: Context (metrics, logs, topology, etc.)
        """
        prompt = self._build_prompt(alert, context)

        # Call LLM for diagnosis
        response = self._call_llm(prompt)

        return self._parse_response(response)

    def _build_prompt(self, alert: dict, context: dict) -> str:
        """Build diagnostic prompt"""
        return f"""You are a senior SRE engineer. Analyze the following alert and provide a diagnosis.

## Alert Information
- Name: {alert.get('alertname', '')}
- Severity: {alert.get('severity', '')}
- Service: {alert.get('labels', {}).get('service', '')}
- Instance: {alert.get('labels', {}).get('instance', '')}
- Message: {alert.get('message', '')}

## Context
- Relevant metrics:
{json.dumps(context.get('metrics', {}), indent=2)}
- Recent logs (last 5 minutes):
{context.get('recent_logs', 'N/A')}
- Service topology:
{context.get('topology', 'N/A')}
- Recent changes:
{context.get('recent_changes', 'N/A')}

## Output
1. Root cause: Most likely cause of the failure
2. Severity assessment: Re-evaluate based on impact
3. Impact analysis: Which services and users may be affected
4. Remediation plan: Specific repair steps (prioritize automated solutions)

Output as JSON:
{{"root_cause": "...", "severity_assessment": "...", "impact_analysis": "...", "remediation_plan": "...", "confidence": 0.0-1.0}}
"""

    def _call_llm(self, prompt: str) -> str:
        """Call LLM API"""
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.llm_api_key}",
        }
        payload = {
            "messages": [{"role": "user", "content": prompt}],
            "temperature": 0.3,  # Low temperature for stable output
            "max_tokens": 2000,
        }
        response = requests.post(
            self.llm_api_url,
            headers=headers,
            json=payload,
            timeout=30
        )
        response.raise_for_status()
        return response.json()["choices"][0]["message"]["content"]

    def _parse_response(self, response: str) -> DiagnosticResult:
        """Parse LLM response"""
        try:
            # Try to extract JSON
            start = response.find("{")
            end = response.rfind("}") + 1
            if start >= 0 and end > start:
                data = json.loads(response[start:end])
                return DiagnosticResult(
                    root_cause=data.get("root_cause", ""),
                    severity_assessment=data.get("severity_assessment", ""),
                    impact_analysis=data.get("impact_analysis", ""),
                    remediation_plan=data.get("remediation_plan", ""),
                    confidence=data.get("confidence", 0.5),
                )
        except (json.JSONDecodeError, KeyError) as e:
            pass

        # Fallback: return raw text
        return DiagnosticResult(
            root_cause=response[:500],
            severity_assessment="unknown",
            impact_analysis="unknown",
            remediation_plan="Manual analysis required",
            confidence=0.3,
        )

if __name__ == "__main__":
    engine = AlertDiagnosticEngine(
        llm_api_url="https://api.example.com/v1/chat/completions",
        llm_api_key="your-api-key"
    )

    alert = {
        "alertname": "HighErrorRate",
        "severity": "critical",
        "labels": {"service": "payment-api", "instance": "10.0.1.5:8080"},
        "message": "Error rate 15.2%, sustained 3 minutes",
    }

    context = {
        "metrics": {
            "error_rate": 0.152,
            "p99_latency_ms": 3500,
            "qps": 1200,
            "cpu_usage": 0.89,
            "memory_usage": 0.92,
        },
        "recent_logs": "[ERROR] 2026-07-11 02:20:01 connection refused: db-pool exhausted",
        "topology": "payment-api → redis-cluster → mysql-primary",
        "recent_changes": "Deployed payment-api v2.3.1 2 hours ago",
    }

    result = engine.diagnose(alert, context)
    print(f"Root cause: {result.root_cause}")
    print(f"Severity: {result.severity_assessment}")
    print(f"Impact: {result.impact_analysis}")
    print(f"Remediation: {result.remediation_plan}")
    print(f"Confidence: {result.confidence}")

Alert Feedback Loop

AI diagnostic accuracy depends on continuous learning. Here is a complete alert feedback loop:

#!/usr/bin/env python3
"""Alert feedback loop — continuous learning to improve alert quality"""

import time
import json
from dataclasses import dataclass, field, asdict
from pathlib import Path

@dataclass
class AlertFeedback:
    """Alert feedback record"""
    alert_id: str
    alert_name: str
    severity: str
    was_actionable: bool        # Whether alert needed human action
    was_auto_resolved: bool    # Whether auto-resolved
    false_positive: bool       # Whether false positive
    resolution_time: float     # Resolution time (minutes)
    root_cause: str            # Root cause
    action_taken: str          # Actual action taken
    operator: str              # Handler
    feedback: str              # Additional feedback
    timestamp: float = field(default_factory=time.time)

class FeedbackLoop:
    """Alert feedback loop manager"""

    def __init__(self, storage_path: str = "/data/feedback"):
        self.storage_path = Path(storage_path)
        self.storage_path.mkdir(parents=True, exist_ok=True)
        self.feedback_store: list[AlertFeedback] = []
        self._load()

    def record(self, feedback: AlertFeedback):
        """Record feedback"""
        self.feedback_store.append(feedback)
        self._save(feedback)
        self._analyze_patterns()

    def _save(self, feedback: AlertFeedback):
        """Persist feedback record"""
        filepath = self.storage_path / f"{feedback.alert_id}.json"
        filepath.write_text(json.dumps(asdict(feedback), indent=2, ensure_ascii=False))

    def _load(self):
        """Load historical feedback"""
        for filepath in self.storage_path.glob("*.json"):
            data = json.loads(filepath.read_text())
            self.feedback_store.append(AlertFeedback(**data))

    def _analyze_patterns(self):
        """Analyze feedback patterns, output improvement suggestions"""
        if len(self.feedback_store) < 10:
            return

        total = len(self.feedback_store)
        false_positives = sum(1 for f in self.feedback_store if f.false_positive)
        auto_resolved = sum(1 for f in self.feedback_store if f.was_auto_resolved)

        fp_rate = false_positives / total * 100
        auto_rate = auto_resolved / total * 100

        print(f"\n=== Alert Quality Report ===")
        print(f"Total alerts: {total}")
        print(f"False positive rate: {fp_rate:.1f}%")
        print(f"Auto-resolution rate: {auto_rate:.1f}%")
        print(f"Average resolution time: {sum(f.resolution_time for f in self.feedback_store)/total:.1f} min")

        # False positive stats by alert type
        by_name = {}
        for f in self.feedback_store:
            if f.alert_name not in by_name:
                by_name[f.alert_name] = {"total": 0, "fp": 0}
            by_name[f.alert_name]["total"] += 1
            if f.false_positive:
                by_name[f.alert_name]["fp"] += 1

        print(f"\n=== Top 5 False Positive Alerts ===")
        sorted_alerts = sorted(
            by_name.items(),
            key=lambda x: x[1]["fp"] / max(x[1]["total"], 1),
            reverse=True
        )[:5]
        for name, stats in sorted_alerts:
            rate = stats["fp"] / stats["total"] * 100
            print(f"  {name:30s} | FP rate {rate:.0f}% ({stats['fp']}/{stats['total']})")

        # Improvement suggestions
        if fp_rate > 20:
            print("\n[SUGGESTION] False positive rate too high, recommend adjusting thresholds or adding preconditions")
        if auto_rate < 30:
            print("[SUGGESTION] Low auto-resolution rate, recommend adding Runbooks for high-frequency alerts")

Effectiveness Measurement

Key Metrics

MetricDefinitionTargetMeasurement
Average alert countDaily alert volume< 20/dayAlert system stats
Actionable alert rateAlerts requiring human action> 70%Manual labeling
False positive rateAlerts not requiring action< 10%Manual labeling
Auto-resolution rateAlerts resolved by Runbooks> 50%Auto tracking
MTTA (Mean Time to Acknowledge)Time from alert to response< 5 minSystem records
MTTR (Mean Time to Resolve)Time from alert to resolution< 15 minSystem records
Alert fatigue indexRate of ignored alerts< 5%Manual survey

Measurement Dashboard

#!/usr/bin/env python3
"""Alert automation effectiveness dashboard"""

import time
import json
from dataclasses import dataclass, field
from collections import defaultdict

@dataclass
class AlertMetrics:
    """Alert metrics data"""
    total_alerts: int = 0
    actionable_alerts: int = 0       # Requiring human action
    false_positives: int = 0         # False positives
    auto_resolved: int = 0            # Auto-resolved
    escalated: int = 0               # Escalated to human
    mtta_seconds: float = 0          # Mean time to acknowledge
    mttr_seconds: float = 0          # Mean time to resolve
    by_severity: dict = field(default_factory=lambda: defaultdict(int))
    by_service: dict = field(default_factory=lambda: defaultdict(int))
    by_runbook: dict = field(default_factory=lambda: {"executed": 0, "success": 0})

    def to_dict(self) -> dict:
        return {
            "total_alerts": self.total_alerts,
            "actionable_alerts": self.actionable_alerts,
            "false_positive_rate": f"{self.false_positives/max(self.total_alerts,1)*100:.1f}%",
            "auto_resolution_rate": f"{self.auto_resolved/max(self.total_alerts,1)*100:.1f}%",
            "mtta": f"{self.mtta_seconds:.0f}s",
            "mttr": f"{self.mttr_seconds:.0f}s",
            "by_severity": dict(self.by_severity),
            "by_service": dict(self.by_service),
            "runbook_stats": dict(self.by_runbook),
        }

if __name__ == "__main__":
    metrics = AlertMetrics()

    # Simulated data
    metrics.total_alerts = 156
    metrics.actionable_alerts = 98
    metrics.false_positives = 12
    metrics.auto_resolved = 58
    metrics.escalated = 40
    metrics.mtta_seconds = 45
    metrics.mttr_seconds = 480
    metrics.by_severity = {"critical": 8, "high": 25, "medium": 68, "low": 55}
    metrics.by_service = {"api-gw": 35, "db": 12, "web": 45, "cache": 28, "other": 36}
    metrics.by_runbook = {"executed": 58, "success": 45}

    print("=== Alert Automation Dashboard ===")
    print(json.dumps(metrics.to_dict(), indent=2))

    print(f"\n=== Key Metrics ===")
    print(f"Total alerts:       {metrics.total_alerts}/day")
    print(f"Actionable rate:    {metrics.actionable_alerts/metrics.total_alerts*100:.1f}%")
    print(f"False positive rate: {metrics.false_positives/metrics.total_alerts*100:.1f}%")
    print(f"Auto-resolution:    {metrics.auto_resolved/metrics.total_alerts*100:.1f}%")
    print(f"Runbook success:    {metrics.by_runbook['success']/max(metrics.by_runbook['executed'],1)*100:.1f}%")
    print(f"MTTA:               {metrics.mtta_seconds:.0f}s")
    print(f"MTTR:               {metrics.mttr_seconds/60:.1f} min")

Summary

Alert automation is not a one-time project, but a progressive journey from “noise to signal, signal to action, action to self-healing.”

Core building path:

  1. Noise Reduction is the Foundation: Through Alertmanager’s grouping, inhibition, and silencing, combined with custom fingerprint deduplication and multi-dimensional correlation, compress alert storms into manageable events. The goal is to reduce daily alerts from 100+ to under 20, with an actionable rate above 70%.

  2. Severity Routing is the Framework: Establish unified P0-P3 severity standards, with routing rules and escalation mechanisms ensuring each alert reaches the right person at the right time. The key is finding the balance between automated remediation and human intervention — safe operations auto-execute, high-risk operations require confirmation.

  3. Runbook Automation is the Core: Encode known fault handling procedures into auto-executable Runbooks, covering high-frequency scenarios: high CPU, disk full, OOM, service down, cert expiry, high IO. Pair with whitelists, rate limiting, and circuit breakers for safety.

  4. Self-Healing Platform is the Carrier: Build a unified platform for alert ingestion, processing, routing, remediation, and verification, integrating scattered automation capabilities into a complete self-healing chain. The key design is “remediation verification” — not only execute repairs, but also verify effectiveness, with automatic rollback and escalation on failure.

  5. AI Assistance is the Accelerator: Introduce AI capabilities on top of rule-driven foundations, using LLMs for alert diagnosis, root cause analysis, and remediation suggestions. But AI doesn’t replace rules — it provides intelligent assistance for scenarios rules can’t cover, learning continuously through feedback loops.

The ultimate goal is to build a reliability system that responds faster than the best engineer — automatically detecting, analyzing, and fixing issues before they impact users, transforming SREs from “firefighters” to “reliability engineers.”