165 lines
3.9 KiB
Go
165 lines
3.9 KiB
Go
// 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
|
||
}
|