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 }