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. # should also be updated.
golang: golang:
docker: docker:
- image: cimg/go:1.24 - image: cimg/go:1.23
arm: arm:
docker: docker:
- image: cimg/go:1.24 - image: cimg/go:1.23
resource_class: arm.medium resource_class: arm.medium
jobs: jobs:
@ -42,7 +42,7 @@ jobs:
- run: git diff --exit-code - run: git diff --exit-code
build: build:
machine: machine:
image: ubuntu-2404:current image: ubuntu-2204:current
parallelism: 3 parallelism: 3
steps: steps:
- prometheus/setup_environment - prometheus/setup_environment
@ -68,9 +68,9 @@ jobs:
destination: /build destination: /build
test_docker: test_docker:
machine: machine:
image: ubuntu-2404:current image: ubuntu-2204:current
environment: 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 REPO_PATH: github.com/prometheus/node_exporter
steps: steps:
- prometheus/setup_environment - prometheus/setup_environment

View file

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

View file

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

View file

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

View file

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

View file

@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_
SKIP_GOLANGCI_LINT := SKIP_GOLANGCI_LINT :=
GOLANGCI_LINT := GOLANGCI_LINT :=
GOLANGCI_LINT_OPTS ?= 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. # 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. # windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))

View file

@ -1,8 +1,7 @@
# Node exporter # Node exporter
[![CircleCI](https://circleci.com/gh/prometheus/node_exporter/tree/master.svg?style=shield)][circleci] [![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) [![Buildkite status](https://badge.buildkite.com/94a0c1fb00b1f46883219c256efe9ce01d63b6505f3a942f9b.svg)](https://buildkite.com/prometheus/node-exporter)
![golangci-lint workflow](https://github.com/prometheus/node_exporter/actions/workflows/golangci-lint.yml/badge.svg)
[![Docker Repository on Quay](https://quay.io/repository/prometheus/node-exporter/status)][quay] [![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] [![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] [![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 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 mountstats | Exposes filesystem statistics from `/proc/self/mountstats`. Exposes detailed NFS client statistics. | Linux
network_route | Exposes the routing table as metrics | 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 perf | Exposes perf based metrics (Warning: Metrics are dependent on kernel configuration and settings). | Linux
processes | Exposes aggregate process statistics from `/proc`. | Linux processes | Exposes aggregate process statistics from `/proc`. | Linux
qdisc | Exposes [queuing discipline](https://en.wikipedia.org/wiki/Network_scheduler#Linux_kernel) statistics | 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 { for _, s := range stats {
// match up procfs and ioctl info by filesystem UUID (without dashes) // 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] ioctlStats := ioctlStatsMap[fsUUID]
c.updateBtrfsStats(ch, s, ioctlStats) c.updateBtrfsStats(ch, s, ioctlStats)
} }

View file

@ -30,50 +30,22 @@ import (
"github.com/prometheus/client_golang/prometheus" "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 { type cpuCollector struct {
cpu typedDesc cpu typedDesc
cpuPhysical typedDesc logger *slog.Logger
cpuRunQueue typedDesc tickPerSecond int64
cpuFlags typedDesc
cpuContextSwitch typedDesc
logger *slog.Logger
tickPerSecond float64
purrTicksPerSecond float64
} }
func init() { func init() {
registerCollector("cpu", defaultEnabled, NewCpuCollector) registerCollector("cpu", defaultEnabled, NewCpuCollector)
} }
func tickPerSecond() (float64, error) { func tickPerSecond() (int64, error) {
ticks, err := C.sysconf(C._SC_CLK_TCK) ticks, err := C.sysconf(C._SC_CLK_TCK)
if ticks == -1 || err != nil { if ticks == -1 || err != nil {
return 0, fmt.Errorf("failed to get clock ticks per second: %v", err) 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) { func NewCpuCollector(logger *slog.Logger) (Collector, error) {
@ -81,22 +53,10 @@ func NewCpuCollector(logger *slog.Logger) (Collector, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
pconfig, err := perfstat.PartitionStat()
if err != nil {
return nil, err
}
return &cpuCollector{ return &cpuCollector{
cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue}, cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue},
cpuPhysical: typedDesc{nodeCPUPhysicalSecondsDesc, prometheus.CounterValue}, logger: logger,
cpuRunQueue: typedDesc{nodeCPUSRunQueueDesc, prometheus.GaugeValue}, tickPerSecond: ticks,
cpuFlags: typedDesc{nodeCPUFlagsDesc, prometheus.GaugeValue},
cpuContextSwitch: typedDesc{nodeCPUContextSwitchDesc, prometheus.CounterValue},
logger: logger,
tickPerSecond: ticks,
purrTicksPerSecond: float64(pconfig.ProcessorMhz * 1e6),
}, nil }, nil
} }
@ -107,26 +67,10 @@ func (c *cpuCollector) Update(ch chan<- prometheus.Metric) error {
} }
for n, stat := range stats { 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.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.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.Idle)/c.tickPerSecond, strconv.Itoa(n), "idle") ch <- c.cpu.mustNewConstMetric(float64(stat.Wait/c.tickPerSecond), strconv.Itoa(n), "wait")
ch <- c.cpu.mustNewConstMetric(float64(stat.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))
} }
return nil return nil
} }

View file

