初始化提交
This commit is contained in:
265
mengyamonitor-backend/main.go
Normal file
265
mengyamonitor-backend/main.go
Normal file
@@ -0,0 +1,265 @@
|
||||
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)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user