package main import ( "encoding/json" "fmt" "log" "net/http" "os" "runtime" "time" ) // envelope keeps JSON responses consistent. type envelope map[string]any func main() { host := getenv("HOST", "0.0.0.0") port := getenv("PORT", "9292") mux := http.NewServeMux() mux.HandleFunc("/", rootHandler) mux.HandleFunc("/api/health", healthHandler) // 拆分的细粒度API端点 mux.HandleFunc("/api/metrics/cpu", cpuMetricsHandler) mux.HandleFunc("/api/metrics/memory", memoryMetricsHandler) mux.HandleFunc("/api/metrics/storage", storageMetricsHandler) mux.HandleFunc("/api/metrics/gpu", gpuMetricsHandler) mux.HandleFunc("/api/metrics/network", networkMetricsHandler) mux.HandleFunc("/api/metrics/system", systemMetricsHandler) mux.HandleFunc("/api/metrics/docker", dockerMetricsHandler) mux.HandleFunc("/api/metrics/latency", latencyMetricsHandler) srv := &http.Server{ Addr: fmt.Sprintf("%s:%s", host, port), Handler: loggingMiddleware(corsMiddleware(mux)), ReadHeaderTimeout: 5 * time.Second, } log.Printf("server starting on http://%s:%s", host, port) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("server error: %v", err) } } func rootHandler(w http.ResponseWriter, r *http.Request) { respondJSON(w, http.StatusOK, envelope{ "service": "萌芽监控面板 API", "version": "1.0.0", "endpoints": []map[string]string{ { "path": "/", "description": "API 信息和可用端点列表", }, { "path": "/api/health", "description": "健康检查", }, { "path": "/api/metrics/cpu", "description": "获取 CPU 监控数据", }, { "path": "/api/metrics/memory", "description": "获取内存监控数据", }, { "path": "/api/metrics/storage", "description": "获取存储监控数据", }, { "path": "/api/metrics/gpu", "description": "获取 GPU 监控数据", }, { "path": "/api/metrics/network", "description": "获取网络接口监控数据", }, { "path": "/api/metrics/system", "description": "获取系统统计信息(进程、包、磁盘速度等)", }, { "path": "/api/metrics/docker", "description": "获取 Docker 容器监控数据", }, }, }) } func healthHandler(w http.ResponseWriter, r *http.Request) { respondJSON(w, http.StatusOK, envelope{ "status": "ok", "timestamp": time.Now().UTC(), }) } // CPU监控数据 func cpuMetricsHandler(w http.ResponseWriter, r *http.Request) { cpuModel := firstMatchInFile("/proc/cpuinfo", "model name") cpuUsage, err := readCPUUsage() if err != nil { cpuUsage = 0 } cpuTemp := readCPUTemperature() perCoreUsage := readPerCoreUsage() loads := readLoadAverages() cores := runtime.NumCPU() respondJSON(w, http.StatusOK, envelope{ "data": CPUMetrics{ Model: cpuModel, Cores: cores, UsagePercent: round(cpuUsage, 2), LoadAverages: loads, Temperature: cpuTemp, PerCoreUsage: perCoreUsage, }, }) } // 内存监控数据 func memoryMetricsHandler(w http.ResponseWriter, r *http.Request) { mem, err := readMemory() if err != nil { respondJSON(w, http.StatusInternalServerError, envelope{ "error": "failed to read memory", }) return } respondJSON(w, http.StatusOK, envelope{ "data": mem, }) } // 存储监控数据 func storageMetricsHandler(w http.ResponseWriter, r *http.Request) { storage, err := readAllStorage() if err != nil { respondJSON(w, http.StatusInternalServerError, envelope{ "error": "failed to read storage", }) return } respondJSON(w, http.StatusOK, envelope{ "data": storage, }) } // GPU监控数据 func gpuMetricsHandler(w http.ResponseWriter, r *http.Request) { gpu := readGPU() respondJSON(w, http.StatusOK, envelope{ "data": gpu, }) } // 网络监控数据 func networkMetricsHandler(w http.ResponseWriter, r *http.Request) { network := readNetworkInterfaces() respondJSON(w, http.StatusOK, envelope{ "data": network, }) } // 系统统计信息 func systemMetricsHandler(w http.ResponseWriter, r *http.Request) { stats := readSystemStats() // 读取系统基本信息 hostname, _ := os.Hostname() osInfo := readOSInfo() uptime := readUptime() // 计算总网络速度(汇总所有接口) networkInterfaces := readNetworkInterfaces() var totalRxSpeed, totalTxSpeed float64 for _, iface := range networkInterfaces { totalRxSpeed += iface.RxSpeed // bytes/s totalTxSpeed += iface.TxSpeed // bytes/s } // 转换为 MB/s stats.NetworkRxSpeed = round(totalRxSpeed/1024/1024, 2) stats.NetworkTxSpeed = round(totalTxSpeed/1024/1024, 2) respondJSON(w, http.StatusOK, envelope{ "data": map[string]interface{}{ "hostname": hostname, "os": osInfo, "uptimeSeconds": uptime, "processCount": stats.ProcessCount, "packageCount": stats.PackageCount, "packageManager": stats.PackageManager, "temperature": stats.Temperature, "diskReadSpeed": stats.DiskReadSpeed, "diskWriteSpeed": stats.DiskWriteSpeed, "networkRxSpeed": stats.NetworkRxSpeed, "networkTxSpeed": stats.NetworkTxSpeed, "topProcesses": stats.TopProcesses, "systemLogs": stats.SystemLogs, }, }) } // Docker监控数据 func dockerMetricsHandler(w http.ResponseWriter, r *http.Request) { docker := readDockerStats() respondJSON(w, http.StatusOK, envelope{ "data": docker, }) } // 延迟监控数据 func latencyMetricsHandler(w http.ResponseWriter, r *http.Request) { // 记录请求开始时间,用于计算客户端到服务器的延迟 startTime := time.Now() // 读取外部网站延迟 externalLatencies := readExternalLatencies() // 计算服务器处理时间(这个可以作为参考,实际客户端延迟由前端计算) serverProcessTime := time.Since(startTime).Milliseconds() respondJSON(w, http.StatusOK, envelope{ "data": map[string]interface{}{ "serverProcessTime": serverProcessTime, // 服务器处理时间(参考) "external": externalLatencies, }, }) } func respondJSON(w http.ResponseWriter, status int, body envelope) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) if err := json.NewEncoder(w).Encode(body); err != nil { log.Printf("write json error: %v", err) } } func getenv(key, fallback string) string { if v, ok := os.LookupEnv(key); ok && v != "" { return v } return fallback } func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() next.ServeHTTP(w, r) log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(start)) }) } func corsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") if r.Method == http.MethodOptions { w.WriteHeader(http.StatusNoContent) return } next.ServeHTTP(w, r) }) }