From f2ec547b49af53815038a50265aa2adcd1275959 Mon Sep 17 00:00:00 2001 From: Ben Kochie Date: Tue, 1 Apr 2025 17:14:14 +0200 Subject: [PATCH] Release v1.9.1 (#3285) * Avoid memory leak by using value rather than reference. (#3277) Signed-off-by: Rolf Klemenz * pressure: Fix missing IRQ on older kernels (#3263) Fix "no data" error on kernels that support some PSI status, but don't yet have IRQ presure metrics. Only report "no data" error if `pressure` is enabled and no PSI metrics were found. Fixes: https://github.com/prometheus/node_exporter/issues/3259 Signed-off-by: Ben Kochie * Release v1.9.1 * [BUGFIX] pressure: Fix missing IRQ on older kernels #3263 * [BUGFIX] Fix Darwin memory leak #3277 Signed-off-by: Ben Kochie --------- Signed-off-by: Rolf Klemenz Signed-off-by: Ben Kochie Co-authored-by: Rolf Klemenz --- CHANGELOG.md | 5 +++++ VERSION | 2 +- collector/filesystem_common.go | 7 +++--- collector/filesystem_macos.go | 17 +++++++-------- collector/pressure_linux.go | 39 +++++++++++++++++++++++++--------- go.mod | 14 ++++++------ go.sum | 24 ++++++++++----------- 7 files changed, 65 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a39ddaa..2360e857 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ * [ENHANCEMENT] * [BUGFIX] +## 1.9.1 / 2025-04-01 + +* [BUGFIX] pressure: Fix missing IRQ on older kernels #3263 +* [BUGFIX] Fix Darwin memory leak #3277 + ## 1.9.0 / 2025-02-17 * [CHANGE] meminfo: Convert linux implementation to use procfs lib #3049 diff --git a/VERSION b/VERSION index f8e233b2..9ab8337f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.9.0 +1.9.1 diff --git a/collector/filesystem_common.go b/collector/filesystem_common.go index 272366b3..4161b3fe 100644 --- a/collector/filesystem_common.go +++ b/collector/filesystem_common.go @@ -89,7 +89,7 @@ type filesystemStats struct { labels filesystemLabels size, free, avail float64 files, filesFree float64 - purgeable *float64 + purgeable float64 ro, deviceError float64 } @@ -232,11 +232,10 @@ func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) error { c.mountInfoDesc, prometheus.GaugeValue, 1.0, s.labels.device, s.labels.major, s.labels.minor, s.labels.mountPoint, ) - if s.purgeable != nil { + if s.purgeable >= 0 { ch <- prometheus.MustNewConstMetric( c.purgeableDesc, prometheus.GaugeValue, - *s.purgeable, s.labels.device, s.labels.mountPoint, - s.labels.fsType, s.labels.deviceError, + s.purgeable, s.labels.device, s.labels.mountPoint, s.labels.fsType, s.labels.deviceError, ) } } diff --git a/collector/filesystem_macos.go b/collector/filesystem_macos.go index 0894cabc..26b30644 100644 --- a/collector/filesystem_macos.go +++ b/collector/filesystem_macos.go @@ -20,23 +20,22 @@ package collector #cgo CFLAGS: -x objective-c #cgo LDFLAGS: -framework Foundation #import -Float64 *purgeable(char *path) { +Float64 purgeable(char *path) { CFNumberRef tmp; - Float64 *value; NSError *error = nil; NSString *str = [NSString stringWithUTF8String:path]; NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:str]; NSDictionary *results = [fileURL resourceValuesForKeys:@[NSURLVolumeAvailableCapacityForImportantUsageKey] error:&error]; if (results) { - if ((tmp = CFDictionaryGetValue((CFDictionaryRef)results, NSURLVolumeAvailableCapacityForImportantUsageKey)) == NULL) - return NULL; - value = (Float64 *)malloc(sizeof(Float64)); - if (CFNumberGetValue(tmp, kCFNumberFloat64Type, value)) { + if ((tmp = CFDictionaryGetValue((CFDictionaryRef)results, NSURLVolumeAvailableCapacityForImportantUsageKey)) == NULL) { + return -1.0f; + } + Float64 value; + if (CFNumberGetValue(tmp, kCFNumberFloat64Type, &value)) { return value; } } - free(value); - return NULL; + return -1.0f; } */ import "C" @@ -100,7 +99,7 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { avail: float64(mnt[i].f_bavail) * float64(mnt[i].f_bsize), files: float64(mnt[i].f_files), filesFree: float64(mnt[i].f_ffree), - purgeable: (*float64)(C.purgeable(C.CString(mountpoint))), + purgeable: float64(C.purgeable(C.CString(mountpoint))), ro: ro, }) } diff --git a/collector/pressure_linux.go b/collector/pressure_linux.go index 7338b7e6..63b32d2a 100644 --- a/collector/pressure_linux.go +++ b/collector/pressure_linux.go @@ -27,8 +27,15 @@ import ( "github.com/prometheus/procfs" ) +const ( + psiResourceCPU = "cpu" + psiResourceIO = "io" + psiResourceMemory = "memory" + psiResourceIRQ = "irq" +) + var ( - psiResources = []string{"cpu", "io", "memory", "irq"} + psiResources = []string{psiResourceCPU, psiResourceIO, psiResourceMemory, psiResourceIRQ} ) type pressureStatsCollector struct { @@ -93,13 +100,18 @@ func NewPressureStatsCollector(logger *slog.Logger) (Collector, error) { // Update calls procfs.NewPSIStatsForResource for the different resources and updates the values func (c *pressureStatsCollector) Update(ch chan<- prometheus.Metric) error { + foundResources := 0 for _, res := range psiResources { c.logger.Debug("collecting statistics for resource", "resource", res) vals, err := c.fs.PSIStatsForResource(res) if err != nil { - if errors.Is(err, os.ErrNotExist) { - c.logger.Debug("pressure information is unavailable, you need a Linux kernel >= 4.20 and/or CONFIG_PSI enabled for your kernel") - return ErrNoData + if errors.Is(err, os.ErrNotExist) && res != psiResourceIRQ { + c.logger.Debug("pressure information is unavailable, you need a Linux kernel >= 4.20 and/or CONFIG_PSI enabled for your kernel", "resource", res) + continue + } + if errors.Is(err, os.ErrNotExist) && res == psiResourceIRQ { + c.logger.Debug("IRQ pressure information is unavailable, you need a Linux kernel >= 6.1 and/or CONFIG_PSI enabled for your kernel", "resource", res) + continue } if errors.Is(err, syscall.ENOTSUP) { c.logger.Debug("pressure information is disabled, add psi=1 kernel command line to enable it") @@ -109,28 +121,35 @@ func (c *pressureStatsCollector) Update(ch chan<- prometheus.Metric) error { } // IRQ pressure does not have 'some' data. // See https://github.com/torvalds/linux/blob/v6.9/include/linux/psi_types.h#L65 - if vals.Some == nil && res != "irq" { + if vals.Some == nil && res != psiResourceIRQ { c.logger.Debug("pressure information returned no 'some' data") return ErrNoData } - if vals.Full == nil && res != "cpu" { + if vals.Full == nil && res != psiResourceCPU { c.logger.Debug("pressure information returned no 'full' data") return ErrNoData } switch res { - case "cpu": + case psiResourceCPU: ch <- prometheus.MustNewConstMetric(c.cpu, prometheus.CounterValue, float64(vals.Some.Total)/1000.0/1000.0) - case "io": + case psiResourceIO: ch <- prometheus.MustNewConstMetric(c.io, prometheus.CounterValue, float64(vals.Some.Total)/1000.0/1000.0) ch <- prometheus.MustNewConstMetric(c.ioFull, prometheus.CounterValue, float64(vals.Full.Total)/1000.0/1000.0) - case "memory": + case psiResourceMemory: ch <- prometheus.MustNewConstMetric(c.mem, prometheus.CounterValue, float64(vals.Some.Total)/1000.0/1000.0) ch <- prometheus.MustNewConstMetric(c.memFull, prometheus.CounterValue, float64(vals.Full.Total)/1000.0/1000.0) - case "irq": + case psiResourceIRQ: ch <- prometheus.MustNewConstMetric(c.irqFull, prometheus.CounterValue, float64(vals.Full.Total)/1000.0/1000.0) default: c.logger.Debug("did not account for resource", "resource", res) + continue } + foundResources++ + } + + if foundResources == 0 { + c.logger.Debug("pressure information is unavailable, you need a Linux kernel >= 4.20 and/or CONFIG_PSI enabled for your kernel") + return ErrNoData } return nil diff --git a/go.mod b/go.mod index 02e01d54..bd81e19e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/prometheus/node_exporter -go 1.22.0 +go 1.23.0 require ( github.com/alecthomas/kingpin/v2 v2.4.0 @@ -29,7 +29,7 @@ require ( github.com/prometheus/procfs v0.15.2-0.20240603130017-1754b780536b // == v0.15.1 + https://github.com/prometheus/procfs/commit/1754b780536bb81082baa913e04cc4fff4d2baea github.com/safchain/ethtool v0.5.10 golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 - golang.org/x/sys v0.30.0 + golang.org/x/sys v0.31.0 howett.net/plist v1.0.1 ) @@ -51,11 +51,11 @@ require ( github.com/xhit/go-str2duration/v2 v2.1.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect - golang.org/x/crypto v0.32.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/net v0.37.0 // indirect + golang.org/x/oauth2 v0.28.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/text v0.23.0 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index ded35a69..bfe9a05a 100644 --- a/go.sum +++ b/go.sum @@ -102,23 +102,23 @@ go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 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.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=