From dbe4c8c0d38c4290f9322da706a1fd5bb67f6369 Mon Sep 17 00:00:00 2001 From: Shashwat Hiregoudar Date: Fri, 9 May 2025 14:55:53 +0530 Subject: [PATCH 01/25] improving nvme collector Improvement of the NVMe collector in node-exporter, to include the below-mentioned NVMe namespace-specific parameters NUSE NCAP NSZE LBA Size ANA State Signed-off-by: Shashwat Hiregoudar Signed-off-by: Shashwat Hiregoudar --- collector/nvme_linux.go | 152 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 141 insertions(+), 11 deletions(-) diff --git a/collector/nvme_linux.go b/collector/nvme_linux.go index d1a9a87b55..6be5dafeb5 100644 --- a/collector/nvme_linux.go +++ b/collector/nvme_linux.go @@ -21,14 +21,24 @@ import ( "fmt" "log/slog" "os" + "path/filepath" + "regexp" + "strconv" + "strings" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs/sysfs" ) type nvmeCollector struct { - fs sysfs.FS - logger *slog.Logger + fs sysfs.FS + logger *slog.Logger + namespaceInfo *prometheus.Desc + namespaceCapacityBytes *prometheus.Desc + namespaceSizeBytes *prometheus.Desc + namespaceUsedBytes *prometheus.Desc + namespaceLogicalBlockSizeBytes *prometheus.Desc + info *prometheus.Desc } func init() { @@ -42,9 +52,51 @@ func NewNVMeCollector(logger *slog.Logger) (Collector, error) { return nil, fmt.Errorf("failed to open sysfs: %w", err) } + info := prometheus.NewDesc( + prometheus.BuildFQName(namespace, "nvme", "info"), + "Non-numeric data from /sys/class/nvme/, value is always 1.", + []string{"device", "firmware_revision", "model", "serial", "state", "cntlid"}, + nil, + ) + namespaceInfo := prometheus.NewDesc( + prometheus.BuildFQName(namespace, "nvme", "namespace_info"), + "Information about NVMe namespaces. Value is always 1", + []string{"device", "nsid", "ana_state"}, nil, + ) + + namespaceCapacityBytes := prometheus.NewDesc( + prometheus.BuildFQName(namespace, "nvme", "namespace_capacity_bytes"), + "Capacity of the NVMe namespace in bytes. Computed as namespace_size * namespace_logical_block_size", + []string{"device", "nsid"}, nil, + ) + + namespaceSizeBytes := prometheus.NewDesc( + prometheus.BuildFQName(namespace, "nvme", "namespace_size_bytes"), + "Size of the NVMe namespace in bytes. Available in /sys/class/nvme///size", + []string{"device", "nsid"}, nil, + ) + + namespaceUsedBytes := prometheus.NewDesc( + prometheus.BuildFQName(namespace, "nvme", "namespace_used_bytes"), + "Used space of the NVMe namespace in bytes. Available in /sys/class/nvme///nuse", + []string{"device", "nsid"}, nil, + ) + + namespaceLogicalBlockSizeBytes := prometheus.NewDesc( + prometheus.BuildFQName(namespace, "nvme", "namespace_logical_block_size_bytes"), + "Logical block size of the NVMe namespace in bytes. Usually 4Kb. Available in /sys/class/nvme///queue/logical_block_size", + []string{"device", "nsid"}, nil, + ) + return &nvmeCollector{ - fs: fs, - logger: logger, + fs: fs, + logger: logger, + namespaceInfo: namespaceInfo, + namespaceCapacityBytes: namespaceCapacityBytes, + namespaceSizeBytes: namespaceSizeBytes, + namespaceUsedBytes: namespaceUsedBytes, + namespaceLogicalBlockSizeBytes: namespaceLogicalBlockSizeBytes, + info: info, }, nil } @@ -59,14 +111,92 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { } for _, device := range devices { - infoDesc := prometheus.NewDesc( - prometheus.BuildFQName(namespace, "nvme", "info"), - "Non-numeric data from /sys/class/nvme/, value is always 1.", - []string{"device", "firmware_revision", "model", "serial", "state"}, - nil, - ) infoValue := 1.0 - ch <- prometheus.MustNewConstMetric(infoDesc, prometheus.GaugeValue, infoValue, device.Name, device.FirmwareRevision, device.Model, device.Serial, device.State) + + devicePath := filepath.Join(*sysPath, "class/nvme", device.Name) + cntlid, err := readUintFromFile(filepath.Join(devicePath, "cntlid")) + if err != nil { + c.logger.Debug("failed to read cntlid", "device", device.Name, "err", err) + } + ch <- prometheus.MustNewConstMetric(c.info, prometheus.GaugeValue, infoValue, device.Name, device.FirmwareRevision, device.Model, device.Serial, device.State, strconv.FormatUint(cntlid, 10)) + + // Find namespace directories. + namespacePaths, err := filepath.Glob(filepath.Join(devicePath, "nvme[0-9]*c[0-9]*n[0-9]*")) + if err != nil { + c.logger.Error("failed to list NVMe namespaces", "device", device.Name, "err", err) + continue + } + re := regexp.MustCompile(`nvme[0-9]+c[0-9]+n([0-9]+)`) + + for _, namespacePath := range namespacePaths { + // Read namespace data. + match := re.FindStringSubmatch(filepath.Base(namespacePath)) + if len(match) == 0 { + continue + } + nsid := match[1] + nuse, err := readUintFromFile(filepath.Join(namespacePath, "nuse")) + if err != nil { + c.logger.Debug("failed to read nuse", "device", device.Name, "namespace", match[0], "err", err) + } + nsze, err := readUintFromFile(filepath.Join(namespacePath, "size")) + if err != nil { + c.logger.Debug("failed to read size", "device", device.Name, "namespace", match[0], "err", err) + } + lbaSize, err := readUintFromFile(filepath.Join(namespacePath, "queue", "logical_block_size")) + if err != nil { + c.logger.Debug("failed to read queue/logical_block_size", "device", device.Name, "namespace", match[0], "err", err) + } + ncap := nsze * lbaSize + anaState := "unknown" + anaStateSysfs, err := os.ReadFile(filepath.Join(namespacePath, "ana_state")) + if err == nil { + anaState = strings.TrimSpace(string(anaStateSysfs)) + } else { + c.logger.Debug("failed to read ana_state", "device", device.Name, "namespace", match[0], "err", err) + } + + ch <- prometheus.MustNewConstMetric( + c.namespaceInfo, + prometheus.GaugeValue, + 1.0, + device.Name, + nsid, + anaState, + ) + + ch <- prometheus.MustNewConstMetric( + c.namespaceCapacityBytes, + prometheus.GaugeValue, + float64(ncap), + device.Name, + nsid, + ) + + ch <- prometheus.MustNewConstMetric( + c.namespaceSizeBytes, + prometheus.GaugeValue, + float64(nsze), + device.Name, + nsid, + ) + + ch <- prometheus.MustNewConstMetric( + c.namespaceUsedBytes, + prometheus.GaugeValue, + float64(nuse*lbaSize), + device.Name, + nsid, + ) + + ch <- prometheus.MustNewConstMetric( + c.namespaceLogicalBlockSizeBytes, + prometheus.GaugeValue, + float64(lbaSize), + device.Name, + nsid, + ) + } } return nil From 4ed35903deea1d411c8a924b5023bcf3823970a0 Mon Sep 17 00:00:00 2001 From: Shashwat Hiregoudar Date: Fri, 9 May 2025 09:59:45 +0000 Subject: [PATCH 02/25] correcting the logger Signed-off-by: Shashwat Hiregoudar --- collector/nvme_linux.go | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/collector/nvme_linux.go b/collector/nvme_linux.go index 6be5dafeb5..5d3c2ac7cf 100644 --- a/collector/nvme_linux.go +++ b/collector/nvme_linux.go @@ -19,20 +19,21 @@ package collector import ( "errors" "fmt" - "log/slog" "os" "path/filepath" "regexp" "strconv" "strings" + "github.com/go-kit/log" + "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs/sysfs" ) type nvmeCollector struct { fs sysfs.FS - logger *slog.Logger + logger log.Logger namespaceInfo *prometheus.Desc namespaceCapacityBytes *prometheus.Desc namespaceSizeBytes *prometheus.Desc @@ -46,7 +47,7 @@ func init() { } // NewNVMeCollector returns a new Collector exposing NVMe stats. -func NewNVMeCollector(logger *slog.Logger) (Collector, error) { +func NewNVMeCollector(logger log.Logger) (Collector, error) { fs, err := sysfs.NewFS(*sysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) @@ -104,7 +105,7 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { devices, err := c.fs.NVMeClass() if err != nil { if errors.Is(err, os.ErrNotExist) { - c.logger.Debug("nvme statistics not found, skipping") + level.Debug(c.logger).Log("msg", "nvme statistics not found, skipping") return ErrNoData } return fmt.Errorf("error obtaining NVMe class info: %w", err) @@ -114,21 +115,21 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { infoValue := 1.0 devicePath := filepath.Join(*sysPath, "class/nvme", device.Name) - cntlid, err := readUintFromFile(filepath.Join(devicePath, "cntlid")) + if cntlid, err := readUintFromFile(filepath.Join(devicePath, "cntlid")) if err != nil { - c.logger.Debug("failed to read cntlid", "device", device.Name, "err", err) + level.Debug(c.logger).Log("msg", "failed to read cntlid", "device", device.Name, "err", err) } ch <- prometheus.MustNewConstMetric(c.info, prometheus.GaugeValue, infoValue, device.Name, device.FirmwareRevision, device.Model, device.Serial, device.State, strconv.FormatUint(cntlid, 10)) - // Find namespace directories. namespacePaths, err := filepath.Glob(filepath.Join(devicePath, "nvme[0-9]*c[0-9]*n[0-9]*")) if err != nil { - c.logger.Error("failed to list NVMe namespaces", "device", device.Name, "err", err) + level.Error(c.logger).Log("msg", "failed to list NVMe namespaces", "device", device.Name, "err", err) continue } re := regexp.MustCompile(`nvme[0-9]+c[0-9]+n([0-9]+)`) for _, namespacePath := range namespacePaths { + // Read namespace data. match := re.FindStringSubmatch(filepath.Base(namespacePath)) if len(match) == 0 { @@ -137,15 +138,15 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { nsid := match[1] nuse, err := readUintFromFile(filepath.Join(namespacePath, "nuse")) if err != nil { - c.logger.Debug("failed to read nuse", "device", device.Name, "namespace", match[0], "err", err) + level.Debug(c.logger).Log("msg", "failed to read nuse", "device", device.Name, "namespace", match[0], "err", err) } nsze, err := readUintFromFile(filepath.Join(namespacePath, "size")) if err != nil { - c.logger.Debug("failed to read size", "device", device.Name, "namespace", match[0], "err", err) + level.Debug(c.logger).Log("msg", "failed to read size", "device", device.Name, "namespace", match[0], "err", err) } lbaSize, err := readUintFromFile(filepath.Join(namespacePath, "queue", "logical_block_size")) if err != nil { - c.logger.Debug("failed to read queue/logical_block_size", "device", device.Name, "namespace", match[0], "err", err) + level.Debug(c.logger).Log("msg", "failed to read queue/logical_block_size", "device", device.Name, "namespace", match[0], "err", err) } ncap := nsze * lbaSize anaState := "unknown" @@ -153,7 +154,7 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { if err == nil { anaState = strings.TrimSpace(string(anaStateSysfs)) } else { - c.logger.Debug("failed to read ana_state", "device", device.Name, "namespace", match[0], "err", err) + level.Debug(c.logger).Log("msg", "failed to read ana_state", "device", device.Name, "namespace", match[0], "err", err) } ch <- prometheus.MustNewConstMetric( @@ -200,4 +201,4 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { } return nil -} +} \ No newline at end of file From 875c5240744cf3efb85b1643809869a6a7b8539c Mon Sep 17 00:00:00 2001 From: Charlie Chiang Date: Thu, 15 May 2025 14:41:20 +0800 Subject: [PATCH 03/25] Fix macos filesystem collector cgo memory leak (#3315) Signed-off-by: Charlie Chiang Signed-off-by: Shashwat Hiregoudar --- collector/filesystem_macos.go | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/collector/filesystem_macos.go b/collector/filesystem_macos.go index 26b3064428..cc5c97ced3 100644 --- a/collector/filesystem_macos.go +++ b/collector/filesystem_macos.go @@ -21,21 +21,25 @@ package collector #cgo LDFLAGS: -framework Foundation #import Float64 purgeable(char *path) { - CFNumberRef tmp; - 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 -1.0f; - } - Float64 value; - if (CFNumberGetValue(tmp, kCFNumberFloat64Type, &value)) { - return value; + Float64 value = -1.0f; + + @autoreleasepool { + NSError *error = nil; + NSString *str = [NSString stringWithUTF8String:path]; + NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:str]; + + NSDictionary *results = [fileURL resourceValuesForKeys:@[NSURLVolumeAvailableCapacityForImportantUsageKey] error:&error]; + if (results) { + CFNumberRef tmp = CFDictionaryGetValue((CFDictionaryRef)results, NSURLVolumeAvailableCapacityForImportantUsageKey); + if (tmp != NULL) { + CFNumberGetValue(tmp, kCFNumberFloat64Type, &value); + } } + + [fileURL release]; } - return -1.0f; + + return value; } */ import "C" @@ -88,6 +92,9 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { ro = 1 } + mountpointCString := C.CString(mountpoint) + defer C.free(unsafe.Pointer(mountpointCString)) + stats = append(stats, filesystemStats{ labels: filesystemLabels{ device: device, @@ -99,7 +106,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(mountpointCString)), ro: ro, }) } From bcfdb0a93eba045680346748bf6f6dcab287a93d Mon Sep 17 00:00:00 2001 From: Siavash Safi Date: Sun, 18 May 2025 11:53:48 +0200 Subject: [PATCH 04/25] fix: darwin netdev i/o bytes metric (#3336) There is a bug in darwin kernel since macOS Ventura 13.2.1, which results in interface i/o bytes values to be truncated at 4GiB. This change uses a workaround to collect the same metrics, taking advantage of another bug. fixes #3333 Signed-off-by: Siavash Safi Signed-off-by: Shashwat Hiregoudar --- collector/netdev_darwin.go | 133 ++++++++++++++++++++++++++----------- 1 file changed, 95 insertions(+), 38 deletions(-) diff --git a/collector/netdev_darwin.go b/collector/netdev_darwin.go index 2367ebe5c6..4283559441 100644 --- a/collector/netdev_darwin.go +++ b/collector/netdev_darwin.go @@ -22,6 +22,7 @@ import ( "fmt" "log/slog" "net" + "unsafe" "golang.org/x/sys/unix" ) @@ -71,51 +72,107 @@ func getIfaceData(index int) (*ifMsghdr2, error) { return nil, err } err = binary.Read(bytes.NewReader(rawData), binary.LittleEndian, &data) + if err != nil { + return &data, err + } + + /* + As of macOS Ventura 13.2.1, there’s a kernel bug which truncates traffic values at the 4GiB mark. + This is a workaround to fetch the interface traffic metrics using a sysctl call. + Apple wants to prevent fingerprinting by 3rdparty apps and might fix this bug in future which would break this implementation. + */ + mib := []int32{ + unix.CTL_NET, + unix.AF_LINK, + 0, // NETLINK_GENERIC: functions not specific to a type of iface + 2, //IFMIB_IFDATA: per-interface data table + int32(index), + 1, // IFDATA_GENERAL: generic stats for all kinds of ifaces + } + + var mibData ifMibData + size := unsafe.Sizeof(mibData) + + if _, _, errno := unix.Syscall6( + unix.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), + uintptr(len(mib)), + uintptr(unsafe.Pointer(&mibData)), + uintptr(unsafe.Pointer(&size)), + uintptr(unsafe.Pointer(nil)), + 0, + ); errno != 0 { + return &data, err + } + + var ifdata ifData64 + err = binary.Read(bytes.NewReader(mibData.Data[:]), binary.LittleEndian, &ifdata) + if err != nil { + return &data, err + } + + data.Data.Ibytes = ifdata.Ibytes + data.Data.Obytes = ifdata.Obytes return &data, err } +// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if.h#L220-L232 type ifMsghdr2 struct { - Msglen uint16 - Version uint8 - Type uint8 - Addrs int32 - Flags int32 - Index uint16 - _ [2]byte - SndLen int32 - SndMaxlen int32 - SndDrops int32 - Timer int32 - Data ifData64 + Msglen uint16 // to skip over non-understood messages + Version uint8 // future binary compatabilit + Type uint8 // message type + Addrs int32 // like rtm_addrs + Flags int32 // value of if_flags + Index uint16 // index for associated ifp + _ [2]byte // padding for alignment + SndLen int32 // instantaneous length of send queue + SndMaxlen int32 // maximum length of send queue + SndDrops int32 // number of drops in send queue + Timer int32 // time until if_watchdog called + Data ifData64 // statistics and other data } -// https://github.com/apple/darwin-xnu/blob/main/bsd/net/if_var.h#L199-L231 +// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if_var.h#L207-L235 type ifData64 struct { - Type uint8 - Typelen uint8 - Physical uint8 - Addrlen uint8 - Hdrlen uint8 - Recvquota uint8 - Xmitquota uint8 - Unused1 uint8 - Mtu uint32 - Metric uint32 - Baudrate uint64 - Ipackets uint64 - Ierrors uint64 - Opackets uint64 - Oerrors uint64 - Collisions uint64 - Ibytes uint64 - Obytes uint64 - Imcasts uint64 - Omcasts uint64 - Iqdrops uint64 - Noproto uint64 - Recvtiming uint32 - Xmittiming uint32 - Lastchange unix.Timeval32 + Type uint8 // ethernet, tokenring, etc + Typelen uint8 // Length of frame type id + Physical uint8 // e.g., AUI, Thinnet, 10base-T, etc + Addrlen uint8 // media address length + Hdrlen uint8 // media header length + Recvquota uint8 // polling quota for receive intrs + Xmitquota uint8 // polling quota for xmit intrs + Unused1 uint8 // for future use + Mtu uint32 // maximum transmission unit + Metric uint32 // routing metric (external only) + Baudrate uint64 // linespeed + + // volatile statistics + Ipackets uint64 // packets received on interface + Ierrors uint64 // input errors on interface + Opackets uint64 // packets sent on interface + Oerrors uint64 // output errors on interface + Collisions uint64 // collisions on csma interfaces + Ibytes uint64 // total number of octets received + Obytes uint64 // total number of octets sent + Imcasts uint64 // packets received via multicast + Omcasts uint64 // packets sent via multicast + Iqdrops uint64 // dropped on input, this interface + Noproto uint64 // destined for unsupported protocol + Recvtiming uint32 // usec spent receiving when timing + Xmittiming uint32 // usec spent xmitting when timing + Lastchange unix.Timeval32 // time of last administrative change +} + +// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if_mib.h#L65-L74 +type ifMibData struct { + Name [16]byte // name of interface + PCount uint32 // number of promiscuous listeners + Flags uint32 // interface flags + SendLength uint32 // instantaneous length of send queue + MaxSendLength uint32 // maximum length of send queue + SendDrops uint32 // number of drops in send queue + _ [4]uint32 // for future expansion + Data [128]byte // generic information and statistics } func getNetDevLabels() (map[string]map[string]string, error) { From bfef50313f3b9b7f3057d367f9f91ca3bc8bf064 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 11:54:03 +0200 Subject: [PATCH 05/25] build(deps): bump github.com/mdlayher/wifi from 0.3.1 to 0.5.0 (#3323) Bumps [github.com/mdlayher/wifi](https://github.com/mdlayher/wifi) from 0.3.1 to 0.5.0. - [Release notes](https://github.com/mdlayher/wifi/releases) - [Commits](https://github.com/mdlayher/wifi/compare/v0.3.1...v0.5.0) --- updated-dependencies: - dependency-name: github.com/mdlayher/wifi dependency-version: 0.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Shashwat Hiregoudar --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index c7a2580acc..c3efa89197 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/mattn/go-xmlrpc v0.0.3 github.com/mdlayher/ethtool v0.2.0 github.com/mdlayher/netlink v1.7.2 - github.com/mdlayher/wifi v0.3.1 + github.com/mdlayher/wifi v0.5.0 github.com/opencontainers/selinux v1.11.1 github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 github.com/prometheus-community/go-runit v0.1.0 @@ -29,7 +29,7 @@ require ( github.com/prometheus/procfs v0.16.0 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.32.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.35.0 // indirect - golang.org/x/net v0.36.0 // indirect + golang.org/x/crypto v0.37.0 // indirect + golang.org/x/net v0.38.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.22.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/text v0.24.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 ef94789fd0..bfce0bd440 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= -github.com/mdlayher/wifi v0.3.1 h1:bZDuMI1f7z5BtUUO3NgHRdR/R88YtywIe6dsEFI0Txs= -github.com/mdlayher/wifi v0.3.1/go.mod h1:ODQaObvsglghTuNhezD9grkTB4shVNc28aJfTXmvSi8= +github.com/mdlayher/wifi v0.5.0 h1:TGZIcrhL6h3710amshpEJnMzLs74MrZOF+8qbm8Gx/I= +github.com/mdlayher/wifi v0.5.0/go.mod h1:yfQs+5zr1eOIfdsWDcZonWdznnt/Iiz0/4772cfZuHk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= @@ -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.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 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.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= -golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= 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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.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.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= 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= From f3de6d8b74fd3d959733a8b254c592cf3427b6b1 Mon Sep 17 00:00:00 2001 From: "Guillaume E." <262623+quatre@users.noreply.github.com> Date: Mon, 19 May 2025 11:41:17 +0200 Subject: [PATCH 06/25] Fix ethtool returning 0 for sanitized metrics (#3335) The ethtool_linux looks for ethtool stats with their sanitized name which might be different from the name provisioned by ethtool. This caused node-exporter to return a 0-value for sanitized metrics. This patch works-around the missing key by copying ethtool stats to another map under their sanitized name. Signed-off-by: Guillaume Espanel Co-authored-by: Guillaume Espanel Signed-off-by: Shashwat Hiregoudar --- collector/ethtool_linux.go | 5 ++++- collector/ethtool_linux_test.go | 4 ++++ collector/fixtures/ethtool/eth0/statistics | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/collector/ethtool_linux.go b/collector/ethtool_linux.go index 01410d6449..d9f66469cd 100644 --- a/collector/ethtool_linux.go +++ b/collector/ethtool_linux.go @@ -453,6 +453,7 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error { // Sanitizing the metric names can lead to duplicate metric names. Therefore check for clashes beforehand. metricFQNames := make(map[string]string) + renamedStats := make(map[string]uint64, len(stats)) for metric := range stats { metricName := SanitizeMetricName(metric) if !c.metricsPattern.MatchString(metricName) { @@ -467,6 +468,8 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error { metricFQNames[metricFQName] = "" } else { metricFQNames[metricFQName] = metricName + // Later we'll go look for the stat with the "sanitized" metric name, so we can copy it there already + renamedStats[metricName] = stats[metric] } } @@ -484,7 +487,7 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error { continue } - val := stats[metric] + val := renamedStats[metric] // Check to see if this metric exists; if not then create it and store it in c.entries. entry := c.entryWithCreate(metric, metricFQName) diff --git a/collector/ethtool_linux_test.go b/collector/ethtool_linux_test.go index 98e66dbc20..48babbc442 100644 --- a/collector/ethtool_linux_test.go +++ b/collector/ethtool_linux_test.go @@ -269,6 +269,7 @@ func NewEthtoolTestCollector(logger *slog.Logger) (Collector, error) { func TestBuildEthtoolFQName(t *testing.T) { testcases := map[string]string{ + "port.rx_errors": "node_ethtool_port_received_errors", "rx_errors": "node_ethtool_received_errors", "Queue[0] AllocFails": "node_ethtool_queue_0_allocfails", "Tx LPI entry count": "node_ethtool_transmitted_lpi_entry_count", @@ -292,6 +293,9 @@ node_ethtool_align_errors{device="eth0"} 0 # HELP node_ethtool_info A metric with a constant '1' value labeled by bus_info, device, driver, expansion_rom_version, firmware_version, version. # TYPE node_ethtool_info gauge node_ethtool_info{bus_info="0000:00:1f.6",device="eth0",driver="e1000e",expansion_rom_version="",firmware_version="0.5-4",version="5.11.0-22-generic"} 1 +# HELP node_ethtool_port_received_dropped Network interface port_rx_dropped +# TYPE node_ethtool_port_received_dropped untyped +node_ethtool_port_received_dropped{device="eth0"} 12028 # HELP node_ethtool_received_broadcast Network interface rx_broadcast # TYPE node_ethtool_received_broadcast untyped node_ethtool_received_broadcast{device="eth0"} 5792 diff --git a/collector/fixtures/ethtool/eth0/statistics b/collector/fixtures/ethtool/eth0/statistics index 80423bd6c3..81e511e7ec 100644 --- a/collector/fixtures/ethtool/eth0/statistics +++ b/collector/fixtures/ethtool/eth0/statistics @@ -4,6 +4,7 @@ NIC statistics: rx_packets: 1260062 tx_errors: 0 rx_errors: 0 + port.rx_dropped: 12028 rx_missed: 401 align_errors: 0 tx_single_collisions: 0 From cbdaefa6ed2080d52d868a42047b9b39e9ca446c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 11:48:03 +0200 Subject: [PATCH 07/25] build(deps): bump golang.org/x/sys from 0.30.0 to 0.32.0 (#3324) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.30.0 to 0.32.0. - [Commits](https://github.com/golang/sys/compare/v0.30.0...v0.32.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-version: 0.32.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Shashwat Hiregoudar --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c3efa89197..7003d9a701 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/prometheus/procfs v0.16.0 github.com/safchain/ethtool v0.5.10 golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 - golang.org/x/sys v0.32.0 + golang.org/x/sys v0.33.0 howett.net/plist v1.0.1 ) diff --git a/go.sum b/go.sum index bfce0bd440..236c1b3f57 100644 --- a/go.sum +++ b/go.sum @@ -115,8 +115,8 @@ golang.org/x/sync v0.13.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.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= From b224f499d2cce112c26002559c3b4a9e60477779 Mon Sep 17 00:00:00 2001 From: Nabil <26463615+ncharaf@users.noreply.github.com> Date: Wed, 21 May 2025 19:53:59 +0200 Subject: [PATCH 08/25] chore: fix some typos (#3316) Signed-off-by: Nabil Signed-off-by: Shashwat Hiregoudar --- collector/cpu_vulnerabilities_linux.go | 6 +++--- collector/processes_linux.go | 2 +- collector/processes_linux_test.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/collector/cpu_vulnerabilities_linux.go b/collector/cpu_vulnerabilities_linux.go index 180d56d6c3..a41d5b17a5 100644 --- a/collector/cpu_vulnerabilities_linux.go +++ b/collector/cpu_vulnerabilities_linux.go @@ -22,12 +22,12 @@ import ( ) const ( - cpuVulerabilitiesCollector = "cpu_vulnerabilities" + cpuVulnerabilitiesCollectorSubsystem = "cpu_vulnerabilities" ) var ( vulnerabilityDesc = prometheus.NewDesc( - prometheus.BuildFQName(namespace, cpuVulerabilitiesCollector, "info"), + prometheus.BuildFQName(namespace, cpuVulnerabilitiesCollectorSubsystem, "info"), "Details of each CPU vulnerability reported by sysfs. The value of the series is an int encoded state of the vulnerability. The same state is stored as a string in the label", []string{"codename", "state", "mitigation"}, nil, @@ -37,7 +37,7 @@ var ( type cpuVulnerabilitiesCollector struct{} func init() { - registerCollector(cpuVulerabilitiesCollector, defaultDisabled, NewVulnerabilitySysfsCollector) + registerCollector(cpuVulnerabilitiesCollectorSubsystem, defaultDisabled, NewVulnerabilitySysfsCollector) } func NewVulnerabilitySysfsCollector(logger *slog.Logger) (Collector, error) { diff --git a/collector/processes_linux.go b/collector/processes_linux.go index 653045e553..add7f0dfa7 100644 --- a/collector/processes_linux.go +++ b/collector/processes_linux.go @@ -106,7 +106,7 @@ func (c *processCollector) Update(ch chan<- prometheus.Metric) error { pidM, err := readUintFromFile(procFilePath("sys/kernel/pid_max")) if err != nil { - return fmt.Errorf("unable to retrieve limit number of maximum pids alloved: %w", err) + return fmt.Errorf("unable to retrieve limit number of maximum pids allowed: %w", err) } ch <- prometheus.MustNewConstMetric(c.pidUsed, prometheus.GaugeValue, float64(pids)) ch <- prometheus.MustNewConstMetric(c.pidMax, prometheus.GaugeValue, float64(pidM)) diff --git a/collector/processes_linux_test.go b/collector/processes_linux_test.go index c50d16c8db..f89ad12f2f 100644 --- a/collector/processes_linux_test.go +++ b/collector/processes_linux_test.go @@ -48,7 +48,7 @@ func TestReadProcessStatus(t *testing.T) { } maxPid, err := readUintFromFile(procFilePath("sys/kernel/pid_max")) if err != nil { - t.Fatalf("Unable to retrieve limit number of maximum pids alloved %v\n", err) + t.Fatalf("Unable to retrieve limit number of maximum pids allowed %v\n", err) } if uint64(pids) > maxPid || pids == 0 { t.Fatalf("Total running pids cannot be greater than %d or equals to 0", maxPid) From 543263b186f94c1982d7bfdeb5f2e3745c84cae3 Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Sat, 29 Mar 2025 13:27:45 +0100 Subject: [PATCH 09/25] AIX: Add physical cpu, runqueue and flag metrics Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/cpu_aix.go | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/collector/cpu_aix.go b/collector/cpu_aix.go index 9d896e2ded..36837948cc 100644 --- a/collector/cpu_aix.go +++ b/collector/cpu_aix.go @@ -30,8 +30,29 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +var ( + nodeCPUPhysicalSecondsDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "physical_seconds_total"), + "Seconds the physical CPUs spent in each mode.", + []string{"cpu", "mode"}, nil, + ) + nodeCPUSRunQueueDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "runqueue"), + "Length of the run queue.", []string{"cpu"}, nil, + ) + nodeCPUFlagsDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "flags"), + "CPU flags.", + []string{"cpu", "flag"}, nil, + ) +) + type cpuCollector struct { - cpu typedDesc + cpu typedDesc + cpuPhysical typedDesc + cpuRunQueue typedDesc + cpuFlags typedDesc + logger *slog.Logger tickPerSecond int64 } @@ -55,6 +76,9 @@ func NewCpuCollector(logger *slog.Logger) (Collector, error) { } return &cpuCollector{ cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue}, + cpuPhysical: typedDesc{nodeCPUPhysicalSecondsDesc, prometheus.CounterValue}, + cpuRunQueue: typedDesc{nodeCPUSRunQueueDesc, prometheus.GaugeValue}, + cpuFlags: typedDesc{nodeCPUFlagsDesc, prometheus.GaugeValue}, logger: logger, tickPerSecond: ticks, }, nil @@ -67,10 +91,23 @@ func (c *cpuCollector) Update(ch chan<- prometheus.Metric) error { } for n, stat := range stats { + // LPAR metrics ch <- c.cpu.mustNewConstMetric(float64(stat.User/c.tickPerSecond), strconv.Itoa(n), "user") ch <- c.cpu.mustNewConstMetric(float64(stat.Sys/c.tickPerSecond), strconv.Itoa(n), "system") ch <- c.cpu.mustNewConstMetric(float64(stat.Idle/c.tickPerSecond), strconv.Itoa(n), "idle") ch <- c.cpu.mustNewConstMetric(float64(stat.Wait/c.tickPerSecond), strconv.Itoa(n), "wait") + + // Physical CPU metrics + ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PIdle/c.tickPerSecond), strconv.Itoa(n), "pidle") + ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PUser/c.tickPerSecond), strconv.Itoa(n), "puser") + ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PSys/c.tickPerSecond), strconv.Itoa(n), "psys") + ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PWait/c.tickPerSecond), strconv.Itoa(n), "pwait") + + // Run queue length + ch <- c.cpuRunQueue.mustNewConstMetric(float64(stat.RunQueue), strconv.Itoa(n)) + + // Flags + ch <- c.cpuFlags.mustNewConstMetric(float64(stat.SpurrFlag), strconv.Itoa(n), "spurr") } return nil } From 0cc7a80a02a6cabd8e2581fc4266e89f55046fbf Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Thu, 3 Apr 2025 16:47:09 +0200 Subject: [PATCH 10/25] AIX: Add more disk metrics Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/diskstats_aix.go | 84 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/collector/diskstats_aix.go b/collector/diskstats_aix.go index c6619fd9bd..78522ec2bb 100644 --- a/collector/diskstats_aix.go +++ b/collector/diskstats_aix.go @@ -30,6 +30,17 @@ type diskstatsCollector struct { rbytes typedDesc wbytes typedDesc time typedDesc + bsize typedDesc + qdepth typedDesc + + rblks typedDesc + wblks typedDesc + + rserv typedDesc + wserv typedDesc + + xfers typedDesc + xrate typedDesc deviceFilter deviceFilter logger *slog.Logger @@ -57,6 +68,70 @@ func NewDiskstatsCollector(logger *slog.Logger) (Collector, error) { wbytes: typedDesc{writtenBytesDesc, prometheus.CounterValue}, time: typedDesc{ioTimeSecondsDesc, prometheus.CounterValue}, + bsize: typedDesc{ + prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "block_size_bytes"), + "Size of the block device in bytes.", + diskLabelNames, nil, + ), + prometheus.GaugeValue, + }, + qdepth: typedDesc{ + prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "queue_depth"), + "Number of requests in the queue.", + diskLabelNames, nil, + ), + prometheus.GaugeValue, + }, + rblks: typedDesc{ + prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "read_blocks_total"), + "The total number of read blocks.", + diskLabelNames, nil, + ), + prometheus.CounterValue, + }, + wblks: typedDesc{ + prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "written_blocks_total"), + "The total number of written blocks.", + diskLabelNames, nil, + ), + prometheus.CounterValue, + }, + rserv: typedDesc{ + prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "read_time_seconds_total"), + "The total time spent servicing read requests.", + diskLabelNames, nil, + ), + prometheus.CounterValue, + }, + wserv: typedDesc{ + prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "write_time_seconds_total"), + "The total time spent servicing write requests.", + diskLabelNames, nil, + ), + prometheus.CounterValue, + }, + xfers: typedDesc{ + prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "transfers_total"), + "The total number of transfers to/from disk.", + diskLabelNames, nil, + ), + prometheus.CounterValue, + }, + xrate: typedDesc{ + prometheus.NewDesc( + prometheus.BuildFQName(namespace, diskSubsystem, "transfers_to_disk_total"), + "The total number of transfers from disk.", + diskLabelNames, nil, + ), + prometheus.CounterValue, + }, deviceFilter: deviceFilter, logger: logger, @@ -77,6 +152,15 @@ func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error { ch <- c.rbytes.mustNewConstMetric(float64(stat.Rblks*512), stat.Name) ch <- c.wbytes.mustNewConstMetric(float64(stat.Wblks*512), stat.Name) ch <- c.time.mustNewConstMetric(float64(stat.Time/c.tickPerSecond), stat.Name) + + ch <- c.bsize.mustNewConstMetric(float64(stat.BSize), stat.Name) + ch <- c.qdepth.mustNewConstMetric(float64(stat.QDepth), stat.Name) + ch <- c.rblks.mustNewConstMetric(float64(stat.Rblks), stat.Name) + ch <- c.wblks.mustNewConstMetric(float64(stat.Wblks), stat.Name) + ch <- c.rserv.mustNewConstMetric(float64(stat.Rserv/c.tickPerSecond), stat.Name) + ch <- c.wserv.mustNewConstMetric(float64(stat.Wserv/c.tickPerSecond), stat.Name) + ch <- c.xfers.mustNewConstMetric(float64(stat.Xfers), stat.Name) + ch <- c.xrate.mustNewConstMetric(float64(stat.XRate), stat.Name) } return nil } From 048a8abde5610518fa2959cf25dda11aa39793f3 Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Tue, 22 Apr 2025 14:08:23 +0200 Subject: [PATCH 11/25] AIX: Add paging memory metrics Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/meminfo_aix.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/collector/meminfo_aix.go b/collector/meminfo_aix.go index ff59105b04..f90b1fd827 100644 --- a/collector/meminfo_aix.go +++ b/collector/meminfo_aix.go @@ -40,8 +40,12 @@ func (c *meminfoCollector) getMemInfo() (map[string]float64, error) { } return map[string]float64{ - "total_bytes": float64(stats.RealTotal * 4096), - "free_bytes": float64(stats.RealFree * 4096), - "available_bytes": float64(stats.RealAvailable * 4096), + "total_bytes": float64(stats.RealTotal * 4096), + "free_bytes": float64(stats.RealFree * 4096), + "available_bytes": float64(stats.RealAvailable * 4096), + "process_bytes": float64(stats.RealProcess * 4096), + "paging_space_total_bytes": float64(stats.PgSpTotal * 4096), + "paging_space_free_bytes": float64(stats.PgSpFree * 4096), + "page_scans_total": float64(stats.Scans), }, nil } From f48bc4d25effa45a46425e71c47fdcfbdf53b000 Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Tue, 22 Apr 2025 14:15:49 +0200 Subject: [PATCH 12/25] AIX: Add transmit_queue_overflow metric to netdev collector Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/netdev_aix.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/collector/netdev_aix.go b/collector/netdev_aix.go index ae316443cf..7ddc002e8c 100644 --- a/collector/netdev_aix.go +++ b/collector/netdev_aix.go @@ -32,16 +32,17 @@ func getNetDevStats(filter *deviceFilter, logger *slog.Logger) (netDevStats, err for _, stat := range stats { netDev[stat.Name] = map[string]uint64{ - "receive_packets": uint64(stat.RxPackets), - "transmit_packets": uint64(stat.TxPackets), - "receive_bytes": uint64(stat.RxBytes), - "transmit_bytes": uint64(stat.TxBytes), - "receive_errors": uint64(stat.RxErrors), - "transmit_errors": uint64(stat.TxErrors), - "receive_dropped": uint64(stat.RxPacketsDropped), - "transmit_dropped": uint64(stat.TxPacketsDropped), - "receive_multicast": uint64(stat.RxMulticastPackets), - "transmit_multicast": uint64(stat.TxMulticastPackets), + "receive_bytes": uint64(stat.RxBytes), + "receive_dropped": uint64(stat.RxPacketsDropped), + "receive_errors": uint64(stat.RxErrors), + "receive_multicast": uint64(stat.RxMulticastPackets), + "receive_packets": uint64(stat.RxPackets), + "transmit_bytes": uint64(stat.TxBytes), + "transmit_dropped": uint64(stat.TxPacketsDropped), + "transmit_errors": uint64(stat.TxErrors), + "transmit_multicast": uint64(stat.TxMulticastPackets), + "transmit_packets": uint64(stat.TxPackets), + "transmit_queue_overflow": uint64(stat.TxQueueOverflow), } } From 9c0ca73bcb6108e0becfa098eb0605d0b2300021 Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Thu, 22 May 2025 17:53:32 +0200 Subject: [PATCH 13/25] AIX: Add netadapter collision counters Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/netdev_aix.go | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/collector/netdev_aix.go b/collector/netdev_aix.go index 7ddc002e8c..e29371b100 100644 --- a/collector/netdev_aix.go +++ b/collector/netdev_aix.go @@ -32,17 +32,20 @@ func getNetDevStats(filter *deviceFilter, logger *slog.Logger) (netDevStats, err for _, stat := range stats { netDev[stat.Name] = map[string]uint64{ - "receive_bytes": uint64(stat.RxBytes), - "receive_dropped": uint64(stat.RxPacketsDropped), - "receive_errors": uint64(stat.RxErrors), - "receive_multicast": uint64(stat.RxMulticastPackets), - "receive_packets": uint64(stat.RxPackets), - "transmit_bytes": uint64(stat.TxBytes), - "transmit_dropped": uint64(stat.TxPacketsDropped), - "transmit_errors": uint64(stat.TxErrors), - "transmit_multicast": uint64(stat.TxMulticastPackets), - "transmit_packets": uint64(stat.TxPackets), - "transmit_queue_overflow": uint64(stat.TxQueueOverflow), + "receive_bytes": uint64(stat.RxBytes), + "receive_dropped": uint64(stat.RxPacketsDropped), + "receive_errors": uint64(stat.RxErrors), + "receive_multicast": uint64(stat.RxMulticastPackets), + "receive_packets": uint64(stat.RxPackets), + "receive_collision_errors": uint64(stat.RxCollisionErrors), + "transmit_bytes": uint64(stat.TxBytes), + "transmit_dropped": uint64(stat.TxPacketsDropped), + "transmit_errors": uint64(stat.TxErrors), + "transmit_multicast": uint64(stat.TxMulticastPackets), + "transmit_packets": uint64(stat.TxPackets), + "transmit_queue_overflow": uint64(stat.TxQueueOverflow), + "transmit_collision_single_errors": uint64(stat.TxSingleCollisionCount), + "transmit_collision_multiple_errors": uint64(stat.TxMultipleCollisionCount), } } From 1292993082be0ddcc2f1dc857e02cae4dfe7fb51 Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Fri, 23 May 2025 14:57:57 +0200 Subject: [PATCH 14/25] AIX: Add partition stats Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/partition_aix.go | 118 +++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 collector/partition_aix.go diff --git a/collector/partition_aix.go b/collector/partition_aix.go new file mode 100644 index 0000000000..3c54e0f41e --- /dev/null +++ b/collector/partition_aix.go @@ -0,0 +1,118 @@ +// Copyright 2025 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build !nopartition +// +build !nopartition + +package collector + +import ( + "log/slog" + + "github.com/power-devops/perfstat" + "github.com/prometheus/client_golang/prometheus" +) + +type partitionCollector struct { + logger *slog.Logger + entitledCapacity *prometheus.Desc + memoryMax *prometheus.Desc + memoryOnline *prometheus.Desc + cpuOnline *prometheus.Desc + cpuSys *prometheus.Desc + cpuPool *prometheus.Desc + powerSaveMode *prometheus.Desc + smtThreads *prometheus.Desc +} + +const ( + partitionCollectorSubsystem = "partition" +) + +func init() { + registerCollector("partition", defaultEnabled, NewPartitionCollector) +} + +func NewPartitionCollector(logger *slog.Logger) (Collector, error) { + return &partitionCollector{ + logger: logger, + entitledCapacity: prometheus.NewDesc( + prometheus.BuildFQName(namespace, partitionCollectorSubsystem, "entitled_capacity"), + "Entitled processor capacity of the partition in CPU units (e.g. 1.0 = one core).", + nil, nil, + ), + memoryMax: prometheus.NewDesc( + prometheus.BuildFQName(namespace, partitionCollectorSubsystem, "memory_max"), + "Maximum memory of the partition in bytes.", + nil, nil, + ), + memoryOnline: prometheus.NewDesc( + prometheus.BuildFQName(namespace, partitionCollectorSubsystem, "memory_online"), + "Online memory of the partition in bytes.", + nil, nil, + ), + cpuOnline: prometheus.NewDesc( + prometheus.BuildFQName(namespace, partitionCollectorSubsystem, "cpus_online"), + "Number of online CPUs in the partition.", + nil, nil, + ), + cpuSys: prometheus.NewDesc( + prometheus.BuildFQName(namespace, partitionCollectorSubsystem, "cpus_sys"), + "Number of physical CPUs in the system.", + nil, nil, + ), + cpuPool: prometheus.NewDesc( + prometheus.BuildFQName(namespace, partitionCollectorSubsystem, "cpus_pool"), + "Number of physical CPUs in the pool.", + nil, nil, + ), + powerSaveMode: prometheus.NewDesc( + prometheus.BuildFQName(namespace, partitionCollectorSubsystem, "power_save_mode"), + "Power save mode of the partition (1 for enabled, 0 for disabled).", + nil, nil, + ), + smtThreads: prometheus.NewDesc( + prometheus.BuildFQName(namespace, partitionCollectorSubsystem, "smt_threads"), + "Number of SMT threads per core.", + nil, nil, + ), + }, nil +} + +func (c *partitionCollector) Update(ch chan<- prometheus.Metric) error { + stats, err := perfstat.PartitionStat() + if err != nil { + return err + } + + powerSaveMode := 0.0 + if stats.Conf.PowerSave { + powerSaveMode = 1.0 + } + + ch <- prometheus.MustNewConstMetric(c.entitledCapacity, prometheus.GaugeValue, float64(stats.EntCapacity)/100.0) + + ch <- prometheus.MustNewConstMetric(c.memoryMax, prometheus.GaugeValue, float64(stats.Mem.Max)*1024*1024) + ch <- prometheus.MustNewConstMetric(c.memoryOnline, prometheus.GaugeValue, float64(stats.Mem.Online)*1024*1024) + + ch <- prometheus.MustNewConstMetric(c.cpuOnline, prometheus.GaugeValue, float64(stats.VCpus.Online)) + + ch <- prometheus.MustNewConstMetric(c.cpuSys, prometheus.GaugeValue, float64(stats.NumProcessors.Online)) + + ch <- prometheus.MustNewConstMetric(c.cpuPool, prometheus.GaugeValue, float64(stats.ActiveCpusInPool)) + + ch <- prometheus.MustNewConstMetric(c.powerSaveMode, prometheus.GaugeValue, powerSaveMode) + ch <- prometheus.MustNewConstMetric(c.smtThreads, prometheus.GaugeValue, float64(stats.SmtThreads)) + + return nil +} From f365644d94239860345386688d195929d5fa80d4 Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Fri, 23 May 2025 15:10:17 +0200 Subject: [PATCH 15/25] AIX: Add context switches to cpu collector Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/cpu_aix.go | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/collector/cpu_aix.go b/collector/cpu_aix.go index 36837948cc..8b3f17c547 100644 --- a/collector/cpu_aix.go +++ b/collector/cpu_aix.go @@ -45,13 +45,19 @@ var ( "CPU flags.", []string{"cpu", "flag"}, nil, ) + nodeCPUContextSwitchDesc = prometheus.NewDesc( + prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "context_switches_total"), + "Number of context switches.", + []string{"cpu"}, nil, + ) ) type cpuCollector struct { - cpu typedDesc - cpuPhysical typedDesc - cpuRunQueue typedDesc - cpuFlags typedDesc + cpu typedDesc + cpuPhysical typedDesc + cpuRunQueue typedDesc + cpuFlags typedDesc + cpuContextSwitch typedDesc logger *slog.Logger tickPerSecond int64 @@ -75,12 +81,13 @@ func NewCpuCollector(logger *slog.Logger) (Collector, error) { return nil, err } return &cpuCollector{ - cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue}, - cpuPhysical: typedDesc{nodeCPUPhysicalSecondsDesc, prometheus.CounterValue}, - cpuRunQueue: typedDesc{nodeCPUSRunQueueDesc, prometheus.GaugeValue}, - cpuFlags: typedDesc{nodeCPUFlagsDesc, prometheus.GaugeValue}, - logger: logger, - tickPerSecond: ticks, + cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue}, + cpuPhysical: typedDesc{nodeCPUPhysicalSecondsDesc, prometheus.CounterValue}, + cpuRunQueue: typedDesc{nodeCPUSRunQueueDesc, prometheus.GaugeValue}, + cpuFlags: typedDesc{nodeCPUFlagsDesc, prometheus.GaugeValue}, + cpuContextSwitch: typedDesc{nodeCPUContextSwitchDesc, prometheus.CounterValue}, + logger: logger, + tickPerSecond: ticks, }, nil } @@ -108,6 +115,9 @@ func (c *cpuCollector) Update(ch chan<- prometheus.Metric) error { // Flags ch <- c.cpuFlags.mustNewConstMetric(float64(stat.SpurrFlag), strconv.Itoa(n), "spurr") + + // Context switches + ch <- c.cpuContextSwitch.mustNewConstMetric(float64(stat.CSwitches), strconv.Itoa(n)) } return nil } From ed39f60612cf5bceaa2eeb1ab5f52638c238e82f Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Mon, 26 May 2025 14:45:58 +0200 Subject: [PATCH 16/25] AIX: Fix physical cpu usage calculation Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/cpu_aix.go | 47 +++++++++++++++++++++++--------------- collector/diskstats_aix.go | 8 +++---- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/collector/cpu_aix.go b/collector/cpu_aix.go index 8b3f17c547..017e1a0c22 100644 --- a/collector/cpu_aix.go +++ b/collector/cpu_aix.go @@ -59,20 +59,21 @@ type cpuCollector struct { cpuFlags typedDesc cpuContextSwitch typedDesc - logger *slog.Logger - tickPerSecond int64 + logger *slog.Logger + tickPerSecond float64 + purrTicksPerSecond float64 } func init() { registerCollector("cpu", defaultEnabled, NewCpuCollector) } -func tickPerSecond() (int64, error) { +func tickPerSecond() (float64, error) { ticks, err := C.sysconf(C._SC_CLK_TCK) if ticks == -1 || err != nil { return 0, fmt.Errorf("failed to get clock ticks per second: %v", err) } - return int64(ticks), nil + return float64(ticks), nil } func NewCpuCollector(logger *slog.Logger) (Collector, error) { @@ -80,14 +81,22 @@ func NewCpuCollector(logger *slog.Logger) (Collector, error) { if err != nil { return nil, err } + + pconfig, err := perfstat.PartitionStat() + + if err != nil { + return nil, err + } + return &cpuCollector{ - cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue}, - cpuPhysical: typedDesc{nodeCPUPhysicalSecondsDesc, prometheus.CounterValue}, - cpuRunQueue: typedDesc{nodeCPUSRunQueueDesc, prometheus.GaugeValue}, - cpuFlags: typedDesc{nodeCPUFlagsDesc, prometheus.GaugeValue}, - cpuContextSwitch: typedDesc{nodeCPUContextSwitchDesc, prometheus.CounterValue}, - logger: logger, - tickPerSecond: ticks, + cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue}, + cpuPhysical: typedDesc{nodeCPUPhysicalSecondsDesc, prometheus.CounterValue}, + cpuRunQueue: typedDesc{nodeCPUSRunQueueDesc, prometheus.GaugeValue}, + cpuFlags: typedDesc{nodeCPUFlagsDesc, prometheus.GaugeValue}, + cpuContextSwitch: typedDesc{nodeCPUContextSwitchDesc, prometheus.CounterValue}, + logger: logger, + tickPerSecond: ticks, + purrTicksPerSecond: float64(pconfig.ProcessorMhz * 1e6), }, nil } @@ -99,16 +108,16 @@ func (c *cpuCollector) Update(ch chan<- prometheus.Metric) error { for n, stat := range stats { // LPAR metrics - ch <- c.cpu.mustNewConstMetric(float64(stat.User/c.tickPerSecond), strconv.Itoa(n), "user") - ch <- c.cpu.mustNewConstMetric(float64(stat.Sys/c.tickPerSecond), strconv.Itoa(n), "system") - ch <- c.cpu.mustNewConstMetric(float64(stat.Idle/c.tickPerSecond), strconv.Itoa(n), "idle") - ch <- c.cpu.mustNewConstMetric(float64(stat.Wait/c.tickPerSecond), strconv.Itoa(n), "wait") + ch <- c.cpu.mustNewConstMetric(float64(stat.User)/c.tickPerSecond, strconv.Itoa(n), "user") + ch <- c.cpu.mustNewConstMetric(float64(stat.Sys)/c.tickPerSecond, strconv.Itoa(n), "system") + ch <- c.cpu.mustNewConstMetric(float64(stat.Idle)/c.tickPerSecond, strconv.Itoa(n), "idle") + ch <- c.cpu.mustNewConstMetric(float64(stat.Wait)/c.tickPerSecond, strconv.Itoa(n), "wait") // Physical CPU metrics - ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PIdle/c.tickPerSecond), strconv.Itoa(n), "pidle") - ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PUser/c.tickPerSecond), strconv.Itoa(n), "puser") - ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PSys/c.tickPerSecond), strconv.Itoa(n), "psys") - ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PWait/c.tickPerSecond), strconv.Itoa(n), "pwait") + ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PIdle)/c.purrTicksPerSecond, strconv.Itoa(n), "pidle") + ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PUser)/c.purrTicksPerSecond, strconv.Itoa(n), "puser") + ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PSys)/c.purrTicksPerSecond, strconv.Itoa(n), "psys") + ch <- c.cpuPhysical.mustNewConstMetric(float64(stat.PWait)/c.purrTicksPerSecond, strconv.Itoa(n), "pwait") // Run queue length ch <- c.cpuRunQueue.mustNewConstMetric(float64(stat.RunQueue), strconv.Itoa(n)) diff --git a/collector/diskstats_aix.go b/collector/diskstats_aix.go index 78522ec2bb..9b6962c0a9 100644 --- a/collector/diskstats_aix.go +++ b/collector/diskstats_aix.go @@ -45,7 +45,7 @@ type diskstatsCollector struct { deviceFilter deviceFilter logger *slog.Logger - tickPerSecond int64 + tickPerSecond float64 } func init() { @@ -151,14 +151,14 @@ func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error { } ch <- c.rbytes.mustNewConstMetric(float64(stat.Rblks*512), stat.Name) ch <- c.wbytes.mustNewConstMetric(float64(stat.Wblks*512), stat.Name) - ch <- c.time.mustNewConstMetric(float64(stat.Time/c.tickPerSecond), stat.Name) + ch <- c.time.mustNewConstMetric(float64(stat.Time)/c.tickPerSecond, stat.Name) ch <- c.bsize.mustNewConstMetric(float64(stat.BSize), stat.Name) ch <- c.qdepth.mustNewConstMetric(float64(stat.QDepth), stat.Name) ch <- c.rblks.mustNewConstMetric(float64(stat.Rblks), stat.Name) ch <- c.wblks.mustNewConstMetric(float64(stat.Wblks), stat.Name) - ch <- c.rserv.mustNewConstMetric(float64(stat.Rserv/c.tickPerSecond), stat.Name) - ch <- c.wserv.mustNewConstMetric(float64(stat.Wserv/c.tickPerSecond), stat.Name) + ch <- c.rserv.mustNewConstMetric(float64(stat.Rserv)/c.tickPerSecond, stat.Name) + ch <- c.wserv.mustNewConstMetric(float64(stat.Wserv)/c.tickPerSecond, stat.Name) ch <- c.xfers.mustNewConstMetric(float64(stat.Xfers), stat.Name) ch <- c.xrate.mustNewConstMetric(float64(stat.XRate), stat.Name) } From c230ccfef936fc82dfe39356e99522c31e19ad71 Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Mon, 26 May 2025 15:58:54 +0200 Subject: [PATCH 17/25] AIX: Remove redundant disk blocks metric, fix times Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/diskstats_aix.go | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/collector/diskstats_aix.go b/collector/diskstats_aix.go index 9b6962c0a9..4ad39ff38d 100644 --- a/collector/diskstats_aix.go +++ b/collector/diskstats_aix.go @@ -33,9 +33,6 @@ type diskstatsCollector struct { bsize typedDesc qdepth typedDesc - rblks typedDesc - wblks typedDesc - rserv typedDesc wserv typedDesc @@ -84,22 +81,6 @@ func NewDiskstatsCollector(logger *slog.Logger) (Collector, error) { ), prometheus.GaugeValue, }, - rblks: typedDesc{ - prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "read_blocks_total"), - "The total number of read blocks.", - diskLabelNames, nil, - ), - prometheus.CounterValue, - }, - wblks: typedDesc{ - prometheus.NewDesc( - prometheus.BuildFQName(namespace, diskSubsystem, "written_blocks_total"), - "The total number of written blocks.", - diskLabelNames, nil, - ), - prometheus.CounterValue, - }, rserv: typedDesc{ prometheus.NewDesc( prometheus.BuildFQName(namespace, diskSubsystem, "read_time_seconds_total"), @@ -151,14 +132,12 @@ func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error { } ch <- c.rbytes.mustNewConstMetric(float64(stat.Rblks*512), stat.Name) ch <- c.wbytes.mustNewConstMetric(float64(stat.Wblks*512), stat.Name) - ch <- c.time.mustNewConstMetric(float64(stat.Time)/c.tickPerSecond, stat.Name) + ch <- c.time.mustNewConstMetric(float64(stat.Time)/float64(c.tickPerSecond), stat.Name) ch <- c.bsize.mustNewConstMetric(float64(stat.BSize), stat.Name) ch <- c.qdepth.mustNewConstMetric(float64(stat.QDepth), stat.Name) - ch <- c.rblks.mustNewConstMetric(float64(stat.Rblks), stat.Name) - ch <- c.wblks.mustNewConstMetric(float64(stat.Wblks), stat.Name) - ch <- c.rserv.mustNewConstMetric(float64(stat.Rserv)/c.tickPerSecond, stat.Name) - ch <- c.wserv.mustNewConstMetric(float64(stat.Wserv)/c.tickPerSecond, stat.Name) + ch <- c.rserv.mustNewConstMetric(float64(stat.Rserv)/1e9, stat.Name) + ch <- c.wserv.mustNewConstMetric(float64(stat.Wserv)/1e9, stat.Name) ch <- c.xfers.mustNewConstMetric(float64(stat.Xfers), stat.Name) ch <- c.xrate.mustNewConstMetric(float64(stat.XRate), stat.Name) } From 53cfd7a0e4867c81c5cacf56e301a8e38e1d70ba Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Mon, 26 May 2025 16:38:20 +0200 Subject: [PATCH 18/25] AIX: Fix disk blocks to bytes conversion Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/filesystem_aix.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/collector/filesystem_aix.go b/collector/filesystem_aix.go index a1314a0f01..84bb89131d 100644 --- a/collector/filesystem_aix.go +++ b/collector/filesystem_aix.go @@ -53,9 +53,9 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { mountPoint: stat.MountPoint, fsType: fstype, }, - size: float64(stat.TotalBlocks / 512.0), - free: float64(stat.FreeBlocks / 512.0), - avail: float64(stat.FreeBlocks / 512.0), // AIX doesn't distinguish between free and available blocks. + size: float64(stat.TotalBlocks * 512.0), + free: float64(stat.FreeBlocks * 512.0), + avail: float64(stat.FreeBlocks * 512.0), // AIX doesn't distinguish between free and available blocks. files: float64(stat.TotalInodes), filesFree: float64(stat.FreeInodes), ro: ro, From f28f871c4301c619d5e57e3983c3c17ae324e20e Mon Sep 17 00:00:00 2001 From: Johannes Ziemke Date: Mon, 26 May 2025 16:43:23 +0200 Subject: [PATCH 19/25] AIX: Add netinterface collector While having overlap with NetAdpter metrics, the metrics are slightly different so need to be exposed as well. Signed-off-by: Johannes Ziemke Signed-off-by: Shashwat Hiregoudar --- collector/netinterface_aix.go | 86 +++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 collector/netinterface_aix.go diff --git a/collector/netinterface_aix.go b/collector/netinterface_aix.go new file mode 100644 index 0000000000..9a5b766828 --- /dev/null +++ b/collector/netinterface_aix.go @@ -0,0 +1,86 @@ +// Copyright 2025 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build !nonetinterface +// +build !nonetinterface + +package collector + +import ( + "log/slog" + + "github.com/power-devops/perfstat" + "github.com/prometheus/client_golang/prometheus" +) + +type netinterfaceCollector struct { + logger *slog.Logger + collisions *prometheus.Desc + ibytes *prometheus.Desc + ipackets *prometheus.Desc + obytes *prometheus.Desc + opackets *prometheus.Desc +} + +const ( + netinterfaceSubsystem = "netinterface" +) + +func init() { + registerCollector("netinterface", defaultEnabled, NewNetinterfaceCollector) +} + +func NewNetinterfaceCollector(logger *slog.Logger) (Collector, error) { + labels := []string{"interface"} + return &netinterfaceCollector{ + logger: logger, + collisions: prometheus.NewDesc( + prometheus.BuildFQName(namespace, netinterfaceSubsystem, "collisions_total"), + "Total number of CSMA collisions on the interface.", labels, nil, + ), + ibytes: prometheus.NewDesc( + prometheus.BuildFQName(namespace, netinterfaceSubsystem, "receive_bytes_total"), + "Total number of bytes received on the interface.", labels, nil, + ), + ipackets: prometheus.NewDesc( + prometheus.BuildFQName(namespace, netinterfaceSubsystem, "receive_packets_total"), + "Total number of packets received on the interface.", labels, nil, + ), + obytes: prometheus.NewDesc( + prometheus.BuildFQName(namespace, netinterfaceSubsystem, "transmit_bytes_total"), + "Total number of bytes transmitted on the interface.", labels, nil, + ), + opackets: prometheus.NewDesc( + prometheus.BuildFQName(namespace, netinterfaceSubsystem, "transmit_packets_total"), + "Total number of packets transmitted on the interface.", labels, nil, + ), + }, nil +} + +func (c *netinterfaceCollector) Update(ch chan<- prometheus.Metric) error { + stats, err := perfstat.NetIfaceStat() + if err != nil { + return err + } + + for _, stat := range stats { + iface := stat.Name + + ch <- prometheus.MustNewConstMetric(c.collisions, prometheus.CounterValue, float64(stat.Collisions), iface) + ch <- prometheus.MustNewConstMetric(c.ibytes, prometheus.CounterValue, float64(stat.IBytes), iface) + ch <- prometheus.MustNewConstMetric(c.ipackets, prometheus.CounterValue, float64(stat.IPackets), iface) + ch <- prometheus.MustNewConstMetric(c.obytes, prometheus.CounterValue, float64(stat.OBytes), iface) + ch <- prometheus.MustNewConstMetric(c.opackets, prometheus.CounterValue, float64(stat.OPackets), iface) + } + return nil +} From 822731ce7bb1ae4cf2fc54815afb65f28eeaa9fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 10:28:04 +0000 Subject: [PATCH 20/25] build(deps): bump github.com/prometheus/common from 0.62.0 to 0.63.0 Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.62.0 to 0.63.0. - [Release notes](https://github.com/prometheus/common/releases) - [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md) - [Commits](https://github.com/prometheus/common/compare/v0.62.0...v0.63.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-version: 0.63.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: Shashwat Hiregoudar --- go.mod | 16 ++++++++-------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 7003d9a701..c786fac1df 100644 --- a/go.mod +++ b/go.mod @@ -23,8 +23,8 @@ require ( github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 github.com/prometheus-community/go-runit v0.1.0 github.com/prometheus/client_golang v1.21.1 - github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.62.0 + github.com/prometheus/client_model v0.6.2 + github.com/prometheus/common v0.64.0 github.com/prometheus/exporter-toolkit v0.14.0 github.com/prometheus/procfs v0.16.0 github.com/safchain/ethtool v0.5.10 @@ -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.37.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sync v0.13.0 // indirect - golang.org/x/text v0.24.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect + golang.org/x/crypto v0.38.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/text v0.25.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 236c1b3f57..e15a683b1d 100644 --- a/go.sum +++ b/go.sum @@ -77,10 +77,10 @@ github.com/prometheus-community/go-runit v0.1.0 h1:uTWEj/Fn2RoLdfg/etSqwzgYNOYPr github.com/prometheus-community/go-runit v0.1.0/go.mod h1:AvJ9Jo3gAFu2lbM4+qfjdpq30FfiLDJZKbQ015u08IQ= github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= +github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg= github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA= github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= @@ -102,25 +102,25 @@ 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.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= 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.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -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.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.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.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= -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= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From 9c892a95437e0015030e65a186ec9af266f7b20c Mon Sep 17 00:00:00 2001 From: Michael Fuller Date: Tue, 20 May 2025 11:23:04 -0500 Subject: [PATCH 21/25] go.mod: bump procfs to 0.16.1, go mod tidy Signed-off-by: Michael Fuller Signed-off-by: Shashwat Hiregoudar --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c786fac1df..23a4923fd5 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/prometheus/client_model v0.6.2 github.com/prometheus/common v0.64.0 github.com/prometheus/exporter-toolkit v0.14.0 - github.com/prometheus/procfs v0.16.0 + github.com/prometheus/procfs v0.16.1 github.com/safchain/ethtool v0.5.10 golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/sys v0.33.0 diff --git a/go.sum b/go.sum index e15a683b1d..73f3cbc546 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,8 @@ github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQP github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg= github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA= -github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= -github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= 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.5.10 h1:Im294gZtuf4pSGJRAOGKaASNi3wMeFaGaWuSaomedpc= From 3ad608989a1903d5a3f8f47cdc98aadab97ae7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Sat, 31 May 2025 08:08:50 +0200 Subject: [PATCH 22/25] chore: Lint with golangci-lint v2 (#3301) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger Signed-off-by: Shashwat Hiregoudar --- collector/btrfs_linux.go | 2 +- collector/cpu_linux.go | 2 +- collector/cpu_netbsd.go | 2 +- collector/ethtool_linux_test.go | 10 ++++++---- collector/filesystem_linux.go | 4 ++-- collector/meminfo_linux.go | 2 +- collector/perf_linux_test.go | 2 +- collector/systemd_linux_test.go | 7 ++++--- collector/zfs_linux.go | 2 +- node_exporter.go | 2 +- 10 files changed, 19 insertions(+), 16 deletions(-) diff --git a/collector/btrfs_linux.go b/collector/btrfs_linux.go index 2dbdf5aa35..acb7e64c85 100644 --- a/collector/btrfs_linux.go +++ b/collector/btrfs_linux.go @@ -69,7 +69,7 @@ func (c *btrfsCollector) Update(ch chan<- prometheus.Metric) error { for _, s := range stats { // match up procfs and ioctl info by filesystem UUID (without dashes) - var fsUUID = strings.Replace(s.UUID, "-", "", -1) + var fsUUID = strings.ReplaceAll(s.UUID, "-", "") ioctlStats := ioctlStatsMap[fsUUID] c.updateBtrfsStats(ch, s, ioctlStats) } diff --git a/collector/cpu_linux.go b/collector/cpu_linux.go index 8ca703657b..078a4611de 100644 --- a/collector/cpu_linux.go +++ b/collector/cpu_linux.go @@ -87,7 +87,7 @@ func NewCPUCollector(logger *slog.Logger) (Collector, error) { isolcpus, err := sfs.IsolatedCPUs() if err != nil { if !os.IsNotExist(err) { - return nil, fmt.Errorf("Unable to get isolated cpus: %w", err) + return nil, fmt.Errorf("unable to get isolated cpus: %w", err) } logger.Debug("Could not open isolated file", "error", err) } diff --git a/collector/cpu_netbsd.go b/collector/cpu_netbsd.go index ae1235eb74..459365d60f 100644 --- a/collector/cpu_netbsd.go +++ b/collector/cpu_netbsd.go @@ -155,7 +155,7 @@ func getCPUTemperatures() (map[int]float64, error) { } keys := sortFilterSysmonProperties(props, "coretemp") - for idx, _ := range keys { + for idx := range keys { convertTemperatures(props[keys[idx]], res) } diff --git a/collector/ethtool_linux_test.go b/collector/ethtool_linux_test.go index 48babbc442..c72adcb485 100644 --- a/collector/ethtool_linux_test.go +++ b/collector/ethtool_linux_test.go @@ -212,16 +212,18 @@ func (e *EthtoolFixture) LinkInfo(intf string) (ethtool.EthtoolCmd, error) { items := strings.Split(line, ": ") if items[0] == "Supported pause frame use" { - if items[1] == "Symmetric" { + switch items[1] { + case "Symmetric": res.Supported |= (1 << unix.ETHTOOL_LINK_MODE_Pause_BIT) - } else if items[1] == "Receive-only" { + case "Receive-only": res.Supported |= (1 << unix.ETHTOOL_LINK_MODE_Asym_Pause_BIT) } } if items[0] == "Advertised pause frame use" { - if items[1] == "Symmetric" { + switch items[1] { + case "Symmetric": res.Advertising |= (1 << unix.ETHTOOL_LINK_MODE_Pause_BIT) - } else if items[1] == "Receive-only" { + case "Receive-only": res.Advertising |= (1 << unix.ETHTOOL_LINK_MODE_Asym_Pause_BIT) } } diff --git a/collector/filesystem_linux.go b/collector/filesystem_linux.go index 3a7bda4d24..127a3be1d6 100644 --- a/collector/filesystem_linux.go +++ b/collector/filesystem_linux.go @@ -215,8 +215,8 @@ func parseFilesystemLabels(r io.Reader) ([]filesystemLabels, error) { // Ensure we handle the translation of \040 and \011 // as per fstab(5). - parts[4] = strings.Replace(parts[4], "\\040", " ", -1) - parts[4] = strings.Replace(parts[4], "\\011", "\t", -1) + parts[4] = strings.ReplaceAll(parts[4], "\\040", " ") + parts[4] = strings.ReplaceAll(parts[4], "\\011", "\t") filesystems = append(filesystems, filesystemLabels{ device: parts[m+3], diff --git a/collector/meminfo_linux.go b/collector/meminfo_linux.go index 98d5a5c06b..62807c2fe9 100644 --- a/collector/meminfo_linux.go +++ b/collector/meminfo_linux.go @@ -44,7 +44,7 @@ func NewMeminfoCollector(logger *slog.Logger) (Collector, error) { func (c *meminfoCollector) getMemInfo() (map[string]float64, error) { meminfo, err := c.fs.Meminfo() if err != nil { - return nil, fmt.Errorf("Failed to get memory info: %s", err) + return nil, fmt.Errorf("failed to get memory info: %s", err) } metrics := make(map[string]float64) diff --git a/collector/perf_linux_test.go b/collector/perf_linux_test.go index e385851153..7560b0a0d3 100644 --- a/collector/perf_linux_test.go +++ b/collector/perf_linux_test.go @@ -33,7 +33,7 @@ func canTestPerf(t *testing.T) { if err != nil { t.Skip("Procfs not mounted, skipping perf tests") } - paranoidStr := strings.Replace(string(paranoidBytes), "\n", "", -1) + paranoidStr := strings.ReplaceAll(string(paranoidBytes), "\n", "") paranoid, err := strconv.Atoi(paranoidStr) if err != nil { t.Fatalf("Expected perf_event_paranoid to be an int, got: %s", paranoidStr) diff --git a/collector/systemd_linux_test.go b/collector/systemd_linux_test.go index 1c290377e6..f12b6ef896 100644 --- a/collector/systemd_linux_test.go +++ b/collector/systemd_linux_test.go @@ -122,11 +122,12 @@ func TestSystemdSummary(t *testing.T) { summary := summarizeUnits(fixtures[0]) for _, state := range unitStatesName { - if state == "inactive" { + switch state { + case "inactive": testSummaryHelper(t, state, summary[state], 3.0) - } else if state == "active" { + case "active": testSummaryHelper(t, state, summary[state], 1.0) - } else { + default: testSummaryHelper(t, state, summary[state], 0.0) } } diff --git a/collector/zfs_linux.go b/collector/zfs_linux.go index 4baf2b3569..ff544a7929 100644 --- a/collector/zfs_linux.go +++ b/collector/zfs_linux.go @@ -435,5 +435,5 @@ type zfsSysctl string func (s zfsSysctl) metricName() string { parts := strings.Split(string(s), ".") - return strings.Replace(parts[len(parts)-1], "-", "_", -1) + return strings.ReplaceAll(parts[len(parts)-1], "-", "_") } diff --git a/node_exporter.go b/node_exporter.go index 88441e1e21..22939cbc56 100644 --- a/node_exporter.go +++ b/node_exporter.go @@ -112,7 +112,7 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err != nil { h.logger.Warn("Couldn't create filtered metrics handler:", "err", err) w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(fmt.Sprintf("Couldn't create filtered metrics handler: %s", err))) + fmt.Fprintf(w, "Couldn't create filtered metrics handler: %s", err) return } filteredHandler.ServeHTTP(w, r) From 5919d9d15cbe1137faa168d707e9483c079f52c7 Mon Sep 17 00:00:00 2001 From: mengxun <30499307+mengxunQAQ@users.noreply.github.com> Date: Wed, 11 Jun 2025 23:00:43 +0800 Subject: [PATCH 23/25] fix:use %w to wrap error (#3345) Signed-off-by: mengxun Signed-off-by: Shashwat Hiregoudar --- collector/meminfo_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/meminfo_linux.go b/collector/meminfo_linux.go index 62807c2fe9..4e67ac589f 100644 --- a/collector/meminfo_linux.go +++ b/collector/meminfo_linux.go @@ -44,7 +44,7 @@ func NewMeminfoCollector(logger *slog.Logger) (Collector, error) { func (c *meminfoCollector) getMemInfo() (map[string]float64, error) { meminfo, err := c.fs.Meminfo() if err != nil { - return nil, fmt.Errorf("failed to get memory info: %s", err) + return nil, fmt.Errorf("failed to get memory info: %w", err) } metrics := make(map[string]float64) From 74533358f987749985c053fef2fb6d382118b799 Mon Sep 17 00:00:00 2001 From: Shashwat Hiregoudar Date: Tue, 17 Jun 2025 16:42:08 +0530 Subject: [PATCH 24/25] correction Signed-off-by: Shashwat Hiregoudar --- collector/nvme_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/nvme_linux.go b/collector/nvme_linux.go index 5d3c2ac7cf..7cb90e17fb 100644 --- a/collector/nvme_linux.go +++ b/collector/nvme_linux.go @@ -115,7 +115,7 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { infoValue := 1.0 devicePath := filepath.Join(*sysPath, "class/nvme", device.Name) - if cntlid, err := readUintFromFile(filepath.Join(devicePath, "cntlid")) + cntlid, err := readUintFromFile(filepath.Join(devicePath, "cntlid")) if err != nil { level.Debug(c.logger).Log("msg", "failed to read cntlid", "device", device.Name, "err", err) } From 6cc12c3a032b85c7299f34898817dc124c9c50ef Mon Sep 17 00:00:00 2001 From: Shashwat Hiregoudar Date: Tue, 17 Jun 2025 17:34:15 +0530 Subject: [PATCH 25/25] making sure the tests pass Signed-off-by: Shashwat Hiregoudar --- collector/fixtures/e2e-output.txt | 2 +- collector/fixtures/sys.ttar | 5 +++++ collector/nvme_linux.go | 23 +++++++++++------------ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/collector/fixtures/e2e-output.txt b/collector/fixtures/e2e-output.txt index 45938a2b98..ce555fc804 100644 --- a/collector/fixtures/e2e-output.txt +++ b/collector/fixtures/e2e-output.txt @@ -2847,7 +2847,7 @@ node_nfsd_server_rpcs_total 18628 node_nfsd_server_threads 8 # HELP node_nvme_info Non-numeric data from /sys/class/nvme/, value is always 1. # TYPE node_nvme_info gauge -node_nvme_info{device="nvme0",firmware_revision="1B2QEXP7",model="Samsung SSD 970 PRO 512GB",serial="S680HF8N190894I",state="live"} 1 +node_nvme_info{cntlid="1997",device="nvme0",firmware_revision="1B2QEXP7",model="Samsung SSD 970 PRO 512GB",serial="S680HF8N190894I",state="live"} 1 # HELP node_os_info A metric with a constant '1' value labeled by build_id, id, id_like, image_id, image_version, name, pretty_name, variant, variant_id, version, version_codename, version_id. # TYPE node_os_info gauge node_os_info{build_id="",id="ubuntu",id_like="debian",image_id="",image_version="",name="Ubuntu",pretty_name="Ubuntu 20.04.2 LTS",variant="",variant_id="",version="20.04.2 LTS (Focal Fossa)",version_codename="focal",version_id="20.04"} 1 diff --git a/collector/fixtures/sys.ttar b/collector/fixtures/sys.ttar index 486dfd3103..dbbf814053 100644 --- a/collector/fixtures/sys.ttar +++ b/collector/fixtures/sys.ttar @@ -2179,6 +2179,11 @@ Lines: 1 1B2QEXP7 Mode: 444 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/nvme/nvme0/cntlid +Lines: 1 +1997 +Mode: 666 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: sys/class/nvme/nvme0/model Lines: 1 Samsung SSD 970 PRO 512GB diff --git a/collector/nvme_linux.go b/collector/nvme_linux.go index 7cb90e17fb..98f7fc1b18 100644 --- a/collector/nvme_linux.go +++ b/collector/nvme_linux.go @@ -25,15 +25,14 @@ import ( "strconv" "strings" - "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs/sysfs" + "log/slog" ) type nvmeCollector struct { fs sysfs.FS - logger log.Logger + logger *slog.Logger namespaceInfo *prometheus.Desc namespaceCapacityBytes *prometheus.Desc namespaceSizeBytes *prometheus.Desc @@ -47,7 +46,7 @@ func init() { } // NewNVMeCollector returns a new Collector exposing NVMe stats. -func NewNVMeCollector(logger log.Logger) (Collector, error) { +func NewNVMeCollector(logger *slog.Logger) (Collector, error) { fs, err := sysfs.NewFS(*sysPath) if err != nil { return nil, fmt.Errorf("failed to open sysfs: %w", err) @@ -105,7 +104,7 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { devices, err := c.fs.NVMeClass() if err != nil { if errors.Is(err, os.ErrNotExist) { - level.Debug(c.logger).Log("msg", "nvme statistics not found, skipping") + c.logger.Debug("nvme statistics not found, skipping") return ErrNoData } return fmt.Errorf("error obtaining NVMe class info: %w", err) @@ -117,13 +116,13 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { devicePath := filepath.Join(*sysPath, "class/nvme", device.Name) cntlid, err := readUintFromFile(filepath.Join(devicePath, "cntlid")) if err != nil { - level.Debug(c.logger).Log("msg", "failed to read cntlid", "device", device.Name, "err", err) + c.logger.Debug("failed to read cntlid", "device", device.Name, "err", err) } ch <- prometheus.MustNewConstMetric(c.info, prometheus.GaugeValue, infoValue, device.Name, device.FirmwareRevision, device.Model, device.Serial, device.State, strconv.FormatUint(cntlid, 10)) // Find namespace directories. namespacePaths, err := filepath.Glob(filepath.Join(devicePath, "nvme[0-9]*c[0-9]*n[0-9]*")) if err != nil { - level.Error(c.logger).Log("msg", "failed to list NVMe namespaces", "device", device.Name, "err", err) + c.logger.Error("failed to list NVMe namespaces", "device", device.Name, "err", err) continue } re := regexp.MustCompile(`nvme[0-9]+c[0-9]+n([0-9]+)`) @@ -138,15 +137,15 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { nsid := match[1] nuse, err := readUintFromFile(filepath.Join(namespacePath, "nuse")) if err != nil { - level.Debug(c.logger).Log("msg", "failed to read nuse", "device", device.Name, "namespace", match[0], "err", err) + c.logger.Debug("failed to read nuse", "device", device.Name, "namespace", match[0], "err", err) } nsze, err := readUintFromFile(filepath.Join(namespacePath, "size")) if err != nil { - level.Debug(c.logger).Log("msg", "failed to read size", "device", device.Name, "namespace", match[0], "err", err) + c.logger.Debug("failed to read size", "device", device.Name, "namespace", match[0], "err", err) } lbaSize, err := readUintFromFile(filepath.Join(namespacePath, "queue", "logical_block_size")) if err != nil { - level.Debug(c.logger).Log("msg", "failed to read queue/logical_block_size", "device", device.Name, "namespace", match[0], "err", err) + c.logger.Debug("failed to read queue/logical_block_size", "device", device.Name, "namespace", match[0], "err", err) } ncap := nsze * lbaSize anaState := "unknown" @@ -154,7 +153,7 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { if err == nil { anaState = strings.TrimSpace(string(anaStateSysfs)) } else { - level.Debug(c.logger).Log("msg", "failed to read ana_state", "device", device.Name, "namespace", match[0], "err", err) + c.logger.Debug("failed to read ana_state", "device", device.Name, "namespace", match[0], "err", err) } ch <- prometheus.MustNewConstMetric( @@ -201,4 +200,4 @@ func (c *nvmeCollector) Update(ch chan<- prometheus.Metric) error { } return nil -} \ No newline at end of file +}