如何在Golang中实现获取系统内存、磁盘、CPU指标的函数
实现系统资源使用率监控(无第三方库)
针对Linux系统(你的CPU监控代码依赖/proc/stat,属于Linux特有的虚拟文件系统),以下是无需第三方库的内存、磁盘使用率实现,同时优化了你的CPU监控代码的错误处理:
1. 内存使用率监控
读取/proc/meminfo文件,解析MemTotal和MemAvailable字段(MemAvailable是系统估算的可立即分配给新进程的内存,比MemFree更准确),计算使用率:
import ( "bufio" "fmt" "os" "strconv" "strings" ) func getMemUsage() (float64, error) { file, err := os.Open("/proc/meminfo") if err != nil { return 0, err } defer file.Close() var total, available uint64 scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() fields := strings.Fields(line) if len(fields) < 2 { continue } switch fields[0] { case "MemTotal:": val, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { return 0, fmt.Errorf("parse MemTotal failed: %w", err) } total = val case "MemAvailable:": val, err := strconv.ParseUint(fields[1], 10, 64) if err != nil { return 0, fmt.Errorf("parse MemAvailable failed: %w", err) } available = val } } if err := scanner.Err(); err != nil { return 0, err } if total == 0 { return 0, fmt.Errorf("invalid total memory value") } usage := 100 * float64(total-available) / float64(total) return usage, nil }
2. 磁盘使用率监控
使用syscall.Statfs获取指定挂载点的磁盘空间信息,计算使用率:
import "syscall" func getDiskUsage(mountPoint string) (float64, error) { var stat syscall.Statfs_t if err := syscall.Statfs(mountPoint, &stat); err != nil { return 0, err } // 总空间:块数 * 块大小 total := uint64(stat.Blocks) * uint64(stat.Bsize) // 可用空间:普通用户可使用的块数 * 块大小(Bavail比Bfree更符合实际场景) available := uint64(stat.Bavail) * uint64(stat.Bsize) if total == 0 { return 0, fmt.Errorf("invalid total disk space") } usage := 100 * float64(total-available) / float64(total) return usage, nil }
3. 优化后的CPU监控代码
修复了原代码的错误处理逻辑(返回错误而非直接打印),替换了已废弃的ioutil.ReadFile为os.ReadFile:
import ( "fmt" "os" "strconv" "strings" "time" ) func getCPUTrack() (idle, total uint64, err error) { contents, err := os.ReadFile("/proc/stat") if err != nil { return 0, 0, err } lines := strings.Split(string(contents), "\n") for _, line := range lines { fields := strings.Fields(line) if len(fields) == 0 { continue } if fields[0] == "cpu" { if len(fields) < 5 { return 0, 0, fmt.Errorf("invalid cpu stat line format") } for i := 1; i < len(fields); i++ { val, parseErr := strconv.ParseUint(fields[i], 10, 64) if parseErr != nil { return 0, 0, fmt.Errorf("parse cpu stat field %d failed: %w", i, parseErr) } total += val if i == 4 { idle = val } } return idle, total, nil } } return 0, 0, fmt.Errorf("cpu stat line not found") } func getCPUUsage() (float64, error) { idle0, total0, err := getCPUTrack() if err != nil { return 0, err } time.Sleep(3 * time.Second) idle1, total1, err := getCPUTrack() if err != nil { return 0, err } idleTicks := float64(idle1 - idle0) totalTicks := float64(total1 - total0) if totalTicks == 0 { return 0, fmt.Errorf("total cpu ticks unchanged") } cpuUsage := 100 * (totalTicks - idleTicks) / totalTicks return cpuUsage, nil }
示例使用
func main() { // 获取内存使用率 memUsage, err := getMemUsage() if err != nil { fmt.Printf("Failed to get memory usage: %v\n", err) return } fmt.Printf("Memory usage: %.2f%%\n", memUsage) // 获取根目录磁盘使用率 diskUsage, err := getDiskUsage("/") if err != nil { fmt.Printf("Failed to get disk usage: %v\n", err) return } fmt.Printf("Disk usage (/): %.2f%%\n", diskUsage) // 获取CPU使用率 cpuUsage, err := getCPUUsage() if err != nil { fmt.Printf("Failed to get CPU usage: %v\n", err) return } fmt.Printf("CPU usage: %.2f%%\n", cpuUsage) }
注意事项
- 以上代码仅适用于Linux系统,依赖
/proc虚拟文件系统和Linux专属的syscall.Statfs实现。 - 磁盘监控需传入正确的挂载点(如
/home、/var等)。 - CPU监控需要等待3秒获取两次采样值,实际使用中可根据需求调整等待时长。
内容的提问来源于stack exchange,提问作者Anna P
相关产品推荐
相关产品推荐

