2026-08-15 01:27:23 +08:00

165 lines
3.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package collect 实现主机指标采集与文件日志 tail 采集。
package collect
import (
"fmt"
"github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/disk"
"github.com/shirou/gopsutil/v4/load"
"github.com/shirou/gopsutil/v4/mem"
"github.com/shirou/gopsutil/v4/net"
"github.com/shirou/gopsutil/v4/process"
)
// 以下结构是对 gopsutil 原始返回值的抽象,采集层不直接暴露 gopsutil 类型,
// 便于单元测试注入 fake 数据。
// DiskUsageStat 描述一个挂载点的磁盘使用率。
type DiskUsageStat struct {
Mountpoint string
UsedPercent float64
}
// DiskIOCounter 描述一个块设备的累计读写字节数。
type DiskIOCounter struct {
ReadBytes uint64
WriteBytes uint64
}
// NetIOCounter 描述一个网卡的累计收发/丢包计数。
type NetIOCounter struct {
BytesSent uint64
BytesRecv uint64
DropOut uint64
DropIn uint64
}
// ProcessStat 描述一个进程的关键资源占用。
type ProcessStat struct {
PID int32
Name string
CPUPercent float64
MemPercent float64
MemBytes uint64
}
// System 抽象主机系统信息读取。生产环境使用 GopsutilSystem测试注入 fake。
type System interface {
CPUUsage() (float64, error)
PerCPUUsage() ([]float64, error)
MemUsedPercent() (float64, error)
Load1() (float64, error)
DiskUsages() ([]DiskUsageStat, error)
DiskIOCounters() (map[string]DiskIOCounter, error)
NetIOCounters() (map[string]NetIOCounter, error)
Processes() ([]ProcessStat, error)
}
// GopsutilSystem 是 System 的 gopsutil/v4 实现。
type GopsutilSystem struct{}
func (GopsutilSystem) CPUUsage() (float64, error) {
ps, err := cpu.Percent(0, false)
if err != nil {
return 0, err
}
if len(ps) == 0 {
return 0, fmt.Errorf("cpu.Percent returned no samples")
}
return ps[0], nil
}
func (GopsutilSystem) PerCPUUsage() ([]float64, error) {
return cpu.Percent(0, true)
}
func (GopsutilSystem) MemUsedPercent() (float64, error) {
vm, err := mem.VirtualMemory()
if err != nil {
return 0, err
}
return vm.UsedPercent, nil
}
func (GopsutilSystem) Load1() (float64, error) {
avg, err := load.Avg()
if err != nil {
return 0, err
}
return avg.Load1, nil
}
func (GopsutilSystem) DiskUsages() ([]DiskUsageStat, error) {
parts, err := disk.Partitions(false)
if err != nil {
return nil, err
}
out := make([]DiskUsageStat, 0, len(parts))
for _, p := range parts {
if p.Mountpoint == "" {
continue
}
usage, err := disk.Usage(p.Mountpoint)
if err != nil {
continue
}
out = append(out, DiskUsageStat{Mountpoint: p.Mountpoint, UsedPercent: usage.UsedPercent})
}
return out, nil
}
func (GopsutilSystem) DiskIOCounters() (map[string]DiskIOCounter, error) {
raw, err := disk.IOCounters()
if err != nil {
return nil, err
}
out := make(map[string]DiskIOCounter, len(raw))
for name, v := range raw {
out[name] = DiskIOCounter{ReadBytes: v.ReadBytes, WriteBytes: v.WriteBytes}
}
return out, nil
}
func (GopsutilSystem) NetIOCounters() (map[string]NetIOCounter, error) {
raw, err := net.IOCounters(true)
if err != nil {
return nil, err
}
out := make(map[string]NetIOCounter, len(raw))
for _, v := range raw {
out[v.Name] = NetIOCounter{
BytesSent: v.BytesSent,
BytesRecv: v.BytesRecv,
DropOut: v.Dropout,
DropIn: v.Dropin,
}
}
return out, nil
}
func (GopsutilSystem) Processes() ([]ProcessStat, error) {
raw, err := process.Processes()
if err != nil {
return nil, err
}
out := make([]ProcessStat, 0, len(raw))
for _, p := range raw {
stat := ProcessStat{PID: p.Pid}
if name, err := p.Name(); err == nil {
stat.Name = name
}
if cpuPercent, err := p.CPUPercent(); err == nil {
stat.CPUPercent = cpuPercent
}
if memPercent, err := p.MemoryPercent(); err == nil {
stat.MemPercent = float64(memPercent)
}
if memInfo, err := p.MemoryInfo(); err == nil {
stat.MemBytes = memInfo.RSS
}
out = append(out, stat)
}
return out, nil
}