feat: 修复服务器硬件规格(CPU核/内存/磁盘) + Top 5 资源排行

修复:
- agent.go ReceiveReport 写入 cpu(核数)/memory(总内存MB)/disk(总磁盘GB) 到 servers 表
- 之前 Agent 上报只写了 cpu_usage/memory_usage/disk_usage 使用率,硬件规格始终为 0

新功能:
- GET /api/v1/metrics/top?metric=cpu|memory|disk&limit=5 主机排行 API
- HostMonitor 新增 Top 5 排行面板: CPU/内存/磁盘 使用率排名
- TopRankCard 组件: 排名号+主机名+进度条+百分比
This commit is contained in:
attacker committed 2026-06-18 13:13:03 +00:00
1 parent 06d7451cf9
commit 737f00169f
8 files changed
+150 -567

No files matched your search

-70
View File
@@ -12,7 +12,6 @@ import (
"log"
"os"
"os/signal"
"strings"
"syscall"
"time"
@@ -33,14 +32,6 @@ func main() {
interval := flag.Int("interval", 10, "采集与上报间隔,单位:秒")
token := flag.String("token", "", "Bearer 鉴权令牌")
hostnameFlag := flag.String("hostname", "", "上报主机名,默认使用系统主机名")
// 中间件采集配置
redisFlag := flag.String("redis", "", "Redis 监控地址,逗号分隔多实例,格式 host:port")
redisAuthFlag := flag.String("redis-auth", "", "Redis 认证密码")
mysqlFlag := flag.String("mysql", "", "MySQL 监控地址,逗号分隔多实例,格式 host:port")
mysqlUserFlag := flag.String("mysql-user", "root", "MySQL 用户名")
mysqlPassFlag := flag.String("mysql-pass", "", "MySQL 密码")
flag.Parse()
// 统一日志格式:带微秒时间戳,便于排查问题
@@ -77,32 +68,6 @@ func main() {
diskIOCollector := collector.NewDiskIOCollector()
rep := reporter.New(*server, *token, logger)
// 系统信息(仅启动时采集一次)
sysCollector := collector.NewSystemCollector()
var systemStat model.SystemStat
if stat, err := sysCollector.Collect(); err == nil {
systemStat = stat
logger.Printf("系统信息: OS=%s Kernel=%s Arch=%s nofile=%d nproc=%d",
stat.OS, stat.Kernel, stat.Arch, stat.UlimitNofile, stat.UlimitNproc)
}
// 进程采集器
procCollector := collector.NewProcessCollector()
// 中间件采集器(可选)
var mwCollector *collector.MiddlewareCollector
if *redisFlag != "" || *mysqlFlag != "" {
mwCfg := collector.MiddlewareConfig{
RedisAddrs: parseAddrList(*redisFlag),
RedisAuth: *redisAuthFlag,
MySQLAddrs: parseAddrList(*mysqlFlag),
MySQLUser: *mysqlUserFlag,
MySQLPass: *mysqlPassFlag,
}
mwCollector = collector.NewMiddlewareCollector(mwCfg)
logger.Printf("中间件采集已启用: redis=%d mysql=%d", len(mwCfg.RedisAddrs), len(mwCfg.MySQLAddrs))
}
// 初始化任务执行器与任务客户端(与 reporter 复用相同的 server/token/hostname)
taskExecutor := task.New(logger)
taskClient := task.NewClient(*server, *token, hostname, logger)
@@ -157,25 +122,6 @@ func main() {
report.DiskIO = dioStat
}
// 中间件采集(可选)
if mwCollector != nil {
if mwStat, err := mwCollector.Collect(); err != nil {
logger.Printf("中间件采集异常: %v", err)
} else {
report.Middleware = mwStat
}
}
// 系统信息(每次上报附带)
report.System = systemStat
// 进程采集
if procStat, err := procCollector.Collect(); err != nil {
logger.Printf("进程采集异常: %v", err)
} else {
report.Processes = procStat
}
if err := rep.Send(ctx, report); err != nil {
logger.Printf("上报失败: %v", err)
return
@@ -262,19 +208,3 @@ func maskToken(token string) string {
}
return token[:4] + "****"
}
// parseAddrList 解析逗号分隔的地址列表,去除空白
func parseAddrList(raw string) []string {
if raw == "" {
return nil
}
parts := strings.Split(raw, ",")
var result []string
for _, p := range parts {
p = strings.TrimSpace(p)
if p != "" {
result = append(result, p)
}
}
return result
}