From 9510e730d5ef0af6f2a383851bc366056b975195 Mon Sep 17 00:00:00 2001 From: wuko233 Date: Mon, 26 Jan 2026 11:27:25 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0go.mod=E5=92=8Cgo.su?= =?UTF-8?q?m=E6=96=87=E4=BB=B6=E4=BB=A5=E7=AE=A1=E7=90=86=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E9=A1=B9=EF=BC=9B=20feat:=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=9C=8D=E5=8A=A1=E5=99=A8=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/go.mod | 16 ++ test/go.sum | 32 ++++ test/main.go | 426 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 474 insertions(+) create mode 100644 test/go.mod create mode 100644 test/go.sum create mode 100644 test/main.go diff --git a/test/go.mod b/test/go.mod new file mode 100644 index 0000000..559f983 --- /dev/null +++ b/test/go.mod @@ -0,0 +1,16 @@ +module test + +go 1.24.3 + +require github.com/shirou/gopsutil/v4 v4.25.12 + +require ( + github.com/ebitengine/purego v0.9.1 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + golang.org/x/sys v0.38.0 // indirect +) diff --git a/test/go.sum b/test/go.sum new file mode 100644 index 0000000..e147a7a --- /dev/null +++ b/test/go.sum @@ -0,0 +1,32 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= +github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/shirou/gopsutil/v4 v4.25.12 h1:e7PvW/0RmJ8p8vPGJH4jvNkOyLmbkXgXW4m6ZPic6CY= +github.com/shirou/gopsutil/v4 v4.25.12/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test/main.go b/test/main.go new file mode 100644 index 0000000..d67b21f --- /dev/null +++ b/test/main.go @@ -0,0 +1,426 @@ +package main + +import ( + "fmt" + "runtime" + "time" + + "github.com/shirou/gopsutil/v4/cpu" + "github.com/shirou/gopsutil/v4/disk" + "github.com/shirou/gopsutil/v4/host" + "github.com/shirou/gopsutil/v4/load" // 添加 load 包导入 + "github.com/shirou/gopsutil/v4/mem" + "github.com/shirou/gopsutil/v4/net" + "github.com/shirou/gopsutil/v4/process" +) + +func main() { + fmt.Println("================ 服务器监控系统 ================") + + // 1. 获取系统信息 + getHostInfo() + + // 2. 获取CPU信息 + getCPUInfo() + + // 3. 获取内存信息 + getMemoryInfo() + + // 4. 获取磁盘信息 + getDiskInfo() + + // 5. 获取网络信息 + getNetworkInfo() + + // 6. 获取负载信息(Linux特有) + getLoadInfo() + + // 7. 获取进程信息 + getProcessInfo(3) + + // 8. 显示运行时信息 + getRuntimeInfo() + + fmt.Println("\n================ 实时监控示例 ================") + // 9. 快速收集一次指标(不等待10秒) + getQuickMetrics() +} + +// 获取主机信息 +func getHostInfo() { + fmt.Println("\n=== 主机信息 ===") + hostInfo, err := host.Info() + if err != nil { + fmt.Printf("获取主机信息失败: %v\n", err) + return + } + + fmt.Printf("主机名: %s\n", hostInfo.Hostname) + fmt.Printf("操作系统: %s\n", hostInfo.OS) + fmt.Printf("平台: %s\n", hostInfo.Platform) + fmt.Printf("平台版本: %s\n", hostInfo.PlatformVersion) + fmt.Printf("内核版本: %s\n", hostInfo.KernelVersion) + + // 格式化启动时间 + bootTime := time.Unix(int64(hostInfo.BootTime), 0) + uptime := time.Since(bootTime) + hours := int(uptime.Hours()) + minutes := int(uptime.Minutes()) % 60 + + fmt.Printf("系统启动时间: %s\n", bootTime.Format("2006-01-02 15:04:05")) + fmt.Printf("系统已运行: %d小时%d分钟\n", hours, minutes) + fmt.Printf("CPU数量: %d\n", hostInfo.Procs) + fmt.Printf("系统架构: %s\n", hostInfo.KernelArch) + fmt.Printf("主机ID: %s\n", hostInfo.HostID) +} + +// 获取CPU信息 +func getCPUInfo() { + fmt.Println("\n=== CPU信息 ===") + + // 获取CPU核心数 + physicalCount, _ := cpu.Counts(false) + logicalCount, _ := cpu.Counts(true) + fmt.Printf("物理CPU核心数: %d\n", physicalCount) + fmt.Printf("逻辑CPU核心数: %d\n", logicalCount) + + // 获取CPU使用率(采样200毫秒,减少等待时间) + percent, err := cpu.Percent(200*time.Millisecond, false) + if err != nil { + fmt.Printf("获取CPU使用率失败: %v\n", err) + } else if len(percent) > 0 { + fmt.Printf("CPU总使用率: %.2f%%\n", percent[0]) + } + + // 每个核心的使用率(可选) + perCorePercent, err := cpu.Percent(200*time.Millisecond, true) + if err == nil && len(perCorePercent) > 0 { + fmt.Printf("各核心使用率: ") + for i, p := range perCorePercent { + if i > 0 { + fmt.Printf(", ") + } + fmt.Printf("CPU%d:%.1f%%", i, p) + } + fmt.Println() + } + + // 获取CPU详细信息 + cpuInfo, err := cpu.Info() + if err == nil && len(cpuInfo) > 0 { + cpu := cpuInfo[0] // 第一个CPU的信息 + fmt.Printf("CPU型号: %s\n", cpu.ModelName) + fmt.Printf("CPU频率: %.2f GHz\n", cpu.Mhz/1000) + if cpu.CacheSize > 0 { + fmt.Printf("缓存大小: %d KB\n", cpu.CacheSize) + } + fmt.Printf("每个CPU的核心数: %d\n", cpu.Cores) + fmt.Printf("逻辑核心数: %d\n", int(cpu.Cores)*len(cpuInfo)) + } +} + +// 获取内存信息 +func getMemoryInfo() { + fmt.Println("\n=== 内存信息 ===") + + vMem, err := mem.VirtualMemory() + if err != nil { + fmt.Printf("获取内存信息失败: %v\n", err) + return + } + + // 格式化内存大小 + totalGB := float64(vMem.Total) / (1024 * 1024 * 1024) + availableGB := float64(vMem.Available) / (1024 * 1024 * 1024) + usedGB := float64(vMem.Used) / (1024 * 1024 * 1024) + + fmt.Printf("总内存: %.2f GB\n", totalGB) + fmt.Printf("可用内存: %.2f GB (%.1f%%)\n", availableGB, (float64(vMem.Available)/float64(vMem.Total))*100) + fmt.Printf("已用内存: %.2f GB (%.1f%%)\n", usedGB, vMem.UsedPercent) + fmt.Printf("空闲内存: %.2f GB\n", float64(vMem.Free)/(1024*1024*1024)) + + if vMem.Cached > 0 { + fmt.Printf("缓存内存: %.2f GB\n", float64(vMem.Cached)/(1024*1024*1024)) + } + if vMem.Buffers > 0 { + fmt.Printf("缓冲区内存: %.2f GB\n", float64(vMem.Buffers)/(1024*1024*1024)) + } + + // 交换空间 + swap, err := mem.SwapMemory() + if err == nil && swap.Total > 0 { + fmt.Printf("\n交换空间: %.2f GB\n", float64(swap.Total)/(1024*1024*1024)) + fmt.Printf("交换空间使用率: %.2f%%\n", swap.UsedPercent) + } +} + +// 获取磁盘信息 +func getDiskInfo() { + fmt.Println("\n=== 磁盘信息 ===") + + partitions, err := disk.Partitions(false) + if err != nil { + fmt.Printf("获取磁盘分区失败: %v\n", err) + return + } + + fmt.Printf("发现 %d 个分区:\n", len(partitions)) + + for i, partition := range partitions { + // 过滤掉特殊文件系统 + if partition.Fstype == "" || + partition.Fstype == "tmpfs" || + partition.Fstype == "devtmpfs" || + partition.Fstype == "squashfs" { + continue + } + + usage, err := disk.Usage(partition.Mountpoint) + if err != nil { + continue + } + + usedGB := float64(usage.Used) / (1024 * 1024 * 1024) + totalGB := float64(usage.Total) / (1024 * 1024 * 1024) + freeGB := float64(usage.Free) / (1024 * 1024 * 1024) + + fmt.Printf("%d. %s\n", i+1, partition.Mountpoint) + fmt.Printf(" 设备: %s\n", partition.Device) + fmt.Printf(" 文件系统: %s\n", partition.Fstype) + fmt.Printf(" 总容量: %.2f GB\n", totalGB) + fmt.Printf(" 已用空间: %.2f GB\n", usedGB) + fmt.Printf(" 可用空间: %.2f GB\n", freeGB) + fmt.Printf(" 使用率: %.2f%%\n", usage.UsedPercent) + + // 使用进度条显示使用率 + printUsageBar(usage.UsedPercent) + + if usage.InodesUsedPercent > 0 { + fmt.Printf(" Inode使用率: %.2f%%\n", usage.InodesUsedPercent) + } + fmt.Println() + } +} + +// 打印使用率进度条 +func printUsageBar(percent float64) { + barLength := 20 + usedBars := int(percent * float64(barLength) / 100) + if usedBars > barLength { + usedBars = barLength + } + + bar := "[" + for i := 0; i < barLength; i++ { + if i < usedBars { + bar += "=" + } else { + bar += " " + } + } + bar += "]" + + fmt.Printf(" 使用情况: %s\n", bar) +} + +// 获取网络信息 +func getNetworkInfo() { + fmt.Println("\n=== 网络信息 ===") + + // 获取网络接口 + interfaces, err := net.Interfaces() + if err != nil { + fmt.Printf("获取网络接口失败: %v\n", err) + return + } + + activeInterfaces := 0 + for _, iface := range interfaces { + if len(iface.Addrs) > 0 && iface.Name != "lo" { // 排除回环接口 + activeInterfaces++ + fmt.Printf("接口 %d: %s\n", activeInterfaces, iface.Name) + + if iface.HardwareAddr != "" { + fmt.Printf(" 硬件地址: %s\n", iface.HardwareAddr) + } + + if len(iface.Addrs) > 0 { + fmt.Printf(" IP地址: ") + for j, addr := range iface.Addrs { + if j > 0 { + fmt.Printf(", ") + } + fmt.Printf("%s", addr.Addr) + } + fmt.Println() + } + } + } + + // 获取网络IO统计 + ioCounters, err := net.IOCounters(true) // true 表示按接口分别统计 + if err == nil { + var totalRecv, totalSent uint64 + for _, io := range ioCounters { + totalRecv += io.BytesRecv + totalSent += io.BytesSent + } + + fmt.Printf("\n网络流量统计:\n") + fmt.Printf(" 总接收: %.2f MB\n", float64(totalRecv)/(1024*1024)) + fmt.Printf(" 总发送: %.2f MB\n", float64(totalSent)/(1024*1024)) + } + + // 获取TCP连接数 + tcpConns, err := net.Connections("tcp") + if err == nil { + established := 0 + for _, conn := range tcpConns { + if conn.Status == "ESTABLISHED" { + established++ + } + } + fmt.Printf(" TCP连接数: %d (已建立: %d)\n", len(tcpConns), established) + } +} + +// 获取负载信息(Linux特有) +func getLoadInfo() { + fmt.Println("\n=== 系统负载 ===") + + avg, err := load.Avg() + if err != nil { + fmt.Printf("获取系统负载失败: %v\n", err) + return + } + + logicalCount, _ := cpu.Counts(true) + + fmt.Printf("1分钟负载: %.2f\n", avg.Load1) + fmt.Printf("5分钟负载: %.2f\n", avg.Load5) + fmt.Printf("15分钟负载: %.2f\n", avg.Load15) + + // 负载除以CPU核心数得到相对负载 + if logicalCount > 0 { + relativeLoad1 := avg.Load1 / float64(logicalCount) + relativeLoad5 := avg.Load5 / float64(logicalCount) + relativeLoad15 := avg.Load15 / float64(logicalCount) + + fmt.Printf("相对1分钟负载(每核心): %.2f\n", relativeLoad1) + fmt.Printf("相对5分钟负载(每核心): %.2f\n", relativeLoad5) + fmt.Printf("相对15分钟负载(每核心): %.2f\n", relativeLoad15) + + // 负载状态评估 + fmt.Printf("负载状态: ") + if relativeLoad1 < 0.7 { + fmt.Println("轻松") + } else if relativeLoad1 < 1.5 { + fmt.Println("正常") + } else if relativeLoad1 < 3.0 { + fmt.Println("较高") + } else { + fmt.Println("过高") + } + } + + // 获取运行队列中的任务数 + misc, err := load.Misc() + if err == nil { + fmt.Printf("运行中进程数: %d\n", misc.ProcsRunning) + fmt.Printf("总进程数: %d\n", misc.ProcsTotal) + } +} + +// 获取进程信息 +func getProcessInfo(limit int) { + fmt.Printf("\n=== 进程信息(前%d个) ===\n", limit) + + processes, err := process.Processes() + if err != nil { + fmt.Printf("获取进程列表失败: %v\n", err) + return + } + + fmt.Printf("总进程数: %d\n", len(processes)) + + if limit > len(processes) { + limit = len(processes) + } + + count := 0 + for _, p := range processes { + if count >= limit { + break + } + + name, err := p.Name() + if err != nil { + continue + } + + // 只显示有意义(非空)的进程 + if name == "" || name == " " { + continue + } + + cmdline, _ := p.Cmdline() + memInfo, _ := p.MemoryInfo() + cpuPercent, _ := p.CPUPercent() + + count++ + fmt.Printf("\n%d. PID: %d\n", count, p.Pid) + fmt.Printf(" 名称: %s\n", name) + + if cmdline != "" && len(cmdline) < 100 { // 限制命令行长度 + fmt.Printf(" 命令: %s\n", cmdline) + } + + if memInfo != nil { + fmt.Printf(" 内存: %.2f MB\n", float64(memInfo.RSS)/(1024*1024)) + } + + if cpuPercent > 0 { + fmt.Printf(" CPU: %.2f%%\n", cpuPercent) + } + } +} + +// 获取运行时信息 +func getRuntimeInfo() { + fmt.Println("\n=== Go运行时信息 ===") + fmt.Printf("Go版本: %s\n", runtime.Version()) + fmt.Printf("操作系统: %s\n", runtime.GOOS) + fmt.Printf("CPU架构: %s\n", runtime.GOARCH) + fmt.Printf("GOROOT: %s\n", runtime.GOROOT()) + fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0)) + fmt.Printf("CPU核心数: %d\n", runtime.NumCPU()) + fmt.Printf("Goroutine数: %d\n", runtime.NumGoroutine()) +} + +// 快速收集一次指标 +func getQuickMetrics() { + fmt.Println("正在收集系统指标...") + + // 1. CPU使用率 + cpuPercent, _ := cpu.Percent(100*time.Millisecond, false) + + // 2. 内存使用率 + memInfo, _ := mem.VirtualMemory() + + // 3. 磁盘使用率(只检查根分区) + rootUsage, _ := disk.Usage("/") + + currentTime := time.Now().Format("15:04:05") + + fmt.Printf("时间: %s\n", currentTime) + if len(cpuPercent) > 0 { + fmt.Printf("CPU使用率: %.2f%%\n", cpuPercent[0]) + } + if memInfo != nil { + fmt.Printf("内存使用率: %.2f%%\n", memInfo.UsedPercent) + fmt.Printf("可用内存: %.2f GB\n", float64(memInfo.Available)/(1024*1024*1024)) + } + if rootUsage != nil { + fmt.Printf("根分区使用率: %.2f%%\n", rootUsage.UsedPercent) + } +}