// Package monitor 提供系统资源监控(CPU/内存/磁盘/网络/进程/连接/主机),后台定时采集,GetInfo 随时取最新快照。 package monitor import ( "fmt" "sync" "time" ) // MonInfo 全量监控信息快照 type MonInfo struct { Host HostInfo `json:"host"` Cpu CpuInfo `json:"cpu"` Mem MemInfo `json:"mem"` Load LoadInfo `json:"load"` Process []ProcessInfo `json:"process"` Disk []DiskInfo `json:"disk"` Net []NetInfo `json:"net"` Conn NetConnInfo `json:"conn"` Ver string `json:"ver"` } // MonInfoSimple 精简版监控信息(适合定时上报) type MonInfoSimple struct { Host HostInfo `json:"host"` Cpu CpuInfoLite `json:"cpu"` Mem MemInfo `json:"mem"` Load LoadInfo `json:"load"` Conn NetConnInfo `json:"conn"` Net NetInfoLite `json:"net"` Disk []DiskInfoLite `json:"disk"` Ver string `json:"ver"` } var ( interval int = 1 monInfo MonInfo mux sync.Mutex one sync.Once ) // Start 启动后台采集 // 普通信息每秒刷新,主机/连接信息每 5 秒刷新一次;ver 为程序版本号 func Start(ver string) { monInfo.Ver = ver one.Do(proc) } // GetInfo 获取最新的监控信息快照 func GetInfo() MonInfo { mux.Lock() info := monInfo mux.Unlock() return info } // proc 监控采集主循环 func proc() { go func() { var i uint64 = 0 // CPU信息应该不会变,CPU热插拨除外 { cpuBaseVal, _ := getCpuInfo() monInfo.Cpu.Core = cpuBaseVal.Core monInfo.Cpu.Logic = cpuBaseVal.Logic monInfo.Cpu.Info = cpuBaseVal.Info monInfo.Cpu.Core = cpuBaseVal.Core } // 循环获取信息 for { i = i + uint64(interval) //每次都获取 diskVal, err := getDiskInfo() if err != nil { fmt.Println("获取硬盘信出错:", err.Error()) } cpuUsedVal, _ := getCpuUsed() memVal, _ := getMemInfo() netVal, _ := getNetInfo() loadVal, _ := getLoadInfo() process, _ := GetProcessInfo() mux.Lock() //只获取CPU使用率,CPU基本信息一般不会发生改变 monInfo.Cpu.UsedPercent = cpuUsedVal.UsedPercent monInfo.Cpu.Used = cpuUsedVal.Used monInfo.Load = loadVal monInfo.Disk = diskVal monInfo.Mem = memVal monInfo.Net = netVal monInfo.Process = process mux.Unlock() // 间隔5次调用一次 // 建议60秒获取一次,例如更改计算机名,导致获取不准确 if i%5 == 0 { hostVal, _ := getHostInfo() connVal, _ := getNetConnInfo() mux.Lock() monInfo.Host = hostVal monInfo.Conn = connVal mux.Unlock() } time.Sleep(time.Second * time.Duration(interval)) } }() } // ToLiteInfo 将全量信息转换为精简版 func ToLiteInfo(info MonInfo) MonInfoSimple { lite := MonInfoSimple{} lite.Host = info.Host lite.Load = info.Load lite.Mem = info.Mem lite.Conn = info.Conn lite.Cpu.Core = info.Cpu.Core lite.Cpu.Logic = info.Cpu.Logic lite.Cpu.UsedPercent = info.Cpu.UsedPercent lite.Cpu.Logic = info.Cpu.Logic lite.Cpu.Name = make([]string, len(info.Cpu.Info)) for index, c := range info.Cpu.Info { lite.Cpu.Name[index] = c.ModelName } lite.Disk = make([]DiskInfoLite, len(info.Disk)) for index, d := range info.Disk { lite.Disk[index].Device = d.Device lite.Disk[index].MountPoint = d.MountPoint lite.Disk[index].UsedPercent = d.UsedPercent lite.Disk[index].UsedVolume = d.UsedVolume lite.Disk[index].ReadBytes = d.ReadBytes lite.Disk[index].WriteBytes = d.WriteBytes } lite.Net = NetInfoLite{} for _, n := range info.Net { lite.Net.BytesSent += n.BytesSent lite.Net.BytesRecv += n.BytesRecv lite.Net.PacketsSent += n.PacketsSent lite.Net.PacketsRecv += n.PacketsRecv lite.Net.TotalBytesSent += n.TotalBytesSent lite.Net.TotalBytesRecv += n.TotalBytesRecv } lite.Ver = info.Ver return lite } // 字节的单位转换 保留两位小数 func formatFileSize(fileSize uint64) (size string) { if fileSize < 1024 { //return strconv.FormatInt(fileSize, 10) + "B" return fmt.Sprintf("%.2fB", float64(fileSize)/float64(1)) } else if fileSize < (1024 * 1024) { return fmt.Sprintf("%.2fKB", float64(fileSize)/float64(1024)) } else if fileSize < (1024 * 1024 * 1024) { return fmt.Sprintf("%.2fMB", float64(fileSize)/float64(1024*1024)) } else if fileSize < (1024 * 1024 * 1024 * 1024) { return fmt.Sprintf("%.2fGB", float64(fileSize)/float64(1024*1024*1024)) } else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) { return fmt.Sprintf("%.2fTB", float64(fileSize)/float64(1024*1024*1024*1024)) } else { //if fileSize < (1024 * 1024 * 1024 * 1024 * 1024 * 1024) return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(1024*1024*1024*1024*1024)) } }