From 37d49746bc012054ecdf3438a5e49ebaa4eeba12 Mon Sep 17 00:00:00 2001 From: Haoyu Sun Date: Fri, 17 Feb 2023 18:47:40 +0100 Subject: [PATCH] Remove metrics of offline CPUs in CPU collector Signed-off-by: Haoyu Sun --- CHANGELOG.md | 4 +- collector/cpu_linux.go | 10 +++++ collector/cpu_linux_test.go | 85 +++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 + 5 files changed, 101 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31abbbfb..aa5ee7bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ * [ENHANCEMENT] * [BUGFIX] +* [BUGFIX] Remove metrics of offline CPUs in CPU collector #2605 + ## 1.5.0 / 2022-11-29 NOTE: This changes the Go runtime "GOMAXPROCS" to 1. This is done to limit the @@ -139,7 +141,7 @@ NOTE: Filesystem collector flags have been renamed. `--collector.filesystem.igno * [BUGFIX] Fix wrong value for OpenBSD memory buffer cache #2015 * [BUGFIX] Only initiate collectors once #2048 * [BUGFIX] Handle small backwards jumps in CPU idle #2067 - + ## 1.1.2 / 2021-03-05 * [BUGFIX] Handle errors from disabled PSI subsystem #1983 diff --git a/collector/cpu_linux.go b/collector/cpu_linux.go index e16764d4..c323ec14 100644 --- a/collector/cpu_linux.go +++ b/collector/cpu_linux.go @@ -29,6 +29,8 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs" "github.com/prometheus/procfs/sysfs" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" "gopkg.in/alecthomas/kingpin.v2" ) @@ -424,4 +426,12 @@ func (c *cpuCollector) updateCPUStats(newStats map[int64]procfs.CPUStat) { c.cpuStats[i] = cpuStats } + + // Remove offline CPUs. + if len(newStats) != len(c.cpuStats) { + onlineCPUIds := maps.Keys(newStats) + maps.DeleteFunc(c.cpuStats, func(key int64, item procfs.CPUStat) bool { + return !slices.Contains(onlineCPUIds, key) + }) + } } diff --git a/collector/cpu_linux_test.go b/collector/cpu_linux_test.go index 586087f3..b148ffcd 100644 --- a/collector/cpu_linux_test.go +++ b/collector/cpu_linux_test.go @@ -115,3 +115,88 @@ func TestCPU(t *testing.T) { t.Fatalf("should have %v CPU Stat: got %v", resetIdle, got) } } + +func TestCPUOffline(t *testing.T) { + // CPU 1 goes offline. + firstCPUStat := map[int64]procfs.CPUStat{ + 0: { + User: 100.0, + Nice: 100.0, + System: 100.0, + Idle: 100.0, + Iowait: 100.0, + IRQ: 100.0, + SoftIRQ: 100.0, + Steal: 100.0, + Guest: 100.0, + GuestNice: 100.0, + }, + 1: { + User: 101.0, + Nice: 101.0, + System: 101.0, + Idle: 101.0, + Iowait: 101.0, + IRQ: 101.0, + SoftIRQ: 101.0, + Steal: 101.0, + Guest: 101.0, + GuestNice: 101.0, + }, + } + + c := makeTestCPUCollector(firstCPUStat) + want := map[int64]procfs.CPUStat{ + 0: { + User: 100.0, + Nice: 100.0, + System: 100.0, + Idle: 100.0, + Iowait: 100.0, + IRQ: 100.0, + SoftIRQ: 100.0, + Steal: 100.0, + Guest: 100.0, + GuestNice: 100.0, + }, + } + c.updateCPUStats(want) + got := c.cpuStats + if !reflect.DeepEqual(want, got) { + t.Fatalf("should have %v CPU Stat: got %v", want, got) + } + + // CPU 1 comes back online. + want = map[int64]procfs.CPUStat{ + 0: { + User: 100.0, + Nice: 100.0, + System: 100.0, + Idle: 100.0, + Iowait: 100.0, + IRQ: 100.0, + SoftIRQ: 100.0, + Steal: 100.0, + Guest: 100.0, + GuestNice: 100.0, + }, + 1: { + User: 101.0, + Nice: 101.0, + System: 101.0, + Idle: 101.0, + Iowait: 101.0, + IRQ: 101.0, + SoftIRQ: 101.0, + Steal: 101.0, + Guest: 101.0, + GuestNice: 101.0, + }, + } + c.updateCPUStats(want) + got = c.cpuStats + if !reflect.DeepEqual(want, got) { + t.Fatalf("should have %v CPU Stat: got %v", want, got) + } + +} diff --git a/go.mod b/go.mod index 93fc7ccc..b0ed690b 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( github.com/prometheus/procfs v0.9.0 github.com/safchain/ethtool v0.2.0 github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a + golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb golang.org/x/sys v0.5.0 gopkg.in/alecthomas/kingpin.v2 v2.2.6 ) diff --git a/go.sum b/go.sum index dda6e32a..d1fce499 100644 --- a/go.sum +++ b/go.sum @@ -116,6 +116,8 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg= golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w= +golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=