feat(inputs.cgroup): Support more cgroup v2 formats (#16474)

This commit is contained in:
Vlad Panazan 2025-02-24 16:18:44 +01:00 committed by GitHub
parent 1eeabf9c97
commit c505caf6e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 528 additions and 4 deletions

View File

@ -4,6 +4,7 @@ package cgroup
import (
"fmt"
"math"
"os"
"path"
"path/filepath"
@ -29,7 +30,6 @@ func (g *CGroup) Gather(acc telegraf.Accumulator) error {
acc.AddError(err)
}
}
return nil
}
@ -175,7 +175,7 @@ type fileFormat struct {
}
const keyPattern = "[[:alnum:]:_.]+"
const valuePattern = "[\\d-]+"
const valuePattern = "(?:max|[\\d-\\.]+)"
var fileFormats = [...]fileFormat{
// VAL\n
@ -205,7 +205,7 @@ var fileFormats = [...]fileFormat{
// VAL0 VAL1 ...\n
{
name: "Space separated values",
pattern: "^(" + valuePattern + " )+\n$",
pattern: "^(" + valuePattern + " ?)+\n$",
parser: func(measurement string, fields map[string]interface{}, b []byte) {
re := regexp.MustCompile("(" + valuePattern + ")")
matches := re.FindAllStringSubmatch(string(b), -1)
@ -229,6 +229,46 @@ var fileFormats = [...]fileFormat{
}
},
},
// NAME0 KEY0=VAL0 ...\n
// NAME1 KEY1=VAL1 ...\n
// ...
{
name: "Equal sign separated key-value pairs, multiple lines with name",
pattern: fmt.Sprintf("^(%s( %s=%s)+\n)+$", keyPattern, keyPattern, valuePattern),
parser: func(measurement string, fields map[string]interface{}, b []byte) {
lines := strings.Split(string(b), "\n")
for _, line := range lines {
f := strings.Fields(line)
if len(f) == 0 {
continue
}
name := f[0]
for _, field := range f[1:] {
k, v, found := strings.Cut(field, "=")
if found {
fields[strings.Join([]string{measurement, name, k}, ".")] = numberOrString(v)
}
}
}
},
},
// KEY0=VAL0 KEY1=VAL1 ...\n
{
name: "Equal sign separated key-value pairs on a single line",
pattern: fmt.Sprintf("^(%s=%s ?)+\n$", keyPattern, valuePattern),
parser: func(measurement string, fields map[string]interface{}, b []byte) {
f := strings.Fields(string(b))
if len(f) == 0 {
return
}
for _, field := range f {
k, v, found := strings.Cut(field, "=")
if found {
fields[strings.Join([]string{measurement, k}, ".")] = numberOrString(v)
}
}
},
},
}
func numberOrString(s string) interface{} {
@ -236,6 +276,19 @@ func numberOrString(s string) interface{} {
if err == nil {
return i
}
if s == "max" {
return int64(math.MaxInt64)
}
// Care should be taken to always interpret each field as the same type on every cycle.
// *.pressure files follow the PSI format and contain numbers with fractional parts
// that always have a decimal separator, even when the fractional part is 0 (e.g., "0.00"),
// thus they will always be interpreted as floats.
// https://www.kernel.org/doc/Documentation/accounting/psi.txt
f, err := strconv.ParseFloat(s, 64)
if err == nil {
return f
}
return s
}

View File

@ -0,0 +1,327 @@
//go:build linux
package cgroup
import (
"math"
"testing"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
"github.com/influxdata/telegraf/testutil"
"github.com/stretchr/testify/require"
)
func TestCgroupV2Cpu(t *testing.T) {
var acc testutil.Accumulator
var cg = &CGroup{
Paths: []string{"testdata/v2"},
Files: []string{"cpu.*"},
logged: make(map[string]bool),
}
expected := []telegraf.Metric{
metric.New(
"cgroup",
map[string]string{"path": `testdata/v2`},
map[string]interface{}{
"cpu.idle": int64(0),
"cpu.max.0": int64(4800000),
"cpu.max.1": int64(100000),
"cpu.max.burst": int64(0),
"cpu.pressure.full.avg10": float64(0),
"cpu.pressure.full.avg300": float64(0.05),
"cpu.pressure.full.avg60": float64(0.08),
"cpu.pressure.full.total": int64(277111656),
"cpu.pressure.some.avg10": float64(0),
"cpu.pressure.some.avg300": float64(0.06),
"cpu.pressure.some.avg60": float64(0.08),
"cpu.pressure.some.total": int64(293391454),
"cpu.stat.burst_usec": int64(0),
"cpu.stat.core_sched.force_idle_usec": int64(0),
"cpu.stat.nr_bursts": int64(0),
"cpu.stat.nr_periods": int64(3936904),
"cpu.stat.nr_throttled": int64(6004),
"cpu.stat.system_usec": int64(37345608977),
"cpu.stat.throttled_usec": int64(19175137007),
"cpu.stat.usage_usec": int64(98701325189),
"cpu.stat.user_usec": int64(61355716211),
"cpu.weight": int64(79),
"cpu.weight.nice": int64(1),
},
time.Unix(0, 0),
),
}
require.NoError(t, acc.GatherError(cg.Gather))
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
}
func TestCgroupV2Memory(t *testing.T) {
var acc testutil.Accumulator
var cg = &CGroup{
Paths: []string{"testdata/v2"},
Files: []string{"memory.*"},
logged: make(map[string]bool),
}
expected := []telegraf.Metric{
metric.New(
"cgroup",
map[string]string{"path": `testdata/v2`},
map[string]interface{}{
"memory.current": int64(13071106048),
"memory.events.high": int64(0),
"memory.events.local.high": int64(0),
"memory.events.local.low": int64(0),
"memory.events.local.max": int64(0),
"memory.events.local.oom": int64(0),
"memory.events.local.oom_group_kill": int64(0),
"memory.events.local.oom_kill": int64(0),
"memory.events.low": int64(0),
"memory.events.max": int64(0),
"memory.events.oom": int64(0),
"memory.events.oom_group_kill": int64(0),
"memory.events.oom_kill": int64(0),
"memory.high": int64(math.MaxInt64),
"memory.low": int64(0),
"memory.max": int64(103079215104),
"memory.min": int64(0),
"memory.numa_stat.active_anon.N0": int64(81920),
"memory.numa_stat.active_anon.N1": int64(98304),
"memory.numa_stat.active_file.N0": int64(2946760704),
"memory.numa_stat.active_file.N1": int64(2650640384),
"memory.numa_stat.anon.N0": int64(1330585600),
"memory.numa_stat.anon.N1": int64(1141161984),
"memory.numa_stat.anon_thp.N0": int64(0),
"memory.numa_stat.anon_thp.N1": int64(2097152),
"memory.numa_stat.file.N0": int64(4531773440),
"memory.numa_stat.file.N1": int64(4001075200),
"memory.numa_stat.file_dirty.N0": int64(258048),
"memory.numa_stat.file_dirty.N1": int64(45056),
"memory.numa_stat.file_mapped.N0": int64(10272768),
"memory.numa_stat.file_mapped.N1": int64(3940352),
"memory.numa_stat.file_thp.N0": int64(0),
"memory.numa_stat.file_thp.N1": int64(0),
"memory.numa_stat.file_writeback.N0": int64(0),
"memory.numa_stat.file_writeback.N1": int64(0),
"memory.numa_stat.inactive_anon.N0": int64(1330479104),
"memory.numa_stat.inactive_anon.N1": int64(1141067776),
"memory.numa_stat.inactive_file.N0": int64(1584979968),
"memory.numa_stat.inactive_file.N1": int64(1350430720),
"memory.numa_stat.kernel_stack.N0": int64(4161536),
"memory.numa_stat.kernel_stack.N1": int64(5537792),
"memory.numa_stat.pagetables.N0": int64(7839744),
"memory.numa_stat.pagetables.N1": int64(8462336),
"memory.numa_stat.sec_pagetables.N0": int64(0),
"memory.numa_stat.sec_pagetables.N1": int64(0),
"memory.numa_stat.shmem.N0": int64(0),
"memory.numa_stat.shmem.N1": int64(4096),
"memory.numa_stat.shmem_thp.N0": int64(0),
"memory.numa_stat.shmem_thp.N1": int64(0),
"memory.numa_stat.slab_reclaimable.N0": int64(950447920),
"memory.numa_stat.slab_reclaimable.N1": int64(1081869088),
"memory.numa_stat.slab_unreclaimable.N0": int64(2654816),
"memory.numa_stat.slab_unreclaimable.N1": int64(2661512),
"memory.numa_stat.swapcached.N0": int64(0),
"memory.numa_stat.swapcached.N1": int64(0),
"memory.numa_stat.unevictable.N0": int64(0),
"memory.numa_stat.unevictable.N1": int64(0),
"memory.numa_stat.workingset_activate_anon.N0": int64(0),
"memory.numa_stat.workingset_activate_anon.N1": int64(0),
"memory.numa_stat.workingset_activate_file.N0": int64(40145),
"memory.numa_stat.workingset_activate_file.N1": int64(65541),
"memory.numa_stat.workingset_nodereclaim.N0": int64(0),
"memory.numa_stat.workingset_nodereclaim.N1": int64(0),
"memory.numa_stat.workingset_refault_anon.N0": int64(0),
"memory.numa_stat.workingset_refault_anon.N1": int64(0),
"memory.numa_stat.workingset_refault_file.N0": int64(346752),
"memory.numa_stat.workingset_refault_file.N1": int64(282604),
"memory.numa_stat.workingset_restore_anon.N0": int64(0),
"memory.numa_stat.workingset_restore_anon.N1": int64(0),
"memory.numa_stat.workingset_restore_file.N0": int64(19386),
"memory.numa_stat.workingset_restore_file.N1": int64(10010),
"memory.oom.group": int64(1),
"memory.peak": int64(87302021120),
"memory.pressure.full.avg10": float64(0),
"memory.pressure.full.avg300": float64(0),
"memory.pressure.full.avg60": float64(0),
"memory.pressure.full.total": int64(250662),
"memory.pressure.some.avg10": float64(0),
"memory.pressure.some.avg300": float64(0),
"memory.pressure.some.avg60": float64(0),
"memory.pressure.some.total": int64(250773),
"memory.stat.active_anon": int64(180224),
"memory.stat.active_file": int64(5597401088),
"memory.stat.anon": int64(2471755776),
"memory.stat.anon_thp": int64(2097152),
"memory.stat.file": int64(8532865024),
"memory.stat.file_dirty": int64(319488),
"memory.stat.file_mapped": int64(14213120),
"memory.stat.file_thp": int64(0),
"memory.stat.file_writeback": int64(0),
"memory.stat.inactive_anon": int64(2471559168),
"memory.stat.inactive_file": int64(2935459840),
"memory.stat.kernel": int64(2065149952),
"memory.stat.kernel_stack": int64(9699328),
"memory.stat.pagetables": int64(16302080),
"memory.stat.percpu": int64(3528),
"memory.stat.pgactivate": int64(13516655),
"memory.stat.pgdeactivate": int64(9151751),
"memory.stat.pgfault": int64(1973187551),
"memory.stat.pglazyfree": int64(5549),
"memory.stat.pglazyfreed": int64(1),
"memory.stat.pgmajfault": int64(8497),
"memory.stat.pgrefill": int64(9153617),
"memory.stat.pgscan": int64(12149209),
"memory.stat.pgscan_direct": int64(4436521),
"memory.stat.pgscan_kswapd": int64(7712688),
"memory.stat.pgsteal": int64(12139915),
"memory.stat.pgsteal_direct": int64(4429690),
"memory.stat.pgsteal_kswapd": int64(7710225),
"memory.stat.sec_pagetables": int64(0),
"memory.stat.shmem": int64(4096),
"memory.stat.shmem_thp": int64(0),
"memory.stat.slab": int64(2037641160),
"memory.stat.slab_reclaimable": int64(2032322192),
"memory.stat.slab_unreclaimable": int64(5318968),
"memory.stat.sock": int64(0),
"memory.stat.swapcached": int64(0),
"memory.stat.thp_collapse_alloc": int64(3),
"memory.stat.thp_fault_alloc": int64(13),
"memory.stat.unevictable": int64(0),
"memory.stat.vmalloc": int64(0),
"memory.stat.workingset_activate_anon": int64(0),
"memory.stat.workingset_activate_file": int64(105686),
"memory.stat.workingset_nodereclaim": int64(0),
"memory.stat.workingset_refault_anon": int64(0),
"memory.stat.workingset_refault_file": int64(629356),
"memory.stat.workingset_restore_anon": int64(0),
"memory.stat.workingset_restore_file": int64(29396),
"memory.swap.current": int64(0),
"memory.swap.events.fail": int64(0),
"memory.swap.events.high": int64(0),
"memory.swap.events.max": int64(0),
"memory.swap.high": int64(math.MaxInt64),
"memory.swap.max": int64(0),
},
time.Unix(0, 0),
),
}
require.NoError(t, acc.GatherError(cg.Gather))
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
}
func TestCgroupV2Io(t *testing.T) {
var acc testutil.Accumulator
var cg = &CGroup{
Paths: []string{"testdata/v2"},
Files: []string{"io.*"},
logged: make(map[string]bool),
}
expected := []telegraf.Metric{
metric.New(
"cgroup",
map[string]string{"path": `testdata/v2`},
map[string]interface{}{
"io.bfq.weight.default": int64(100),
"io.pressure.full.avg10": float64(0),
"io.pressure.full.avg300": float64(0),
"io.pressure.full.avg60": float64(0),
"io.pressure.full.total": 184607952,
"io.pressure.some.avg10": float64(0),
"io.pressure.some.avg300": float64(0),
"io.pressure.some.avg60": float64(0),
"io.pressure.some.total": 185162400,
"io.stat.259:8.dbytes": int64(0),
"io.stat.259:8.dios": int64(0),
"io.stat.259:8.rbytes": int64(74526720),
"io.stat.259:8.rios": int64(2936),
"io.stat.259:8.wbytes": int64(3789381632),
"io.stat.259:8.wios": int64(181928),
},
time.Unix(0, 0),
),
}
require.NoError(t, acc.GatherError(cg.Gather))
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
}
func TestCgroupV2Hugetlb(t *testing.T) {
var acc testutil.Accumulator
var cg = &CGroup{
Paths: []string{"testdata/v2"},
Files: []string{"hugetlb.*"},
logged: make(map[string]bool),
}
expected := []telegraf.Metric{
metric.New(
"cgroup",
map[string]string{"path": `testdata/v2`},
map[string]interface{}{
"hugetlb.1GB.current": int64(0),
"hugetlb.1GB.events.0": int64(math.MaxInt64),
"hugetlb.1GB.events.1": int64(0),
"hugetlb.1GB.events.local.0": int64(math.MaxInt64),
"hugetlb.1GB.events.local.1": int64(0),
"hugetlb.1GB.max": int64(math.MaxInt64),
"hugetlb.1GB.numa_stat.N0": int64(0),
"hugetlb.1GB.numa_stat.N1": int64(0),
"hugetlb.1GB.numa_stat.total": int64(0),
"hugetlb.1GB.rsvd.current": int64(0),
"hugetlb.1GB.rsvd.max": int64(math.MaxInt64),
"hugetlb.2MB.current": int64(0),
"hugetlb.2MB.events.0": int64(math.MaxInt64),
"hugetlb.2MB.events.1": int64(0),
"hugetlb.2MB.events.local.0": int64(math.MaxInt64),
"hugetlb.2MB.events.local.1": int64(0),
"hugetlb.2MB.max": int64(math.MaxInt64),
"hugetlb.2MB.numa_stat.N0": int64(0),
"hugetlb.2MB.numa_stat.N1": int64(0),
"hugetlb.2MB.numa_stat.total": int64(0),
"hugetlb.2MB.rsvd.current": int64(0),
"hugetlb.2MB.rsvd.max": int64(math.MaxInt64),
},
time.Unix(0, 0),
),
}
require.NoError(t, acc.GatherError(cg.Gather))
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
}
func TestCgroupV2Pids(t *testing.T) {
var acc testutil.Accumulator
var cg = &CGroup{
Paths: []string{"testdata/v2"},
Files: []string{"pids.*"},
logged: make(map[string]bool),
}
expected := []telegraf.Metric{
metric.New(
"cgroup",
map[string]string{"path": `testdata/v2`},
map[string]interface{}{
"pids.current": int64(592),
"pids.events.0": int64(math.MaxInt64),
"pids.events.1": int64(0),
"pids.max": int64(629145),
"pids.peak": int64(2438),
},
time.Unix(0, 0),
),
}
require.NoError(t, acc.GatherError(cg.Gather))
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
}

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1 @@
4800000 100000

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,2 @@
some avg10=0.00 avg60=0.08 avg300=0.06 total=293391454
full avg10=0.00 avg60=0.08 avg300=0.05 total=277111656

View File

@ -0,0 +1,9 @@
usage_usec 98701325189
user_usec 61355716211
system_usec 37345608977
core_sched.force_idle_usec 0
nr_periods 3936904
nr_throttled 6004
throttled_usec 19175137007
nr_bursts 0
burst_usec 0

View File

@ -0,0 +1 @@
79

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
0-95

View File

@ -0,0 +1 @@
member

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
0-1

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1 @@
max 0

View File

@ -0,0 +1 @@
max 0

View File

@ -0,0 +1 @@
max

View File

@ -0,0 +1 @@
total=0 N0=0 N1=0

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1 @@
max

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1 @@
max 0

View File

@ -0,0 +1 @@
max 0

View File

@ -0,0 +1 @@
max

View File

@ -0,0 +1 @@
total=0 N0=0 N1=0

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1 @@
max

View File

@ -0,0 +1 @@
default 100

View File

View File

@ -0,0 +1,2 @@
some avg10=0.00 avg60=0.00 avg300=0.00 total=185162400
full avg10=0.00 avg60=0.00 avg300=0.00 total=184607952

View File

@ -0,0 +1 @@
259:8 rbytes=74526720 wbytes=3789381632 rios=2936 wios=181928 dbytes=0 dios=0

View File

@ -0,0 +1 @@
13071106048

View File

@ -0,0 +1,6 @@
low 0
high 0
max 0
oom 0
oom_kill 0
oom_group_kill 0

View File

@ -0,0 +1,6 @@
low 0
high 0
max 0
oom 0
oom_kill 0
oom_group_kill 0

View File

@ -0,0 +1 @@
max

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1 @@
103079215104

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,27 @@
anon N0=1330585600 N1=1141161984
file N0=4531773440 N1=4001075200
kernel_stack N0=4161536 N1=5537792
pagetables N0=7839744 N1=8462336
sec_pagetables N0=0 N1=0
shmem N0=0 N1=4096
file_mapped N0=10272768 N1=3940352
file_dirty N0=258048 N1=45056
file_writeback N0=0 N1=0
swapcached N0=0 N1=0
anon_thp N0=0 N1=2097152
file_thp N0=0 N1=0
shmem_thp N0=0 N1=0
inactive_anon N0=1330479104 N1=1141067776
active_anon N0=81920 N1=98304
inactive_file N0=1584979968 N1=1350430720
active_file N0=2946760704 N1=2650640384
unevictable N0=0 N1=0
slab_reclaimable N0=950447920 N1=1081869088
slab_unreclaimable N0=2654816 N1=2661512
workingset_refault_anon N0=0 N1=0
workingset_refault_file N0=346752 N1=282604
workingset_activate_anon N0=0 N1=0
workingset_activate_file N0=40145 N1=65541
workingset_restore_anon N0=0 N1=0
workingset_restore_file N0=19386 N1=10010
workingset_nodereclaim N0=0 N1=0

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1 @@
87302021120

View File

@ -0,0 +1,2 @@
some avg10=0.00 avg60=0.00 avg300=0.00 total=250773
full avg10=0.00 avg60=0.00 avg300=0.00 total=250662

View File

View File

@ -0,0 +1,47 @@
anon 2471755776
file 8532865024
kernel 2065149952
kernel_stack 9699328
pagetables 16302080
sec_pagetables 0
percpu 3528
sock 0
vmalloc 0
shmem 4096
file_mapped 14213120
file_dirty 319488
file_writeback 0
swapcached 0
anon_thp 2097152
file_thp 0
shmem_thp 0
inactive_anon 2471559168
active_anon 180224
inactive_file 2935459840
active_file 5597401088
unevictable 0
slab_reclaimable 2032322192
slab_unreclaimable 5318968
slab 2037641160
workingset_refault_anon 0
workingset_refault_file 629356
workingset_activate_anon 0
workingset_activate_file 105686
workingset_restore_anon 0
workingset_restore_file 29396
workingset_nodereclaim 0
pgscan 12149209
pgsteal 12139915
pgscan_kswapd 7712688
pgscan_direct 4436521
pgsteal_kswapd 7710225
pgsteal_direct 4429690
pgfault 1973187551
pgmajfault 8497
pgrefill 9153617
pgactivate 13516655
pgdeactivate 9151751
pglazyfree 5549
pglazyfreed 1
thp_fault_alloc 13
thp_collapse_alloc 3

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,3 @@
high 0
max 0
fail 0

View File

@ -0,0 +1 @@
max

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1 @@
592

View File

@ -0,0 +1 @@
max 0

View File

@ -0,0 +1 @@
629145

View File

@ -0,0 +1 @@
2438