fix(alerts): expose alertmanager webhook request metrics
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 2m0s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped

This commit is contained in:
Your Name
2026-07-02 20:25:33 +08:00
parent aaee079cc2
commit d30436573b
3 changed files with 127 additions and 1 deletions

View File

@@ -25,6 +25,7 @@ Endpoints:
import asyncio
import hashlib
import hmac
import time
import uuid
from typing import Literal
@@ -34,7 +35,7 @@ from pydantic import BaseModel, Field
from src.core.config import settings
from src.core.constants import is_cicd_alertname, is_heartbeat_alertname
from src.core.logging import get_logger
from src.core.metrics import record_alert_chain_success
from src.core.metrics import record_alert_chain_success, record_webhook_request
from src.models.approval import (
ApprovalRequestCreate,
BlastRadius,
@@ -2606,6 +2607,27 @@ async def alertmanager_webhook(
- 內網 IP (192.168.x.x, 10.x.x.x, 172.x.x.x): 免 HMAC
- 外網 IP: 拒絕
"""
metric_started_at = time.monotonic()
metric_recorded = False
def _record_webhook_metric(metric_status: str) -> None:
nonlocal metric_recorded
if metric_recorded:
return
metric_recorded = True
try:
record_webhook_request(
"alertmanager",
metric_status,
time.monotonic() - metric_started_at,
)
except Exception as metric_err:
logger.warning(
"alertmanager_webhook_metric_record_failed",
status=metric_status,
error=str(metric_err),
)
# 取得客戶端 IP
client_ip = request.client.host if request.client else "unknown"
forwarded_for = request.headers.get("X-Forwarded-For", "").split(",")[0].strip()
@@ -2618,6 +2640,7 @@ async def alertmanager_webhook(
client_ip=actual_ip,
reason="External IP must use /alerts with HMAC",
)
_record_webhook_metric("error")
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="External sources must use /alerts endpoint with HMAC signature",
@@ -2633,6 +2656,7 @@ async def alertmanager_webhook(
# 只處理第一個 firing 告警 (避免告警風暴)
firing_alerts = [a for a in payload.alerts if a.status == "firing"]
if not firing_alerts:
_record_webhook_metric("success")
return AlertResponse(
success=True,
message="No firing alerts to process",
@@ -2712,6 +2736,7 @@ async def alertmanager_webhook(
)
record_alert_chain_success("alertmanager")
_record_webhook_metric("success")
return AlertResponse(
success=True,
message=f"CI/CD alert processed (simple format): {alertname}",
@@ -2721,6 +2746,7 @@ async def alertmanager_webhook(
except Exception as e:
logger.error("cicd_telegram_failed", error=str(e), alertname=alertname)
# CI/CD 通知失敗不阻擋流程
_record_webhook_metric("success")
return AlertResponse(
success=True,
message=f"CI/CD alert logged (telegram failed): {alertname}",
@@ -2866,6 +2892,7 @@ async def alertmanager_webhook(
parent_fingerprint=grouping_result.parent_fingerprint,
fingerprint=fingerprint,
)
_record_webhook_metric("success")
return AlertResponse(
success=True,
message=(
@@ -2940,6 +2967,7 @@ async def alertmanager_webhook(
notification_type=notification_type,
)
_record_webhook_metric("success")
return AlertResponse(
success=True,
message=f"🛡️ 告警收斂 (x{updated_approval.hit_count}) - 已排程節流再通知",
@@ -3004,6 +3032,7 @@ async def alertmanager_webhook(
severity=severity,
)
record_alert_chain_success("alertmanager")
_record_webhook_metric("success")
return AlertResponse(
success=True,
message="✅ TYPE-1 純資訊告警已通知 (no LLM)",
@@ -3050,6 +3079,7 @@ async def alertmanager_webhook(
notification_type=notification_type,
recurrence_stage="llm_inflight",
)
_record_webhook_metric("success")
return AlertResponse(
success=True,
message="🛡️ 告警已由同指紋背景 AI 分析處理中,已排程節流再通知",
@@ -3096,6 +3126,7 @@ async def alertmanager_webhook(
)
record_alert_chain_success("alertmanager")
_record_webhook_metric("success")
return AlertResponse(
success=True,
message="✅ 告警已排入背景分析 (202 Accepted)",
@@ -3110,6 +3141,7 @@ async def alertmanager_webhook(
fingerprint=fingerprint,
error=str(e),
)
_record_webhook_metric("error")
return AlertResponse(
success=False,
message="⚠️ 告警已接收但處理降級,避免 Alertmanager retry storm已交由背景治理/人工介入追蹤",