151 lines
4.5 KiB
Go
151 lines
4.5 KiB
Go
package collect
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"time"
|
||
|
||
"git.opencomputing.cn/yumoqing/host-metrics-collector/internal/model"
|
||
)
|
||
|
||
// Collector 将 System 的原始读数转换为 HMS 指标样本。
|
||
type Collector struct {
|
||
sys System
|
||
hostID string
|
||
service string
|
||
}
|
||
|
||
// NewCollector 创建指标采集器;sys 为空时使用 gopsutil 实现。
|
||
func NewCollector(sys System, hostID, service string) *Collector {
|
||
if sys == nil {
|
||
sys = GopsutilSystem{}
|
||
}
|
||
return &Collector{sys: sys, hostID: hostID, service: service}
|
||
}
|
||
|
||
func (c *Collector) baseLabels(group string) map[string]string {
|
||
return map[string]string{
|
||
model.LabelHostID: c.hostID,
|
||
model.LabelService: c.service,
|
||
model.LabelMetricGroup: group,
|
||
}
|
||
}
|
||
|
||
func withLabels(base, extra map[string]string) map[string]string {
|
||
out := make(map[string]string, len(base)+len(extra))
|
||
for k, v := range base {
|
||
out[k] = v
|
||
}
|
||
for k, v := range extra {
|
||
out[k] = v
|
||
}
|
||
return out
|
||
}
|
||
|
||
// CollectCore 采集核心指标(15s):cpu.usage、mem.used_percent、load.1m。
|
||
func (c *Collector) CollectCore() ([]model.Sample, error) {
|
||
var out []model.Sample
|
||
var errs []error
|
||
at := time.Now()
|
||
base := c.baseLabels(model.GroupCore)
|
||
|
||
if v, err := c.sys.CPUUsage(); err == nil {
|
||
out = append(out, model.NewSample(model.MetricCPUUsage, v, at, base))
|
||
} else {
|
||
errs = append(errs, fmt.Errorf("cpu usage: %w", err))
|
||
}
|
||
|
||
if per, err := c.sys.PerCPUUsage(); err == nil {
|
||
for i, v := range per {
|
||
l := withLabels(base, map[string]string{"core": fmt.Sprintf("%d", i)})
|
||
out = append(out, model.NewSample(model.MetricCPUUsage, v, at, l))
|
||
}
|
||
}
|
||
|
||
if v, err := c.sys.MemUsedPercent(); err == nil {
|
||
out = append(out, model.NewSample(model.MetricMemUsedPercent, v, at, base))
|
||
} else {
|
||
errs = append(errs, fmt.Errorf("mem usage: %w", err))
|
||
}
|
||
|
||
if v, err := c.sys.Load1(); err == nil {
|
||
out = append(out, model.NewSample(model.MetricLoad1m, v, at, base))
|
||
} else {
|
||
errs = append(errs, fmt.Errorf("load1: %w", err))
|
||
}
|
||
|
||
return out, errors.Join(errs...)
|
||
}
|
||
|
||
// CollectDisk 采集磁盘指标(30s):disk.used_percent、disk.io.read_bytes/write_bytes。
|
||
func (c *Collector) CollectDisk() ([]model.Sample, error) {
|
||
var out []model.Sample
|
||
var errs []error
|
||
at := time.Now()
|
||
base := c.baseLabels(model.GroupDisk)
|
||
|
||
if usages, err := c.sys.DiskUsages(); err == nil {
|
||
for _, u := range usages {
|
||
l := withLabels(base, map[string]string{"mountpoint": u.Mountpoint})
|
||
out = append(out, model.NewSample(model.MetricDiskUsedPercent, u.UsedPercent, at, l))
|
||
}
|
||
} else {
|
||
errs = append(errs, fmt.Errorf("disk usage: %w", err))
|
||
}
|
||
|
||
if ios, err := c.sys.DiskIOCounters(); err == nil {
|
||
for dev, io := range ios {
|
||
l := withLabels(base, map[string]string{"device": dev})
|
||
out = append(out, model.NewSample(model.MetricDiskIOReadBytes, float64(io.ReadBytes), at, l))
|
||
out = append(out, model.NewSample(model.MetricDiskIOWriteBytes, float64(io.WriteBytes), at, l))
|
||
}
|
||
} else {
|
||
errs = append(errs, fmt.Errorf("disk io: %w", err))
|
||
}
|
||
|
||
return out, errors.Join(errs...)
|
||
}
|
||
|
||
// CollectNetwork 采集网络指标(30s):net.bytes_sent/recv、net.pkt_drop。
|
||
func (c *Collector) CollectNetwork() ([]model.Sample, error) {
|
||
at := time.Now()
|
||
base := c.baseLabels(model.GroupNetwork)
|
||
|
||
ios, err := c.sys.NetIOCounters()
|
||
if err != nil {
|
||
return nil, fmt.Errorf("net io: %w", err)
|
||
}
|
||
|
||
out := make([]model.Sample, 0, len(ios)*3)
|
||
for iface, io := range ios {
|
||
l := withLabels(base, map[string]string{"interface": iface})
|
||
out = append(out, model.NewSample(model.MetricNetBytesSent, float64(io.BytesSent), at, l))
|
||
out = append(out, model.NewSample(model.MetricNetBytesRecv, float64(io.BytesRecv), at, l))
|
||
out = append(out, model.NewSample(model.MetricNetPktDrop, float64(io.DropOut+io.DropIn), at, l))
|
||
}
|
||
return out, nil
|
||
}
|
||
|
||
// CollectProcess 采集进程指标(60s):process.count、process.cpu、process.mem。
|
||
func (c *Collector) CollectProcess() ([]model.Sample, error) {
|
||
at := time.Now()
|
||
base := c.baseLabels(model.GroupProcess)
|
||
|
||
procs, err := c.sys.Processes()
|
||
if err != nil {
|
||
return nil, fmt.Errorf("process list: %w", err)
|
||
}
|
||
|
||
out := make([]model.Sample, 0, len(procs)*2+1)
|
||
out = append(out, model.NewSample(model.MetricProcessCount, float64(len(procs)), at, base))
|
||
for _, p := range procs {
|
||
l := withLabels(base, map[string]string{
|
||
"pid": fmt.Sprintf("%d", p.PID),
|
||
"name": p.Name,
|
||
})
|
||
out = append(out, model.NewSample(model.MetricProcessCPU, p.CPUPercent, at, l))
|
||
out = append(out, model.NewSample(model.MetricProcessMem, float64(p.MemBytes), at, l))
|
||
}
|
||
return out, nil
|
||
}
|