Skip to content

Commit da5e7a5

Browse files
committed
collector/cpu: Support CPU online status
Blocked by: prometheus/procfs#644. Signed-off-by: Pranshu Srivastava <[email protected]>
1 parent 40b32e6 commit da5e7a5

File tree

3 files changed

+59
-16
lines changed

3 files changed

+59
-16
lines changed

collector/cpu_linux.go

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package collector
1818

1919
import (
20+
"errors"
2021
"fmt"
2122
"os"
2223
"path/filepath"
@@ -25,17 +26,19 @@ import (
2526
"strconv"
2627
"sync"
2728

29+
"golang.org/x/exp/maps"
30+
2831
"github.com/alecthomas/kingpin/v2"
2932
"github.com/go-kit/log"
3033
"github.com/go-kit/log/level"
3134
"github.com/prometheus/client_golang/prometheus"
3235
"github.com/prometheus/procfs"
3336
"github.com/prometheus/procfs/sysfs"
34-
"golang.org/x/exp/maps"
3537
)
3638

3739
type cpuCollector struct {
38-
fs procfs.FS
40+
procfs procfs.FS
41+
sysfs sysfs.FS
3942
cpu *prometheus.Desc
4043
cpuInfo *prometheus.Desc
4144
cpuFrequencyHz *prometheus.Desc
@@ -45,6 +48,7 @@ type cpuCollector struct {
4548
cpuCoreThrottle *prometheus.Desc
4649
cpuPackageThrottle *prometheus.Desc
4750
cpuIsolated *prometheus.Desc
51+
cpuOnline *prometheus.Desc
4852
logger log.Logger
4953
cpuStats map[int64]procfs.CPUStat
5054
cpuStatsMutex sync.Mutex
@@ -71,17 +75,17 @@ func init() {
7175

7276
// NewCPUCollector returns a new Collector exposing kernel/system statistics.
7377
func NewCPUCollector(logger log.Logger) (Collector, error) {
74-
fs, err := procfs.NewFS(*procPath)
78+
pfs, err := procfs.NewFS(*procPath)
7579
if err != nil {
7680
return nil, fmt.Errorf("failed to open procfs: %w", err)
7781
}
7882

79-
sysfs, err := sysfs.NewFS(*sysPath)
83+
sfs, err := sysfs.NewFS(*sysPath)
8084
if err != nil {
8185
return nil, fmt.Errorf("failed to open sysfs: %w", err)
8286
}
8387

84-
isolcpus, err := sysfs.IsolatedCPUs()
88+
isolcpus, err := sfs.IsolatedCPUs()
8589
if err != nil {
8690
if !os.IsNotExist(err) {
8791
return nil, fmt.Errorf("Unable to get isolated cpus: %w", err)
@@ -90,8 +94,9 @@ func NewCPUCollector(logger log.Logger) (Collector, error) {
9094
}
9195

9296
c := &cpuCollector{
93-
fs: fs,
94-
cpu: nodeCPUSecondsDesc,
97+
procfs: pfs,
98+
sysfs: sfs,
99+
cpu: nodeCPUSecondsDesc,
95100
cpuInfo: prometheus.NewDesc(
96101
prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "info"),
97102
"CPU information from /proc/cpuinfo.",
@@ -132,6 +137,11 @@ func NewCPUCollector(logger log.Logger) (Collector, error) {
132137
"Whether each core is isolated, information from /sys/devices/system/cpu/isolated.",
133138
[]string{"cpu"}, nil,
134139
),
140+
cpuOnline: prometheus.NewDesc(
141+
prometheus.BuildFQName(namespace, cpuCollectorSubsystem, "online"),
142+
"CPUs that are online and being scheduled.",
143+
[]string{"cpu"}, nil,
144+
),
135145
logger: logger,
136146
isolatedCpus: isolcpus,
137147
cpuStats: make(map[int64]procfs.CPUStat),
@@ -178,12 +188,21 @@ func (c *cpuCollector) Update(ch chan<- prometheus.Metric) error {
178188
if c.isolatedCpus != nil {
179189
c.updateIsolated(ch)
180190
}
181-
return c.updateThermalThrottle(ch)
191+
err := c.updateThermalThrottle(ch)
192+
if err != nil {
193+
return err
194+
}
195+
err = c.updateOnline(ch)
196+
if err != nil {
197+
return err
198+
}
199+
200+
return nil
182201
}
183202

184203
// updateInfo reads /proc/cpuinfo
185204
func (c *cpuCollector) updateInfo(ch chan<- prometheus.Metric) error {
186-
info, err := c.fs.CPUInfo()
205+
info, err := c.procfs.CPUInfo()
187206
if err != nil {
188207
return err
189208
}
@@ -334,9 +353,31 @@ func (c *cpuCollector) updateIsolated(ch chan<- prometheus.Metric) {
334353
}
335354
}
336355

356+
// updateOnline reads /sys/devices/system/cpu/cpu*/online through sysfs and exports online status metrics.
357+
func (c *cpuCollector) updateOnline(ch chan<- prometheus.Metric) error {
358+
cpus, err := c.sysfs.CPUs()
359+
if err != nil {
360+
return err
361+
}
362+
// No-op if the system does not support CPU online stats.
363+
cpu0 := cpus[0]
364+
if _, err := cpu0.Online(); err != nil && errors.Is(err, os.ErrNotExist) {
365+
return nil
366+
}
367+
for _, cpu := range cpus {
368+
setOnline := float64(0)
369+
if online, _ := cpu.Online(); online {
370+
setOnline = 1
371+
}
372+
ch <- prometheus.MustNewConstMetric(c.cpuOnline, prometheus.GaugeValue, setOnline, cpu.Number())
373+
}
374+
375+
return nil
376+
}
377+
337378
// updateStat reads /proc/stat through procfs and exports CPU-related metrics.
338379
func (c *cpuCollector) updateStat(ch chan<- prometheus.Metric) error {
339-
stats, err := c.fs.Stat()
380+
stats, err := c.procfs.Stat()
340381
if err != nil {
341382
return err
342383
}

go.mod

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ require (
2626
github.com/prometheus/client_model v0.6.1
2727
github.com/prometheus/common v0.53.0
2828
github.com/prometheus/exporter-toolkit v0.11.0
29-
github.com/prometheus/procfs v0.14.0
29+
github.com/prometheus/procfs v0.15.2-0.20240603130408-f360499722b3
3030
github.com/safchain/ethtool v0.3.0
3131
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
32-
golang.org/x/sys v0.19.0
32+
golang.org/x/sys v0.20.0
3333
howett.net/plist v1.0.1
3434
)
3535

@@ -59,3 +59,5 @@ require (
5959
google.golang.org/protobuf v1.33.0 // indirect
6060
gopkg.in/yaml.v2 v2.4.0 // indirect
6161
)
62+
63+
replace github.com/rexagod/procfs => ../procfs // https://github.com/prometheus/procfs/pull/644

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+a
8282
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
8383
github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g=
8484
github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q=
85-
github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s=
86-
github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ=
85+
github.com/prometheus/procfs v0.15.2-0.20240603130408-f360499722b3 h1:Lzv3yeJQBkCU7lqWhaN6nK9P0KBsDRzugFaahczEYJ8=
86+
github.com/prometheus/procfs v0.15.2-0.20240603130408-f360499722b3/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
8787
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
8888
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
8989
github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
@@ -116,8 +116,8 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
116116
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
117117
golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
118118
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
119-
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
120-
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
119+
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
120+
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
121121
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
122122
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
123123
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=

0 commit comments

Comments
 (0)