Compare commits

..

No commits in common. "master" and "v1.9.0" have entirely different histories.

56 changed files with 282 additions and 4241 deletions

View file

@ -7,10 +7,10 @@ executors:
# should also be updated.
golang:
docker:
- image: cimg/go:1.24
- image: cimg/go:1.23
arm:
docker:
- image: cimg/go:1.24
- image: cimg/go:1.23
resource_class: arm.medium
jobs:
@ -42,7 +42,7 @@ jobs:
- run: git diff --exit-code
build:
machine:
image: ubuntu-2404:current
image: ubuntu-2204:current
parallelism: 3
steps:
- prometheus/setup_environment
@ -68,9 +68,9 @@ jobs:
destination: /build
test_docker:
machine:
image: ubuntu-2404:current
image: ubuntu-2204:current
environment:
DOCKER_TEST_IMAGE_NAME: quay.io/prometheus/golang-builder:1.24-base
DOCKER_TEST_IMAGE_NAME: quay.io/prometheus/golang-builder:1.23-base
REPO_PATH: github.com/prometheus/node_exporter
steps:
- prometheus/setup_environment

View file

@ -13,11 +13,11 @@ permissions:
env:
GNU_TAR_VERSION: "1.35"
GO_VERSION_DRAGONFLY: "1.24.1"
GO_VERSION_DRAGONFLY: "1.23.3"
GO_VERSION_FREEBSD: "123"
GO_VERSION_NETBSD: "1.24.1"
GO_VERSION_NETBSD: "1.23.3"
GO_VERSION_OPENBSD: "1.23.1"
GO_VERSION_SOLARIS: "1.24.1"
GO_VERSION_SOLARIS: "1.23.3"
# To spin up one of the VMs below, see the "Debug Shell" section here: https://github.com/vmactions
jobs:
@ -26,9 +26,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@v4
- name: test-e2e
uses: vmactions/freebsd-vm@8873d98fd1413b5977cb2f7348fe329775159892 # v1.1.9
uses: vmactions/freebsd-vm@v1
with:
copyback: false
envs: 'GO_VERSION_FREEBSD GNU_TAR_VERSION'
@ -73,9 +73,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@v4
- name: test-e2e
uses: vmactions/openbsd-vm@7ac70b6de6f33efc74a90c1964afa3bcf0ee4401 # v1.1.6
uses: vmactions/openbsd-vm@v1
with:
copyback: false
envs: 'GO_VERSION_OPENBSD GNU_TAR_VERSION'
@ -119,9 +119,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@v4
- name: test-e2e
uses: vmactions/netbsd-vm@46a58bbf03682b4cb24142b97fa315ae52bed573 # v1.1.8
uses: vmactions/netbsd-vm@v1
with:
copyback: false
envs: 'GO_VERSION_NETBSD GNU_TAR_VERSION'
@ -167,9 +167,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@v4
- name: test-e2e
uses: vmactions/dragonflybsd-vm@e3c420e8a2362c2496fca6e76a291abd46f5d8e7 # v1.1.0
uses: vmactions/dragonflybsd-vm@v1
with:
copyback: false
envs: 'GO_VERSION_DRAGONFLY'
@ -217,9 +217,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@v4
- name: test-e2e
uses: vmactions/solaris-vm@cc8f82fa1a7cc746153ec3f71bf11f311f16e225 # v1.1.1
uses: vmactions/solaris-vm@v1
with:
copyback: false
envs: 'GO_VERSION_SOLARIS'
@ -276,7 +276,7 @@ jobs:
runs-on: macos-latest
steps:
- name: Checkout the repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@v4
- name: Install dependencies
run: |
brew install \

View file

@ -26,14 +26,14 @@ jobs:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Install Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
with:
go-version: 1.24.x
go-version: 1.23.x
- name: Install snmp_exporter/generator dependencies
run: sudo apt-get update && sudo apt-get -y install libsnmp-dev
if: github.repository == 'prometheus/snmp_exporter'
- name: Lint
uses: golangci/golangci-lint-action@55c2c1448f86e01eaae002a5a3a9624417608d84 # v6.5.2
uses: golangci/golangci-lint-action@ec5d18412c0aeab7936cb16880d708ba2a64e1ae # v6.2.0
with:
args: --verbose
version: v1.64.6
version: v1.63.4

View file

@ -1,7 +1,7 @@
go:
# Whenever the Go version is updated here, .circle/config.yml and
# .promu.yml should also be updated.
version: 1.24
version: 1.23
cgo: true
repository:
path: github.com/prometheus/node_exporter

View file

@ -1,7 +1,7 @@
go:
# Whenever the Go version is updated here, .circle/config.yml and
# .promu-cgo.yml should also be updated.
version: 1.24
version: 1.23
repository:
path: github.com/prometheus/node_exporter
build:

View file

@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_
SKIP_GOLANGCI_LINT :=
GOLANGCI_LINT :=
GOLANGCI_LINT_OPTS ?=
GOLANGCI_LINT_VERSION ?= v1.64.6
GOLANGCI_LINT_VERSION ?= v1.63.4
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64.
# windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))

View file

@ -1,8 +1,7 @@
# Node exporter
[![CircleCI](https://circleci.com/gh/prometheus/node_exporter/tree/master.svg?style=shield)][circleci]
![bsd workflow](https://github.com/prometheus/node_exporter/actions/workflows/bsd.yml/badge.svg)
![golangci-lint workflow](https://github.com/prometheus/node_exporter/actions/workflows/golangci-lint.yml/badge.svg)
[![Buildkite status](https://badge.buildkite.com/94a0c1fb00b1f46883219c256efe9ce01d63b6505f3a942f9b.svg)](https://buildkite.com/prometheus/node-exporter)
[![Docker Repository on Quay](https://quay.io/repository/prometheus/node-exporter/status)][quay]
[![Docker Pulls](https://img.shields.io/docker/pulls/prom/node-exporter.svg?maxAge=604800)][hub]
[![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/node_exporter)][goreportcard]
@ -201,7 +200,6 @@ logind | Exposes session counts from [logind](http://www.freedesktop.org/wiki/So
meminfo\_numa | Exposes memory statistics from `/sys/devices/system/node/node[0-9]*/meminfo`, `/sys/devices/system/node/node[0-9]*/numastat`. | Linux
mountstats | Exposes filesystem statistics from `/proc/self/mountstats`. Exposes detailed NFS client statistics. | Linux
network_route | Exposes the routing table as metrics | Linux
pcidevice | Exposes pci devices' information including their link status and parent devices. | Linux
perf | Exposes perf based metrics (Warning: Metrics are dependent on kernel configuration and settings). | Linux
processes | Exposes aggregate process statistics from `/proc`. | Linux
qdisc | Exposes [queuing discipline](https://en.wikipedia.org/wiki/Network_scheduler#Linux_kernel) statistics | Linux

View file

@ -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.ReplaceAll(s.UUID, "-", "")
var fsUUID = strings.Replace(s.UUID, "-", "", -1)
ioctlStats := ioctlStatsMap[fsUUID]
c.updateBtrfsStats(ch, s, ioctlStats)
}

View file

@ -30,50 +30,22 @@ 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,
)
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
cpuContextSwitch typedDesc
logger *slog.Logger
tickPerSecond float64
purrTicksPerSecond float64
tickPerSecond int64
}
func init() {
registerCollector("cpu", defaultEnabled, NewCpuCollector)
}
func tickPerSecond() (float64, error) {
func tickPerSecond() (int64, 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 float64(ticks), nil
return int64(ticks), nil
}
func NewCpuCollector(logger *slog.Logger) (Collector, error) {
@ -81,22 +53,10 @@ 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,
purrTicksPerSecond: float64(pconfig.ProcessorMhz * 1e6),
}, nil
}
@ -107,26 +67,10 @@ 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.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))
// Flags
ch <- c.cpuFlags.mustNewConstMetric(float64(stat.SpurrFlag), strconv.Itoa(n), "spurr")
// Context switches
ch <- c.cpuContextSwitch.mustNewConstMetric(float64(stat.CSwitches), strconv.Itoa(n))
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")
}
return nil
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -22,12 +22,12 @@ import (
)
const (
cpuVulnerabilitiesCollectorSubsystem = "cpu_vulnerabilities"
cpuVulerabilitiesCollector = "cpu_vulnerabilities"
)
var (
vulnerabilityDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, cpuVulnerabilitiesCollectorSubsystem, "info"),
prometheus.BuildFQName(namespace, cpuVulerabilitiesCollector, "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(cpuVulnerabilitiesCollectorSubsystem, defaultDisabled, NewVulnerabilitySysfsCollector)
registerCollector(cpuVulerabilitiesCollector, defaultDisabled, NewVulnerabilitySysfsCollector)
}
func NewVulnerabilitySysfsCollector(logger *slog.Logger) (Collector, error) {

View file

@ -30,19 +30,11 @@ type diskstatsCollector struct {
rbytes typedDesc
wbytes typedDesc
time typedDesc
bsize typedDesc
qdepth typedDesc
rserv typedDesc
wserv typedDesc
xfers typedDesc
xrate typedDesc
deviceFilter deviceFilter
logger *slog.Logger
tickPerSecond float64
tickPerSecond int64
}
func init() {
@ -65,54 +57,6 @@ 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,
},
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,
@ -132,14 +76,7 @@ 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)/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.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)
ch <- c.time.mustNewConstMetric(float64(stat.Time/c.tickPerSecond), stat.Name)
}
return nil
}

View file

@ -398,9 +398,15 @@ func getUdevDeviceProperties(major, minor uint32) (udevInfo, error) {
line = strings.TrimPrefix(line, udevDevicePropertyPrefix)
/* TODO: After we drop support for Go 1.17, the condition below can be simplified to:
if name, value, found := strings.Cut(line, "="); found {
info[name] = value
}
*/
if fields := strings.SplitN(line, "=", 2); len(fields) == 2 {
info[fields[0]] = fields[1]
}
}
return info, nil

View file

@ -446,14 +446,13 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
}
}
if len(stats) == 0 {
if stats == nil || len(stats) < 1 {
// No stats returned; device does not support ethtool stats.
continue
}
// 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) {
@ -468,8 +467,6 @@ 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]
}
}
@ -487,7 +484,7 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
continue
}
val := renamedStats[metric]
val := stats[metric]
// Check to see if this metric exists; if not then create it and store it in c.entries.
entry := c.entryWithCreate(metric, metricFQName)

