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

151 lines
4.5 KiB
Go
Raw 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
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
}