From da5f9a3a0710bfb895c2b8973b5db55b19531c85 Mon Sep 17 00:00:00 2001 From: attacker Date: Thu, 18 Jun 2026 00:10:39 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=8B=86=E5=88=86AIAlertAnalyzer.t?= =?UTF-8?q?sx(541=E2=86=92190=E8=A1=8C)=E6=8F=90=E5=8F=96analyzerHelpers+A?= =?UTF-8?q?IAnalysisResult+AutoFixDialog=E5=AD=90=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/aiops/AIAlertAnalyzer.tsx | 405 ++---------------- .../src/components/aiops/AIAnalysisResult.tsx | 133 ++++++ .../src/components/aiops/AutoFixDialog.tsx | 73 ++++ .../src/components/aiops/analyzerHelpers.ts | 195 +++++++++ 4 files changed, 428 insertions(+), 378 deletions(-) create mode 100644 frontend/src/components/aiops/AIAnalysisResult.tsx create mode 100644 frontend/src/components/aiops/AutoFixDialog.tsx create mode 100644 frontend/src/components/aiops/analyzerHelpers.ts diff --git a/frontend/src/components/aiops/AIAlertAnalyzer.tsx b/frontend/src/components/aiops/AIAlertAnalyzer.tsx index aad8c2d..33fbc85 100644 --- a/frontend/src/components/aiops/AIAlertAnalyzer.tsx +++ b/frontend/src/components/aiops/AIAlertAnalyzer.tsx @@ -1,16 +1,9 @@ +// AI 告警智能分析主容器:左侧告警列表 + 右侧 AI 分析结果(已拆分子组件) // Logan.Li import { useState, useEffect } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { ScrollArea } from '@/components/ui/scroll-area'; import { alertApi } from '@/services/api'; -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog'; import { AlertTriangle, Brain, @@ -18,202 +11,20 @@ import { XCircle, Clock, Server, - Cpu, - MemoryStick, - HardDrive, - Network, - Zap, - FileText, - Terminal, TrendingUp, AlertCircle, Sparkles, - Play, - Copy, - Check, Loader2, } from 'lucide-react'; - -interface AlertItem { - id: string; - name: string; - severity: 'critical' | 'warning' | 'info'; - status: 'active' | 'resolved'; - source: string; - metric: string; - threshold: string; - currentValue: string; - duration: string; - startedAt: string; - description: string; -} - -interface AIAnalysis { - rootCause: string; - impact: string; - recommendations: string[]; - autoFixScript?: string; - similarCases: number; - confidence: number; -} - -// ─── Dynamic AI analysis generator ─── -// Based on alert metric type, generates contextually relevant root cause analysis, -// impact assessment, recommendations, and auto-fix scripts. - -function generateAIAnalysis(alert: AlertItem): AIAnalysis { - const metric = (alert.metric || '').toLowerCase(); - const target = alert.source || '目标主机'; - const isCritical = alert.severity === 'critical'; - - const baseConfidence = isCritical ? 88 + Math.floor(Math.random() * 8) : 75 + Math.floor(Math.random() * 12); - - // CPU alerts - if (metric.includes('cpu')) { - return { - rootCause: `检测到 ${target} 上 CPU 使用率达到 ${alert.currentValue},持续超过阈值 ${alert.threshold}。可能原因:1) 某进程存在死循环或高计算负载;2) GC 频繁触发(Java/Go 应用);3) 业务流量突增导致处理能力不足。`, - impact: isCritical - ? `CPU 持续高负载将导致服务响应延迟显著增加,严重时可能触发雪崩效应,影响全部依赖该节点的业务。` - : `CPU 使用率偏高,可能导致部分请求处理变慢,建议及时排查避免进一步恶化。`, - recommendations: [ - `登录 ${target} 执行 top/htop 定位高 CPU 进程`, - '检查是否有异常定时任务或批处理任务在运行', - `考虑临时扩容或将部分流量调度到其他节点`, - '优化应用代码,排查是否存在低效算法或资源泄漏', - ], - autoFixScript: `#!/bin/bash\n# CPU 高负载诊断脚本 - ${target}\necho "===== CPU TOP 10 进程 ====="\nps aux --sort=-%cpu | head -11\necho ""\necho "===== 系统负载 ====="\nuptime\necho ""\necho "===== 高 CPU 进程详情 ====="\nPID=$(ps aux --sort=-%cpu | sed -n '2p' | awk '{print $2}')\nif [ -n "$PID" ]; then\n echo "最高 CPU 进程: PID=$PID"\n cat /proc/$PID/cmdline | tr '\\0' ' '\n echo ""\nfi\n`, - similarCases: 18 + Math.floor(Math.random() * 8), - confidence: baseConfidence, - }; - } - - // Memory alerts - if (metric.includes('mem') || metric.includes('ram')) { - return { - rootCause: `检测到 ${target} 内存使用率达到 ${alert.currentValue},接近或超过阈值 ${alert.threshold}。常见原因:1) 应用内存泄漏,对象未被正确释放;2) 缓存配置过大;3) 数据库连接池未及时释放。`, - impact: isCritical - ? `内存即将耗尽可能触发 OOM Killer,导致关键进程被强制终止,服务中断风险极高。` - : `内存持续增长,长期可能导致 OOM,建议尽快排查内存使用情况。`, - recommendations: [ - `检查 ${target} 上的内存占用最高的进程`, - '如果是 Java 应用,检查 JVM 堆内存配置和 GC 日志', - '排查是否存在内存泄漏,必要时生成堆转储分析', - '调整缓存大小限制或增加交换分区', - ], - similarCases: 12 + Math.floor(Math.random() * 6), - confidence: baseConfidence, - }; - } - - // Disk alerts - if (metric.includes('disk') || metric.includes('space')) { - return { - rootCause: `检测到 ${target} 磁盘使用率达到 ${alert.currentValue},超过阈值 ${alert.threshold}。最常见原因:1) 日志文件未配置轮转/清理;2) 临时文件堆积;3) 数据库数据文件膨胀。`, - impact: isCritical - ? `磁盘空间不足可能导致服务无法写入数据/日志,数据库可能崩溃,文件系统变只读,影响范围极大。` - : `磁盘空间告警,如不及时清理可能导致服务异常。`, - recommendations: [ - `清理 ${target} 上 30 天前的日志文件`, - '检查并清理临时目录 /tmp、/var/tmp', - '配置 logrotate 日志轮转策略', - '考虑扩容磁盘或将数据迁移到对象存储', - ], - autoFixScript: `#!/bin/bash\n# 磁盘清理脚本 - ${target}\necho "===== 清理前磁盘使用 ====="\ndf -h /\necho ""\necho "===== 清理 30 天前日志 ====="\nfind /var/log -name "*.log" -mtime +30 -delete 2>/dev/null\nfind /var/log -name "*.gz" -mtime +30 -delete 2>/dev/null\necho ""\necho "===== 清理系统缓存 ====="\njournalctl --vacuum-time=7d 2>/dev/null\necho ""\necho "===== 清理后磁盘使用 ====="\ndf -h /\n`, - similarCases: 23 + Math.floor(Math.random() * 10), - confidence: baseConfidence + 3, - }; - } - - // Network alerts - if (metric.includes('net') || metric.includes('latency') || metric.includes('bandwidth')) { - return { - rootCause: `检测到 ${target} 网络指标异常(当前值 ${alert.currentValue}),可能原因:1) 上游依赖服务响应变慢;2) 网络带宽打满;3) DNS 解析延迟;4) 连接数达到上限。`, - impact: isCritical - ? `网络异常将导致所有经过该节点的请求超时,影响所有上游业务的可用性。` - : `网络延迟偏高,可能影响用户体验,建议排查网络链路。`, - recommendations: [ - `检查 ${target} 的网络连接和带宽使用情况`, - '排查上游依赖服务的健康状态和响应时间', - '检查防火墙规则是否有限速或异常丢弃', - '考虑启用熔断/降级机制保障核心链路', - ], - similarCases: 8 + Math.floor(Math.random() * 5), - confidence: baseConfidence - 5, - }; - } - - // Service availability alerts - if (metric.includes('service') || metric.includes('up') || metric.includes('avail')) { - return { - rootCause: `检测到 ${target} 服务不可用(指标 ${alert.metric} = ${alert.currentValue})。可能原因:1) 进程崩溃或被 OOM Killer 终止;2) 端口被占用或监听异常;3) 健康检查端点返回错误;4) 配置文件错误导致启动失败。`, - impact: isCritical - ? `服务完全不可用,所有依赖该服务的业务功能将中断,需要立即处理。` - : `服务可用性下降,部分功能可能受影响。`, - recommendations: [ - `立即检查 ${target} 的服务状态: systemctl status `, - '查看服务日志排查崩溃原因', - '检查端口占用和监听状态: ss -tlnp', - '必要时重启服务并监控恢复情况', - ], - autoFixScript: `#!/bin/bash\n# 服务恢复脚本 - ${target}\necho "===== 检查服务状态 ====="\nsystemctl list-units --state=failed\necho ""\necho "===== 检查端口监听 ====="\nss -tlnp | grep -E ':(80|443|8080|3306|6379|9090)'\necho ""\necho "===== 重启失败服务 ====="\nsystemctl reset-failed\n`, - similarCases: 6 + Math.floor(Math.random() * 4), - confidence: baseConfidence, - }; - } - - // Default / generic analysis - return { - rootCause: `检测到 ${target} 触发告警「${alert.name}」,当前指标值 ${alert.currentValue} 超过阈值 ${alert.threshold}。建议进一步排查具体指标数据和相关日志以确定根因。`, - impact: isCritical - ? `该告警级别为严重,可能影响业务正常运行,建议优先处理。` - : `该告警需要关注,持续恶化可能影响系统稳定性。`, - recommendations: [ - `查看 ${target} 的监控仪表盘,确认指标趋势`, - '检查对应时间段的系统日志和应用日志', - '关联同时间段的其他告警,排查是否有连锁反应', - '若确认误报,调整告警规则阈值或持续时间', - ], - similarCases: 5 + Math.floor(Math.random() * 5), - confidence: baseConfidence - 8, - }; -} - -// ─── Backend alert event → AlertItem mapping ─── -function mapAlertEvent(event: any): AlertItem { - const expr = event.rule?.expression || ''; - // Extract metric name and threshold from expression like "cpu_usage > 80" - const metricMatch = expr.match(/([\w_]+)\s*[><=!]+\s*([\d.]+)/); - const metric = metricMatch ? metricMatch[1] : expr || 'unknown'; - const threshold = metricMatch ? metricMatch[2] + '%' : '-'; - - const value = event.value ?? 0; - const isPercent = metric.includes('usage') || metric.includes('cpu') || metric.includes('disk') || metric.includes('mem'); - const currentValue = isPercent ? value.toFixed(1) + '%' : value.toFixed(2); - - // Compute duration from started_at to now (or resolved_at) - const endTime = event.resolved_at ? new Date(event.resolved_at) : new Date(); - const startTime = new Date(event.started_at); - const diffMin = Math.max(1, Math.round((endTime.getTime() - startTime.getTime()) / 60000)); - const duration = diffMin >= 60 ? `${Math.floor(diffMin / 60)}小时${diffMin % 60}分钟` : `${diffMin}分钟`; - - const startedAt = startTime.toLocaleString('zh-CN', { hour12: false }); - - return { - id: String(event.id), - name: event.rule_name || event.rule?.name || '未知告警', - severity: event.severity === 'critical' ? 'critical' : event.severity === 'warning' ? 'warning' : 'info', - status: event.status === 'firing' ? 'active' : 'resolved', - source: event.target || '未知目标', - metric, - threshold, - currentValue, - duration, - startedAt, - description: event.message && event.message !== `告警事件 ${event.id}` - ? event.message - : event.rule?.description || `${event.rule_name || '告警'}: ${event.target} 当前值 ${currentValue}`, - }; -} +import { + type AlertItem, + type AIAnalysis, + generateAIAnalysis, + mapAlertEvent, + getSeverityColor, +} from './analyzerHelpers'; +import { AIAnalysisResult } from './AIAnalysisResult'; +import { AutoFixDialog } from './AutoFixDialog'; export function AIAlertAnalyzer() { const [alerts, setAlerts] = useState([]); @@ -222,7 +33,6 @@ export function AIAlertAnalyzer() { const [isAnalyzing, setIsAnalyzing] = useState(false); const [analysis, setAnalysis] = useState(null); const [showScriptDialog, setShowScriptDialog] = useState(false); - const [copied, setCopied] = useState(false); useEffect(() => { loadAlerts(); @@ -232,6 +42,7 @@ export function AIAlertAnalyzer() { setLoading(true); try { const res: any = await alertApi.getAlerts({ page: 1, page_size: 50 }); + // 列表响应格式:http.ts 已提取 .data,此处仍是 {list, total} const list = res?.list || res || []; setAlerts(list.map(mapAlertEvent)); } catch (e) { @@ -242,12 +53,12 @@ export function AIAlertAnalyzer() { } }; + // 触发 AI 分析(模拟 1.5s 思考,实际由 generateAIAnalysis 动态生成上下文相关结果) const handleAnalyze = (alert: AlertItem) => { setSelectedAlert(alert); setIsAnalyzing(true); setAnalysis(null); - // Simulate AI analysis with dynamic generation setTimeout(() => { setAnalysis(generateAIAnalysis(alert)); setIsAnalyzing(false); @@ -258,25 +69,7 @@ export function AIAlertAnalyzer() { setShowScriptDialog(true); }; - const copyScript = () => { - if (analysis?.autoFixScript) { - navigator.clipboard.writeText(analysis.autoFixScript); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - } - }; - - const getSeverityColor = (severity: string) => { - switch (severity) { - case 'critical': - return 'bg-red-500/10 text-red-400 border-red-500/30'; - case 'warning': - return 'bg-amber-500/10 text-amber-400 border-amber-500/30'; - default: - return 'bg-blue-500/10 text-blue-400 border-blue-500/30'; - } - }; - + // 严重等级图标(返回 JSX,保留在主组件中) const getSeverityIcon = (severity: string) => { switch (severity) { case 'critical': @@ -310,7 +103,7 @@ export function AIAlertAnalyzer() {
- {/* Alert List */} + {/* 告警列表(左侧) */}
@@ -377,165 +170,21 @@ export function AIAlertAnalyzer() { - {/* AI Analysis Result */} - - - - - AI 分析结果 - - - - - {!selectedAlert ? ( -
- -

选择左侧告警进行AI智能分析

-
- ) : isAnalyzing ? ( -
- -

AI正在分析告警根因...

-

正在关联日志、指标和历史案例

-
- ) : analysis ? ( -
- {/* Confidence Score */} -
-
- - 分析置信度 -
-
-
-
-
- {analysis.confidence}% -
-
- - {/* Root Cause */} -
-

- - 根因分析 -

-
-

{analysis.rootCause}

-
-
- - {/* Impact */} -
-

- - 影响范围 -

-
-

{analysis.impact}

-
-
- - {/* Recommendations */} -
-

- - 修复建议 -

-
- {analysis.recommendations.map((rec, idx) => ( -
- - {idx + 1} - - {rec} -
- ))} -
-
- - {/* Similar Cases */} -
- - - 发现 {analysis.similarCases} 个相似历史案例 - -
- - {/* Auto Fix */} - {analysis.autoFixScript && ( -
-

- - 自动修复脚本 -

-
-
{analysis.autoFixScript}
-
- -
- )} -
- ) : null} - - - + {/* AI 分析结果(右侧,子组件) */} +
- {/* Auto Fix Dialog */} - - - - - - 自动修复脚本 - - - AI生成的自动修复脚本,请确认后执行 - - -
-
-
- 修复脚本 - -
-
-                {analysis?.autoFixScript}
-              
-
-
- - - 警告:执行脚本前请确保已备份重要数据 - -
-
-
- - -
-
-
+ {/* 自动修复脚本确认弹窗(子组件) */} +
); } diff --git a/frontend/src/components/aiops/AIAnalysisResult.tsx b/frontend/src/components/aiops/AIAnalysisResult.tsx new file mode 100644 index 0000000..857a047 --- /dev/null +++ b/frontend/src/components/aiops/AIAnalysisResult.tsx @@ -0,0 +1,133 @@ +// AI 分析结果卡片(右侧面板):置信度/根因/影响/修复建议/相似案例/自动修复脚本 // Logan.Li +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Button } from '@/components/ui/button'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import { Sparkles, Brain, Loader2 } from 'lucide-react'; +import { AlertCircle, TrendingUp, CheckCircle, FileText, Terminal, Play } from 'lucide-react'; +import type { AlertItem, AIAnalysis } from './analyzerHelpers'; + +interface AIAnalysisResultProps { + selectedAlert: AlertItem | null; + isAnalyzing: boolean; + analysis: AIAnalysis | null; + onAutoFix: () => void; +} + +export function AIAnalysisResult({ selectedAlert, isAnalyzing, analysis, onAutoFix }: AIAnalysisResultProps) { + return ( + + + + + AI 分析结果 + + + + + {!selectedAlert ? ( +
+ +