View file

@ -212,18 +212,16 @@ func (e *EthtoolFixture) LinkInfo(intf string) (ethtool.EthtoolCmd, error) {
items := strings.Split(line, ": ")
if items[0] == "Supported pause frame use" {
switch items[1] {
case "Symmetric":
if items[1] == "Symmetric" {
res.Supported |= (1 << unix.ETHTOOL_LINK_MODE_Pause_BIT)
case "Receive-only":
} else if items[1] == "Receive-only" {
res.Supported |= (1 << unix.ETHTOOL_LINK_MODE_Asym_Pause_BIT)
}
}
if items[0] == "Advertised pause frame use" {
switch items[1] {
case "Symmetric":
if items[1] == "Symmetric" {
res.Advertising |= (1 << unix.ETHTOOL_LINK_MODE_Pause_BIT)
case "Receive-only":
} else if items[1] == "Receive-only" {
res.Advertising |= (1 << unix.ETHTOOL_LINK_MODE_Asym_Pause_BIT)
}
}
@ -271,7 +269,6 @@ 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",
@ -295,9 +292,6 @@ 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

View file

@ -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,

View file

@ -89,7 +89,7 @@ type filesystemStats struct {
labels filesystemLabels
size, free, avail float64
files, filesFree float64
purgeable float64
purgeable *float64
ro, deviceError float64
}
@ -232,10 +232,11 @@ 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 >= 0 {
if s.purgeable != nil {
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,
)
}
}

View file

@ -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.ReplaceAll(parts[4], "\\040", " ")
parts[4] = strings.ReplaceAll(parts[4], "\\011", "\t")
parts[4] = strings.Replace(parts[4], "\\040", " ", -1)
parts[4] = strings.Replace(parts[4], "\\011", "\t", -1)
filesystems = append(filesystems, filesystemLabels{
device: parts[m+3],

View file

@ -20,26 +20,23 @@ package collector
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation
#import <Foundation/Foundation.h>
Float64 purgeable(char *path) {
Float64 value = -1.0f;
@autoreleasepool {
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) {
CFNumberRef tmp = CFDictionaryGetValue((CFDictionaryRef)results, NSURLVolumeAvailableCapacityForImportantUsageKey);
if (tmp != NULL) {
CFNumberGetValue(tmp, kCFNumberFloat64Type, &value);
}
}
[fileURL release];
}
if ((tmp = CFDictionaryGetValue((CFDictionaryRef)results, NSURLVolumeAvailableCapacityForImportantUsageKey)) == NULL)
return NULL;
value = (Float64 *)malloc(sizeof(Float64));
if (CFNumberGetValue(tmp, kCFNumberFloat64Type, value)) {
return value;
}
}
free(value);
return NULL;
}
*/
import "C"
@ -92,9 +89,6 @@ 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,
@ -106,7 +100,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(mountpointCString)),
purgeable: (*float64)(C.purgeable(C.CString(mountpoint))),
ro: ro,
})
}

View file