@ -87,7 +87,7 @@ func NewCPUCollector(logger *slog.Logger) (Collector, error) {
isolcpus, err := sfs.IsolatedCPUs() isolcpus, err := sfs.IsolatedCPUs()
if err != nil { if err != nil {
if !os.IsNotExist(err) { 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) 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") keys := sortFilterSysmonProperties(props, "coretemp")
for idx := range keys { for idx, _ := range keys {
convertTemperatures(props[keys[idx]], res) convertTemperatures(props[keys[idx]], res)
} }

View file

@ -22,12 +22,12 @@ import (
) )
const ( const (
cpuVulnerabilitiesCollectorSubsystem = "cpu_vulnerabilities" cpuVulerabilitiesCollector = "cpu_vulnerabilities"
) )
var ( var (
vulnerabilityDesc = prometheus.NewDesc( 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", "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"}, []string{"codename", "state", "mitigation"},
nil, nil,
@ -37,7 +37,7 @@ var (
type cpuVulnerabilitiesCollector struct{} type cpuVulnerabilitiesCollector struct{}
func init() { func init() {
registerCollector(cpuVulnerabilitiesCollectorSubsystem, defaultDisabled, NewVulnerabilitySysfsCollector) registerCollector(cpuVulerabilitiesCollector, defaultDisabled, NewVulnerabilitySysfsCollector)
} }
func NewVulnerabilitySysfsCollector(logger *slog.Logger) (Collector, error) { func NewVulnerabilitySysfsCollector(logger *slog.Logger) (Collector, error) {

View file

@ -30,19 +30,11 @@ type diskstatsCollector struct {
rbytes typedDesc rbytes typedDesc
wbytes typedDesc wbytes typedDesc
time typedDesc time typedDesc
bsize typedDesc
qdepth typedDesc
rserv typedDesc
wserv typedDesc
xfers typedDesc
xrate typedDesc
deviceFilter deviceFilter deviceFilter deviceFilter
logger *slog.Logger logger *slog.Logger
tickPerSecond float64 tickPerSecond int64
} }
func init() { func init() {
@ -65,54 +57,6 @@ func NewDiskstatsCollector(logger *slog.Logger) (Collector, error) {
wbytes: typedDesc{writtenBytesDesc, prometheus.CounterValue}, wbytes: typedDesc{writtenBytesDesc, prometheus.CounterValue},
time: typedDesc{ioTimeSecondsDesc, 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, deviceFilter: deviceFilter,
logger: logger, 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.rbytes.mustNewConstMetric(float64(stat.Rblks*512), stat.Name)
ch <- c.wbytes.mustNewConstMetric(float64(stat.Wblks*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.time.mustNewConstMetric(float64(stat.Time/c.tickPerSecond), stat.Name)
ch <- c.bsize.mustNewConstMetric(float64(stat.BSize), stat.Name)
ch <- c.qdepth.mustNewConstMetric(float64(stat.QDepth), stat.Name)
ch <- c.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)
} }
return nil return nil
} }

View file

@ -398,9 +398,15 @@ func getUdevDeviceProperties(major, minor uint32) (udevInfo, error) {
line = strings.TrimPrefix(line, udevDevicePropertyPrefix) 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 { if name, value, found := strings.Cut(line, "="); found {
info[name] = value info[name] = value
} }
*/
if fields := strings.SplitN(line, "=", 2); len(fields) == 2 {
info[fields[0]] = fields[1]
}
} }
return info, nil 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. // No stats returned; device does not support ethtool stats.
continue continue
} }
// Sanitizing the metric names can lead to duplicate metric names. Therefore check for clashes beforehand. // Sanitizing the metric names can lead to duplicate metric names. Therefore check for clashes beforehand.
metricFQNames := make(map[string]string) metricFQNames := make(map[string]string)
renamedStats := make(map[string]uint64, len(stats))
for metric := range stats { for metric := range stats {
metricName := SanitizeMetricName(metric) metricName := SanitizeMetricName(metric)
if !c.metricsPattern.MatchString(metricName) { if !c.metricsPattern.MatchString(metricName) {
@ -468,8 +467,6 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
metricFQNames[metricFQName] = "" metricFQNames[metricFQName] = ""
} else { } else {
metricFQNames[metricFQName] = metricName 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 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. // Check to see if this metric exists; if not then create it and store it in c.entries.
entry := c.entryWithCreate(metric, metricFQName) entry := c.entryWithCreate(metric, metricFQName)

View file

@ -212,18 +212,16 @@ func (e *EthtoolFixture) LinkInfo(intf string) (ethtool.EthtoolCmd, error) {
items := strings.Split(line, ": ") items := strings.Split(line, ": ")
if items[0] == "Supported pause frame use" { if items[0] == "Supported pause frame use" {
switch items[1] { if items[1] == "Symmetric" {
case "Symmetric":
res.Supported |= (1 << unix.ETHTOOL_LINK_MODE_Pause_BIT) 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) res.Supported |= (1 << unix.ETHTOOL_LINK_MODE_Asym_Pause_BIT)
} }
} }
if items[0] == "Advertised pause frame use" { if items[0] == "Advertised pause frame use" {
switch items[1] { if items[1] == "Symmetric" {
case "Symmetric":
res.Advertising |= (1 << unix.ETHTOOL_LINK_MODE_Pause_BIT) 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) 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) { func TestBuildEthtoolFQName(t *testing.T) {
testcases := map[string]string{ testcases := map[string]string{
"port.rx_errors": "node_ethtool_port_received_errors",
"rx_errors": "node_ethtool_received_errors", "rx_errors": "node_ethtool_received_errors",
"Queue[0] AllocFails": "node_ethtool_queue_0_allocfails", "Queue[0] AllocFails": "node_ethtool_queue_0_allocfails",
"Tx LPI entry count": "node_ethtool_transmitted_lpi_entry_count", "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. # 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 # 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 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 # HELP node_ethtool_received_broadcast Network interface rx_broadcast
# TYPE node_ethtool_received_broadcast untyped # TYPE node_ethtool_received_broadcast untyped
node_ethtool_received_broadcast{device="eth0"} 5792 node_ethtool_received_broadcast{device="eth0"} 5792

View file

@ -53,9 +53,9 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) {
mountPoint: stat.MountPoint, mountPoint: stat.MountPoint,
fsType: fstype, fsType: fstype,
}, },
size: float64(stat.TotalBlocks * 512.0), size: float64(stat.TotalBlocks / 512.0),
free: float64(stat.FreeBlocks * 512.0), free: float64(stat.FreeBlocks / 512.0),
avail: float64(stat.FreeBlocks * 512.0), // AIX doesn't distinguish between free and available blocks. avail: float64(stat.FreeBlocks / 512.0), // AIX doesn't distinguish between free and available blocks.
files: float64(stat.TotalInodes), files: float64(stat.TotalInodes),
filesFree: float64(stat.FreeInodes), filesFree: float64(stat.FreeInodes),
ro: ro, ro: ro,

View file

@ -89,7 +89,7 @@ type filesystemStats struct {
labels filesystemLabels labels filesystemLabels
size, free, avail float64 size, free, avail float64
files, filesFree float64 files, filesFree float64
purgeable float64 purgeable *float64
ro, deviceError float64 ro, deviceError float64
} }
@ -232,10 +232,11 @@ func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) error {
c.mountInfoDesc, prometheus.GaugeValue, c.mountInfoDesc, prometheus.GaugeValue,
1.0, s.labels.device, s.labels.major, s.labels.minor, s.labels.mountPoint, 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( ch <- prometheus.MustNewConstMetric(
c.purgeableDesc, prometheus.GaugeValue, 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 // Ensure we handle the translation of \040 and \011
// as per fstab(5). // as per fstab(5).
parts[4] = strings.ReplaceAll(parts[4], "\\040", " ") parts[4] = strings.Replace(parts[4], "\\040", " ", -1)
parts[4] = strings.ReplaceAll(parts[4], "\\011", "\t") parts[4] = strings.Replace(parts[4], "\\011", "\t", -1)
filesystems = append(filesystems, filesystemLabels{ filesystems = append(filesystems, filesystemLabels{
device: parts[m+3], device: parts[m+3],

View file

@ -20,26 +20,23 @@ package collector
#cgo CFLAGS: -x objective-c #cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation #cgo LDFLAGS: -framework Foundation
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
Float64 purgeable(char *path) { Float64 *purgeable(char *path) {
Float64 value = -1.0f; CFNumberRef tmp;
Float64 *value;
@autoreleasepool { NSError *error = nil;
NSError *error = nil; NSString *str = [NSString stringWithUTF8String:path];
NSString *str = [NSString stringWithUTF8String:path]; NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:str];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:str]; NSDictionary *results = [fileURL resourceValuesForKeys:@[NSURLVolumeAvailableCapacityForImportantUsageKey] error:&error];
if (results) {
NSDictionary *results = [fileURL resourceValuesForKeys:@[NSURLVolumeAvailableCapacityForImportantUsageKey] error:&error]; if ((tmp = CFDictionaryGetValue((CFDictionaryRef)results, NSURLVolumeAvailableCapacityForImportantUsageKey)) == NULL)
if (results) { return NULL;
CFNumberRef tmp = CFDictionaryGetValue((CFDictionaryRef)results, NSURLVolumeAvailableCapacityForImportantUsageKey); value = (Float64 *)malloc(sizeof(Float64));
if (tmp != NULL) { if (CFNumberGetValue(tmp, kCFNumberFloat64Type, value)) {
CFNumberGetValue(tmp, kCFNumberFloat64Type, &value); return value;
}
} }
[fileURL release];
} }
free(value);
return value; return NULL;
} }
*/ */
import "C" import "C"
@ -92,9 +89,6 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) {
ro = 1 ro = 1
} }
mountpointCString := C.CString(mountpoint)
defer C.free(unsafe.Pointer(mountpointCString))
stats = append(stats, filesystemStats{ stats = append(stats, filesystemStats{
labels: filesystemLabels{ labels: filesystemLabels{
device: device, 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), avail: float64(mnt[i].f_bavail) * float64(mnt[i].f_bsize),
files: float64(mnt[i].f_files), files: float64(mnt[i].f_files),
filesFree: float64(mnt[i].f_ffree), filesFree: float64(mnt[i].f_ffree),
purgeable: float64(C.purgeable(mountpointCString)), purgeable: (*float64)(C.purgeable(C.CString(mountpoint))),
ro: ro, 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. # 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 # 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 # 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 # TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist. # HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge # TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge # TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte. # HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge # 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 # TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created. # HELP go_threads Number of OS threads created.
# TYPE go_threads gauge # 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="md7"} 7.813735424e+09
node_md_blocks_synced{device="md8"} 1.6775552e+07 node_md_blocks_synced{device="md8"} 1.6775552e+07
node_md_blocks_synced{device="md9"} 0 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. # HELP node_md_disks Number of active/failed/spare disks of device.
# TYPE node_md_disks gauge # TYPE node_md_disks gauge
node_md_disks{device="md0",state="active"} 2 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="md7"} 4
node_md_disks_required{device="md8"} 2 node_md_disks_required{device="md8"} 2
node_md_disks_required{device="md9"} 4 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. # HELP node_md_state Indicates the state of md-device.
# TYPE node_md_state gauge # TYPE node_md_state gauge
node_md_state{device="md0",state="active"} 1 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. # HELP node_os_version Metric containing the major.minor part of the OS version.
# TYPE node_os_version gauge # TYPE node_os_version gauge
node_os_version{id="ubuntu",id_like="debian",name="Ubuntu"} 20.04 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>. # HELP node_power_supply_capacity capacity value of /sys/class/power_supply/<power_supply>.
# TYPE node_power_supply_capacity gauge # TYPE node_power_supply_capacity gauge
node_power_supply_capacity{power_supply="BAT0"} 81 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="nfsd"} 1
node_scrape_collector_success{collector="nvme"} 1 node_scrape_collector_success{collector="nvme"} 1
node_scrape_collector_success{collector="os"} 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="powersupplyclass"} 1
node_scrape_collector_success{collector="pressure"} 1 node_scrape_collector_success{collector="pressure"} 1
node_scrape_collector_success{collector="processes"} 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. # 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 # 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 # 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 # TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist. # HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge # TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge # TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte. # HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge # 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 # TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created. # HELP go_threads Number of OS threads created.
# TYPE go_threads gauge # 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 # 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 # TYPE node_xfrm_out_state_seq_error_packets_total counter
node_xfrm_out_state_seq_error_packets_total 543 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. # HELP promhttp_metric_handler_errors_total Total number of internal errors encountered by the promhttp metric handler.
# TYPE promhttp_metric_handler_errors_total counter # TYPE promhttp_metric_handler_errors_total counter
promhttp_metric_handler_errors_total{cause="encoding"} 0 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. # 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 # 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 # 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 # TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist. # HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge # TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge # TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte. # HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge # 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 # TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created. # HELP go_threads Number of OS threads created.
# TYPE go_threads gauge # 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. # 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 # 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 # 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 # TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist. # HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge # TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge # TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte. # HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge # 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 # TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created. # HELP go_threads Number of OS threads created.
# TYPE go_threads gauge # 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. # 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 # 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 # 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 # TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist. # HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge # TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge # TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte. # HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge # 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 # TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created. # HELP go_threads Number of OS threads created.
# TYPE go_threads gauge # 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. # 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 # 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 # 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 # TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist. # HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge # TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge # TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte. # HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge # 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 # TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created. # HELP go_threads Number of OS threads created.
# TYPE go_threads gauge # 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. # 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 # 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 # 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 # TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist. # HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge # TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge # TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte. # HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge # 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 # TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created. # HELP go_threads Number of OS threads created.
# TYPE go_threads gauge # 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="DMA"} 1
node_buddyinfo_blocks{node="0",size="9",zone="DMA32"} 0 node_buddyinfo_blocks{node="0",size="9",zone="DMA32"} 0
node_buddyinfo_blocks{node="0",size="9",zone="Normal"} 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. # 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 # 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. # 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. # 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 # 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 # 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 # TYPE go_gc_gomemlimit_bytes gauge
# HELP go_goroutines Number of goroutines that currently exist. # HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge # TYPE go_goroutines gauge
@ -52,7 +52,7 @@
# TYPE go_memstats_stack_sys_bytes gauge # TYPE go_memstats_stack_sys_bytes gauge
# HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte. # HELP go_memstats_sys_bytes Number of bytes obtained from system. Equals to /memory/classes/total:byte.
# TYPE go_memstats_sys_bytes gauge # 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 # TYPE go_sched_gomaxprocs_threads gauge
# HELP go_threads Number of OS threads created. # HELP go_threads Number of OS threads created.
# TYPE go_threads gauge # 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="md7"} 7.813735424e+09
node_md_blocks_synced{device="md8"} 1.6775552e+07 node_md_blocks_synced{device="md8"} 1.6775552e+07
node_md_blocks_synced{device="md9"} 0 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. # HELP node_md_disks Number of active/failed/spare disks of device.
# TYPE node_md_disks gauge # TYPE node_md_disks gauge
node_md_disks{device="md0",state="active"} 2 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="md7"} 4
node_md_disks_required{device="md8"} 2 node_md_disks_required{device="md8"} 2
node_md_disks_required{device="md9"} 4 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. # HELP node_md_state Indicates the state of md-device.
# TYPE node_md_state gauge # TYPE node_md_state gauge
node_md_state{device="md0",state="active"} 1 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. # HELP node_os_version Metric containing the major.minor part of the OS version.
# TYPE node_os_version gauge # TYPE node_os_version gauge
node_os_version{id="ubuntu",id_like="debian",name="Ubuntu"} 20.04 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>. # HELP node_power_supply_capacity capacity value of /sys/class/power_supply/<power_supply>.
# TYPE node_power_supply_capacity gauge # TYPE node_power_supply_capacity gauge
node_power_supply_capacity{power_supply="BAT0"} 81 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="nfsd"} 1
node_scrape_collector_success{collector="nvme"} 1 node_scrape_collector_success{collector="nvme"} 1
node_scrape_collector_success{collector="os"} 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="powersupplyclass"} 1
node_scrape_collector_success{collector="pressure"} 1 node_scrape_collector_success{collector="pressure"} 1
node_scrape_collector_success{collector="processes"} 1 node_scrape_collector_success{collector="processes"} 1

View file

@ -4,7 +4,6 @@ NIC statistics:
rx_packets: 1260062 rx_packets: 1260062
tx_errors: 0 tx_errors: 0
rx_errors: 0 rx_errors: 0
port.rx_dropped: 12028
rx_missed: 401 rx_missed: 401
align_errors: 0 align_errors: 0
tx_single_collisions: 0 tx_single_collisions: 0

View file

@ -2,4 +2,4 @@ net 70 70 69 45
rpc 1218785755 374636 1218815394 rpc 1218785755 374636 1218815394
proc2 18 16 57 74 52 71 73 45 86 0 52 83 61 17 53 50 23 70 82 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 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" "strconv"
"unsafe" "unsafe"
"github.com/prometheus/node_exporter/collector/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -51,7 +49,7 @@ func intr(idx _C_int) (itr interrupt, err error) {
return return
} }
dev := *(*[128]byte)(unsafe.Pointer(&buf[0])) dev := *(*[128]byte)(unsafe.Pointer(&buf[0]))
itr.device = utils.SafeBytesToString(dev[:]) itr.device = string(dev[:])
mib[2] = KERN_INTRCNT_VECTOR mib[2] = KERN_INTRCNT_VECTOR
buf, err = sysctl(mib[:]) buf, err = sysctl(mib[:])

View file

@ -22,8 +22,6 @@ import (
"log/slog" "log/slog"
"os" "os"
"github.com/prometheus/procfs/sysfs"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs" "github.com/prometheus/procfs"
) )
@ -100,30 +98,17 @@ var (
[]string{"device"}, []string{"device"},
nil, 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 { func (c *mdadmCollector) Update(ch chan<- prometheus.Metric) error {
procFS, err := procfs.NewFS(*procPath) fs, err := procfs.NewFS(*procPath)
if err != nil { if err != nil {
return fmt.Errorf("failed to open procfs: %w", err) return fmt.Errorf("failed to open procfs: %w", err)
} }
mdStats, err := procFS.MDStat() mdStats, err := fs.MDStat()
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
c.logger.Debug("Not collecting mdstat, file does not exist", "file", *procPath) 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 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

@ -40,12 +40,8 @@ func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {
} }
return map[string]float64{ return map[string]float64{
"total_bytes": float64(stats.RealTotal * 4096), "total_bytes": float64(stats.RealTotal * 4096),
"free_bytes": float64(stats.RealFree * 4096), "free_bytes": float64(stats.RealFree * 4096),
"available_bytes": float64(stats.RealAvailable * 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 }, nil
} }

View file

@ -44,7 +44,7 @@ func NewMeminfoCollector(logger *slog.Logger) (Collector, error) {
func (c *meminfoCollector) getMemInfo() (map[string]float64, error) { func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {
meminfo, err := c.fs.Meminfo() meminfo, err := c.fs.Meminfo()
if err != nil { 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) metrics := make(map[string]float64)

View file

@ -32,20 +32,16 @@ func getNetDevStats(filter *deviceFilter, logger *slog.Logger) (netDevStats, err
for _, stat := range stats { for _, stat := range stats {
netDev[stat.Name] = map[string]uint64{ netDev[stat.Name] = map[string]uint64{
"receive_bytes": uint64(stat.RxBytes), "receive_packets": uint64(stat.RxPackets),
"receive_dropped": uint64(stat.RxPacketsDropped), "transmit_packets": uint64(stat.TxPackets),
"receive_errors": uint64(stat.RxErrors), "receive_bytes": uint64(stat.RxBytes),
"receive_multicast": uint64(stat.RxMulticastPackets), "transmit_bytes": uint64(stat.TxBytes),
"receive_packets": uint64(stat.RxPackets), "receive_errors": uint64(stat.RxErrors),
"receive_collision_errors": uint64(stat.RxCollisionErrors), "transmit_errors": uint64(stat.TxErrors),
"transmit_bytes": uint64(stat.TxBytes), "receive_dropped": uint64(stat.RxPacketsDropped),
"transmit_dropped": uint64(stat.TxPacketsDropped), "transmit_dropped": uint64(stat.TxPacketsDropped),
"transmit_errors": uint64(stat.TxErrors), "receive_multicast": uint64(stat.RxMulticastPackets),
"transmit_multicast": uint64(stat.TxMulticastPackets), "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),
} }
} }

View file

@ -22,7 +22,6 @@ import (
"fmt" "fmt"
"log/slog" "log/slog"
"net" "net"
"unsafe"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -72,107 +71,51 @@ func getIfaceData(index int) (*ifMsghdr2, error) {
return nil, err return nil, err
} }
err = binary.Read(bytes.NewReader(rawData), binary.LittleEndian, &data) 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 return &data, err
} }
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if.h#L220-L232
type ifMsghdr2 struct { type ifMsghdr2 struct {
Msglen uint16 // to skip over non-understood messages Msglen uint16
Version uint8 // future binary compatabilit Version uint8
Type uint8 // message type Type uint8
Addrs int32 // like rtm_addrs Addrs int32
Flags int32 // value of if_flags Flags int32
Index uint16 // index for associated ifp Index uint16
_ [2]byte // padding for alignment _ [2]byte
SndLen int32 // instantaneous length of send queue SndLen int32
SndMaxlen int32 // maximum length of send queue SndMaxlen int32
SndDrops int32 // number of drops in send queue SndDrops int32
Timer int32 // time until if_watchdog called Timer int32
Data ifData64 // statistics and other data 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 ifData64 struct {
Type uint8 // ethernet, tokenring, etc Type uint8
Typelen uint8 // Length of frame type id Typelen uint8
Physical uint8 // e.g., AUI, Thinnet, 10base-T, etc Physical uint8
Addrlen uint8 // media address length Addrlen uint8
Hdrlen uint8 // media header length Hdrlen uint8
Recvquota uint8 // polling quota for receive intrs Recvquota uint8
Xmitquota uint8 // polling quota for xmit intrs Xmitquota uint8
Unused1 uint8 // for future use Unused1 uint8
Mtu uint32 // maximum transmission unit Mtu uint32
Metric uint32 // routing metric (external only) Metric uint32
Baudrate uint64 // linespeed Baudrate uint64
Ipackets uint64
// volatile statistics Ierrors uint64
Ipackets uint64 // packets received on interface Opackets uint64
Ierrors uint64 // input errors on interface Oerrors uint64
Opackets uint64 // packets sent on interface Collisions uint64
Oerrors uint64 // output errors on interface Ibytes uint64
Collisions uint64 // collisions on csma interfaces Obytes uint64
Ibytes uint64 // total number of octets received Imcasts uint64
Obytes uint64 // total number of octets sent Omcasts uint64
Imcasts uint64 // packets received via multicast Iqdrops uint64
Omcasts uint64 // packets sent via multicast Noproto uint64
Iqdrops uint64 // dropped on input, this interface Recvtiming uint32
Noproto uint64 // destined for unsupported protocol Xmittiming uint32
Recvtiming uint32 // usec spent receiving when timing Lastchange unix.Timeval32
Xmittiming uint32 // usec spent xmitting when timing
Lastchange unix.Timeval32 // time of last administrative change
}
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if_mib.h#L65-L74
type ifMibData struct {
Name [16]byte // name of interface
PCount uint32 // number of promiscuous listeners
Flags uint32 // interface flags
SendLength uint32 // instantaneous length of send queue
MaxSendLength uint32 // maximum length of send queue
SendDrops uint32 // number of drops in send queue
_ [4]uint32 // for future expansion
Data [128]byte // generic information and statistics
} }
func getNetDevLabels() (map[string]map[string]string, error) { 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 { if err != nil {
t.Skip("Procfs not mounted, skipping perf tests") 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) paranoid, err := strconv.Atoi(paranoidStr)
if err != nil { if err != nil {
t.Fatalf("Expected perf_event_paranoid to be an int, got: %s", paranoidStr) t.Fatalf("Expected perf_event_paranoid to be an int, got: %s", paranoidStr)

View file

@ -27,15 +27,8 @@ import (
"github.com/prometheus/procfs" "github.com/prometheus/procfs"
) )
const (
psiResourceCPU = "cpu"
psiResourceIO = "io"
psiResourceMemory = "memory"
psiResourceIRQ = "irq"
)
var ( var (
psiResources = []string{psiResourceCPU, psiResourceIO, psiResourceMemory, psiResourceIRQ} psiResources = []string{"cpu", "io", "memory", "irq"}
) )
type pressureStatsCollector struct { 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 // Update calls procfs.NewPSIStatsForResource for the different resources and updates the values
func (c *pressureStatsCollector) Update(ch chan<- prometheus.Metric) error { func (c *pressureStatsCollector) Update(ch chan<- prometheus.Metric) error {
foundResources := 0
for _, res := range psiResources { for _, res := range psiResources {
c.logger.Debug("collecting statistics for resource", "resource", res) c.logger.Debug("collecting statistics for resource", "resource", res)
vals, err := c.fs.PSIStatsForResource(res) vals, err := c.fs.PSIStatsForResource(res)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) && res != psiResourceIRQ { 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", "resource", res) c.logger.Debug("pressure information is unavailable, you need a Linux kernel >= 4.20 and/or CONFIG_PSI enabled for your kernel")
continue return ErrNoData
}
if errors.Is(err, os.ErrNotExist) && res == psiResourceIRQ {
c.logger.Debug("IRQ pressure information is unavailable, you need a Linux kernel >= 6.1 and/or CONFIG_PSI enabled for your kernel", "resource", res)
continue
} }
if errors.Is(err, syscall.ENOTSUP) { if errors.Is(err, syscall.ENOTSUP) {
c.logger.Debug("pressure information is disabled, add psi=1 kernel command line to enable it") 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. // IRQ pressure does not have 'some' data.
// See https://github.com/torvalds/linux/blob/v6.9/include/linux/psi_types.h#L65 // 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") c.logger.Debug("pressure information returned no 'some' data")
return ErrNoData return ErrNoData
} }
if vals.Full == nil && res != psiResourceCPU { if vals.Full == nil && res != "cpu" {
c.logger.Debug("pressure information returned no 'full' data") c.logger.Debug("pressure information returned no 'full' data")
return ErrNoData return ErrNoData
} }
switch res { switch res {
case psiResourceCPU: case "cpu":
ch <- prometheus.MustNewConstMetric(c.cpu, prometheus.CounterValue, float64(vals.Some.Total)/1000.0/1000.0) 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.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) 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.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) 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) ch <- prometheus.MustNewConstMetric(c.irqFull, prometheus.CounterValue, float64(vals.Full.Total)/1000.0/1000.0)
default: default:
c.logger.Debug("did not account for resource", "resource", res) 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 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")) pidM, err := readUintFromFile(procFilePath("sys/kernel/pid_max"))
if err != nil { 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.pidUsed, prometheus.GaugeValue, float64(pids))
ch <- prometheus.MustNewConstMetric(c.pidMax, prometheus.GaugeValue, float64(pidM)) 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")) maxPid, err := readUintFromFile(procFilePath("sys/kernel/pid_max"))
if err != nil { 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 { if uint64(pids) > maxPid || pids == 0 {
t.Fatalf("Total running pids cannot be greater than %d or equals to 0", maxPid) 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 socketCurrentConnectionsDesc *prometheus.Desc
socketRefusedConnectionsDesc *prometheus.Desc socketRefusedConnectionsDesc *prometheus.Desc
systemdVersionDesc *prometheus.Desc systemdVersionDesc *prometheus.Desc
virtualizationDesc *prometheus.Desc
// Use regexps for more flexibility than device_filter.go allows // Use regexps for more flexibility than device_filter.go allows
systemdUnitIncludePattern *regexp.Regexp systemdUnitIncludePattern *regexp.Regexp
systemdUnitExcludePattern *regexp.Regexp systemdUnitExcludePattern *regexp.Regexp
@ -133,9 +132,6 @@ func NewSystemdCollector(logger *slog.Logger) (Collector, error) {
systemdVersionDesc := prometheus.NewDesc( systemdVersionDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "version"), prometheus.BuildFQName(namespace, subsystem, "version"),
"Detected systemd version", []string{"version"}, nil) "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 *oldSystemdUnitExclude != "" {
if !systemdUnitExcludeSet { if !systemdUnitExcludeSet {
@ -171,7 +167,6 @@ func NewSystemdCollector(logger *slog.Logger) (Collector, error) {
socketCurrentConnectionsDesc: socketCurrentConnectionsDesc, socketCurrentConnectionsDesc: socketCurrentConnectionsDesc,
socketRefusedConnectionsDesc: socketRefusedConnectionsDesc, socketRefusedConnectionsDesc: socketRefusedConnectionsDesc,
systemdVersionDesc: systemdVersionDesc, systemdVersionDesc: systemdVersionDesc,
virtualizationDesc: virtualizationDesc,
systemdUnitIncludePattern: systemdUnitIncludePattern, systemdUnitIncludePattern: systemdUnitIncludePattern,
systemdUnitExcludePattern: systemdUnitExcludePattern, systemdUnitExcludePattern: systemdUnitExcludePattern,
logger: logger, logger: logger,
@ -199,14 +194,6 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error {
systemdVersionFull, systemdVersionFull,
) )
systemdVirtualization := c.getSystemdVirtualization(conn)
ch <- prometheus.MustNewConstMetric(
c.virtualizationDesc,
prometheus.GaugeValue,
1.0,
systemdVirtualization,
)
allUnits, err := c.getAllUnits(conn) allUnits, err := c.getAllUnits(conn)
if err != nil { if err != nil {
return fmt.Errorf("couldn't get units: %w", err) 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) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
begin := time.Now() begin = time.Now()
c.collectUnitStatusMetrics(conn, ch, units) c.collectUnitStatusMetrics(conn, ch, units)
c.logger.Debug("collectUnitStatusMetrics took", "duration_seconds", time.Since(begin).Seconds()) 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) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
begin := time.Now() begin = time.Now()
c.collectUnitStartTimeMetrics(conn, ch, units) c.collectUnitStartTimeMetrics(conn, ch, units)
c.logger.Debug("collectUnitStartTimeMetrics took", "duration_seconds", time.Since(begin).Seconds()) 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) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
begin := time.Now() begin = time.Now()
c.collectUnitTasksMetrics(conn, ch, units) c.collectUnitTasksMetrics(conn, ch, units)
c.logger.Debug("collectUnitTasksMetrics took", "duration_seconds", time.Since(begin).Seconds()) 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) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
begin := time.Now() begin = time.Now()
c.collectTimers(conn, ch, units) c.collectTimers(conn, ch, units)
c.logger.Debug("collectTimers took", "duration_seconds", time.Since(begin).Seconds()) 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) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
begin := time.Now() begin = time.Now()
c.collectSockets(conn, ch, units) c.collectSockets(conn, ch, units)
c.logger.Debug("collectSockets took", "duration_seconds", time.Since(begin).Seconds()) c.logger.Debug("collectSockets took", "duration_seconds", time.Since(begin).Seconds())
}() }()
if systemdVersion >= minSystemdVersionSystemState { if systemdVersion >= minSystemdVersionSystemState {
begin := time.Now() begin = time.Now()
err = c.collectSystemState(conn, ch) err = c.collectSystemState(conn, ch)
c.logger.Debug("collectSystemState took", "duration_seconds", time.Since(begin).Seconds()) 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 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]) summary := summarizeUnits(fixtures[0])
for _, state := range unitStatesName { for _, state := range unitStatesName {
switch state { if state == "inactive" {
case "inactive":
testSummaryHelper(t, state, summary[state], 3.0) testSummaryHelper(t, state, summary[state], 3.0)
case "active": } else if state == "active" {
testSummaryHelper(t, state, summary[state], 1.0) testSummaryHelper(t, state, summary[state], 1.0)
default: } else {
testSummaryHelper(t, state, summary[state], 0.0) testSummaryHelper(t, state, summary[state], 0.0)
} }
} }

View file

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

View file

@ -13,11 +13,6 @@
package utils package utils
import (
"bytes"
"strings"
)
func SafeDereference[T any](s ...*T) []T { func SafeDereference[T any](s ...*T) []T {
var resolved []T var resolved []T
for _, v := range s { for _, v := range s {
@ -30,18 +25,3 @@ func SafeDereference[T any](s ...*T) []T {
} }
return resolved 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 { func (s zfsSysctl) metricName() string {
parts := strings.Split(string(s), ".") 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([ + dashboard.withVariables([
datasource, datasource,
$._clusterVariable, $._clusterVariable,
variable.query.withDatasourceFromVariable(datasource)
+ variable.query.refresh.onTime()
+ variable.query.withSort(asc=true),
]) ])
+ dashboard.withPanels( + dashboard.withPanels(
grafana.util.grid.makeGrid([ grafana.util.grid.makeGrid([
@ -328,6 +331,9 @@ local diskSpaceUtilisation =
+ dashboard.withUid(std.md5('node-multicluster-rsrc-use.json')) + dashboard.withUid(std.md5('node-multicluster-rsrc-use.json'))
+ dashboard.withVariables([ + dashboard.withVariables([
datasource, datasource,
variable.query.withDatasourceFromVariable(datasource)
+ variable.query.refresh.onTime()
+ variable.query.withSort(asc=true),
]) ])
+ dashboard.withPanels( + dashboard.withPanels(
grafana.util.grid.makeGrid([ grafana.util.grid.makeGrid([

View file

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

39
go.mod
View file

@ -1,6 +1,6 @@
module github.com/prometheus/node_exporter module github.com/prometheus/node_exporter
go 1.23.0 go 1.22.0
require ( require (
github.com/alecthomas/kingpin/v2 v2.4.0 github.com/alecthomas/kingpin/v2 v2.4.0
@ -13,23 +13,23 @@ require (
github.com/hodgesds/perf-utils v0.7.0 github.com/hodgesds/perf-utils v0.7.0
github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973 github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973
github.com/josharian/native v1.1.0 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/lufia/iostat v1.2.1
github.com/mattn/go-xmlrpc v0.0.3 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/netlink v1.7.2
github.com/mdlayher/wifi v0.6.0 github.com/mdlayher/wifi v0.3.1
github.com/opencontainers/selinux v1.12.0 github.com/opencontainers/selinux v1.11.1
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55
github.com/prometheus-community/go-runit v0.1.0 github.com/prometheus-community/go-runit v0.1.0
github.com/prometheus/client_golang v1.23.0 github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_model v0.6.2 github.com/prometheus/client_model v0.6.1
github.com/prometheus/common v0.65.0 github.com/prometheus/common v0.62.0
github.com/prometheus/exporter-toolkit v0.14.0 github.com/prometheus/exporter-toolkit v0.14.0
github.com/prometheus/procfs v0.17.0 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.6.2 github.com/safchain/ethtool v0.5.10
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 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 howett.net/plist v1.0.1
) )
@ -38,8 +38,9 @@ require (
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dennwc/ioctl v1.0.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/jpillora/backoff v1.0.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect
github.com/mdlayher/socket v0.4.1 // indirect github.com/mdlayher/socket v0.4.1 // indirect
@ -50,11 +51,13 @@ require (
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
go.uber.org/atomic v1.7.0 // indirect go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.39.0 // indirect golang.org/x/crypto v0.32.0 // indirect
golang.org/x/net v0.40.0 // indirect golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.15.0 // indirect golang.org/x/sync v0.10.0 // indirect
golang.org/x/text v0.26.0 // indirect golang.org/x/text v0.21.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // 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/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 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4=
github.com/cilium/ebpf v0.19.0/go.mod h1:fLCgMo3l8tZmAdM3B2XqdFzXBpwkcSTroaVqN08OWVY= 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 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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= 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.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 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 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 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY=
github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc=
github.com/hodgesds/perf-utils v0.7.0 h1:7KlHGMuig4FRH5fNw68PV6xLmgTe7jKs9hgAcEAbioU= 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/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 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 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.2 h1:ZKlbCujrIpp4/u3V2Ka0oxlf4BCkt6ojkvpy3nZoCBY=
github.com/jsimonetti/rtnetlink/v2 v2.0.5/go.mod h1:9yTlq3Ojr1rbmh/Y5L30/KIojpFhTRph2xKeZ+y+Pic= github.com/jsimonetti/rtnetlink/v2 v2.0.2/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 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 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 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/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 h1:Y6WEMLEsqs3RviBrAa1/7qmbGB7DVD3brZIbqMbQdGY=
github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA= 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.2.0 h1:akcA4WZVWozzirPASeMq8qgLkxpF3ykftVXwnrMKrhY=
github.com/mdlayher/ethtool v0.4.0/go.mod h1:GrljOneAFOTPGazYlf8qpxvYLdu4mo3pdJqXWLZ2Re8= 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 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= 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/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 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= 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.3.1 h1:bZDuMI1f7z5BtUUO3NgHRdR/R88YtywIe6dsEFI0Txs=
github.com/mdlayher/wifi v0.6.0/go.mod h1:qwcTzRuC2bV+s4PFhGMzPi0sFHAr2jXkUSumSMIU6+4= 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 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 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 h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 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.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jDMcgULaH8=
github.com/opencontainers/selinux v1.12.0/go.mod h1:BTPX+bjVbWGXw7ZZWUbdENt8w0htPSrlgOOysQaU62U= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 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 h1:uTWEj/Fn2RoLdfg/etSqwzgYNOYPrARx1BHUN052tGA=
github.com/prometheus-community/go-runit v0.1.0/go.mod h1:AvJ9Jo3gAFu2lbM4+qfjdpq30FfiLDJZKbQ015u08IQ= 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.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= 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 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg=
github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA= 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.15.2-0.20240603130017-1754b780536b h1:4EJkx3vycI+n5JY5ht+bnSUGamkmmXkpcNeO/OBT/0A=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= 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 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= 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.5.10 h1:Im294gZtuf4pSGJRAOGKaASNi3wMeFaGaWuSaomedpc=
github.com/safchain/ethtool v0.6.2/go.mod h1:VS7cn+bP3Px3rIq55xImBiZGHVLNyBh5dqG6dDQy8+I= 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 h1:GfSdC6wKfTGcgCS7BtzF5694Amne1pGCSTY252WhlEY=
github.com/siebenmann/go-kstat v0.0.0-20210513183136-173c9b0a9973/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8= 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= 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= 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 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 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 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 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.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= 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 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= 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.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 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-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.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 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 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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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 { if err != nil {
h.logger.Warn("Couldn't create filtered metrics handler:", "err", err) h.logger.Warn("Couldn't create filtered metrics handler:", "err", err)
w.WriteHeader(http.StatusBadRequest) 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 return
} }
filteredHandler.ServeHTTP(w, r) filteredHandler.ServeHTTP(w, r)