From 3fec9b19f3c885884adf68ddbaf29e8d6b0a7af8 Mon Sep 17 00:00:00 2001 From: hys Date: Fri, 26 Jun 2026 11:40:19 +0800 Subject: [PATCH] feat: add metric node_acpitz_temp_celsius,node_cpu_dmidecode_info --- Dockerfile | 2 +- collector/cpu_linux.go | 46 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index fd733bade7..b7204a28c6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ RUN go build -ldflags="-s -w" -a -o node_exporter node_exporter.go FROM alpine:3.21 -RUN apk add smartmontools pciutils nvme-cli util-linux +RUN apk add smartmontools pciutils nvme-cli util-linux dmidecode COPY --from=builder /workspace/node_exporter /bin/node_exporter EXPOSE 9100 diff --git a/collector/cpu_linux.go b/collector/cpu_linux.go index e3c947b6d6..d32c8e5f12 100644 --- a/collector/cpu_linux.go +++ b/collector/cpu_linux.go @@ -24,7 +24,9 @@ import ( "regexp" "slices" "strconv" + "strings" "sync" + "time" "golang.org/x/exp/maps" @@ -46,6 +48,7 @@ type cpuCollector struct { cpuCoreThrottle *prometheus.Desc cpuPackageThrottle *prometheus.Desc cpuIsolated *prometheus.Desc + cpuDmidecodeInfo *prometheus.Desc logger *slog.Logger cpuOnline *prometheus.Desc cpuStats map[int64]procfs.CPUStat @@ -140,6 +143,11 @@ func NewCPUCollector(logger *slog.Logger) (Collector, error) { "CPUs that are online and being scheduled.", []string{"cpu"}, nil, ), + cpuDmidecodeInfo: prometheus.NewDesc( + prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "dmidecode_info"), + "CPU information from the dmidecode command.", + []string{"manufacturer", "model_name"}, nil, + ), logger: logger, isolatedCpus: isolcpus, cpuStats: make(map[int64]procfs.CPUStat), @@ -194,10 +202,48 @@ func (c *cpuCollector) Update(ch chan<- prometheus.Metric) error { if err != nil { return err } + c.updateDmidecodeInfo(ch) return nil } +// updateDmidecodeInfo runs the dmidecode command and exposes the CPU +// manufacturer and model name as the node_cpu_dmidecode_info metric. +func (c *cpuCollector) updateDmidecodeInfo(ch chan<- prometheus.Metric) { + manufacturer := c.runDmidecode("processor-manufacturer") + modelName := c.runDmidecode("processor-version") + + if manufacturer == "" && modelName == "" { + return + } + + ch <- prometheus.MustNewConstMetric(c.cpuDmidecodeInfo, + prometheus.GaugeValue, + 1, + manufacturer, + modelName) +} + +// runDmidecode runs `dmidecode -s ` and returns the first non-empty +// output line. It returns an empty string if the command fails. +func (c *cpuCollector) runDmidecode(keyword string) string { + cmd := execCommand("dmidecode", "-s", keyword) + out, err := CombinedOutputTimeout(cmd, 5*time.Second) + if err != nil { + c.logger.Debug("failed to run dmidecode", "keyword", keyword, "error", err) + return "" + } + for _, line := range strings.Split(string(out), "\n") { + line = strings.TrimSpace(line) + // dmidecode may emit comment lines starting with '#'. + if line == "" || strings.HasPrefix(line, "#") { + continue + } + return line + } + return "" +} + // updateInfo reads /proc/cpuinfo func (c *cpuCollector) updateInfo(ch chan<- prometheus.Metric) error { info, err := c.procfs.CPUInfo()