@ -1,8 +1,8 @@
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent.
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent
# TYPE go_gc_gogc_percent gauge
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes.
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes
# TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads.
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads
# TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
@ -1585,14 +1585,6 @@ node_md_blocks_synced{device="md6"} 1.6775552e+07
node_md_blocks_synced{device="md7"} 7.813735424e+09
node_md_blocks_synced{device="md8"} 1.6775552e+07
node_md_blocks_synced{device="md9"} 0
# HELP node_md_degraded Number of degraded disks on device.
# TYPE node_md_degraded gauge
node_md_degraded{device="md0"} 0
node_md_degraded{device="md1"} 0
node_md_degraded{device="md10"} 0
node_md_degraded{device="md4"} 0
node_md_degraded{device="md5"} 1
node_md_degraded{device="md6"} 1
# HELP node_md_disks Number of active/failed/spare disks of device.
# TYPE node_md_disks gauge
node_md_disks{device="md0",state="active"} 2
@ -1665,14 +1657,6 @@ node_md_disks_required{device="md6"} 2
node_md_disks_required{device="md7"} 4
node_md_disks_required{device="md8"} 2
node_md_disks_required{device="md9"} 4
# HELP node_md_raid_disks Number of raid disks on device.
# TYPE node_md_raid_disks gauge
node_md_raid_disks{device="md0"} 2
node_md_raid_disks{device="md1"} 2
node_md_raid_disks{device="md10"} 4
node_md_raid_disks{device="md4"} 3
node_md_raid_disks{device="md5"} 3
node_md_raid_disks{device="md6"} 4
# HELP node_md_state Indicates the state of md-device.
# TYPE node_md_state gauge
node_md_state{device="md0",state="active"} 1
@ -2832,26 +2816,6 @@ node_os_info{build_id="",id="ubuntu",id_like="debian",image_id="",image_version=
# HELP node_os_version Metric containing the major.minor part of the OS version.
# TYPE node_os_version gauge
node_os_version{id="ubuntu",id_like="debian",name="Ubuntu"} 20.04
# HELP node_pcidevice_current_link_transfers_per_second Value of current link's transfers per second (T/s)
# TYPE node_pcidevice_current_link_transfers_per_second gauge
node_pcidevice_current_link_transfers_per_second{bus="00",device="02",function="1",segment="0000"} 8e+09
node_pcidevice_current_link_transfers_per_second{bus="01",device="00",function="0",segment="0000"} 8e+09
# HELP node_pcidevice_current_link_width Value of current link's width (number of lanes)
# TYPE node_pcidevice_current_link_width gauge
node_pcidevice_current_link_width{bus="00",device="02",function="1",segment="0000"} 4
node_pcidevice_current_link_width{bus="01",device="00",function="0",segment="0000"} 4
# HELP node_pcidevice_info Non-numeric data from /sys/bus/pci/devices/<location>, value is always 1.
# TYPE node_pcidevice_info gauge
node_pcidevice_info{bus="00",class_id="0x060400",device="02",function="1",parent_bus="*",parent_device="*",parent_function="*",parent_segment="*",revision="0x00",segment="0000",subsystem_device_id="0x5095",subsystem_vendor_id="0x17aa",vendor_id="0x1634"} 1
node_pcidevice_info{bus="01",class_id="0x010802",device="00",function="0",parent_bus="00",parent_device="02",parent_function="1",parent_segment="0000",revision="0x01",segment="0000",subsystem_device_id="0x5021",subsystem_vendor_id="0xc0a9",vendor_id="0x540a"} 1
# HELP node_pcidevice_max_link_transfers_per_second Value of maximum link's transfers per second (T/s)
# TYPE node_pcidevice_max_link_transfers_per_second gauge
node_pcidevice_max_link_transfers_per_second{bus="00",device="02",function="1",segment="0000"} 8e+09
node_pcidevice_max_link_transfers_per_second{bus="01",device="00",function="0",segment="0000"} 1.6e+10
# HELP node_pcidevice_max_link_width Value of maximum link's width (number of lanes)
# TYPE node_pcidevice_max_link_width gauge
node_pcidevice_max_link_width{bus="00",device="02",function="1",segment="0000"} 8
node_pcidevice_max_link_width{bus="01",device="00",function="0",segment="0000"} 4
# HELP node_power_supply_capacity capacity value of /sys/class/power_supply/<power_supply>.
# TYPE node_power_supply_capacity gauge
node_power_supply_capacity{power_supply="BAT0"} 81
@ -3011,7 +2975,6 @@ node_scrape_collector_success{collector="nfs"} 1
node_scrape_collector_success{collector="nfsd"} 1
node_scrape_collector_success{collector="nvme"} 1
node_scrape_collector_success{collector="os"} 1
node_scrape_collector_success{collector="pcidevice"} 1
node_scrape_collector_success{collector="powersupplyclass"} 1
node_scrape_collector_success{collector="pressure"} 1
node_scrape_collector_success{collector="processes"} 1

View file

@ -1,8 +1,8 @@
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent.
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent
# TYPE go_gc_gogc_percent gauge
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes.
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes
# TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads.
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads
# TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
@ -251,20 +251,6 @@ node_xfrm_out_state_proto_error_packets_total 4542
# HELP node_xfrm_out_state_seq_error_packets_total Sequence error i.e. Sequence number overflow
# TYPE node_xfrm_out_state_seq_error_packets_total counter
node_xfrm_out_state_seq_error_packets_total 543
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
# HELP process_virtual_memory_max_bytes Maximum amount of virtual memory available in bytes.
# TYPE process_virtual_memory_max_bytes gauge
# HELP promhttp_metric_handler_errors_total Total number of internal errors encountered by the promhttp metric handler.
# TYPE promhttp_metric_handler_errors_total counter
promhttp_metric_handler_errors_total{cause="encoding"} 0

View file

@ -1,8 +1,8 @@
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent.
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent
# TYPE go_gc_gogc_percent gauge
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes.
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes
# TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads.
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads
# TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge

View file

@ -1,8 +1,8 @@
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent.
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent
# TYPE go_gc_gogc_percent gauge
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes.
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes
# TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads.
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads
# TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge

View file

@ -1,8 +1,8 @@
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent.
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent
# TYPE go_gc_gogc_percent gauge
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes.
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes
# TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads.
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads
# TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge

View file

@ -1,8 +1,8 @@
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent.
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent
# TYPE go_gc_gogc_percent gauge
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes.
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes
# TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads.
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads
# TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge

View file

@ -1,8 +1,8 @@
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent.
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent
# TYPE go_gc_gogc_percent gauge
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes.
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes
# TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads.
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads
# TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
@ -91,6 +91,12 @@ node_buddyinfo_blocks{node="0",size="8",zone="Normal"} 0
node_buddyinfo_blocks{node="0",size="9",zone="DMA"} 1
node_buddyinfo_blocks{node="0",size="9",zone="DMA32"} 0
node_buddyinfo_blocks{node="0",size="9",zone="Normal"} 0
# HELP node_cpu_frequency_max_hertz Maximum CPU thread frequency in hertz.
# TYPE node_cpu_frequency_max_hertz gauge
node_cpu_frequency_max_hertz{cpu="0"} 2.445e+09
node_cpu_frequency_max_hertz{cpu="1"} 2.445e+09
node_cpu_frequency_max_hertz{cpu="2"} 2.445e+09
node_cpu_frequency_max_hertz{cpu="3"} 2.445e+09
# HELP node_exporter_build_info A metric with a constant '1' value labeled by version, revision, branch, goversion from which node_exporter was built, and the goos and goarch for the build.
# TYPE node_exporter_build_info gauge
# 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.

View file

@ -1,8 +1,8 @@
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent.
# HELP go_gc_gogc_percent Heap size target percentage configured by the user, otherwise 100. This value is set by the GOGC environment variable, and the runtime/debug.SetGCPercent function. Sourced from /gc/gogc:percent
# TYPE go_gc_gogc_percent gauge
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes.
# HELP go_gc_gomemlimit_bytes Go runtime memory limit configured by the user, otherwise math.MaxInt64. This value is set by the GOMEMLIMIT environment variable, and the runtime/debug.SetMemoryLimit function. Sourced from /gc/gomemlimit:bytes
# TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads.
# HELP go_sched_gomaxprocs_threads The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously. Sourced from /sched/gomaxprocs:threads
# TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
@ -1607,14 +1607,6 @@ node_md_blocks_synced{device="md6"} 1.6775552e+07
node_md_blocks_synced{device="md7"} 7.813735424e+09
node_md_blocks_synced{device="md8"} 1.6775552e+07
node_md_blocks_synced{device="md9"} 0
# HELP node_md_degraded Number of degraded disks on device.
# TYPE node_md_degraded gauge
node_md_degraded{device="md0"} 0
node_md_degraded{device="md1"} 0
node_md_degraded{device="md10"} 0
node_md_degraded{device="md4"} 0
node_md_degraded{device="md5"} 1
node_md_degraded{device="md6"} 1
# HELP node_md_disks Number of active/failed/spare disks of device.
# TYPE node_md_disks gauge
node_md_disks{device="md0",state="active"} 2
@ -1687,14 +1679,6 @@ node_md_disks_required{device="md6"} 2
node_md_disks_required{device="md7"} 4
node_md_disks_required{device="md8"} 2
node_md_disks_required{device="md9"} 4
# HELP node_md_raid_disks Number of raid disks on device.
# TYPE node_md_raid_disks gauge
node_md_raid_disks{device="md0"} 2
node_md_raid_disks{device="md1"} 2
node_md_raid_disks{device="md10"} 4
node_md_raid_disks{device="md4"} 3
node_md_raid_disks{device="md5"} 3
node_md_raid_disks{device="md6"} 4
# HELP node_md_state Indicates the state of md-device.
# TYPE node_md_state gauge
node_md_state{device="md0",state="active"} 1
@ -2854,26 +2838,6 @@ node_os_info{build_id="",id="ubuntu",id_like="debian",image_id="",image_version=
# HELP node_os_version Metric containing the major.minor part of the OS version.
# TYPE node_os_version gauge
node_os_version{id="ubuntu",id_like="debian",name="Ubuntu"} 20.04
# HELP node_pcidevice_current_link_transfers_per_second Value of current link's transfers per second (T/s)
# TYPE node_pcidevice_current_link_transfers_per_second gauge
node_pcidevice_current_link_transfers_per_second{bus="00",device="02",function="1",segment="0000"} 8e+09
node_pcidevice_current_link_transfers_per_second{bus="01",device="00",function="0",segment="0000"} 8e+09
# HELP node_pcidevice_current_link_width Value of current link's width (number of lanes)
# TYPE node_pcidevice_current_link_width gauge
node_pcidevice_current_link_width{bus="00",device="02",function="1",segment="0000"} 4
node_pcidevice_current_link_width{bus="01",device="00",function="0",segment="0000"} 4
# HELP node_pcidevice_info Non-numeric data from /sys/bus/pci/devices/<location>, value is always 1.
# TYPE node_pcidevice_info gauge
node_pcidevice_info{bus="00",class_id="0x060400",device="02",function="1",parent_bus="*",parent_device="*",parent_function="*",parent_segment="*",revision="0x00",segment="0000",subsystem_device_id="0x5095",subsystem_vendor_id="0x17aa",vendor_id="0x1634"} 1
node_pcidevice_info{bus="01",class_id="0x010802",device="00",function="0",parent_bus="00",parent_device="02",parent_function="1",parent_segment="0000",revision="0x01",segment="0000",subsystem_device_id="0x5021",subsystem_vendor_id="0xc0a9",vendor_id="0x540a"} 1
# HELP node_pcidevice_max_link_transfers_per_second Value of maximum link's transfers per second (T/s)
# TYPE node_pcidevice_max_link_transfers_per_second gauge
node_pcidevice_max_link_transfers_per_second{bus="00",device="02",function="1",segment="0000"} 8e+09
node_pcidevice_max_link_transfers_per_second{bus="01",device="00",function="0",segment="0000"} 1.6e+10
# HELP node_pcidevice_max_link_width Value of maximum link's width (number of lanes)
# TYPE node_pcidevice_max_link_width gauge
node_pcidevice_max_link_width{bus="00",device="02",function="1",segment="0000"} 8
node_pcidevice_max_link_width{bus="01",device="00",function="0",segment="0000"} 4
# HELP node_power_supply_capacity capacity value of /sys/class/power_supply/<power_supply>.
# TYPE node_power_supply_capacity gauge
node_power_supply_capacity{power_supply="BAT0"} 81
@ -3033,7 +2997,6 @@ node_scrape_collector_success{collector="nfs"} 1
node_scrape_collector_success{collector="nfsd"} 1
node_scrape_collector_success{collector="nvme"} 1
node_scrape_collector_success{collector="os"} 1
node_scrape_collector_success{collector="pcidevice"} 1
node_scrape_collector_success{collector="powersupplyclass"} 1
node_scrape_collector_success{collector="pressure"} 1
node_scrape_collector_success{collector="processes"} 1

View file

@ -4,7 +4,6 @@ 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

View file

@ -2,4 +2,4 @@ net 70 70 69 45
rpc 1218785755 374636 1218815394
proc2 18 16 57 74 52 71 73 45 86 0 52 83 61 17 53 50 23 70 82
proc3 22 0 1061909262 48906 4077635 117661341 5 29391916 2570425 2993289 590 0 0 7815 15 1130 0 3983 92385 13332 2 1 23729
proc4 48 98 51 54 83 85 23 24 1 28 73 68 83 12 84 39 68 59 58 88 29 74 69 96 21 84 15 53 86 54 66 56 97 36 49 32 85 81 11 58 32 67 13 28 35 1 90 26 0
proc4 48 98 51 54 83 85 23 24 1 28 73 68 83 12 84 39 68 59 58 88 29 74 69 96 21 84 15 53 86 54 66 56 97 36 49 32 85 81 11 58 32 67 13 28 35 90 1 26 0

File diff suppressed because it is too large Load diff

View file

@ -21,8 +21,6 @@ import (
"strconv"
"unsafe"
"github.com/prometheus/node_exporter/collector/utils"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/unix"
)
@ -51,7 +49,7 @@ func intr(idx _C_int) (itr interrupt, err error) {
return
}
dev := *(*[128]byte)(unsafe.Pointer(&buf[0]))
itr.device = utils.SafeBytesToString(dev[:])
itr.device = string(dev[:])
mib[2] = KERN_INTRCNT_VECTOR
buf, err = sysctl(mib[:])

View file

@ -22,8 +22,6 @@ import (
"log/slog"
"os"
"github.com/prometheus/procfs/sysfs"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs"
)
@ -100,30 +98,17 @@ var (
[]string{"device"},
nil,
)
mdraidDisks = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "md", "raid_disks"),
"Number of raid disks on device.",
[]string{"device"},
nil,
)
mdraidDegradedDisksDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "md", "degraded"),
"Number of degraded disks on device.",
[]string{"device"},
nil,
)
)
func (c *mdadmCollector) Update(ch chan<- prometheus.Metric) error {
procFS, err := procfs.NewFS(*procPath)
fs, err := procfs.NewFS(*procPath)
if err != nil {
return fmt.Errorf("failed to open procfs: %w", err)
}
mdStats, err := procFS.MDStat()
mdStats, err := fs.MDStat()
if err != nil {
if errors.Is(err, os.ErrNotExist) {
c.logger.Debug("Not collecting mdstat, file does not exist", "file", *procPath)
@ -216,34 +201,5 @@ func (c *mdadmCollector) Update(ch chan<- prometheus.Metric) error {
)
}
sysFS, err := sysfs.NewFS(*sysPath)
if err != nil {
return fmt.Errorf("failed to open sysfs: %w", err)
}
mdraids, err := sysFS.Mdraids()
if err != nil {
if errors.Is(err, os.ErrNotExist) {
c.logger.Debug("Not collecting mdraids, file does not exist", "file", *sysPath)
return ErrNoData
}
return fmt.Errorf("error parsing mdraids: %w", err)
}
for _, mdraid := range mdraids {
ch <- prometheus.MustNewConstMetric(
mdraidDisks,
prometheus.GaugeValue,
float64(mdraid.Disks),
mdraid.Device,
)
ch <- prometheus.MustNewConstMetric(
mdraidDegradedDisksDesc,
prometheus.GaugeValue,
float64(mdraid.DegradedDisks),
mdraid.Device,
)
}
return nil
}

View file

@ -1,294 +0,0 @@
// Copyright 2024 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 !nomdadm
// +build !nomdadm
package collector
import (
"log/slog"
"os"
"strings"
"testing"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
)
type testMdadmCollector struct {
mc Collector
}
func (c testMdadmCollector) Collect(ch chan<- prometheus.Metric) {
c.mc.Update(ch)
}
func (c testMdadmCollector) Describe(ch chan<- *prometheus.Desc) {
prometheus.DescribeByCollect(c, ch)
}
func NewTestMdadmCollector(logger *slog.Logger) (prometheus.Collector, error) {
mc, err := NewMdadmCollector(logger)
if err != nil {
return testMdadmCollector{}, err
}
return &testMdadmCollector{mc}, nil
}
func TestMdadmStats(t *testing.T) {
*sysPath = "fixtures/sys"
*procPath = "fixtures/proc"
testcase := `# HELP node_md_blocks Total number of blocks on device.
# TYPE node_md_blocks gauge
node_md_blocks{device="md0"} 248896
node_md_blocks{device="md00"} 4.186624e+06
node_md_blocks{device="md10"} 3.14159265e+08
node_md_blocks{device="md101"} 322560
node_md_blocks{device="md11"} 4.190208e+06
node_md_blocks{device="md12"} 3.886394368e+09
node_md_blocks{device="md120"} 2.095104e+06
node_md_blocks{device="md126"} 1.855870976e+09
node_md_blocks{device="md127"} 3.12319552e+08
node_md_blocks{device="md201"} 1.993728e+06
node_md_blocks{device="md219"} 7932
node_md_blocks{device="md3"} 5.853468288e+09
node_md_blocks{device="md4"} 4.883648e+06
node_md_blocks{device="md6"} 1.95310144e+08
node_md_blocks{device="md7"} 7.813735424e+09
node_md_blocks{device="md8"} 1.95310144e+08
node_md_blocks{device="md9"} 523968
# HELP node_md_blocks_synced Number of blocks synced on device.
# TYPE node_md_blocks_synced gauge
node_md_blocks_synced{device="md0"} 248896
node_md_blocks_synced{device="md00"} 4.186624e+06
node_md_blocks_synced{device="md10"} 3.14159265e+08
node_md_blocks_synced{device="md101"} 322560
node_md_blocks_synced{device="md11"} 0
node_md_blocks_synced{device="md12"} 3.886394368e+09
node_md_blocks_synced{device="md120"} 2.095104e+06
node_md_blocks_synced{device="md126"} 1.855870976e+09
node_md_blocks_synced{device="md127"} 3.12319552e+08
node_md_blocks_synced{device="md201"} 114176
node_md_blocks_synced{device="md219"} 7932
node_md_blocks_synced{device="md3"} 5.853468288e+09
node_md_blocks_synced{device="md4"} 4.883648e+06
node_md_blocks_synced{device="md6"} 1.6775552e+07
node_md_blocks_synced{device="md7"} 7.813735424e+09
node_md_blocks_synced{device="md8"} 1.6775552e+07
node_md_blocks_synced{device="md9"} 0
# HELP node_md_degraded Number of degraded disks on device.
# TYPE node_md_degraded gauge
node_md_degraded{device="md0"} 0
node_md_degraded{device="md1"} 0
node_md_degraded{device="md10"} 0
node_md_degraded{device="md4"} 0
node_md_degraded{device="md5"} 1
node_md_degraded{device="md6"} 1
# HELP node_md_disks Number of active/failed/spare disks of device.
# TYPE node_md_disks gauge
node_md_disks{device="md0",state="active"} 2
node_md_disks{device="md0",state="failed"} 0
node_md_disks{device="md0",state="spare"} 0
node_md_disks{device="md00",state="active"} 1
node_md_disks{device="md00",state="failed"} 0
node_md_disks{device="md00",state="spare"} 0
node_md_disks{device="md10",state="active"} 2
node_md_disks{device="md10",state="failed"} 0
node_md_disks{device="md10",state="spare"} 0
node_md_disks{device="md101",state="active"} 3
node_md_disks{device="md101",state="failed"} 0
node_md_disks{device="md101",state="spare"} 0
node_md_disks{device="md11",state="active"} 2
node_md_disks{device="md11",state="failed"} 1
node_md_disks{device="md11",state="spare"} 2
node_md_disks{device="md12",state="active"} 2
node_md_disks{device="md12",state="failed"} 0
node_md_disks{device="md12",state="spare"} 0
node_md_disks{device="md120",state="active"} 2
node_md_disks{device="md120",state="failed"} 0
node_md_disks{device="md120",state="spare"} 0
node_md_disks{device="md126",state="active"} 2
node_md_disks{device="md126",state="failed"} 0
node_md_disks{device="md126",state="spare"} 0
node_md_disks{device="md127",state="active"} 2
node_md_disks{device="md127",state="failed"} 0
node_md_disks{device="md127",state="spare"} 0
node_md_disks{device="md201",state="active"} 2
node_md_disks{device="md201",state="failed"} 0
node_md_disks{device="md201",state="spare"} 0
node_md_disks{device="md219",state="active"} 0
node_md_disks{device="md219",state="failed"} 0
node_md_disks{device="md219",state="spare"} 3
node_md_disks{device="md3",state="active"} 8
node_md_disks{device="md3",state="failed"} 0
node_md_disks{device="md3",state="spare"} 2
node_md_disks{device="md4",state="active"} 0
node_md_disks{device="md4",state="failed"} 1
node_md_disks{device="md4",state="spare"} 1
node_md_disks{device="md6",state="active"} 1
node_md_disks{device="md6",state="failed"} 1
node_md_disks{device="md6",state="spare"} 1
node_md_disks{device="md7",state="active"} 3
node_md_disks{device="md7",state="failed"} 1
node_md_disks{device="md7",state="spare"} 0
node_md_disks{device="md8",state="active"} 2
node_md_disks{device="md8",state="failed"} 0
node_md_disks{device="md8",state="spare"} 2
node_md_disks{device="md9",state="active"} 4
node_md_disks{device="md9",state="failed"} 2
node_md_disks{device="md9",state="spare"} 1
# HELP node_md_disks_required Total number of disks of device.
# TYPE node_md_disks_required gauge
node_md_disks_required{device="md0"} 2
node_md_disks_required{device="md00"} 1
node_md_disks_required{device="md10"} 2
node_md_disks_required{device="md101"} 3
node_md_disks_required{device="md11"} 2
node_md_disks_required{device="md12"} 2
node_md_disks_required{device="md120"} 2
node_md_disks_required{device="md126"} 2
node_md_disks_required{device="md127"} 2
node_md_disks_required{device="md201"} 2
node_md_disks_required{device="md219"} 0
node_md_disks_required{device="md3"} 8
node_md_disks_required{device="md4"} 0
node_md_disks_required{device="md6"} 2
node_md_disks_required{device="md7"} 4
node_md_disks_required{device="md8"} 2
node_md_disks_required{device="md9"} 4
# HELP node_md_raid_disks Number of raid disks on device.
# TYPE node_md_raid_disks gauge
node_md_raid_disks{device="md0"} 2
node_md_raid_disks{device="md1"} 2
node_md_raid_disks{device="md10"} 4
node_md_raid_disks{device="md4"} 3
node_md_raid_disks{device="md5"} 3
node_md_raid_disks{device="md6"} 4
# HELP node_md_state Indicates the state of md-device.
# TYPE node_md_state gauge
node_md_state{device="md0",state="active"} 1
node_md_state{device="md0",state="check"} 0
node_md_state{device="md0",state="inactive"} 0
node_md_state{device="md0",state="recovering"} 0
node_md_state{device="md0",state="resync"} 0
node_md_state{device="md00",state="active"} 1
node_md_state{device="md00",state="check"} 0
node_md_state{device="md00",state="inactive"} 0
node_md_state{device="md00",state="recovering"} 0
node_md_state{device="md00",state="resync"} 0
node_md_state{device="md10",state="active"} 1
node_md_state{device="md10",state="check"} 0
node_md_state{device="md10",state="inactive"} 0
node_md_state{device="md10",state="recovering"} 0
node_md_state{device="md10",state="resync"} 0
node_md_state{device="md101",state="active"} 1
node_md_state{device="md101",state="check"} 0
node_md_state{device="md101",state="inactive"} 0
node_md_state{device="md101",state="recovering"} 0
node_md_state{device="md101",state="resync"} 0
node_md_state{device="md11",state="active"} 0
node_md_state{device="md11",state="check"} 0
node_md_state{device="md11",state="inactive"} 0
node_md_state{device="md11",state="recovering"} 0
node_md_state{device="md11",state="resync"} 1
node_md_state{device="md12",state="active"} 1
node_md_state{device="md12",state="check"} 0
node_md_state{device="md12",state="inactive"} 0
node_md_state{device="md12",state="recovering"} 0
node_md_state{device="md12",state="resync"} 0
node_md_state{device="md120",state="active"} 1
node_md_state{device="md120",state="check"} 0
node_md_state{device="md120",state="inactive"} 0
node_md_state{device="md120",state="recovering"} 0
node_md_state{device="md120",state="resync"} 0
node_md_state{device="md126",state="active"} 1
node_md_state{device="md126",state="check"} 0
node_md_state{device="md126",state="inactive"} 0
node_md_state{device="md126",state="recovering"} 0
node_md_state{device="md126",state="resync"} 0
node_md_state{device="md127",state="active"} 1
node_md_state{device="md127",state="check"} 0
node_md_state{device="md127",state="inactive"} 0
node_md_state{device="md127",state="recovering"} 0
node_md_state{device="md127",state="resync"} 0
node_md_state{device="md201",state="active"} 0
node_md_state{device="md201",state="check"} 1
node_md_state{device="md201",state="inactive"} 0
node_md_state{device="md201",state="recovering"} 0
node_md_state{device="md201",state="resync"} 0
node_md_state{device="md219",state="active"} 0
node_md_state{device="md219",state="check"} 0
node_md_state{device="md219",state="inactive"} 1
node_md_state{device="md219",state="recovering"} 0
node_md_state{device="md219",state="resync"} 0
node_md_state{device="md3",state="active"} 1
node_md_state{device="md3",state="check"} 0
node_md_state{device="md3",state="inactive"} 0
node_md_state{device="md3",state="recovering"} 0
node_md_state{device="md3",state="resync"} 0
node_md_state{device="md4",state="active"} 0
node_md_state{device="md4",state="check"} 0
node_md_state{device="md4",state="inactive"} 1
node_md_state{device="md4",state="recovering"} 0
node_md_state{device="md4",state="resync"} 0
node_md_state{device="md6",state="active"} 0
node_md_state{device="md6",state="check"} 0
node_md_state{device="md6",state="inactive"} 0
node_md_state{device="md6",state="recovering"} 1
node_md_state{device="md6",state="resync"} 0
node_md_state{device="md7",state="active"} 1
node_md_state{device="md7",state="check"} 0
node_md_state{device="md7",state="inactive"} 0
node_md_state{device="md7",state="recovering"} 0
node_md_state{device="md7",state="resync"} 0
node_md_state{device="md8",state="active"} 0
node_md_state{device="md8",state="check"} 0
node_md_state{device="md8",state="inactive"} 0
node_md_state{device="md8",state="recovering"} 0
node_md_state{device="md8",state="resync"} 1
node_md_state{device="md9",state="active"} 0
node_md_state{device="md9",state="check"} 0
node_md_state{device="md9",state="inactive"} 0
node_md_state{device="md9",state="recovering"} 0
node_md_state{device="md9",state="resync"} 1
`
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
Level: slog.LevelError,
AddSource: true,
}))
collector, err := NewMdadmCollector(logger)
if err != nil {
panic(err)
}
c, err := NewTestMdadmCollector(logger)
if err != nil {
t.Fatal(err)
}
reg := prometheus.NewRegistry()
reg.MustRegister(c)
sink := make(chan prometheus.Metric)
go func() {
err := collector.Update(sink)
if err != nil {
panic(err)
}
close(sink)
}()
err = testutil.GatherAndCompare(reg, strings.NewReader(testcase))
if err != nil {
t.Fatal(err)
}
}

