From cd694dbdb944a697ea88c73660af4cce5c7c34ec Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Thu, 11 Dec 2025 15:45:17 +0100 Subject: [PATCH 1/3] fix(cgroup): avoid early return when cpu.pressure file is missing When cpu.pressure file doesn't exist, the code was returning early, skipping the remaining CPU stats retrieval. Now it clears the error and continues execution to properly fetch all available stats. --- metric/system/cgroup/cgv2/cpu.go | 2 +- metric/system/cgroup/cgv2/v2_test.go | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/metric/system/cgroup/cgv2/cpu.go b/metric/system/cgroup/cgv2/cpu.go index cca193a513..a21ccdf99c 100644 --- a/metric/system/cgroup/cgv2/cpu.go +++ b/metric/system/cgroup/cgv2/cpu.go @@ -66,7 +66,7 @@ func (cpu *CPUSubsystem) Get(path string) error { cpu.Pressure, err = cgcommon.GetPressure(filepath.Join(path, "cpu.pressure")) // Not all systems have pressure stats. Treat this as a soft error. if os.IsNotExist(err) { - return nil + err = nil } if err != nil { return fmt.Errorf("error fetching Pressure data: %w", err) diff --git a/metric/system/cgroup/cgv2/v2_test.go b/metric/system/cgroup/cgv2/v2_test.go index f8237856c9..5f577af6db 100644 --- a/metric/system/cgroup/cgv2/v2_test.go +++ b/metric/system/cgroup/cgv2/v2_test.go @@ -24,7 +24,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/elastic/elastic-agent-system-metrics/metric/system/cgroup/cgcommon" "github.com/elastic/elastic-agent-system-metrics/metric/system/cgroup/testhelpers" ) @@ -196,8 +198,21 @@ func TestGetMem(t *testing.T) { func TestGetCPU(t *testing.T) { cpu := CPUSubsystem{} err := cpu.Get(v2Path) - assert.NoError(t, err, "error in Get") + require.NoError(t, err, "error in Get") assert.Equal(t, uint64(26772130245), cpu.Stats.Usage.NS) assert.Equal(t, uint64(5793060316), cpu.Stats.System.NS) } + +func TestGetCPUEmpty(t *testing.T) { + cpu := CPUSubsystem{} + err := cpu.Get(t.TempDir()) + require.NoError(t, err, "error in Get") + + assert.EqualValues(t, CPUSubsystem{ + ID: "", + Path: "", + Pressure: map[string]cgcommon.Pressure{}, + Stats: CPUStats{}, + }, cpu) +} From feb20d55cc70ea436b960fd35e63d36144ab4345 Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Fri, 16 Jan 2026 10:29:39 +0100 Subject: [PATCH 2/3] improve tests --- metric/system/cgroup/cgv2/v2_test.go | 111 ++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 18 deletions(-) diff --git a/metric/system/cgroup/cgv2/v2_test.go b/metric/system/cgroup/cgv2/v2_test.go index 80aedba4a6..d90952d926 100644 --- a/metric/system/cgroup/cgv2/v2_test.go +++ b/metric/system/cgroup/cgv2/v2_test.go @@ -21,6 +21,7 @@ package cgv2 import ( "os" + "path/filepath" "testing" "github.com/stretchr/testify/assert" @@ -264,23 +265,97 @@ func TestGetMemNoPressure(t *testing.T) { } func TestGetCPU(t *testing.T) { - cpu := CPUSubsystem{} - err := cpu.Get(v2Path) - require.NoError(t, err, "error in Get") - - assert.Equal(t, uint64(26772130245), cpu.Stats.Usage.NS) - assert.Equal(t, uint64(5793060316), cpu.Stats.System.NS) -} - -func TestGetCPUEmpty(t *testing.T) { - cpu := CPUSubsystem{} - err := cpu.Get(t.TempDir()) - require.NoError(t, err, "error in Get") + tests := []struct { + name string + setup func(t *testing.T) string + expected CPUSubsystem + }{ + { + name: "v2 path with pressure", + setup: func(t *testing.T) string { + return v2Path + }, + expected: CPUSubsystem{ + ID: "", + Path: "", + Pressure: map[string]cgcommon.Pressure{ + "some": { + Ten: opt.Pct{Pct: 4.30}, + Sixty: opt.Pct{Pct: 3.20}, + ThreeHundred: opt.Pct{Pct: 1.11}, + Total: opt.UintWith(1676316), + }, + }, + Stats: CPUStats{ + Usage: cgcommon.CPUUsage{ + NS: 26772130245, + }, + User: cgcommon.CPUUsage{ + NS: 20979069928, + }, + System: cgcommon.CPUUsage{ + NS: 5793060316, + }, + Periods: opt.UintWith(1), + Throttled: ThrottledField{ + Periods: opt.UintWith(4), + Us: opt.UintWith(10), + }, + }, + }, + }, + { + name: "empty directory", + setup: func(t *testing.T) string { + return t.TempDir() + }, + expected: CPUSubsystem{ + ID: "", + Path: "", + Pressure: map[string]cgcommon.Pressure{}, + Stats: CPUStats{}, + }, + }, + { + name: "cpu.stat only", + setup: func(t *testing.T) string { + b, err := os.ReadFile(filepath.Join(v2Path, "cpu.stat")) + require.NoError(t, err) + dir := t.TempDir() + err = os.WriteFile(filepath.Join(dir, "cpu.stat"), b, 0644) + require.NoError(t, err) + return dir + }, + expected: CPUSubsystem{ + ID: "", + Path: "", + Pressure: map[string]cgcommon.Pressure{}, + Stats: CPUStats{ + Usage: cgcommon.CPUUsage{ + NS: 26772130245, + }, + User: cgcommon.CPUUsage{ + NS: 20979069928, + }, + System: cgcommon.CPUUsage{ + NS: 5793060316, + }, + Periods: opt.UintWith(1), + Throttled: ThrottledField{ + Periods: opt.UintWith(4), + Us: opt.UintWith(10), + }, + }, + }, + }, + } - assert.EqualValues(t, CPUSubsystem{ - ID: "", - Path: "", - Pressure: map[string]cgcommon.Pressure{}, - Stats: CPUStats{}, - }, cpu) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + cpu := CPUSubsystem{} + err := cpu.Get(test.setup(t)) + require.NoError(t, err, "error in Get") + assert.EqualValues(t, test.expected, cpu) + }) + } } From 701006c24ddcdbf1dabd1e030dcb89037f2c8cc9 Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Fri, 16 Jan 2026 11:25:51 +0100 Subject: [PATCH 3/3] nitpick --- metric/system/cgroup/cgv2/v2_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metric/system/cgroup/cgv2/v2_test.go b/metric/system/cgroup/cgv2/v2_test.go index d90952d926..13ee43594c 100644 --- a/metric/system/cgroup/cgv2/v2_test.go +++ b/metric/system/cgroup/cgv2/v2_test.go @@ -272,7 +272,7 @@ func TestGetCPU(t *testing.T) { }{ { name: "v2 path with pressure", - setup: func(t *testing.T) string { + setup: func(*testing.T) string { return v2Path }, expected: CPUSubsystem{