diff --git a/apps/api/src/services/telegram_gateway.py b/apps/api/src/services/telegram_gateway.py
index a55e035b..f547c4fe 100644
--- a/apps/api/src/services/telegram_gateway.py
+++ b/apps/api/src/services/telegram_gateway.py
@@ -2655,9 +2655,10 @@ class TelegramGateway:
"""
ADR-050 P2: 傳送事件頻率統計訊息
- 2026-04-01 Claude Code (ADR-050 P2): history button handler
+ 2026-04-10 ogt: 修復 — frequency_stats 不存 DB,改從 AnomalyCounter (Redis) 即時查詢
"""
from src.repositories.incident_repository import get_incident_repository
+ from src.services.anomaly_counter import get_anomaly_counter, AnomalyCounter
try:
repo = get_incident_repository()
@@ -2667,47 +2668,60 @@ class TelegramGateway:
await self.send_notification(f"⚠️ 找不到事件 {html.escape(incident_id)}")
return
- fs = incident.frequency_stats
- if not fs:
+ # frequency_stats 不持久化,從 AnomalyCounter (Redis) 即時查詢
+ anomaly_key = AnomalyCounter.derive_key_from_incident(incident)
+ if not anomaly_key:
await self.send_notification(
- f"📊 事件歷史\n\n🔖 {html.escape(incident.incident_id)}\n\n無頻率統計資料"
+ f"📊 事件歷史\n\n🔖 {html.escape(incident_id)}\n\n⚠️ 無法推導告警鍵(signals 為空)"
)
return
+ counter = get_anomaly_counter()
+ freq = await counter.record_anomaly({
+ "alert_name": incident.signals[0].alert_name if incident.signals else "",
+ "service": incident.affected_services[0] if incident.affected_services else "",
+ "namespace": (incident.signals[0].labels or {}).get("namespace", "") if incident.signals else "",
+ "error_type": (incident.signals[0].labels or {}).get("reason", (incident.signals[0].labels or {}).get("error_type", "")) if incident.signals else "",
+ })
+ disposition = await counter.get_disposition_stats(anomaly_key)
+
lines = [
f"📊 事件歷史統計",
f"",
- f"🔖 {html.escape(incident.incident_id)}",
- f"🔑 告警鍵: {html.escape(fs.anomaly_key[:60])}",
+ f"🔖 {html.escape(incident_id)}",
+ f"🔑 告警鍵: {html.escape(anomaly_key)}",
f"",
f"⏱ 發生頻率",
- f" 1小時: {fs.count_1h} 次",
- f" 24小時: {fs.count_24h} 次",
- f" 7天: {fs.count_7d} 次",
- f" 30天: {fs.count_30d} 次",
+ f" 1小時: {freq.count_1h} 次",
+ f" 24小時: {freq.count_24h} 次",
+ f" 7天: {freq.count_7d} 次",
+ f" 30天: {freq.count_30d} 次",
]
- if fs.auto_repair_count > 0:
+ if freq.auto_repair_count > 0:
lines += [
f"",
f"🔧 自動修復",
- f" 執行次數: {fs.auto_repair_count}",
+ f" 執行次數: {freq.auto_repair_count}",
]
- if fs.last_repair_action:
- lines.append(f" 最後動作: {html.escape(fs.last_repair_action[:80])}")
+ if freq.last_repair_action:
+ lines.append(f" 最後動作: {html.escape(freq.last_repair_action)}")
- # 2026-04-07 Claude Code: Sprint 4 D2 — 處置分佈明細
- total_res = fs.total_resolution_count
+ # 處置分佈
+ auto_r = disposition.get("auto_repair_count", 0)
+ cold_s = disposition.get("cold_start_trust_count", 0)
+ human_a = disposition.get("human_approved_count", 0)
+ manual_r = disposition.get("manual_resolved_count", 0)
+ total_res = auto_r + cold_s + human_a + manual_r
if total_res > 0:
- auto_total = fs.auto_repair_count + fs.cold_start_trust_count
- auto_rate = int(auto_total / total_res * 100) if total_res > 0 else 0
+ auto_rate = int((auto_r + cold_s) / total_res * 100)
lines += [
f"",
f"📋 處置分佈 (共 {total_res} 次)",
- f" 🤖 自動修復: {fs.auto_repair_count}",
- f" ❄️ 冷啟動信任: {fs.cold_start_trust_count}",
- f" 👤 人工審核: {fs.human_approved_count}",
- f" 🔧 手動處理: {fs.manual_resolved_count}",
+ f" 🤖 自動修復: {auto_r}",
+ f" ❄️ 冷啟動信任: {cold_s}",
+ f" 👤 人工審核: {human_a}",
+ f" 🔧 手動處理: {manual_r}",
f" 📈 自動化率: {auto_rate}%",
]
@@ -2715,7 +2729,7 @@ class TelegramGateway:
except Exception as e:
logger.warning("send_incident_history_failed", incident_id=incident_id, error=str(e))
- await self.send_notification(f"⚠️ 無法取得歷史統計: {html.escape(str(e)[:100])}")
+ await self.send_notification(f"⚠️ 無法取得歷史統計: {html.escape(str(e))}")
async def _send_reanalyze_result(self, incident_id: str) -> None:
"""