View file

@ -43,9 +43,5 @@ func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {
"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
}

View file

@ -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: %w", err)
return nil, fmt.Errorf("Failed to get memory info: %s", err)
}
metrics := make(map[string]float64)

View file

@ -32,20 +32,16 @@ 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),
"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),
"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),
}
}

View file

@ -22,7 +22,6 @@ import (
"fmt"
"log/slog"
"net"
"unsafe"
"golang.org/x/sys/unix"
)
@ -72,107 +71,51 @@ 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, theres 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 // 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
Msglen uint16
Version uint8
Type uint8
Addrs int32
Flags int32
Index uint16
_ [2]byte
SndLen int32
SndMaxlen int32
SndDrops int32
Timer int32
Data ifData64
}
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if_var.h#L207-L235
// https://github.com/apple/darwin-xnu/blob/main/bsd/net/if_var.h#L199-L231
type ifData64 struct {
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
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
}
func getNetDevLabels() (map[string]map[string]string, error) {

View file

@ -1,86 +0,0 @@
// 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
}

View file

@ -1,118 +0,0 @@
// 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
}

View file

@ -1,143 +0,0 @@
// Copyright 2017-2019 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 !nopcidevice
// +build !nopcidevice
package collector
import (
"errors"
"fmt"
"log/slog"
"os"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs/sysfs"
)
const (
pcideviceSubsystem = "pcidevice"
)
var (
pcideviceLabelNames = []string{"segment", "bus", "device", "function"}
pcideviceMaxLinkTSDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, pcideviceSubsystem, "max_link_transfers_per_second"),
"Value of maximum link's transfers per second (T/s)",
pcideviceLabelNames, nil,
)
pcideviceMaxLinkWidthDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, pcideviceSubsystem, "max_link_width"),
"Value of maximum link's width (number of lanes)",
pcideviceLabelNames, nil,
)
pcideviceCurrentLinkTSDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, pcideviceSubsystem, "current_link_transfers_per_second"),
"Value of current link's transfers per second (T/s)",
pcideviceLabelNames, nil,
)
pcideviceCurrentLinkWidthDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, pcideviceSubsystem, "current_link_width"),
"Value of current link's width (number of lanes)",
pcideviceLabelNames, nil,
)
)
type pcideviceCollector struct {
fs sysfs.FS
infoDesc typedDesc
descs []typedFactorDesc
logger *slog.Logger
}
func init() {
registerCollector("pcidevice", defaultDisabled, NewPcideviceCollector)
}
// NewPcideviceCollector returns a new Collector exposing PCI devices stats.
func NewPcideviceCollector(logger *slog.Logger) (Collector, error) {
fs, err := sysfs.NewFS(*sysPath)
if err != nil {
return nil, fmt.Errorf("failed to open sysfs: %w", err)
}
c := pcideviceCollector{
fs: fs,
logger: logger,
infoDesc: typedDesc{
desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, pcideviceSubsystem, "info"),
"Non-numeric data from /sys/bus/pci/devices/<location>, value is always 1.",
append(pcideviceLabelNames,
[]string{"parent_segment", "parent_bus", "parent_device", "parent_function",
"class_id", "vendor_id", "subsystem_vendor_id", "subsystem_device_id", "revision"}...),
nil,
),
valueType: prometheus.GaugeValue,
},
descs: []typedFactorDesc{
{desc: pcideviceMaxLinkTSDesc, valueType: prometheus.GaugeValue},
{desc: pcideviceMaxLinkWidthDesc, valueType: prometheus.GaugeValue},
{desc: pcideviceCurrentLinkTSDesc, valueType: prometheus.GaugeValue},
{desc: pcideviceCurrentLinkWidthDesc, valueType: prometheus.GaugeValue},
},
}
return &c, nil
}
func (c *pcideviceCollector) Update(ch chan<- prometheus.Metric) error {
devices, err := c.fs.PciDevices()
if err != nil {
if errors.Is(err, os.ErrNotExist) {
c.logger.Debug("PCI device not found, skipping")
return ErrNoData
}
return fmt.Errorf("error obtaining PCI device info: %w", err)
}
for _, device := range devices {
// The device location is represented in separated format.
values := device.Location.Strings()
if device.ParentLocation != nil {
values = append(values, device.ParentLocation.Strings()...)
} else {
values = append(values, []string{"*", "*", "*", "*"}...)
}
values = append(values, fmt.Sprintf("0x%06x", device.Class))
values = append(values, fmt.Sprintf("0x%04x", device.Device))
values = append(values, fmt.Sprintf("0x%04x", device.SubsystemVendor))
values = append(values, fmt.Sprintf("0x%04x", device.SubsystemDevice))
values = append(values, fmt.Sprintf("0x%02x", device.Revision))
ch <- c.infoDesc.mustNewConstMetric(1.0, values...)
// MaxLinkSpeed and CurrentLinkSpeed are represnted in GT/s
maxLinkSpeedTS := float64(int64(*device.MaxLinkSpeed * 1e9))
currentLinkSpeedTS := float64(int64(*device.CurrentLinkSpeed * 1e9))
for i, val := range []float64{
maxLinkSpeedTS,
float64(*device.MaxLinkWidth),
currentLinkSpeedTS,
float64(*device.CurrentLinkWidth),
} {
ch <- c.descs[i].mustNewConstMetric(val, device.Location.Strings()...)
}
}
return nil
}