选择左侧告警进行AI智能分析

+
+ ) : isAnalyzing ? ( +
+ +

AI正在分析告警根因...

+

正在关联日志、指标和历史案例

+
+ ) : analysis ? ( +
+ {/* 置信度 */} +
+
+ + 分析置信度 +
+
+
+
+
+ {analysis.confidence}% +
+
+ + {/* 根因分析 */} +
+

+ + 根因分析 +

+
+

{analysis.rootCause}

+
+
+ + {/* 影响范围 */} +
+

+ + 影响范围 +

+
+

{analysis.impact}

+
+
+ + {/* 修复建议 */} +
+

+ + 修复建议 +

+
+ {analysis.recommendations.map((rec, idx) => ( +
+ + {idx + 1} + + {rec} +
+ ))} +
+
+ + {/* 相似历史案例 */} +
+ + + 发现 {analysis.similarCases} 个相似历史案例 + +
+ + {/* 自动修复脚本 */} + {analysis.autoFixScript && ( +
+

+ + 自动修复脚本 +

+
+
{analysis.autoFixScript}
+
+ +
+ )} +
+ ) : null} + + + + ); +} diff --git a/frontend/src/components/aiops/AutoFixDialog.tsx b/frontend/src/components/aiops/AutoFixDialog.tsx new file mode 100644 index 0000000..acdc6a4 --- /dev/null +++ b/frontend/src/components/aiops/AutoFixDialog.tsx @@ -0,0 +1,73 @@ +// 自动修复脚本确认弹窗:展示 AI 生成的修复脚本 + 复制按钮 + 确认执行 // Logan.Li +import { useState } from 'react'; +import { Button } from '@/components/ui/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { AlertTriangle, Copy, Check, Play, Terminal } from 'lucide-react'; + +interface AutoFixDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + script?: string; +} + +export function AutoFixDialog({ open, onOpenChange, script }: AutoFixDialogProps) { + const [copied, setCopied] = useState(false); + + const copyScript = () => { + if (script) { + navigator.clipboard.writeText(script); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } + }; + + return ( + + + + + + 自动修复脚本 + + + AI生成的自动修复脚本,请确认后执行 + + +
+
+
+ 修复脚本 + +
+
+              {script}
+            
+
+
+ + + 警告:执行脚本前请确保已备份重要数据 + +
+
+
+ + +
+
+
+ ); +} diff --git a/frontend/src/components/aiops/analyzerHelpers.ts b/frontend/src/components/aiops/analyzerHelpers.ts new file mode 100644 index 0000000..ff6ca15 --- /dev/null +++ b/frontend/src/components/aiops/analyzerHelpers.ts @@ -0,0 +1,195 @@ +// AI 告警分析纯逻辑辅助函数:类型定义 + 后端告警映射 + 动态 AI 分析生成 + 严重等级配色 // Logan.Li + +// 告警条目(前端统一模型,从后端 alert event 映射而来) +export interface AlertItem { + id: string; + name: string; + severity: 'critical' | 'warning' | 'info'; + status: 'active' | 'resolved'; + source: string; + metric: string; + threshold: string; + currentValue: string; + duration: string; + startedAt: string; + description: string; +} + +// AI 分析结果 +export interface AIAnalysis { + rootCause: string; + impact: string; + recommendations: string[]; + autoFixScript?: string; + similarCases: number; + confidence: number; +} + +// ─── Dynamic AI analysis generator ─── +// 基于告警指标类型,生成上下文相关的根因分析、影响评估、修复建议与自动修复脚本。 +export function generateAIAnalysis(alert: AlertItem): AIAnalysis { + const metric = (alert.metric || '').toLowerCase(); + const target = alert.source || '目标主机'; + const isCritical = alert.severity === 'critical'; + + const baseConfidence = isCritical ? 88 + Math.floor(Math.random() * 8) : 75 + Math.floor(Math.random() * 12); + + // CPU 告警 + if (metric.includes('cpu')) { + return { + rootCause: `检测到 ${target} 上 CPU 使用率达到 ${alert.currentValue},持续超过阈值 ${alert.threshold}。可能原因:1) 某进程存在死循环或高计算负载;2) GC 频繁触发(Java/Go 应用);3) 业务流量突增导致处理能力不足。`, + impact: isCritical + ? `CPU 持续高负载将导致服务响应延迟显著增加,严重时可能触发雪崩效应,影响全部依赖该节点的业务。` + : `CPU 使用率偏高,可能导致部分请求处理变慢,建议及时排查避免进一步恶化。`, + recommendations: [ + `登录 ${target} 执行 top/htop 定位高 CPU 进程`, + '检查是否有异常定时任务或批处理任务在运行', + `考虑临时扩容或将部分流量调度到其他节点`, + '优化应用代码,排查是否存在低效算法或资源泄漏', + ], + autoFixScript: `#!/bin/bash\n# CPU 高负载诊断脚本 - ${target}\necho "===== CPU TOP 10 进程 ====="\nps aux --sort=-%cpu | head -11\necho ""\necho "===== 系统负载 ====="\nuptime\necho ""\necho "===== 高 CPU 进程详情 ====="\nPID=$(ps aux --sort=-%cpu | sed -n '2p' | awk '{print $2}')\nif [ -n "$PID" ]; then\n echo "最高 CPU 进程: PID=$PID"\n cat /proc/$PID/cmdline | tr '\\0' ' '\n echo ""\nfi\n`, + similarCases: 18 + Math.floor(Math.random() * 8), + confidence: baseConfidence, + }; + } + + // 内存告警 + if (metric.includes('mem') || metric.includes('ram')) { + return { + rootCause: `检测到 ${target} 内存使用率达到 ${alert.currentValue},接近或超过阈值 ${alert.threshold}。常见原因:1) 应用内存泄漏,对象未被正确释放;2) 缓存配置过大;3) 数据库连接池未及时释放。`, + impact: isCritical + ? `内存即将耗尽可能触发 OOM Killer,导致关键进程被强制终止,服务中断风险极高。` + : `内存持续增长,长期可能导致 OOM,建议尽快排查内存使用情况。`, + recommendations: [ + `检查 ${target} 上的内存占用最高的进程`, + '如果是 Java 应用,检查 JVM 堆内存配置和 GC 日志', + '排查是否存在内存泄漏,必要时生成堆转储分析', + '调整缓存大小限制或增加交换分区', + ], + similarCases: 12 + Math.floor(Math.random() * 6), + confidence: baseConfidence, + }; + } + + // 磁盘告警 + if (metric.includes('disk') || metric.includes('space')) { + return { + rootCause: `检测到 ${target} 磁盘使用率达到 ${alert.currentValue},超过阈值 ${alert.threshold}。最常见原因:1) 日志文件未配置轮转/清理;2) 临时文件堆积;3) 数据库数据文件膨胀。`, + impact: isCritical + ? `磁盘空间不足可能导致服务无法写入数据/日志,数据库可能崩溃,文件系统变只读,影响范围极大。` + : `磁盘空间告警,如不及时清理可能导致服务异常。`, + recommendations: [ + `清理 ${target} 上 30 天前的日志文件`, + '检查并清理临时目录 /tmp、/var/tmp', + '配置 logrotate 日志轮转策略', + '考虑扩容磁盘或将数据迁移到对象存储', + ], + autoFixScript: `#!/bin/bash\n# 磁盘清理脚本 - ${target}\necho "===== 清理前磁盘使用 ====="\ndf -h /\necho ""\necho "===== 清理 30 天前日志 ====="\nfind /var/log -name "*.log" -mtime +30 -delete 2>/dev/null\nfind /var/log -name "*.gz" -mtime +30 -delete 2>/dev/null\necho ""\necho "===== 清理系统缓存 ====="\njournalctl --vacuum-time=7d 2>/dev/null\necho ""\necho "===== 清理后磁盘使用 ====="\ndf -h /\n`, + similarCases: 23 + Math.floor(Math.random() * 10), + confidence: baseConfidence + 3, + }; + } + + // 网络告警 + if (metric.includes('net') || metric.includes('latency') || metric.includes('bandwidth')) { + return { + rootCause: `检测到 ${target} 网络指标异常(当前值 ${alert.currentValue}),可能原因:1) 上游依赖服务响应变慢;2) 网络带宽打满;3) DNS 解析延迟;4) 连接数达到上限。`, + impact: isCritical + ? `网络异常将导致所有经过该节点的请求超时,影响所有上游业务的可用性。` + : `网络延迟偏高,可能影响用户体验,建议排查网络链路。`, + recommendations: [ + `检查 ${target} 的网络连接和带宽使用情况`, + '排查上游依赖服务的健康状态和响应时间', + '检查防火墙规则是否有限速或异常丢弃', + '考虑启用熔断/降级机制保障核心链路', + ], + similarCases: 8 + Math.floor(Math.random() * 5), + confidence: baseConfidence - 5, + }; + } + + // 服务可用性告警 + if (metric.includes('service') || metric.includes('up') || metric.includes('avail')) { + return { + rootCause: `检测到 ${target} 服务不可用(指标 ${alert.metric} = ${alert.currentValue})。可能原因:1) 进程崩溃或被 OOM Killer 终止;2) 端口被占用或监听异常;3) 健康检查端点返回错误;4) 配置文件错误导致启动失败。`, + impact: isCritical + ? `服务完全不可用,所有依赖该服务的业务功能将中断,需要立即处理。` + : `服务可用性下降,部分功能可能受影响。`, + recommendations: [ + `立即检查 ${target} 的服务状态: systemctl status `, + '查看服务日志排查崩溃原因', + '检查端口占用和监听状态: ss -tlnp', + '必要时重启服务并监控恢复情况', + ], + autoFixScript: `#!/bin/bash\n# 服务恢复脚本 - ${target}\necho "===== 检查服务状态 ====="\nsystemctl list-units --state=failed\necho ""\necho "===== 检查端口监听 ====="\nss -tlnp | grep -E ':(80|443|8080|3306|6379|9090)'\necho ""\necho "===== 重启失败服务 ====="\nsystemctl reset-failed\n`, + similarCases: 6 + Math.floor(Math.random() * 4), + confidence: baseConfidence, + }; + } + + // 默认/通用分析 + return { + rootCause: `检测到 ${target} 触发告警「${alert.name}」,当前指标值 ${alert.currentValue} 超过阈值 ${alert.threshold}。建议进一步排查具体指标数据和相关日志以确定根因。`, + impact: isCritical + ? `该告警级别为严重,可能影响业务正常运行,建议优先处理。` + : `该告警需要关注,持续恶化可能影响系统稳定性。`, + recommendations: [ + `查看 ${target} 的监控仪表盘,确认指标趋势`, + '检查对应时间段的系统日志和应用日志', + '关联同时间段的其他告警,排查是否有连锁反应', + '若确认误报,调整告警规则阈值或持续时间', + ], + similarCases: 5 + Math.floor(Math.random() * 5), + confidence: baseConfidence - 8, + }; +} + +// ─── 后端告警事件 → AlertItem 映射 ─── +// 后端 alert event 字段为 snake_case(rule_name/target/started_at/value 等),此处统一映射为前端 AlertItem +export function mapAlertEvent(event: any): AlertItem { + const expr = event.rule?.expression || ''; + // 从表达式(如 "cpu_usage > 80")中提取指标名与阈值 + const metricMatch = expr.match(/([\w_]+)\s*[><=!]+\s*([\d.]+)/); + const metric = metricMatch ? metricMatch[1] : expr || 'unknown'; + const threshold = metricMatch ? metricMatch[2] + '%' : '-'; + + const value = event.value ?? 0; + const isPercent = metric.includes('usage') || metric.includes('cpu') || metric.includes('disk') || metric.includes('mem'); + const currentValue = isPercent ? value.toFixed(1) + '%' : value.toFixed(2); + + // 从 started_at 到现在(或 resolved_at)计算持续时间 + const endTime = event.resolved_at ? new Date(event.resolved_at) : new Date(); + const startTime = new Date(event.started_at); + const diffMin = Math.max(1, Math.round((endTime.getTime() - startTime.getTime()) / 60000)); + const duration = diffMin >= 60 ? `${Math.floor(diffMin / 60)}小时${diffMin % 60}分钟` : `${diffMin}分钟`; + + const startedAt = startTime.toLocaleString('zh-CN', { hour12: false }); + + return { + id: String(event.id), + name: event.rule_name || event.rule?.name || '未知告警', + severity: event.severity === 'critical' ? 'critical' : event.severity === 'warning' ? 'warning' : 'info', + status: event.status === 'firing' ? 'active' : 'resolved', + source: event.target || '未知目标', + metric, + threshold, + currentValue, + duration, + startedAt, + description: event.message && event.message !== `告警事件 ${event.id}` + ? event.message + : event.rule?.description || `${event.rule_name || '告警'}: ${event.target} 当前值 ${currentValue}`, + }; +} + +// 严重等级配色(纯字符串,无 JSX) +export function getSeverityColor(severity: string): string { + switch (severity) { + case 'critical': + return 'bg-red-500/10 text-red-400 border-red-500/30'; + case 'warning': + return 'bg-amber-500/10 text-amber-400 border-amber-500/30'; + default: + return 'bg-blue-500/10 text-blue-400 border-blue-500/30'; + } +}