diff --git a/m18-health-check/package.json b/m18-health-check/package.json new file mode 100644 index 00000000..1887483c --- /dev/null +++ b/m18-health-check/package.json @@ -0,0 +1,16 @@ +{ + "name": "hololake-health", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "express": "^5.2.1" + } +} diff --git a/m18-health-check/server.js b/m18-health-check/server.js new file mode 100644 index 00000000..40ed6a97 --- /dev/null +++ b/m18-health-check/server.js @@ -0,0 +1,240 @@ +const express = require('express'); +const os = require('os'); + +const app = express(); +const PORT = 3000; + +// 记录服务器启动时间 +const SERVER_START_TIME = new Date(); + +// 解析JSON请求体 +app.use(express.json()); + +// ========== 数据存储 ========== +let heartbeats = []; +const patrolHistory = []; +const alerts = []; +const HEARTBEAT_TIMEOUT = 5 * 60 * 1000; // 5分钟 + +// ========== 告警检查函数 ========== +function checkAlerts(memPercent) { + let level = null; + let message = ''; + + if (memPercent > 90) { + level = 'critical'; + message = `内存使用率过高: ${memPercent}%`; + } else if (memPercent > 80) { + level = 'warning'; + message = `内存使用率警告: ${memPercent}%`; + } + + if (level) { + const alert = { + timestamp: new Date().toISOString(), + level: level, + message: message, + memoryPercent: memPercent + }; + alerts.push(alert); + + if (alerts.length > 20) { + alerts.shift(); + } + + console.log(`[ALERT] ${level.toUpperCase()}: ${message}`); + } +} + +// ========== 在线状态检查函数 ========== +function checkOnlineStatus() { + const now = Date.now(); + const onlineServices = []; + const offlineServices = []; + + const latestHeartbeats = {}; + heartbeats.forEach(hb => { + const source = hb.service || 'unknown'; + if (!latestHeartbeats[source] || new Date(hb.timestamp) > new Date(latestHeartbeats[source].timestamp)) { + latestHeartbeats[source] = hb; + } + }); + + for (const [source, hb] of Object.entries(latestHeartbeats)) { + const hbTime = new Date(hb.timestamp).getTime(); + const isOnline = (now - hbTime) < HEARTBEAT_TIMEOUT; + + const serviceInfo = { + source: source, + lastHeartbeat: hb.timestamp, + secondsAgo: Math.floor((now - hbTime) / 1000), + status: isOnline ? 'online' : 'offline' + }; + + if (isOnline) { + onlineServices.push(serviceInfo); + } else { + offlineServices.push(serviceInfo); + } + } + + return { online: onlineServices, offline: offlineServices }; +} + +// ========== API路由 ========== + +// GET /api/health - 快速健康检查 +app.get('/api/health', (req, res) => { + res.json({ + status: 'healthy', + timestamp: new Date().toISOString() + }); +}); + +// GET /api/status - 详细系统状态 +app.get('/api/status', (req, res) => { + const totalMem = os.totalmem(); + const freeMem = os.freemem(); + const usedMem = totalMem - freeMem; + const memPercent = Math.round((usedMem / totalMem) * 100); + + checkAlerts(memPercent); + + res.json({ + service: 'HoloLake Health Monitor', + version: '1.0.0', + status: 'running', + timestamp: new Date().toISOString(), + uptime: { + seconds: Math.floor((Date.now() - SERVER_START_TIME.getTime()) / 1000), + startedAt: SERVER_START_TIME.toISOString() + }, + system: { + platform: os.platform(), + arch: os.arch(), + hostname: os.hostname(), + nodeVersion: process.version + }, + memory: { + totalMB: Math.round(totalMem / 1024 / 1024), + usedMB: Math.round(usedMem / 1024 / 1024), + freeMB: Math.round(freeMem / 1024 / 1024), + usagePercent: memPercent + '%' + }, + services: checkOnlineStatus() + }); +}); + +// POST /api/heartbeat - 心跳上报 +app.post('/api/heartbeat', (req, res) => { + const heartbeat = { + timestamp: new Date().toISOString(), + service: req.body.service || 'unknown', + status: req.body.status || 'ok' + }; + heartbeats.push(heartbeat); + + res.json({ + received: true, + heartbeat: heartbeat + }); +}); + +// GET /api/heartbeat/history - 查看心跳历史 +app.get('/api/heartbeat/history', (req, res) => { + res.json({ + total: heartbeats.length, + heartbeats: heartbeats.slice(-20) + }); +}); + +// GET /api/heartbeat/online - 查看在线服务 +app.get('/api/heartbeat/online', (req, res) => { + const status = checkOnlineStatus(); + res.json({ + timestamp: new Date().toISOString(), + onlineCount: status.online.length, + offlineCount: status.offline.length, + online: status.online, + offline: status.offline + }); +}); + +// GET /api/patrol/history - 查看巡检历史 +app.get('/api/patrol/history', (req, res) => { + res.json({ + total: patrolHistory.length, + patrols: patrolHistory + }); +}); + +// GET /api/alerts - 查看告警历史 +app.get('/api/alerts', (req, res) => { + res.json({ + total: alerts.length, + critical: alerts.filter(a => a.level === 'critical').length, + warning: alerts.filter(a => a.level === 'warning').length, + alerts: alerts + }); +}); + +// GET / - 根路径欢迎页 +app.get('/', (req, res) => { + res.json({ + service: 'HoloLake Health Check & Status Report', + version: '2.0.0', + endpoints: [ + 'GET /api/health - 快速健康检查', + 'GET /api/status - 详细系统状态', + 'POST /api/heartbeat - 心跳上报', + 'GET /api/heartbeat/history - 心跳历史', + 'GET /api/heartbeat/online - 在线服务', + 'GET /api/patrol/history - 巡检历史', + 'GET /api/alerts - 告警历史' + ] + }); +}); + +// ========== 定时自动巡检 ========== +setInterval(() => { + console.log('[PATROL] 开始定时巡检...'); + + const totalMem = os.totalmem(); + const freeMem = os.freemem(); + const usedMem = totalMem - freeMem; + const memPercent = Math.round((usedMem / totalMem) * 100); + + const patrolRecord = { + timestamp: new Date().toISOString(), + memory: { + totalMB: Math.round(totalMem / 1024 / 1024), + usedMB: Math.round(usedMem / 1024 / 1024), + usagePercent: memPercent + }, + uptime: Math.floor((Date.now() - SERVER_START_TIME.getTime()) / 1000), + heartbeatCount: heartbeats.length + }; + + patrolHistory.push(patrolRecord); + if (patrolHistory.length > 50) { + patrolHistory.shift(); + } + + checkAlerts(memPercent); + + console.log(`[PATROL] 巡检完成 - 内存使用: ${memPercent}%`); +}, 60000); + +// 启动服务器 +app.listen(PORT, () => { + console.log('='.repeat(50)); + console.log('🌊 HoloLake Health Check & Status Report'); + console.log('📡 服务运行在: http://localhost:' + PORT); + console.log('💚 GET /api/health - 健康检查'); + console.log('📊 GET /api/status - 系统状态'); + console.log('💓 POST /api/heartbeat - 心跳上报'); + console.log('🔄 定时巡检 - 每60秒'); + console.log('🚨 异常告警 - 内存>80%'); + console.log('⏰ 心跳超时 - 5分钟'); + console.log('='.repeat(50)); +}); \ No newline at end of file