Skip to main content
Glama
monitoring.ts20.2 kB
import { defineStore } from "pinia"; import { ref, computed } from "vue"; import type { DetailedSystemMetrics, PerformanceAlert, MonitoringConfig, ChartSeries, } from "@/types"; // 日志相关类型定义 interface LogEntry { id: string; timestamp: Date; level: "info" | "warn" | "error" | "debug"; message: string; source?: string; data?: any; } interface LogFilter { level?: string; source?: string; search?: string; startTime?: Date; endTime?: Date; } interface LogStats { total: number; info: number; warn: number; error: number; debug: number; } interface SystemHealth { status: "healthy" | "warning" | "critical" | "unknown"; uptime: number; lastCheck: Date; issues: string[]; } export const useMonitoringStore = defineStore("monitoring", () => { // 状态 const metrics = ref<DetailedSystemMetrics[]>([]); const currentMetrics = ref<DetailedSystemMetrics | null>(null); const alerts = ref<PerformanceAlert[]>([]); const config = ref<MonitoringConfig>({ refreshInterval: 5000, // 5秒 alerts: { cpu: { warning: 70, critical: 90 }, memory: { warning: 80, critical: 95 }, disk: { warning: 85, critical: 95 }, network: { warning: 1000000, critical: 10000000 }, // bytes/sec }, enableAlerts: true, enableSound: false, }); const isConnected = ref(false); const isLoading = ref(false); const error = ref<string | null>(null); // 新增状态 const systemMetrics = ref<DetailedSystemMetrics | null>(null); const serverMetrics = ref<any>(null); const systemHealth = ref<SystemHealth>({ status: "unknown", uptime: 0, lastCheck: new Date(), issues: [], }); const metricsHistory = ref<DetailedSystemMetrics[]>([]); const logs = ref<LogEntry[]>([]); const logFilter = ref<LogFilter>({}); const realTimeEnabled = ref(true); const lastUpdate = ref<Date>(new Date()); const loading = ref(false); const isMonitoring = ref(false); // 计算属性 const cpuSeries = computed<ChartSeries>(() => ({ name: "CPU使用率", data: metrics.value.slice(-50).map((m) => ({ timestamp: m.timestamp, value: m.cpu.usage, })), color: "#409EFF", })); const memorySeries = computed<ChartSeries>(() => ({ name: "内存使用率", data: metrics.value.slice(-50).map((m) => ({ timestamp: m.timestamp, value: m.memory.usage, })), color: "#67C23A", })); const networkInSeries = computed<ChartSeries>(() => ({ name: "网络入流量", data: metrics.value.slice(-50).map((m) => ({ timestamp: m.timestamp, value: m.network.bytesIn, })), color: "#E6A23C", })); const networkOutSeries = computed<ChartSeries>(() => ({ name: "网络出流量", data: metrics.value.slice(-50).map((m) => ({ timestamp: m.timestamp, value: m.network.bytesOut, })), color: "#F56C6C", })); const diskSeries = computed<ChartSeries>(() => ({ name: "磁盘使用率", data: metrics.value.slice(-50).map((m) => ({ timestamp: m.timestamp, value: m.disk.usage, })), color: "#909399", })); const activeAlerts = computed(() => alerts.value.filter((alert) => !alert.acknowledged), ); const criticalAlerts = computed(() => activeAlerts.value.filter((alert) => alert.level === "critical"), ); const warningAlerts = computed(() => activeAlerts.value.filter((alert) => alert.level === "warning"), ); const systemStatus = computed(() => { if (!currentMetrics.value) return "unknown"; const cpu = currentMetrics.value.cpu.usage; const memory = currentMetrics.value.memory.usage; const disk = currentMetrics.value.disk.usage; if ( cpu >= config.value.alerts.cpu.critical || memory >= config.value.alerts.memory.critical || disk >= config.value.alerts.disk.critical ) { return "critical"; } if ( cpu >= config.value.alerts.cpu.warning || memory >= config.value.alerts.memory.warning || disk >= config.value.alerts.disk.warning ) { return "warning"; } return "healthy"; }); // 新增计算属性 const filteredLogs = computed(() => { let filtered = logs.value; if (logFilter.value.level) { filtered = filtered.filter((log) => log.level === logFilter.value.level); } if (logFilter.value.source) { filtered = filtered.filter( (log) => log.source === logFilter.value.source, ); } if (logFilter.value.search) { const search = logFilter.value.search.toLowerCase(); filtered = filtered.filter((log) => log.message.toLowerCase().includes(search), ); } if (logFilter.value.startTime) { filtered = filtered.filter( (log) => log.timestamp >= logFilter.value.startTime!, ); } if (logFilter.value.endTime) { filtered = filtered.filter( (log) => log.timestamp <= logFilter.value.endTime!, ); } return filtered.sort( (a, b) => b.timestamp.getTime() - a.timestamp.getTime(), ); }); const logStats = computed<LogStats>(() => { const stats = { total: logs.value.length, info: 0, warn: 0, error: 0, debug: 0, }; logs.value.forEach((log) => { stats[log.level]++; }); return stats; }); // WebSocket连接 let ws: WebSocket | null = null; let reconnectTimer: NodeJS.Timeout | null = null; // 方法 const connectWebSocket = () => { try { // 假设WebSocket端点,实际项目中应该从配置获取 ws = new WebSocket("ws://localhost:3001/ws/monitoring"); ws.onopen = () => { isConnected.value = true; error.value = null; console.log("Monitoring WebSocket connected"); }; ws.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.type === "metrics") { updateMetrics(data.payload); } else if (data.type === "alert") { addAlert(data.payload); } } catch (err) { console.error("Failed to parse WebSocket message:", err); } }; ws.onclose = () => { isConnected.value = false; console.log("Monitoring WebSocket disconnected"); // 尝试重连 if (!reconnectTimer) { reconnectTimer = setTimeout(() => { reconnectTimer = null; connectWebSocket(); }, 5000); } }; ws.onerror = (err) => { error.value = "WebSocket连接错误"; console.error("Monitoring WebSocket error:", err); }; } catch (err) { error.value = "WebSocket连接失败"; console.error("Failed to connect WebSocket:", err); } }; const disconnectWebSocket = () => { if (ws) { ws.close(); ws = null; } if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; } isConnected.value = false; }; const updateMetrics = (newMetrics: DetailedSystemMetrics) => { currentMetrics.value = newMetrics; metrics.value.push(newMetrics); // 保持最近1000个数据点 if (metrics.value.length > 1000) { metrics.value = metrics.value.slice(-1000); } // 检查告警 checkAlerts(newMetrics); }; const checkAlerts = (metrics: DetailedSystemMetrics) => { if (!config.value.enableAlerts) return; const now = new Date(); // CPU告警 if (metrics.cpu.usage >= config.value.alerts.cpu.critical) { addAlert({ id: `cpu-critical-${now.getTime()}`, type: "cpu", level: "critical", message: `CPU使用率过高: ${metrics.cpu.usage.toFixed(1)}%`, value: metrics.cpu.usage, threshold: config.value.alerts.cpu.critical, timestamp: now, acknowledged: false, }); } else if (metrics.cpu.usage >= config.value.alerts.cpu.warning) { addAlert({ id: `cpu-warning-${now.getTime()}`, type: "cpu", level: "warning", message: `CPU使用率较高: ${metrics.cpu.usage.toFixed(1)}%`, value: metrics.cpu.usage, threshold: config.value.alerts.cpu.warning, timestamp: now, acknowledged: false, }); } // 内存告警 if (metrics.memory.usage >= config.value.alerts.memory.critical) { addAlert({ id: `memory-critical-${now.getTime()}`, type: "memory", level: "critical", message: `内存使用率过高: ${metrics.memory.usage.toFixed(1)}%`, value: metrics.memory.usage, threshold: config.value.alerts.memory.critical, timestamp: now, acknowledged: false, }); } else if (metrics.memory.usage >= config.value.alerts.memory.warning) { addAlert({ id: `memory-warning-${now.getTime()}`, type: "memory", level: "warning", message: `内存使用率较高: ${metrics.memory.usage.toFixed(1)}%`, value: metrics.memory.usage, threshold: config.value.alerts.memory.warning, timestamp: now, acknowledged: false, }); } // 磁盘告警 if (metrics.disk.usage >= config.value.alerts.disk.critical) { addAlert({ id: `disk-critical-${now.getTime()}`, type: "disk", level: "critical", message: `磁盘使用率过高: ${metrics.disk.usage.toFixed(1)}%`, value: metrics.disk.usage, threshold: config.value.alerts.disk.critical, timestamp: now, acknowledged: false, }); } else if (metrics.disk.usage >= config.value.alerts.disk.warning) { addAlert({ id: `disk-warning-${now.getTime()}`, type: "disk", level: "warning", message: `磁盘使用率较高: ${metrics.disk.usage.toFixed(1)}%`, value: metrics.disk.usage, threshold: config.value.alerts.disk.warning, timestamp: now, acknowledged: false, }); } }; const addAlert = (alert: PerformanceAlert) => { alerts.value.unshift(alert); // 保持最近100个告警 if (alerts.value.length > 100) { alerts.value = alerts.value.slice(0, 100); } }; const acknowledgeAlert = (alertId: string) => { const alert = alerts.value.find((a) => a.id === alertId); if (alert) { alert.acknowledged = true; } }; const clearAcknowledgedAlerts = () => { alerts.value = alerts.value.filter((alert) => !alert.acknowledged); }; const dismissAlert = (alertId: string) => { const index = alerts.value.findIndex((a) => a.id === alertId); if (index !== -1) { alerts.value.splice(index, 1); } }; const refreshMetrics = async () => { isLoading.value = true; try { // 模拟刷新数据 const mockMetrics = generateMockMetrics(); mockMetrics.memory.free = mockMetrics.memory.total - mockMetrics.memory.used; mockMetrics.memory.usage = (mockMetrics.memory.used / mockMetrics.memory.total) * 100; mockMetrics.disk.free = mockMetrics.disk.total - mockMetrics.disk.used; mockMetrics.disk.usage = (mockMetrics.disk.used / mockMetrics.disk.total) * 100; updateMetrics(mockMetrics); } finally { isLoading.value = false; } }; const startMonitoring = (interval?: number) => { if (interval) { config.value.refreshInterval = interval; } isConnected.value = true; return startMockData(); }; const stopMonitoring = () => { isConnected.value = false; // 实际应用中这里会清除定时器 }; const updateConfig = (newConfig: Partial<MonitoringConfig>) => { config.value = { ...config.value, ...newConfig }; }; // 新增方法 const fetchSystemMetrics = async () => { loading.value = true; try { // 模拟获取系统指标 const mockMetrics = generateMockMetrics(); mockMetrics.memory.free = mockMetrics.memory.total - mockMetrics.memory.used; mockMetrics.memory.usage = (mockMetrics.memory.used / mockMetrics.memory.total) * 100; mockMetrics.disk.free = mockMetrics.disk.total - mockMetrics.disk.used; mockMetrics.disk.usage = (mockMetrics.disk.used / mockMetrics.disk.total) * 100; systemMetrics.value = mockMetrics; metricsHistory.value.push(mockMetrics); // 保持最近1000个数据点 if (metricsHistory.value.length > 1000) { metricsHistory.value = metricsHistory.value.slice(-1000); } lastUpdate.value = new Date(); // 更新系统健康状态 systemHealth.value = { status: systemStatus.value as any, uptime: Math.floor(Date.now() / 1000) - 86400, lastCheck: new Date(), issues: criticalAlerts.value.map((alert) => alert.message), }; } finally { loading.value = false; } }; const fetchServerMetrics = async () => { loading.value = true; try { // 模拟获取服务器指标 serverMetrics.value = { requests: Math.floor(Math.random() * 1000), responses: Math.floor(Math.random() * 1000), errors: Math.floor(Math.random() * 10), avgResponseTime: Math.random() * 100, activeConnections: Math.floor(Math.random() * 50), }; lastUpdate.value = new Date(); } finally { loading.value = false; } }; const fetchLogs = async (options?: { limit?: number; level?: string }) => { loading.value = true; try { // 模拟获取日志 const mockLogs: LogEntry[] = []; const levels: LogEntry["level"][] = ["info", "warn", "error", "debug"]; const sources = ["system", "api", "database", "auth"]; for (let i = 0; i < (options?.limit || 50); i++) { const level = (options?.level as LogEntry["level"]) || levels[Math.floor(Math.random() * levels.length)]; mockLogs.push({ id: `log-${Date.now()}-${i}`, timestamp: new Date(Date.now() - Math.random() * 86400000), level, message: `Sample ${level} message ${i + 1}`, source: sources[Math.floor(Math.random() * sources.length)], data: level === "error" ? { stack: "Error stack trace..." } : undefined, }); } logs.value = [...mockLogs, ...logs.value].slice(0, 1000); lastUpdate.value = new Date(); } finally { loading.value = false; } }; const setLogFilter = (filter: Partial<LogFilter>) => { logFilter.value = { ...logFilter.value, ...filter }; }; const clearLogFilter = () => { logFilter.value = {}; }; const exportLogs = async (format: "json" | "csv" = "json") => { const logsToExport = filteredLogs.value; if (format === "json") { const dataStr = JSON.stringify(logsToExport, null, 2); const dataBlob = new Blob([dataStr], { type: "application/json" }); const url = URL.createObjectURL(dataBlob); const link = document.createElement("a"); link.href = url; link.download = `logs-${new Date().toISOString().split("T")[0]}.json`; link.click(); URL.revokeObjectURL(url); } else { const csvHeader = "Timestamp,Level,Source,Message\n"; const csvContent = logsToExport .map( (log) => `${log.timestamp.toISOString()},${log.level},${log.source || ""},"${log.message.replace(/"/g, '""')}"`, ) .join("\n"); const dataBlob = new Blob([csvHeader + csvContent], { type: "text/csv" }); const url = URL.createObjectURL(dataBlob); const link = document.createElement("a"); link.href = url; link.download = `logs-${new Date().toISOString().split("T")[0]}.csv`; link.click(); URL.revokeObjectURL(url); } }; const clearLogs = () => { logs.value = []; }; const toggleRealTime = () => { realTimeEnabled.value = !realTimeEnabled.value; }; const refreshAll = async () => { await Promise.all([ fetchSystemMetrics(), fetchServerMetrics(), fetchLogs({ limit: 20 }), ]); }; const updateServerMetrics = (serverId: string, metrics: any) => { // Update server-specific metrics if (serverMetrics.value[serverId]) { serverMetrics.value[serverId] = { ...serverMetrics.value[serverId], ...metrics, }; } else { serverMetrics.value[serverId] = metrics; } lastUpdate.value = new Date(); }; const addLogEntry = (entry: LogEntry) => { logs.value.unshift(entry); // Keep only the latest 1000 logs if (logs.value.length > 1000) { logs.value = logs.value.slice(0, 1000); } }; const addLogEntries = (entries: LogEntry[]) => { logs.value.unshift(...entries); // Keep only the latest 1000 logs if (logs.value.length > 1000) { logs.value = logs.value.slice(0, 1000); } }; const updateSystemMetrics = (metrics: any) => { systemMetrics.value = { ...systemMetrics.value, ...metrics }; lastUpdate.value = new Date(); }; // 模拟数据生成器(用于演示) const generateMockMetrics = (): DetailedSystemMetrics => { const now = new Date(); const baseLoad = 0.3 + Math.sin(now.getTime() / 60000) * 0.2; return { timestamp: now, cpu: { usage: Math.max( 0, Math.min(100, baseLoad * 100 + (Math.random() - 0.5) * 30), ), cores: 8, temperature: 45 + Math.random() * 20, frequency: 2400 + Math.random() * 800, // 2.4-3.2 GHz }, memory: { total: 16 * 1024 * 1024 * 1024, // 16GB used: baseLoad * 16 * 1024 * 1024 * 1024 + Math.random() * 2 * 1024 * 1024 * 1024, free: 0, usage: 0, }, network: { bytesIn: Math.random() * 1000000, bytesOut: Math.random() * 1000000, packetsIn: Math.random() * 1000, packetsOut: Math.random() * 1000, connections: Math.floor(Math.random() * 100), }, disk: { total: 500 * 1024 * 1024 * 1024, // 500GB used: baseLoad * 400 * 1024 * 1024 * 1024, free: 0, usage: 0, readOps: Math.random() * 100, writeOps: Math.random() * 50, }, process: { pid: 1234, uptime: Math.floor(Date.now() / 1000) - 86400, // 1天前启动 memory: baseLoad * 1024 * 1024 * 1024, cpu: baseLoad * 100, }, }; }; const startMockData = () => { const interval = setInterval(() => { const mockMetrics = generateMockMetrics(); // 计算派生值 mockMetrics.memory.free = mockMetrics.memory.total - mockMetrics.memory.used; mockMetrics.memory.usage = (mockMetrics.memory.used / mockMetrics.memory.total) * 100; mockMetrics.disk.free = mockMetrics.disk.total - mockMetrics.disk.used; mockMetrics.disk.usage = (mockMetrics.disk.used / mockMetrics.disk.total) * 100; updateMetrics(mockMetrics); }, config.value.refreshInterval); return () => clearInterval(interval); }; return { // 状态 metrics, currentMetrics, alerts, config, isConnected, isLoading, error, systemMetrics, serverMetrics, systemHealth, metricsHistory, logs, logFilter, realTimeEnabled, lastUpdate, loading, isMonitoring, // 计算属性 cpuSeries, memorySeries, networkInSeries, networkOutSeries, diskSeries, activeAlerts, criticalAlerts, warningAlerts, systemStatus, filteredLogs, logStats, // 方法 connectWebSocket, disconnectWebSocket, updateMetrics, addAlert, acknowledgeAlert, clearAcknowledgedAlerts, dismissAlert, refreshMetrics, startMonitoring, stopMonitoring, updateConfig, startMockData, fetchSystemMetrics, fetchServerMetrics, fetchLogs, setLogFilter, clearLogFilter, exportLogs, clearLogs, toggleRealTime, refreshAll, updateServerMetrics, updateSystemMetrics, addLogEntry, addLogEntries, }; });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zaizaizhao/mcp-swagger-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server