View file

@ -33,7 +33,7 @@ func canTestPerf(t *testing.T) {
if err != nil {
t.Skip("Procfs not mounted, skipping perf tests")
}
paranoidStr := strings.ReplaceAll(string(paranoidBytes), "\n", "")
paranoidStr := strings.Replace(string(paranoidBytes), "\n", "", -1)
paranoid, err := strconv.Atoi(paranoidStr)
if err != nil {
t.Fatalf("Expected perf_event_paranoid to be an int, got: %s", paranoidStr)

View file

@ -27,15 +27,8 @@ import (
"github.com/prometheus/procfs"
)
const (
psiResourceCPU = "cpu"
psiResourceIO = "io"
psiResourceMemory = "memory"
psiResourceIRQ = "irq"
)
var (
psiResources = []string{psiResourceCPU, psiResourceIO, psiResourceMemory, psiResourceIRQ}
psiResources = []string{"cpu", "io", "memory", "irq"}
)
type pressureStatsCollector struct {
@ -100,18 +93,13 @@ 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) && 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, 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, syscall.ENOTSUP) {
c.logger.Debug("pressure information is disabled, add psi=1 kernel command line to enable it")
@ -121,35 +109,28 @@ 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 != psiResourceIRQ {
if vals.Some == nil && res != "irq" {
c.logger.Debug("pressure information returned no 'some' data")
return ErrNoData
}
if vals.Full == nil && res != psiResourceCPU {
if vals.Full == nil && res != "cpu" {
c.logger.Debug("pressure information returned no 'full' data")
return ErrNoData
}
switch res {
case psiResourceCPU:
case "cpu":
ch <- prometheus.MustNewConstMetric(c.cpu, prometheus.CounterValue, float64(vals.Some.Total)/1000.0/1000.0)
case psiResourceIO:
case "io":
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 psiResourceMemory:
case "memory":
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 psiResourceIRQ:
case "irq":
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

View file

@ -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 allowed: %w", err)
return fmt.Errorf("unable to retrieve limit number of maximum pids alloved: %w", err)
}
ch <- prometheus.MustNewConstMetric(c.pidUsed, prometheus.GaugeValue, float64(pids))
ch <- prometheus.MustNewConstMetric(c.pidMax, prometheus.GaugeValue, float64(pidM))

View file

@ -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 allowed %v\n", err)
t.Fatalf("Unable to retrieve limit number of maximum pids alloved %v\n", err)
}
if uint64(pids) > maxPid || pids == 0 {
t.Fatalf("Total running pids cannot be greater than %d or equals to 0", maxPid)

View file

@ -74,7 +74,6 @@ type systemdCollector struct {
socketCurrentConnectionsDesc *prometheus.Desc
socketRefusedConnectionsDesc *prometheus.Desc
systemdVersionDesc *prometheus.Desc
virtualizationDesc *prometheus.Desc
// Use regexps for more flexibility than device_filter.go allows
systemdUnitIncludePattern *regexp.Regexp
systemdUnitExcludePattern *regexp.Regexp
@ -133,9 +132,6 @@ func NewSystemdCollector(logger *slog.Logger) (Collector, error) {
systemdVersionDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "version"),
"Detected systemd version", []string{"version"}, nil)
virtualizationDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "virtualization_info"),
"Detected virtualization technology", []string{"virtualization_type"}, nil)
if *oldSystemdUnitExclude != "" {
if !systemdUnitExcludeSet {
@ -171,7 +167,6 @@ func NewSystemdCollector(logger *slog.Logger) (Collector, error) {
socketCurrentConnectionsDesc: socketCurrentConnectionsDesc,
socketRefusedConnectionsDesc: socketRefusedConnectionsDesc,
systemdVersionDesc: systemdVersionDesc,
virtualizationDesc: virtualizationDesc,
systemdUnitIncludePattern: systemdUnitIncludePattern,
systemdUnitExcludePattern: systemdUnitExcludePattern,
logger: logger,
@ -199,14 +194,6 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error {
systemdVersionFull,
)
systemdVirtualization := c.getSystemdVirtualization(conn)
ch <- prometheus.MustNewConstMetric(
c.virtualizationDesc,
prometheus.GaugeValue,
1.0,
systemdVirtualization,
)
allUnits, err := c.getAllUnits(conn)
if err != nil {
return fmt.Errorf("couldn't get units: %w", err)
@ -228,7 +215,7 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error {
wg.Add(1)
go func() {
defer wg.Done()
begin := time.Now()
begin = time.Now()
c.collectUnitStatusMetrics(conn, ch, units)
c.logger.Debug("collectUnitStatusMetrics took", "duration_seconds", time.Since(begin).Seconds())
}()
@ -237,7 +224,7 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error {
wg.Add(1)
go func() {
defer wg.Done()
begin := time.Now()
begin = time.Now()
c.collectUnitStartTimeMetrics(conn, ch, units)
c.logger.Debug("collectUnitStartTimeMetrics took", "duration_seconds", time.Since(begin).Seconds())
}()
@ -247,7 +234,7 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error {
wg.Add(1)
go func() {
defer wg.Done()
begin := time.Now()
begin = time.Now()
c.collectUnitTasksMetrics(conn, ch, units)
c.logger.Debug("collectUnitTasksMetrics took", "duration_seconds", time.Since(begin).Seconds())
}()
@ -257,7 +244,7 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error {
wg.Add(1)
go func() {
defer wg.Done()
begin := time.Now()
begin = time.Now()
c.collectTimers(conn, ch, units)
c.logger.Debug("collectTimers took", "duration_seconds", time.Since(begin).Seconds())
}()
@ -266,13 +253,13 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error {
wg.Add(1)
go func() {
defer wg.Done()
begin := time.Now()
begin = time.Now()
c.collectSockets(conn, ch, units)
c.logger.Debug("collectSockets took", "duration_seconds", time.Since(begin).Seconds())
}()
if systemdVersion >= minSystemdVersionSystemState {
begin := time.Now()
begin = time.Now()
err = c.collectSystemState(conn, ch)
c.logger.Debug("collectSystemState took", "duration_seconds", time.Since(begin).Seconds())
}
@ -518,19 +505,3 @@ func (c *systemdCollector) getSystemdVersion(conn *dbus.Conn) (float64, string)
}
return v, version
}
func (c *systemdCollector) getSystemdVirtualization(conn *dbus.Conn) string {
virt, err := conn.GetManagerProperty("Virtualization")
if err != nil {
c.logger.Debug("Could not get Virtualization property", "err", err)
return "unknown"
}
virtStr := strings.Trim(virt, `"`)
if virtStr == "" {
// If no virtualization type is returned, assume it's bare metal.
return "none"
}
return virtStr
}

View file

@ -122,12 +122,11 @@ func TestSystemdSummary(t *testing.T) {
summary := summarizeUnits(fixtures[0])
for _, state := range unitStatesName {
switch state {
case "inactive":
if state == "inactive" {
testSummaryHelper(t, state, summary[state], 3.0)
case "active":
} else if state == "active" {
testSummaryHelper(t, state, summary[state], 1.0)
default:
} else {
testSummaryHelper(t, state, summary[state], 0.0)
}
}

View file

@ -50,8 +50,6 @@ import (
"log/slog"
"unsafe"
"github.com/prometheus/node_exporter/collector/utils"
"github.com/prometheus/client_golang/prometheus"
)
@ -178,7 +176,7 @@ func mappingCFStringToString(s C.CFStringRef) string {
buf := make([]byte, maxBufLen)
var usedBufLen C.CFIndex
_ = C.CFStringGetBytes(s, C.CFRange{0, length}, C.kCFStringEncodingUTF8, C.UInt8(0), C.false, (*C.UInt8)(&buf[0]), maxBufLen, &usedBufLen)
return utils.SafeBytesToString(buf[:usedBufLen])
return string(buf[:usedBufLen])
}
func mappingCFNumberLongToInt(n C.CFNumberRef) int {

View file

@ -13,11 +13,6 @@
package utils
import (
"bytes"
"strings"
)
func SafeDereference[T any](s ...*T) []T {
var resolved []T
for _, v := range s {
@ -30,18 +25,3 @@ func SafeDereference[T any](s ...*T) []T {
}
return resolved
}
// SafeBytesToString takes a slice of bytes and sanitizes it for Prometheus label
// values.
// * Terminate the string at the first null byte.
// * Convert any invalid UTF-8 to "<22>".
func SafeBytesToString(b []byte) string {
var s string
zeroIndex := bytes.IndexByte(b, 0)
if zeroIndex == -1 {
s = string(b)
} else {
s = string(b[:zeroIndex])
}
return strings.ToValidUTF8(s, "<22>")
}

View file

@ -1,30 +0,0 @@
// Copyright 2025 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file ewcept 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.
package utils
import (
"testing"
)
func TestSafeBytesToString(t *testing.T) {
foo := []byte("foo\x00")
if want, got := SafeBytesToString(foo), "foo"; want != got {
t.Errorf("Expected: %s, Got: %s", want, got)
}
foo = []byte{115, 97, 110, 101, 253, 190, 214}
if want, got := SafeBytesToString(foo), "sane<6E>"; want != got {
t.Errorf("Expected: %s, Got: %s", want, got)
}
}

View file

@ -435,5 +435,5 @@ type zfsSysctl string
func (s zfsSysctl) metricName() string {
parts := strings.Split(string(s), ".")
return strings.ReplaceAll(parts[len(parts)-1], "-", "_")
return strings.Replace(parts[len(parts)-1], "-", "_", -1)
}

View file

@ -200,6 +200,9 @@ local diskSpaceUtilisation =
+ dashboard.withVariables([
datasource,
$._clusterVariable,
variable.query.withDatasourceFromVariable(datasource)
+ variable.query.refresh.onTime()
+ variable.query.withSort(asc=true),
])
+ dashboard.withPanels(
grafana.util.grid.makeGrid([
@ -328,6 +331,9 @@ local diskSpaceUtilisation =
+ dashboard.withUid(std.md5('node-multicluster-rsrc-use.json'))
+ dashboard.withVariables([
datasource,
variable.query.withDatasourceFromVariable(datasource)
+ variable.query.refresh.onTime()
+ variable.query.withSort(asc=true),
])
+ dashboard.withPanels(
grafana.util.grid.makeGrid([

View file

@ -67,7 +67,6 @@ enabled_collectors=$(cat << COLLECTORS
netstat
nfs
nfsd
pcidevice
pressure
processes
qdisc
@ -326,7 +325,6 @@ get "127.0.0.1:${port}/metrics" | grep --text -E -v "${skip_re}" > "${generated_
non_deterministic_metrics=$(cat << METRICS
node_boot_time_seconds
node_cpu_frequency_hertz
node_cpu_frequency_max_hertz
node_cpu_seconds_total
node_disk_io_time_seconds_total
node_disk_read_bytes_total

39
go.mod
View file

@ -1,6 +1,6 @@
module github.com/prometheus/node_exporter
go 1.23.0
go 1.22.0
require (
github.com/alecthomas/kingpin/v2 v2.4.0
@ -13,23 +13,23 @@ require (
github.com/hodgesds/perf-utils v0.7.0
github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973
github.com/josharian/native v1.1.0
github.com/jsimonetti/rtnetlink/v2 v2.0.5
github.com/jsimonetti/rtnetlink/v2 v2.0.2
github.com/lufia/iostat v1.2.1
github.com/mattn/go-xmlrpc v0.0.3
github.com/mdlayher/ethtool v0.4.0
github.com/mdlayher/ethtool v0.2.0
github.com/mdlayher/netlink v1.7.2
github.com/mdlayher/wifi v0.6.0
github.com/opencontainers/selinux v1.12.0
github.com/mdlayher/wifi v0.3.1
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
github.com/prometheus/client_golang v1.23.0
github.com/prometheus/client_model v0.6.2
github.com/prometheus/common v0.65.0
github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_model v0.6.1
github.com/prometheus/common v0.62.0
github.com/prometheus/exporter-toolkit v0.14.0
github.com/prometheus/procfs v0.17.0
github.com/safchain/ethtool v0.6.2
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.34.0
golang.org/x/sys v0.30.0
howett.net/plist v1.0.1
)
@ -38,8 +38,9 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dennwc/ioctl v1.0.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mdlayher/genetlink v1.3.2 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
@ -50,11 +51,13 @@ 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.39.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/text v0.26.0 // indirect
google.golang.org/protobuf v1.36.6 // 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
google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
//replace github.com/prometheus/procfs => github.com/rexagod/procfs v0.0.0-20241124020414-857c5b813f1b

79
go.sum
View file

@ -8,8 +8,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cilium/ebpf v0.19.0 h1:Ro/rE64RmFBeA9FGjcTc+KmCeY6jXmryu6FfnzPRIao=
github.com/cilium/ebpf v0.19.0/go.mod h1:fLCgMo3l8tZmAdM3B2XqdFzXBpwkcSTroaVqN08OWVY=
github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4=
github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -24,8 +24,8 @@ github.com/ema/qdisc v1.0.0/go.mod h1:FhIc0fLYi7f+lK5maMsesDqwYojIOh3VfRs8EVd5YJ
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY=
github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc=
github.com/hodgesds/perf-utils v0.7.0 h1:7KlHGMuig4FRH5fNw68PV6xLmgTe7jKs9hgAcEAbioU=
@ -37,10 +37,10 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/jsimonetti/rtnetlink/v2 v2.0.5 h1:l5S9iedrSW4thUfgiU+Hzsnk1cOR0upGD5ttt6mirHw=
github.com/jsimonetti/rtnetlink/v2 v2.0.5/go.mod h1:9yTlq3Ojr1rbmh/Y5L30/KIojpFhTRph2xKeZ+y+Pic=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/jsimonetti/rtnetlink/v2 v2.0.2 h1:ZKlbCujrIpp4/u3V2Ka0oxlf4BCkt6ojkvpy3nZoCBY=
github.com/jsimonetti/rtnetlink/v2 v2.0.2/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -51,8 +51,8 @@ github.com/lufia/iostat v1.2.1 h1:tnCdZBIglgxD47RyD55kfWQcJMGzO+1QBziSQfesf2k=
github.com/lufia/iostat v1.2.1/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg=
github.com/mattn/go-xmlrpc v0.0.3 h1:Y6WEMLEsqs3RviBrAa1/7qmbGB7DVD3brZIbqMbQdGY=
github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA=
github.com/mdlayher/ethtool v0.4.0 h1:jjMGNSQfqauwFCtSzcqpa57R0AJdxKdQgbQ9mAOtM4Q=
github.com/mdlayher/ethtool v0.4.0/go.mod h1:GrljOneAFOTPGazYlf8qpxvYLdu4mo3pdJqXWLZ2Re8=
github.com/mdlayher/ethtool v0.2.0 h1:akcA4WZVWozzirPASeMq8qgLkxpF3ykftVXwnrMKrhY=
github.com/mdlayher/ethtool v0.2.0/go.mod h1:W0pIBrNPK1TslIN4Z9wt1EVbay66Kbvek2z2f29VBfw=
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
@ -61,34 +61,34 @@ 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.6.0 h1:yBVPVgyCWcdyLkztUVM2Czd2XFKRJegHOoBm2gBWKG8=
github.com/mdlayher/wifi v0.6.0/go.mod h1:qwcTzRuC2bV+s4PFhGMzPi0sFHAr2jXkUSumSMIU6+4=
github.com/mdlayher/wifi v0.3.1 h1:bZDuMI1f7z5BtUUO3NgHRdR/R88YtywIe6dsEFI0Txs=
github.com/mdlayher/wifi v0.3.1/go.mod h1:ODQaObvsglghTuNhezD9grkTB4shVNc28aJfTXmvSi8=
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=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/opencontainers/selinux v1.12.0 h1:6n5JV4Cf+4y0KNXW48TLj5DwfXpvWlxXplUkdTrmPb8=
github.com/opencontainers/selinux v1.12.0/go.mod h1:BTPX+bjVbWGXw7ZZWUbdENt8w0htPSrlgOOysQaU62U=
github.com/opencontainers/selinux v1.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jDMcgULaH8=
github.com/opencontainers/selinux v1.11.1/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus-community/go-runit v0.1.0 h1:uTWEj/Fn2RoLdfg/etSqwzgYNOYPrARx1BHUN052tGA=
github.com/prometheus-community/go-runit v0.1.0/go.mod h1:AvJ9Jo3gAFu2lbM4+qfjdpq30FfiLDJZKbQ015u08IQ=
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
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.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
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/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.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/prometheus/procfs v0.15.2-0.20240603130017-1754b780536b h1:4EJkx3vycI+n5JY5ht+bnSUGamkmmXkpcNeO/OBT/0A=
github.com/prometheus/procfs v0.15.2-0.20240603130017-1754b780536b/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
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.6.2 h1:O3ZPFAKEUEfbtE6J/feEe2Ft7dIJ2Sy8t4SdMRiIMHY=
github.com/safchain/ethtool v0.6.2/go.mod h1:VS7cn+bP3Px3rIq55xImBiZGHVLNyBh5dqG6dDQy8+I=
github.com/safchain/ethtool v0.5.10 h1:Im294gZtuf4pSGJRAOGKaASNi3wMeFaGaWuSaomedpc=
github.com/safchain/ethtool v0.5.10/go.mod h1:w9jh2Lx7YBR4UwzLkzCmWl85UY0W2uZdd7/DckVE5+c=
github.com/siebenmann/go-kstat v0.0.0-20210513183136-173c9b0a9973 h1:GfSdC6wKfTGcgCS7BtzF5694Amne1pGCSTY252WhlEY=
github.com/siebenmann/go-kstat v0.0.0-20210513183136-173c9b0a9973/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -100,28 +100,27 @@ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
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.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
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.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.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
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/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.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
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=
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=
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=

View file

@ -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)
fmt.Fprintf(w, "Couldn't create filtered metrics handler: %s", err)
w.Write([]byte(fmt.Sprintf("Couldn't create filtered metrics handler: %s", err)))
return
}
filteredHandler.ServeHTTP(w, r)