From 3780958e8479d9a2a759c6d308d28dfaccf25826 Mon Sep 17 00:00:00 2001 From: Deezzir Date: Wed, 2 Oct 2024 18:21:30 -0400 Subject: [PATCH 1/4] Extend DRM labels Signed-off-by: Deezzir --- collector/drm_linux.go | 35 +++++++++++++++++++++++++++++++---- go.mod | 6 +++--- go.sum | 8 ++++---- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/collector/drm_linux.go b/collector/drm_linux.go index 80356ee84c..fbc223ec0f 100644 --- a/collector/drm_linux.go +++ b/collector/drm_linux.go @@ -31,6 +31,7 @@ type drmCollector struct { fs sysfs.FS logger *slog.Logger CardInfo *prometheus.Desc + CardInfoWithChip *prometheus.Desc GPUBusyPercent *prometheus.Desc MemoryGTTSize *prometheus.Desc MemoryGTTUsed *prometheus.Desc @@ -59,6 +60,11 @@ func NewDrmCollector(logger *slog.Logger) (Collector, error) { "Card information", []string{"card", "memory_vendor", "power_performance_level", "unique_id", "vendor"}, nil, ), + CardInfoWithChip: prometheus.NewDesc( + prometheus.BuildFQName(namespace, drmCollectorSubsystem, "card_info"), + "Card information", + []string{"card", "memory_vendor", "power_performance_level", "unique_id", "chip", "vendor"}, nil, + ), GPUBusyPercent: prometheus.NewDesc( prometheus.BuildFQName(namespace, drmCollectorSubsystem, "gpu_busy_percent"), "How busy the GPU is as a percentage.", @@ -101,6 +107,22 @@ func (c *drmCollector) Update(ch chan<- prometheus.Metric) error { return c.updateAMDCards(ch) } +func chipName(s sysfs.ClassDRMCardAMDGPUStats) string { + // generate a chip name based on the deviceType and devName + cleanDevName := cleanMetricName(s.DevName) + cleanDevType := cleanMetricName(s.DevType) + + if cleanDevType != "" && cleanDevName != "" { + return cleanDevType + "_" + cleanDevName + } + + if cleanDevName != "" { + return cleanDevName + } + + return "" +} + func (c *drmCollector) updateAMDCards(ch chan<- prometheus.Metric) error { vendor := "amd" stats, err := c.fs.ClassDRMCardAMDGPUStats() @@ -109,10 +131,15 @@ func (c *drmCollector) updateAMDCards(ch chan<- prometheus.Metric) error { } for _, s := range stats { - ch <- prometheus.MustNewConstMetric( - c.CardInfo, prometheus.GaugeValue, 1, - s.Name, s.MemoryVRAMVendor, s.PowerDPMForcePerformanceLevel, s.UniqueID, vendor) - + if chip := chipName(s); chip != "" { + ch <- prometheus.MustNewConstMetric( + c.CardInfoWithChip, prometheus.GaugeValue, 1, + s.Name, s.MemoryVRAMVendor, s.PowerDPMForcePerformanceLevel, s.UniqueID, chip, vendor) + } else { + ch <- prometheus.MustNewConstMetric( + c.CardInfo, prometheus.GaugeValue, 1, + s.Name, s.MemoryVRAMVendor, s.PowerDPMForcePerformanceLevel, s.UniqueID, vendor) + } ch <- prometheus.MustNewConstMetric( c.GPUBusyPercent, prometheus.GaugeValue, float64(s.GPUBusyPercent), s.Name) diff --git a/go.mod b/go.mod index b70e1edbf6..02ec38a928 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus/node_exporter -go 1.24.0 +go 1.25.0 require ( github.com/alecthomas/kingpin/v2 v2.4.0 @@ -25,9 +25,9 @@ require ( github.com/prometheus/client_model v0.6.2 github.com/prometheus/common v0.67.5 github.com/prometheus/exporter-toolkit v0.15.0 - github.com/prometheus/procfs v0.19.2 + github.com/prometheus/procfs v0.20.0 github.com/safchain/ethtool v0.7.0 - golang.org/x/sys v0.40.0 + golang.org/x/sys v0.41.0 howett.net/plist v1.0.1 ) diff --git a/go.sum b/go.sum index 20e615f5da..1d615f0d26 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,8 @@ github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTU github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= github.com/prometheus/exporter-toolkit v0.15.0 h1:Pcle5sSViwR1x0gdPd0wtYrPQENBieQAM7TmT0qtb2U= github.com/prometheus/exporter-toolkit v0.15.0/go.mod h1:OyRWd2iTo6Xge9Kedvv0IhCrJSBu36JCfJ2yVniRIYk= -github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= -github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/prometheus/procfs v0.20.0 h1:AA7aCvjxwAquZAlonN7888f2u4IN8WVeFgBi4k82M4Q= +github.com/prometheus/procfs v0.20.0/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/safchain/ethtool v0.7.0 h1:rlJzfDetsVvT61uz8x1YIcFn12akMfuPulHtZjtb7Is= @@ -127,8 +127,8 @@ golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= From 0ab5dfa26afaec8d47766735b47396eb499eda67 Mon Sep 17 00:00:00 2001 From: Julien <291750+roidelapluie@users.noreply.github.com> Date: Wed, 1 Apr 2026 15:01:54 +0200 Subject: [PATCH 2/4] chore: add distroless docker image (#3592) Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> Signed-off-by: Deezzir --- Dockerfile.distroless | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Dockerfile.distroless diff --git a/Dockerfile.distroless b/Dockerfile.distroless new file mode 100644 index 0000000000..37e096d6e4 --- /dev/null +++ b/Dockerfile.distroless @@ -0,0 +1,24 @@ +ARG DISTROLESS_ARCH="amd64" + +# Use DISTROLESS_ARCH for base image selection (handles armv7->arm mapping). +FROM gcr.io/distroless/static-debian13:nonroot-${DISTROLESS_ARCH} +# Base image sets USER to 65532:65532 (nonroot user). + +ARG ARCH="amd64" +ARG OS="linux" + +LABEL org.opencontainers.image.authors="The Prometheus Authors" +LABEL org.opencontainers.image.vendor="Prometheus" +LABEL org.opencontainers.image.title="node_exporter" +LABEL org.opencontainers.image.description="Prometheus exporter for hardware and OS metrics exposed by *NIX kernels" +LABEL org.opencontainers.image.source="https://github.com/prometheus/node_exporter" +LABEL org.opencontainers.image.url="https://github.com/prometheus/node_exporter" +LABEL org.opencontainers.image.documentation="https://github.com/prometheus/node_exporter" +LABEL org.opencontainers.image.licenses="Apache License 2.0" +LABEL io.prometheus.image.variant="distroless" + +COPY LICENSE NOTICE / +COPY .build/${OS}-${ARCH}/node_exporter /bin/node_exporter + +EXPOSE 9100 +ENTRYPOINT [ "/bin/node_exporter" ] From 29eefc537c979798df2c3259bda379e9106ecfd8 Mon Sep 17 00:00:00 2001 From: Julien <291750+roidelapluie@users.noreply.github.com> Date: Wed, 1 Apr 2026 15:40:52 +0200 Subject: [PATCH 3/4] chore: add OCI image labels to Dockerfile (#3593) Signed-off-by: Julien Pivotto <291750+roidelapluie@users.noreply.github.com> Signed-off-by: Deezzir --- Dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Dockerfile b/Dockerfile index 4ba28f97d6..3686a54177 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,6 +2,15 @@ ARG ARCH="amd64" ARG OS="linux" FROM quay.io/prometheus/busybox-${OS}-${ARCH}:latest LABEL maintainer="The Prometheus Authors " +LABEL org.opencontainers.image.authors="The Prometheus Authors" +LABEL org.opencontainers.image.vendor="Prometheus" +LABEL org.opencontainers.image.title="node_exporter" +LABEL org.opencontainers.image.description="Prometheus exporter for hardware and OS metrics exposed by *NIX kernels" +LABEL org.opencontainers.image.source="https://github.com/prometheus/node_exporter" +LABEL org.opencontainers.image.url="https://github.com/prometheus/node_exporter" +LABEL org.opencontainers.image.documentation="https://github.com/prometheus/node_exporter" +LABEL org.opencontainers.image.licenses="Apache License 2.0" +LABEL io.prometheus.image.variant="busybox" ARG ARCH="amd64" ARG OS="linux" From bae3229b0048303830b104a6301ece5c8b858972 Mon Sep 17 00:00:00 2001 From: Deezzir Date: Mon, 6 Apr 2026 13:40:45 -0400 Subject: [PATCH 4/4] chore: rebase with main Signed-off-by: Deezzir --- collector/drm_linux.go | 124 ++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 65 deletions(-) diff --git a/collector/drm_linux.go b/collector/drm_linux.go index fbc223ec0f..4a45e6aa7b 100644 --- a/collector/drm_linux.go +++ b/collector/drm_linux.go @@ -28,23 +28,62 @@ const ( ) type drmCollector struct { - fs sysfs.FS - logger *slog.Logger - CardInfo *prometheus.Desc - CardInfoWithChip *prometheus.Desc - GPUBusyPercent *prometheus.Desc - MemoryGTTSize *prometheus.Desc - MemoryGTTUsed *prometheus.Desc - MemoryVisibleVRAMSize *prometheus.Desc - MemoryVisibleVRAMUsed *prometheus.Desc - MemoryVRAMSize *prometheus.Desc - MemoryVRAMUsed *prometheus.Desc + fs sysfs.FS + logger *slog.Logger } func init() { registerCollector("drm", defaultDisabled, NewDrmCollector) } +var ( + drmCardInfo = prometheus.NewDesc( + prometheus.BuildFQName(namespace, drmCollectorSubsystem, "card_info"), + "Card information", + []string{"card", "memory_vendor", "power_performance_level", "unique_id", "vendor"}, nil, + ) + drmCardInfoWithChip = prometheus.NewDesc( + prometheus.BuildFQName(namespace, drmCollectorSubsystem, "card_info"), + "Card information", + []string{"card", "memory_vendor", "power_performance_level", "unique_id", "chip", "vendor"}, nil, + ), + drmGPUBusyPercent = prometheus.NewDesc( + prometheus.BuildFQName(namespace, drmCollectorSubsystem, "gpu_busy_percent"), + "How busy the GPU is as a percentage.", + []string{"card"}, nil, + ) + drmMemoryGTTSize = prometheus.NewDesc( + prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_gtt_size_bytes"), + "The size of the graphics translation table (GTT) block in bytes.", + []string{"card"}, nil, + ) + drmMemoryGTTUsed = prometheus.NewDesc( + prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_gtt_used_bytes"), + "The used amount of the graphics translation table (GTT) block in bytes.", + []string{"card"}, nil, + ) + drmMemoryVisibleVRAMSize = prometheus.NewDesc( + prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_vis_vram_size_bytes"), + "The size of visible VRAM in bytes.", + []string{"card"}, nil, + ) + drmMemoryVisibleVRAMUsed = prometheus.NewDesc( + prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_vis_vram_used_bytes"), + "The used amount of visible VRAM in bytes.", + []string{"card"}, nil, + ) + drmMemoryVRAMSize = prometheus.NewDesc( + prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_vram_size_bytes"), + "The size of VRAM in bytes.", + []string{"card"}, nil, + ) + drmMemoryVRAMUsed = prometheus.NewDesc( + prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_vram_used_bytes"), + "The used amount of VRAM in bytes.", + []string{"card"}, nil, + ) +) + // NewDrmCollector returns a new Collector exposing /sys/class/drm/card?/device stats. func NewDrmCollector(logger *slog.Logger) (Collector, error) { fs, err := sysfs.NewFS(*sysPath) @@ -55,51 +94,6 @@ func NewDrmCollector(logger *slog.Logger) (Collector, error) { return &drmCollector{ fs: fs, logger: logger, - CardInfo: prometheus.NewDesc( - prometheus.BuildFQName(namespace, drmCollectorSubsystem, "card_info"), - "Card information", - []string{"card", "memory_vendor", "power_performance_level", "unique_id", "vendor"}, nil, - ), - CardInfoWithChip: prometheus.NewDesc( - prometheus.BuildFQName(namespace, drmCollectorSubsystem, "card_info"), - "Card information", - []string{"card", "memory_vendor", "power_performance_level", "unique_id", "chip", "vendor"}, nil, - ), - GPUBusyPercent: prometheus.NewDesc( - prometheus.BuildFQName(namespace, drmCollectorSubsystem, "gpu_busy_percent"), - "How busy the GPU is as a percentage.", - []string{"card"}, nil, - ), - MemoryGTTSize: prometheus.NewDesc( - prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_gtt_size_bytes"), - "The size of the graphics translation table (GTT) block in bytes.", - []string{"card"}, nil, - ), - MemoryGTTUsed: prometheus.NewDesc( - prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_gtt_used_bytes"), - "The used amount of the graphics translation table (GTT) block in bytes.", - []string{"card"}, nil, - ), - MemoryVisibleVRAMSize: prometheus.NewDesc( - prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_vis_vram_size_bytes"), - "The size of visible VRAM in bytes.", - []string{"card"}, nil, - ), - MemoryVisibleVRAMUsed: prometheus.NewDesc( - prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_vis_vram_used_bytes"), - "The used amount of visible VRAM in bytes.", - []string{"card"}, nil, - ), - MemoryVRAMSize: prometheus.NewDesc( - prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_vram_size_bytes"), - "The size of VRAM in bytes.", - []string{"card"}, nil, - ), - MemoryVRAMUsed: prometheus.NewDesc( - prometheus.BuildFQName(namespace, drmCollectorSubsystem, "memory_vram_used_bytes"), - "The used amount of VRAM in bytes.", - []string{"card"}, nil, - ), }, nil } @@ -133,33 +127,33 @@ func (c *drmCollector) updateAMDCards(ch chan<- prometheus.Metric) error { for _, s := range stats { if chip := chipName(s); chip != "" { ch <- prometheus.MustNewConstMetric( - c.CardInfoWithChip, prometheus.GaugeValue, 1, + drmCardInfoWithChip, prometheus.GaugeValue, 1, s.Name, s.MemoryVRAMVendor, s.PowerDPMForcePerformanceLevel, s.UniqueID, chip, vendor) } else { ch <- prometheus.MustNewConstMetric( - c.CardInfo, prometheus.GaugeValue, 1, + drmCardInfo, prometheus.GaugeValue, 1, s.Name, s.MemoryVRAMVendor, s.PowerDPMForcePerformanceLevel, s.UniqueID, vendor) } ch <- prometheus.MustNewConstMetric( - c.GPUBusyPercent, prometheus.GaugeValue, float64(s.GPUBusyPercent), s.Name) + drmGPUBusyPercent, prometheus.GaugeValue, float64(s.GPUBusyPercent), s.Name) ch <- prometheus.MustNewConstMetric( - c.MemoryGTTSize, prometheus.GaugeValue, float64(s.MemoryGTTSize), s.Name) + drmMemoryGTTSize, prometheus.GaugeValue, float64(s.MemoryGTTSize), s.Name) ch <- prometheus.MustNewConstMetric( - c.MemoryGTTUsed, prometheus.GaugeValue, float64(s.MemoryGTTUsed), s.Name) + drmMemoryGTTUsed, prometheus.GaugeValue, float64(s.MemoryGTTUsed), s.Name) ch <- prometheus.MustNewConstMetric( - c.MemoryVRAMSize, prometheus.GaugeValue, float64(s.MemoryVRAMSize), s.Name) + drmMemoryVRAMSize, prometheus.GaugeValue, float64(s.MemoryVRAMSize), s.Name) ch <- prometheus.MustNewConstMetric( - c.MemoryVRAMUsed, prometheus.GaugeValue, float64(s.MemoryVRAMUsed), s.Name) + drmMemoryVRAMUsed, prometheus.GaugeValue, float64(s.MemoryVRAMUsed), s.Name) ch <- prometheus.MustNewConstMetric( - c.MemoryVisibleVRAMSize, prometheus.GaugeValue, float64(s.MemoryVisibleVRAMSize), s.Name) + drmMemoryVisibleVRAMSize, prometheus.GaugeValue, float64(s.MemoryVisibleVRAMSize), s.Name) ch <- prometheus.MustNewConstMetric( - c.MemoryVisibleVRAMUsed, prometheus.GaugeValue, float64(s.MemoryVisibleVRAMUsed), s.Name) + drmMemoryVisibleVRAMUsed, prometheus.GaugeValue, float64(s.MemoryVisibleVRAMUsed), s.Name) } return nil