package monitor import ( "fmt" "log" "os" "path/filepath" "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" "github.com/shirou/gopsutil/v4/mem" "github.com/shirou/gopsutil/v4/net" "github.com/shirou/gopsutil/v4/process" ) // InfoMonitor 服务器信息监控器 type InfoMonitor struct { config *InfoMonitorConfig logFile *os.File stopChan chan struct{} metricsChan chan ServerMetrics } // InfoMonitorConfig 信息监控配置 type InfoMonitorConfig struct { Enabled bool `yaml:"enabled"` Interval time.Duration `yaml:"interval"` // 采集间隔 LogFilePath string `yaml:"log_file_path"` // 日志文件路径 MaxLogSize int64 `yaml:"max_log_size"` // 最大日志大小(字节) LogRetention int `yaml:"log_retention"` // 日志保留天数 ProcessLimit int `yaml:"process_limit"` // 显示进程数限制 CollectNetwork bool `yaml:"collect_network"` // 是否收集网络信息 CollectProcess bool `yaml:"collect_process"` // 是否收集进程信息 } // ServerMetrics 服务器指标 type ServerMetrics struct { Timestamp time.Time `json:"timestamp"` CPU CPUInfo `json:"cpu"` Memory MemoryInfo `json:"memory"` Disk []DiskInfo `json:"disk"` Network NetworkInfo `json:"network"` Load LoadInfo `json:"load"` Processes []ProcessInfo `json:"processes"` Host HostInfo `json:"host"` Runtime RuntimeInfo `json:"runtime"` QuickMetrics QuickMetrics `json:"quick_metrics"` } // CPUInfo CPU信息 type CPUInfo struct { Model string `json:"model"` Cores int `json:"cores"` LogicalCores int `json:"logical_cores"` UsagePercent float64 `json:"usage_percent"` PerCorePercent []float64 `json:"per_core_percent"` Mhz float64 `json:"mhz"` CacheSize int `json:"cache_size"` } // MemoryInfo 内存信息 type MemoryInfo struct { TotalGB float64 `json:"total_gb"` UsedGB float64 `json:"used_gb"` AvailableGB float64 `json:"available_gb"` UsedPercent float64 `json:"used_percent"` SwapTotalGB float64 `json:"swap_total_gb"` SwapUsedGB float64 `json:"swap_used_gb"` } // DiskInfo 磁盘信息 type DiskInfo struct { Mountpoint string `json:"mountpoint"` Device string `json:"device"` Fstype string `json:"fstype"` TotalGB float64 `json:"total_gb"` UsedGB float64 `json:"used_gb"` FreeGB float64 `json:"free_gb"` UsedPercent float64 `json:"used_percent"` InodesPercent float64 `json:"inodes_percent"` } // NetworkInfo 网络信息 type NetworkInfo struct { Interfaces []NetworkInterface `json:"interfaces"` TotalRecvMB float64 `json:"total_recv_mb"` TotalSentMB float64 `json:"total_sent_mb"` TCPConnections int `json:"tcp_connections"` EstablishedConn int `json:"established_conn"` } // NetworkInterface 网络接口 type NetworkInterface struct { Name string `json:"name"` HardwareAddr string `json:"hardware_addr"` IPAddresses []string `json:"ip_addresses"` } // LoadInfo 负载信息 type LoadInfo struct { Load1 float64 `json:"load_1"` Load5 float64 `json:"load_5"` Load15 float64 `json:"load_15"` RelativeLoad1 float64 `json:"relative_load_1"` RelativeLoad5 float64 `json:"relative_load_5"` RelativeLoad15 float64 `json:"relative_load_15"` ProcsRunning int `json:"procs_running"` // 改为 int 类型 ProcsTotal int `json:"procs_total"` // 改为 int 类型 } // ProcessInfo 进程信息 type ProcessInfo struct { PID int32 `json:"pid"` Name string `json:"name"` Cmdline string `json:"cmdline"` MemoryMB float64 `json:"memory_mb"` CPUPercent float64 `json:"cpu_percent"` } // HostInfo 主机信息 type HostInfo struct { Hostname string `json:"hostname"` OS string `json:"os"` Platform string `json:"platform"` PlatformVersion string `json:"platform_version"` KernelVersion string `json:"kernel_version"` BootTime time.Time `json:"boot_time"` Uptime string `json:"uptime"` CPUCount uint64 `json:"cpu_count"` Architecture string `json:"architecture"` HostID string `json:"host_id"` } // RuntimeInfo 运行时信息 type RuntimeInfo struct { GoVersion string `json:"go_version"` GOOS string `json:"goos"` GOARCH string `json:"goarch"` GOROOT string `json:"goroot"` GOMAXPROCS int `json:"gomaxprocs"` NumCPU int `json:"num_cpu"` NumGoroutine int `json:"num_goroutine"` } // QuickMetrics 快速指标 type QuickMetrics struct { CPUPercent float64 `json:"cpu_percent"` MemoryPercent float64 `json:"memory_percent"` RootDiskPercent float64 `json:"root_disk_percent"` AvailableMemoryGB float64 `json:"available_memory_gb"` } // NewInfoMonitor 创建信息监控器 func NewInfoMonitor(cfg *InfoMonitorConfig, metricsChan chan ServerMetrics) *InfoMonitor { if cfg == nil { cfg = &InfoMonitorConfig{ Enabled: true, Interval: 30 * time.Second, ProcessLimit: 10, CollectNetwork: true, CollectProcess: true, } } if cfg.Interval == 0 { cfg.Interval = 30 * time.Second } if cfg.ProcessLimit == 0 { cfg.ProcessLimit = 10 } if cfg.MaxLogSize == 0 { cfg.MaxLogSize = 100 * 1024 * 1024 // 100MB } if cfg.LogFilePath == "" { cfg.LogFilePath = "/var/log/sysmonitord/info_monitor.log" } return &InfoMonitor{ config: cfg, stopChan: make(chan struct{}), metricsChan: metricsChan, } } // Start 启动信息监控 func (m *InfoMonitor) Start() error { log.Println("启动服务器信息监控...") // 初始化日志文件 if err := m.initLogFile(); err != nil { return fmt.Errorf("初始化日志文件失败: %v", err) } // 启动监控循环 go m.monitorLoop() return nil } // Stop 停止信息监控 func (m *InfoMonitor) Stop() error { log.Println("停止服务器信息监控...") close(m.stopChan) if m.logFile != nil { m.logFile.Close() } return nil } // initLogFile 初始化日志文件 func (m *InfoMonitor) initLogFile() error { if m.config.LogFilePath == "" { m.config.LogFilePath = "/var/log/sysmonitord/info_monitor.log" } // 创建日志目录 logDir := filepath.Dir(m.config.LogFilePath) if err := os.MkdirAll(logDir, 0755); err != nil { return err } // 打开日志文件 file, err := os.OpenFile(m.config.LogFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return err } m.logFile = file // 启动日志轮转检查 go m.logRotateCheck() return nil } // logRotateCheck 日志轮转检查 func (m *InfoMonitor) logRotateCheck() { ticker := time.NewTicker(1 * time.Hour) defer ticker.Stop() for { select { case <-m.stopChan: return case <-ticker.C: if m.logFile != nil { // 检查文件大小 if info, err := m.logFile.Stat(); err == nil { if info.Size() > m.config.MaxLogSize { m.rotateLogFile() } } } } } } // rotateLogFile 轮转日志文件 func (m *InfoMonitor) rotateLogFile() { if m.logFile != nil { m.logFile.Close() // 重命名旧文件 timestamp := time.Now().Format("20060102_150405") backupFile := fmt.Sprintf("%s.%s", m.config.LogFilePath, timestamp) oldPath := m.config.LogFilePath // 重新打开日志文件 file, err := os.OpenFile(m.config.LogFilePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { log.Printf("重新打开日志文件失败: %v", err) return } m.logFile = file // 异步重命名旧文件 go func() { if err := os.Rename(oldPath, backupFile); err != nil { log.Printf("重命名日志文件失败: %v", err) } }() } } // monitorLoop 监控循环 func (m *InfoMonitor) monitorLoop() { // 首次立即执行 m.collectAndLogMetrics() ticker := time.NewTicker(m.config.Interval) defer ticker.Stop() for { select { case <-m.stopChan: return case <-ticker.C: m.collectAndLogMetrics() } } } // collectAndLogMetrics 收集并记录指标 func (m *InfoMonitor) collectAndLogMetrics() { startTime := time.Now() metrics := m.collectAllMetrics() collectionTime := time.Since(startTime) log.Printf("收集指标完成,耗时: %v", collectionTime) // 记录到日志文件 m.logMetrics(metrics) // 发送到metrics通道(如果有) if m.metricsChan != nil { select { case m.metricsChan <- metrics: default: // 通道满,丢弃数据 log.Printf("警告: metrics通道已满,丢弃数据") } } // 输出到控制台 m.displayMetrics(metrics) } // collectAllMetrics 收集所有指标 func (m *InfoMonitor) collectAllMetrics() ServerMetrics { return ServerMetrics{ Timestamp: time.Now(), CPU: m.getCPUInfo(), Memory: m.getMemoryInfo(), Disk: m.getDiskInfo(), Network: m.getNetworkInfo(), Load: m.getLoadInfo(), Processes: m.getProcessInfo(), Host: m.getHostInfo(), Runtime: m.getRuntimeInfo(), QuickMetrics: m.getQuickMetrics(), } } // getHostInfo 获取主机信息 func (m *InfoMonitor) getHostInfo() HostInfo { hostInfo, err := host.Info() if err != nil { log.Printf("获取主机信息失败: %v", err) return HostInfo{} } bootTime := time.Unix(int64(hostInfo.BootTime), 0) uptime := time.Since(bootTime) hours := int(uptime.Hours()) minutes := int(uptime.Minutes()) % 60 seconds := int(uptime.Seconds()) % 60 return HostInfo{ Hostname: hostInfo.Hostname, OS: hostInfo.OS, Platform: hostInfo.Platform, PlatformVersion: hostInfo.PlatformVersion, KernelVersion: hostInfo.KernelVersion, BootTime: bootTime, Uptime: fmt.Sprintf("%d小时%d分钟%d秒", hours, minutes, seconds), CPUCount: hostInfo.Procs, Architecture: hostInfo.KernelArch, HostID: hostInfo.HostID, } } // getCPUInfo 获取CPU信息 func (m *InfoMonitor) getCPUInfo() CPUInfo { physicalCount, _ := cpu.Counts(false) logicalCount, _ := cpu.Counts(true) percent, _ := cpu.Percent(200*time.Millisecond, false) perCorePercent, _ := cpu.Percent(200*time.Millisecond, true) cpuInfoList, _ := cpu.Info() var model string var mhz float64 var cacheSize int if len(cpuInfoList) > 0 { model = cpuInfoList[0].ModelName mhz = cpuInfoList[0].Mhz // 将 int32 转换为 int cacheSize = int(cpuInfoList[0].CacheSize) } usagePercent := 0.0 if len(percent) > 0 { usagePercent = percent[0] } return CPUInfo{ Model: model, Cores: physicalCount, LogicalCores: logicalCount, UsagePercent: usagePercent, PerCorePercent: perCorePercent, Mhz: mhz, CacheSize: cacheSize, } } // getMemoryInfo 获取内存信息 func (m *InfoMonitor) getMemoryInfo() MemoryInfo { vMem, err := mem.VirtualMemory() if err != nil { log.Printf("获取内存信息失败: %v", err) return MemoryInfo{} } swap, _ := mem.SwapMemory() return MemoryInfo{ TotalGB: float64(vMem.Total) / (1024 * 1024 * 1024), UsedGB: float64(vMem.Used) / (1024 * 1024 * 1024), AvailableGB: float64(vMem.Available) / (1024 * 1024 * 1024), UsedPercent: vMem.UsedPercent, SwapTotalGB: float64(swap.Total) / (1024 * 1024 * 1024), SwapUsedGB: float64(swap.Used) / (1024 * 1024 * 1024), } } // getDiskInfo 获取磁盘信息 func (m *InfoMonitor) getDiskInfo() []DiskInfo { partitions, err := disk.Partitions(false) if err != nil { log.Printf("获取磁盘分区失败: %v", err) return nil } var disks []DiskInfo for _, partition := range partitions { // 过滤掉特殊文件系统 if partition.Fstype == "" || partition.Fstype == "tmpfs" || partition.Fstype == "devtmpfs" || partition.Fstype == "squashfs" || partition.Fstype == "efivarfs" || partition.Fstype == "debugfs" || partition.Fstype == "securityfs" || partition.Fstype == "cgroup" || partition.Fstype == "cgroup2" || partition.Fstype == "pstore" || partition.Fstype == "autofs" { continue } usage, err := disk.Usage(partition.Mountpoint) if err != nil { continue } inodesPercent := 0.0 if usage.InodesUsedPercent > 0 { inodesPercent = usage.InodesUsedPercent } disks = append(disks, DiskInfo{ Mountpoint: partition.Mountpoint, Device: partition.Device, Fstype: partition.Fstype, TotalGB: float64(usage.Total) / (1024 * 1024 * 1024), UsedGB: float64(usage.Used) / (1024 * 1024 * 1024), FreeGB: float64(usage.Free) / (1024 * 1024 * 1024), UsedPercent: usage.UsedPercent, InodesPercent: inodesPercent, }) } return disks } // getNetworkInfo 获取网络信息 func (m *InfoMonitor) getNetworkInfo() NetworkInfo { if !m.config.CollectNetwork { return NetworkInfo{} } interfaces, err := net.Interfaces() if err != nil { log.Printf("获取网络接口失败: %v", err) return NetworkInfo{} } var netInterfaces []NetworkInterface for _, iface := range interfaces { if len(iface.Addrs) > 0 && iface.Name != "lo" { var ips []string for _, addr := range iface.Addrs { ips = append(ips, addr.Addr) } netInterfaces = append(netInterfaces, NetworkInterface{ Name: iface.Name, HardwareAddr: iface.HardwareAddr, IPAddresses: ips, }) } } // 获取网络IO统计 ioCounters, _ := net.IOCounters(true) var totalRecv, totalSent uint64 for _, io := range ioCounters { totalRecv += io.BytesRecv totalSent += io.BytesSent } // 获取TCP连接数 tcpConns, _ := net.Connections("tcp") established := 0 for _, conn := range tcpConns { if conn.Status == "ESTABLISHED" { established++ } } return NetworkInfo{ Interfaces: netInterfaces, TotalRecvMB: float64(totalRecv) / (1024 * 1024), TotalSentMB: float64(totalSent) / (1024 * 1024), TCPConnections: len(tcpConns), EstablishedConn: established, } } // getLoadInfo 获取负载信息 func (m *InfoMonitor) getLoadInfo() LoadInfo { avg, err := load.Avg() if err != nil { log.Printf("获取系统负载失败: %v", err) return LoadInfo{} } misc, _ := load.Misc() logicalCount, _ := cpu.Counts(true) relativeLoad1 := 0.0 relativeLoad5 := 0.0 relativeLoad15 := 0.0 if logicalCount > 0 { relativeLoad1 = avg.Load1 / float64(logicalCount) relativeLoad5 = avg.Load5 / float64(logicalCount) relativeLoad15 = avg.Load15 / float64(logicalCount) } return LoadInfo{ Load1: avg.Load1, Load5: avg.Load5, Load15: avg.Load15, RelativeLoad1: relativeLoad1, RelativeLoad5: relativeLoad5, RelativeLoad15: relativeLoad15, // load.Misc() 返回的是 int 类型 ProcsRunning: misc.ProcsRunning, ProcsTotal: misc.ProcsTotal, } } // getProcessInfo 获取进程信息 func (m *InfoMonitor) getProcessInfo() []ProcessInfo { if !m.config.CollectProcess { return nil } processes, err := process.Processes() if err != nil { log.Printf("获取进程列表失败: %v", err) return nil } var procList []ProcessInfo limit := m.config.ProcessLimit if limit <= 0 { limit = 10 // 默认显示10个进程 } count := 0 for _, p := range processes { if count >= limit { break } name, err := p.Name() if err != nil || name == "" || name == " " { continue } cmdline, _ := p.Cmdline() memInfo, _ := p.MemoryInfo() cpuPercent, _ := p.CPUPercent() var memMB float64 if memInfo != nil { memMB = float64(memInfo.RSS) / (1024 * 1024) } procList = append(procList, ProcessInfo{ PID: p.Pid, Name: name, Cmdline: cmdline, MemoryMB: memMB, CPUPercent: cpuPercent, }) count++ } return procList } // getRuntimeInfo 获取运行时信息 func (m *InfoMonitor) getRuntimeInfo() RuntimeInfo { return RuntimeInfo{ GoVersion: runtime.Version(), GOOS: runtime.GOOS, GOARCH: runtime.GOARCH, GOROOT: runtime.GOROOT(), GOMAXPROCS: runtime.GOMAXPROCS(0), NumCPU: runtime.NumCPU(), NumGoroutine: runtime.NumGoroutine(), } } // getQuickMetrics 获取快速指标 func (m *InfoMonitor) getQuickMetrics() QuickMetrics { cpuPercent, _ := cpu.Percent(100*time.Millisecond, false) memInfo, _ := mem.VirtualMemory() rootUsage, _ := disk.Usage("/") quickCPU := 0.0 if len(cpuPercent) > 0 { quickCPU = cpuPercent[0] } memPercent := 0.0 availableGB := 0.0 if memInfo != nil { memPercent = memInfo.UsedPercent availableGB = float64(memInfo.Available) / (1024 * 1024 * 1024) } rootDiskPercent := 0.0 if rootUsage != nil { rootDiskPercent = rootUsage.UsedPercent } return QuickMetrics{ CPUPercent: quickCPU, MemoryPercent: memPercent, RootDiskPercent: rootDiskPercent, AvailableMemoryGB: availableGB, } } // logMetrics 记录指标到日志文件 func (m *InfoMonitor) logMetrics(metrics ServerMetrics) { if m.logFile == nil { return } // 基本指标日志 basicLog := fmt.Sprintf("[INFO-METRIC] %s | CPU:%.2f%% | MEM:%.2f%% | Load1:%.2f | DiskRoot:%.2f%%", metrics.Timestamp.Format("2006-01-02 15:04:05"), metrics.QuickMetrics.CPUPercent, metrics.QuickMetrics.MemoryPercent, metrics.Load.Load1, metrics.QuickMetrics.RootDiskPercent, ) // 详细指标日志 detailedLog := fmt.Sprintf("\n[INFO-DETAIL] Host: %s, Uptime: %s, Cores: %d/%d, Mem: %.2f/%.2f GB", metrics.Host.Hostname, metrics.Host.Uptime, metrics.CPU.Cores, metrics.CPU.LogicalCores, metrics.Memory.UsedGB, metrics.Memory.TotalGB, ) logLine := basicLog + detailedLog + "\n" if _, err := m.logFile.WriteString(logLine); err != nil { log.Printf("写入日志文件失败: %v", err) } // 确保数据写入磁盘 m.logFile.Sync() } // displayMetrics 显示指标到控制台 func (m *InfoMonitor) displayMetrics(metrics ServerMetrics) { // 使用不同颜色显示不同类型的指标 fmt.Printf("\n\x1b[36m════════════════ 服务器监控指标 [%s] ════════════════\x1b[0m\n", metrics.Timestamp.Format("15:04:05")) // 主机信息 fmt.Printf("\n\x1b[33m主机信息:\x1b[0m\n") fmt.Printf(" \x1b[32m主机名:\x1b[0m %s\n", metrics.Host.Hostname) fmt.Printf(" \x1b[32m运行时间:\x1b[0m %s\n", metrics.Host.Uptime) fmt.Printf(" \x1b[32m系统:\x1b[0m %s %s\n", metrics.Host.Platform, metrics.Host.PlatformVersion) // CPU信息 fmt.Printf("\n\x1b[33mCPU信息:\x1b[0m\n") fmt.Printf(" \x1b[32m型号:\x1b[0m %s\n", metrics.CPU.Model) fmt.Printf(" \x1b[32m核心:\x1b[0m %d物理/%d逻辑\n", metrics.CPU.Cores, metrics.CPU.LogicalCores) // 根据CPU使用率显示不同颜色 cpuColor := "\x1b[32m" // 绿色 if metrics.CPU.UsagePercent > 70 { cpuColor = "\x1b[33m" // 黄色 } if metrics.CPU.UsagePercent > 90 { cpuColor = "\x1b[31m" // 红色 } fmt.Printf(" \x1b[32m使用率:\x1b[0m %s%.2f%%\x1b[0m", cpuColor, metrics.CPU.UsagePercent) if len(metrics.CPU.PerCorePercent) > 0 { fmt.Printf(" (") for i, p := range metrics.CPU.PerCorePercent { if i > 0 { fmt.Printf(" ") } coreColor := "\x1b[32m" if p > 70 { coreColor = "\x1b[33m" } if p > 90 { coreColor = "\x1b[31m" } fmt.Printf("%s%d:%.0f%%\x1b[0m", coreColor, i, p) } fmt.Printf(")") } fmt.Println() // 内存信息 fmt.Printf("\n\x1b[33m内存信息:\x1b[0m\n") // 根据内存使用率显示不同颜色 memColor := "\x1b[32m" if metrics.Memory.UsedPercent > 70 { memColor = "\x1b[33m" } if metrics.Memory.UsedPercent > 90 { memColor = "\x1b[31m" } memBar := getProgressBar(metrics.Memory.UsedPercent, 20) fmt.Printf(" \x1b[32m使用率:\x1b[0m %s%.1f%%\x1b[0m %s\n", memColor, metrics.Memory.UsedPercent, memBar) fmt.Printf(" \x1b[32m总量/已用/可用:\x1b[0m %.2f/%.2f/%.2f GB\n", metrics.Memory.TotalGB, metrics.Memory.UsedGB, metrics.Memory.AvailableGB) if metrics.Memory.SwapTotalGB > 0 { fmt.Printf(" \x1b[32m交换空间:\x1b[0m %.2f GB\n", metrics.Memory.SwapTotalGB) } // 磁盘信息 if len(metrics.Disk) > 0 { fmt.Printf("\n\x1b[33m磁盘使用情况:\x1b[0m\n") for _, disk := range metrics.Disk { diskColor := "\x1b[32m" if disk.UsedPercent > 70 { diskColor = "\x1b[33m" } if disk.UsedPercent > 90 { diskColor = "\x1b[31m" } diskBar := getProgressBar(disk.UsedPercent, 15) fmt.Printf(" \x1b[32m%s:\x1b[0m %s%.1f%%\x1b[0m %s %.2f/%.2f GB\n", disk.Mountpoint, diskColor, disk.UsedPercent, diskBar, disk.UsedGB, disk.TotalGB) } } // 负载信息 fmt.Printf("\n\x1b[33m系统负载:\x1b[0m\n") load1Color := "\x1b[32m" if metrics.Load.RelativeLoad1 > 1.0 { load1Color = "\x1b[33m" } if metrics.Load.RelativeLoad1 > 2.0 { load1Color = "\x1b[31m" } fmt.Printf(" \x1b[32m1/5/15分钟:\x1b[0m %s%.2f\x1b[0m/%.2f/%.2f\n", load1Color, metrics.Load.Load1, metrics.Load.Load5, metrics.Load.Load15) fmt.Printf(" \x1b[32m相对负载:\x1b[0m %.2f/%.2f/%.2f\n", metrics.Load.RelativeLoad1, metrics.Load.RelativeLoad5, metrics.Load.RelativeLoad15) fmt.Printf(" \x1b[32m进程:\x1b[0m %d运行中 / %d总计\n", metrics.Load.ProcsRunning, metrics.Load.ProcsTotal) // 网络信息(如果启用了) if m.config.CollectNetwork && len(metrics.Network.Interfaces) > 0 { fmt.Printf("\n\x1b[33m网络信息:\x1b[0m\n") fmt.Printf(" \x1b[32mTCP连接:\x1b[0m %d (已建立: %d)\n", metrics.Network.TCPConnections, metrics.Network.EstablishedConn) fmt.Printf(" \x1b[32m流量:\x1b[0m 接收:%.2f MB 发送:%.2f MB\n", metrics.Network.TotalRecvMB, metrics.Network.TotalSentMB) } // 进程信息 if len(metrics.Processes) > 0 { fmt.Printf("\n\x1b[33mTOP进程 (按内存排序):\x1b[0m\n") for i, proc := range metrics.Processes { if i >= 5 { // 只显示前5个 break } procColor := "\x1b[36m" if proc.CPUPercent > 10 { procColor = "\x1b[33m" } if proc.CPUPercent > 30 { procColor = "\x1b[31m" } // 截断过长的命令行 cmdDisplay := proc.Cmdline if len(cmdDisplay) > 50 { cmdDisplay = cmdDisplay[:47] + "..." } fmt.Printf(" %s%5d\x1b[0m %-20s %s%.1f%%\x1b[0m %.1fMB %s\n", procColor, proc.PID, proc.Name, procColor, proc.CPUPercent, proc.MemoryMB, cmdDisplay) } } fmt.Printf("\n\x1b[36m══════════════════════════════════════════════════════\x1b[0m\n") } // getProgressBar 获取进度条 func getProgressBar(percent float64, width int) string { filled := int((percent / 100.0) * float64(width)) if filled > width { filled = width } bar := "[" for i := 0; i < width; i++ { if i < filled { // 根据填充量使用不同颜色 if i < width/3 { bar += "\x1b[32m=\x1b[0m" // 绿色 } else if i < width*2/3 { bar += "\x1b[33m=\x1b[0m" // 黄色 } else { bar += "\x1b[31m=\x1b[0m" // 红色 } } else { bar += " " } } bar += "]" return bar }