From a35e25cf3a6ddb35e77a11b450b831d8feae87d4 Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 27 Apr 2022 16:36:49 +0900 Subject: [PATCH 01/16] feat: add slab metrics input plugin --- etc/telegraf.conf | 3 + plugins/inputs/all/all.go | 1 + plugins/inputs/slab/README.md | 42 +++++++++++ plugins/inputs/slab/slab.go | 32 ++++++++ plugins/inputs/slab/slab_linux.go | 69 ++++++++++++++++++ plugins/inputs/slab/slab_notlinux.go | 15 ++++ plugins/inputs/slab/slab_sample_config.go | 8 ++ plugins/inputs/slab/slab_test.go | 89 +++++++++++++++++++++++ 8 files changed, 259 insertions(+) create mode 100644 plugins/inputs/slab/README.md create mode 100644 plugins/inputs/slab/slab.go create mode 100644 plugins/inputs/slab/slab_linux.go create mode 100644 plugins/inputs/slab/slab_notlinux.go create mode 100644 plugins/inputs/slab/slab_sample_config.go create mode 100644 plugins/inputs/slab/slab_test.go diff --git a/etc/telegraf.conf b/etc/telegraf.conf index 4dd4021759557..11a9a16f54639 100644 --- a/etc/telegraf.conf +++ b/etc/telegraf.conf @@ -6918,6 +6918,9 @@ # # key = "device_name" # # value = 'one_of("sda", "sdb")' +# # Get slab statistics from procfs +# [[inputs.slab]] +# # no configuration # # Get synproxy counter statistics from procfs # [[inputs.synproxy]] diff --git a/plugins/inputs/all/all.go b/plugins/inputs/all/all.go index d55bb98f18c76..549397d24d877 100644 --- a/plugins/inputs/all/all.go +++ b/plugins/inputs/all/all.go @@ -174,6 +174,7 @@ import ( _ "github.com/influxdata/telegraf/plugins/inputs/salesforce" _ "github.com/influxdata/telegraf/plugins/inputs/sensors" _ "github.com/influxdata/telegraf/plugins/inputs/sflow" + _ "github.com/influxdata/telegraf/plugins/inputs/slab" _ "github.com/influxdata/telegraf/plugins/inputs/smart" _ "github.com/influxdata/telegraf/plugins/inputs/snmp" _ "github.com/influxdata/telegraf/plugins/inputs/snmp_legacy" diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md new file mode 100644 index 0000000000000..f7e6b602ac6e9 --- /dev/null +++ b/plugins/inputs/slab/README.md @@ -0,0 +1,42 @@ +# Slab Input Plugin + +This plugin collects details on how much memory each entry in Slab cache is +consuming. For example, it collects the consumption of `kmalloc-1024` and +`xfs_inode`. Since this information is obtained by parsing `/proc/slabinfo` +file, only Linux is supported. The specification of `/proc/slabinfo` has +not changed since [Linux v2.6.12 (April 2005)](https://github.com/torvalds/linux/blob/1da177e4/mm/slab.c#L2848-L2861), +so it can be regarded as sufficiently stable. The memory usage is +equivalent to the `CACHE_SIZE` column of `slabtop` command. + +## Configuration + +```toml +# Get slab statistics from procfs +[[inputs.slab]] + # no configuration +``` + +## Metrics + +Metrics include generic ones such as `kmalloc-*` as well as those of kernel +subsystems and drivers used by the system such as `xfs_inode`. + +- mem + - fields: + - kmalloc-8_size_in_bytes (integer) + - kmalloc-16_size_in_bytes (integer) + - kmalloc-32_size_in_bytes (integer) + - kmalloc-64_size_in_bytes (integer) + - kmalloc-96_size_in_bytes (integer) + - kmalloc-128_size_in_bytes (integer) + - kmalloc-256_size_in_bytes (integer) + - kmalloc-512_size_in_bytes (integer) + - xfs_ili_size_in_bytes (integer) + - xfs_inode_size_in_bytes (integer) + +## Example Output + +```shel +slab +kmalloc-1024_size_in_bytes=239927296i,kmalloc-512_size_in_bytes=5582848i 1651049129000000000 +``` diff --git a/plugins/inputs/slab/slab.go b/plugins/inputs/slab/slab.go new file mode 100644 index 0000000000000..9c0a106ed07de --- /dev/null +++ b/plugins/inputs/slab/slab.go @@ -0,0 +1,32 @@ +package slab + +import ( + "os" + "path" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs" +) + +type SlabStats struct { + Log telegraf.Logger `toml:"-"` + + // slab stats filename (proc filesystem) + statFile string +} + +func getHostProc() string { + procPath := "/proc" + if os.Getenv("HOST_PROC") != "" { + procPath = os.Getenv("HOST_PROC") + } + return procPath +} + +func init() { + inputs.Add("slab", func() telegraf.Input { + return &SlabStats{ + statFile: path.Join(getHostProc(), "/slabinfo"), + } + }) +} diff --git a/plugins/inputs/slab/slab_linux.go b/plugins/inputs/slab/slab_linux.go new file mode 100644 index 0000000000000..8cc01345cc0f6 --- /dev/null +++ b/plugins/inputs/slab/slab_linux.go @@ -0,0 +1,69 @@ +//go:build linux +// +build linux + +package slab + +import ( + "bufio" + "errors" + "os" + "strconv" + "strings" + + "github.com/influxdata/telegraf" +) + +func (ss *SlabStats) Init() error { + return nil +} + +func (ss *SlabStats) Gather(acc telegraf.Accumulator) error { + fields, err := ss.getSlabStats() + if err != nil { + return err + } + + acc.AddGauge("slab", fields, nil) + return nil +} + +func (ss *SlabStats) getSlabStats() (map[string]interface{}, error) { + fields := map[string]interface{}{} + + file, err := os.Open(ss.statFile) + if err != nil { + return nil, err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + + // Read header rows + scanner.Scan() // for "slabinfo - version: 2.1" + scanner.Scan() // for "# name ..." + + // Read data rows + for scanner.Scan() { + line := scanner.Text() + cols := strings.Fields(line) + + if len(cols) < 4 { + return nil, errors.New("the content of /proc/slabinfo is invalid") + } + + var numObj, sizObj int + + numObj, err = strconv.Atoi(cols[2]) + if err != nil { + return nil, err + } + + sizObj, err = strconv.Atoi(cols[3]) + if err != nil { + return nil, err + } + + fields[cols[0]+"_size_in_bytes"] = numObj * sizObj + } + return fields, nil +} diff --git a/plugins/inputs/slab/slab_notlinux.go b/plugins/inputs/slab/slab_notlinux.go new file mode 100644 index 0000000000000..95047ea2e5c86 --- /dev/null +++ b/plugins/inputs/slab/slab_notlinux.go @@ -0,0 +1,15 @@ +//go:build !linux +// +build !linux + +package slab + +import "github.com/influxdata/telegraf" + +func (ss *SlabStats) Init() error { + ss.Log.Warn("Current platform is not supported") + return nil +} + +func (ss *SlabStats) Gather(acc telegraf.Accumulator) error { + return nil +} diff --git a/plugins/inputs/slab/slab_sample_config.go b/plugins/inputs/slab/slab_sample_config.go new file mode 100644 index 0000000000000..b45c9b259fc02 --- /dev/null +++ b/plugins/inputs/slab/slab_sample_config.go @@ -0,0 +1,8 @@ +//go:generate go run ../../../tools/generate_plugindata/main.go +//go:generate go run ../../../tools/generate_plugindata/main.go --clean +// DON'T EDIT; This file is used as a template by tools/generate_plugindata +package slab + +func (ss *SlabStats) SampleConfig() string { + return `{{ .SampleConfig }}` +} diff --git a/plugins/inputs/slab/slab_test.go b/plugins/inputs/slab/slab_test.go new file mode 100644 index 0000000000000..a09566abc6fed --- /dev/null +++ b/plugins/inputs/slab/slab_test.go @@ -0,0 +1,89 @@ +//go:build linux +// +build linux + +package slab + +import ( + "os" + "testing" + + "github.com/influxdata/telegraf/testutil" + "github.com/stretchr/testify/require" +) + +func makeFakeStatFile(content []byte) string { + tmpfile, err := os.CreateTemp("", "slab_test") + if err != nil { + panic(err) + } + + if _, err := tmpfile.Write(content); err != nil { + panic(err) + } + if err := tmpfile.Close(); err != nil { + panic(err) + } + + return tmpfile.Name() +} + +func TestSlab(t *testing.T) { + slabStats := SlabStats{ + statFile: makeFakeStatFile([]byte(procSlabInfo)), + } + + var acc testutil.Accumulator + err := acc.GatherError(slabStats.Gather) + require.NoError(t, err) + + fields := map[string]interface{}{ + "ext4_allocation_context_size_in_bytes": int(16384), + "ext4_extent_status_size_in_bytes": int(8160), + "ext4_free_data_size_in_bytes": int(0), + "ext4_inode_cache_size_in_bytes": int(491520), + "ext4_io_end_size_in_bytes": int(4032), + "ext4_xattr_size_in_bytes": int(0), + "kmalloc-1024_size_in_bytes": int(239927296), + "kmalloc-128_size_in_bytes": int(5586944), + "kmalloc-16_size_in_bytes": int(17002496), + "kmalloc-192_size_in_bytes": int(4015872), + "kmalloc-2048_size_in_bytes": int(3309568), + "kmalloc-256_size_in_bytes": int(5423104), + "kmalloc-32_size_in_bytes": int(3657728), + "kmalloc-4096_size_in_bytes": int(2359296), + "kmalloc-512_size_in_bytes": int(41435136), + "kmalloc-64_size_in_bytes": int(8536064), + "kmalloc-8_size_in_bytes": int(229376), + "kmalloc-8192_size_in_bytes": int(1048576), + "kmalloc-96_size_in_bytes": int(12378240), + "kmem_cache_size_in_bytes": int(81920), + "kmem_cache_node_size_in_bytes": int(36864), + } + + acc.AssertContainsFields(t, "slab", fields) +} + +var procSlabInfo = `slabinfo - version: 2.1 +# name : tunables : slabdata +ext4_inode_cache 480 480 1024 32 8 : tunables 0 0 0 : slabdata 15 15 0 +ext4_xattr 0 0 88 46 1 : tunables 0 0 0 : slabdata 0 0 0 +ext4_free_data 0 0 64 64 1 : tunables 0 0 0 : slabdata 0 0 0 +ext4_allocation_context 128 128 128 32 1 : tunables 0 0 0 : slabdata 4 4 0 +ext4_io_end 56 56 72 56 1 : tunables 0 0 0 : slabdata 1 1 0 +ext4_extent_status 204 204 40 102 1 : tunables 0 0 0 : slabdata 2 2 0 +kmalloc-8192 106 128 8192 4 8 : tunables 0 0 0 : slabdata 32 32 0 +kmalloc-4096 486 576 4096 8 8 : tunables 0 0 0 : slabdata 72 72 0 +kmalloc-2048 1338 1616 2048 16 8 : tunables 0 0 0 : slabdata 101 101 0 +kmalloc-1024 155845 234304 1024 32 8 : tunables 0 0 0 : slabdata 7329 7329 0 +kmalloc-512 18995 80928 512 32 4 : tunables 0 0 0 : slabdata 2529 2529 0 +kmalloc-256 16366 21184 256 32 2 : tunables 0 0 0 : slabdata 662 662 0 +kmalloc-192 18835 20916 192 21 1 : tunables 0 0 0 : slabdata 996 996 0 +kmalloc-128 23600 43648 128 32 1 : tunables 0 0 0 : slabdata 1364 1364 0 +kmalloc-96 95106 128940 96 42 1 : tunables 0 0 0 : slabdata 3070 3070 0 +kmalloc-64 82432 133376 64 64 1 : tunables 0 0 0 : slabdata 2084 2084 0 +kmalloc-32 78477 114304 32 128 1 : tunables 0 0 0 : slabdata 893 893 0 +kmalloc-16 885605 1062656 16 256 1 : tunables 0 0 0 : slabdata 4151 4151 0 +kmalloc-8 28672 28672 8 512 1 : tunables 0 0 0 : slabdata 56 56 0 +kmem_cache_node 576 576 64 64 1 : tunables 0 0 0 : slabdata 9 9 0 +kmem_cache 320 320 256 32 2 : tunables 0 0 0 : slabdata 10 10 0 +` From a7aa43180f42a60bc160bbee6363aaa5cb2edd12 Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 11 May 2022 16:21:32 +0900 Subject: [PATCH 02/16] add use_sudo option Signed-off-by: Nobuhiro MIKI --- plugins/inputs/slab/README.md | 5 ++++- plugins/inputs/slab/slab.go | 1 + plugins/inputs/slab/slab_linux.go | 33 +++++++++++++++++++++++-------- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md index f7e6b602ac6e9..e5622c166e5e4 100644 --- a/plugins/inputs/slab/README.md +++ b/plugins/inputs/slab/README.md @@ -8,12 +8,15 @@ not changed since [Linux v2.6.12 (April 2005)](https://github.com/torvalds/linux so it can be regarded as sufficiently stable. The memory usage is equivalent to the `CACHE_SIZE` column of `slabtop` command. +**Note: `/proc/slabinfo` is usually restricted to read as root user. Enable `use_sudo` option if necessary.** + ## Configuration ```toml # Get slab statistics from procfs [[inputs.slab]] - # no configuration + ## Use sudo to run LVM commands + use_sudo = false ``` ## Metrics diff --git a/plugins/inputs/slab/slab.go b/plugins/inputs/slab/slab.go index 9c0a106ed07de..e54ef0da4c1de 100644 --- a/plugins/inputs/slab/slab.go +++ b/plugins/inputs/slab/slab.go @@ -13,6 +13,7 @@ type SlabStats struct { // slab stats filename (proc filesystem) statFile string + UseSudo bool `toml:"use_sudo"` } func getHostProc() string { diff --git a/plugins/inputs/slab/slab_linux.go b/plugins/inputs/slab/slab_linux.go index 8cc01345cc0f6..4c90694a7a477 100644 --- a/plugins/inputs/slab/slab_linux.go +++ b/plugins/inputs/slab/slab_linux.go @@ -5,12 +5,16 @@ package slab import ( "bufio" + "bytes" "errors" - "os" + "fmt" + "os/exec" "strconv" "strings" + "time" "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/internal" ) func (ss *SlabStats) Init() error { @@ -30,13 +34,9 @@ func (ss *SlabStats) Gather(acc telegraf.Accumulator) error { func (ss *SlabStats) getSlabStats() (map[string]interface{}, error) { fields := map[string]interface{}{} - file, err := os.Open(ss.statFile) - if err != nil { - return nil, err - } - defer file.Close() - - scanner := bufio.NewScanner(file) + out, err := ss.runCmd("/bin/cat", []string{ss.statFile}) + bytesReader := bytes.NewReader(out) + scanner := bufio.NewScanner(bytesReader) // Read header rows scanner.Scan() // for "slabinfo - version: 2.1" @@ -67,3 +67,20 @@ func (ss *SlabStats) getSlabStats() (map[string]interface{}, error) { } return fields, nil } + +func (ss *SlabStats) runCmd(cmd string, args []string) ([]byte, error) { + execCmd := exec.Command(cmd, args...) + if ss.UseSudo { + execCmd = exec.Command("sudo", append([]string{"-n", cmd}, args...)...) + } + + out, err := internal.StdOutputTimeout(execCmd, 5*time.Second) + if err != nil { + return nil, fmt.Errorf( + "failed to run command %s: %s - %s", + strings.Join(execCmd.Args, " "), err, string(out), + ) + } + + return out, nil +} From fc8e88b05328b0d467c725442c94380a87f8909b Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 11 May 2022 16:22:36 +0900 Subject: [PATCH 03/16] remove unused comment Signed-off-by: Nobuhiro MIKI --- plugins/inputs/slab/slab.go | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/inputs/slab/slab.go b/plugins/inputs/slab/slab.go index e54ef0da4c1de..f502d401aa78f 100644 --- a/plugins/inputs/slab/slab.go +++ b/plugins/inputs/slab/slab.go @@ -11,7 +11,6 @@ import ( type SlabStats struct { Log telegraf.Logger `toml:"-"` - // slab stats filename (proc filesystem) statFile string UseSudo bool `toml:"use_sudo"` } From b35fb14dcb68365db6a2eff83497abcfb699a5e1 Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 11 May 2022 16:36:31 +0900 Subject: [PATCH 04/16] fix naming Signed-off-by: Nobuhiro MIKI --- plugins/inputs/slab/README.md | 25 +++++++++--------- plugins/inputs/slab/slab_linux.go | 6 ++++- plugins/inputs/slab/slab_test.go | 42 +++++++++++++++---------------- 3 files changed, 39 insertions(+), 34 deletions(-) diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md index e5622c166e5e4..ddbc15296286c 100644 --- a/plugins/inputs/slab/README.md +++ b/plugins/inputs/slab/README.md @@ -21,25 +21,26 @@ equivalent to the `CACHE_SIZE` column of `slabtop` command. ## Metrics -Metrics include generic ones such as `kmalloc-*` as well as those of kernel +Metrics include generic ones such as `kmalloc_*` as well as those of kernel subsystems and drivers used by the system such as `xfs_inode`. +Each field with `_size` suffix indicates memory consumption in bytes. - mem - fields: - - kmalloc-8_size_in_bytes (integer) - - kmalloc-16_size_in_bytes (integer) - - kmalloc-32_size_in_bytes (integer) - - kmalloc-64_size_in_bytes (integer) - - kmalloc-96_size_in_bytes (integer) - - kmalloc-128_size_in_bytes (integer) - - kmalloc-256_size_in_bytes (integer) - - kmalloc-512_size_in_bytes (integer) - - xfs_ili_size_in_bytes (integer) - - xfs_inode_size_in_bytes (integer) + _ kmalloc_8_size (integer) + _ kmalloc_16_size (integer) + _ kmalloc_32_size (integer) + _ kmalloc_64_size (integer) + _ kmalloc_96_size (integer) + _ kmalloc_128_size (integer) + _ kmalloc_256_size (integer) + _ kmalloc_512_size (integer) + _ xfs_ili_size (integer) + _ xfs_inode_size (integer) ## Example Output ```shel slab -kmalloc-1024_size_in_bytes=239927296i,kmalloc-512_size_in_bytes=5582848i 1651049129000000000 +kmalloc_1024_size=239927296i,kmalloc_512_size=5582848i 1651049129000000000 ``` diff --git a/plugins/inputs/slab/slab_linux.go b/plugins/inputs/slab/slab_linux.go index 4c90694a7a477..17056d96bcc53 100644 --- a/plugins/inputs/slab/slab_linux.go +++ b/plugins/inputs/slab/slab_linux.go @@ -63,7 +63,7 @@ func (ss *SlabStats) getSlabStats() (map[string]interface{}, error) { return nil, err } - fields[cols[0]+"_size_in_bytes"] = numObj * sizObj + fields[normalizeName(cols[0])] = numObj * sizObj } return fields, nil } @@ -84,3 +84,7 @@ func (ss *SlabStats) runCmd(cmd string, args []string) ([]byte, error) { return out, nil } + +func normalizeName(name string) string { + return strings.ReplaceAll(strings.ToLower(name), "-", "_") + "_size" +} diff --git a/plugins/inputs/slab/slab_test.go b/plugins/inputs/slab/slab_test.go index a09566abc6fed..e5eda8f13666b 100644 --- a/plugins/inputs/slab/slab_test.go +++ b/plugins/inputs/slab/slab_test.go @@ -37,27 +37,27 @@ func TestSlab(t *testing.T) { require.NoError(t, err) fields := map[string]interface{}{ - "ext4_allocation_context_size_in_bytes": int(16384), - "ext4_extent_status_size_in_bytes": int(8160), - "ext4_free_data_size_in_bytes": int(0), - "ext4_inode_cache_size_in_bytes": int(491520), - "ext4_io_end_size_in_bytes": int(4032), - "ext4_xattr_size_in_bytes": int(0), - "kmalloc-1024_size_in_bytes": int(239927296), - "kmalloc-128_size_in_bytes": int(5586944), - "kmalloc-16_size_in_bytes": int(17002496), - "kmalloc-192_size_in_bytes": int(4015872), - "kmalloc-2048_size_in_bytes": int(3309568), - "kmalloc-256_size_in_bytes": int(5423104), - "kmalloc-32_size_in_bytes": int(3657728), - "kmalloc-4096_size_in_bytes": int(2359296), - "kmalloc-512_size_in_bytes": int(41435136), - "kmalloc-64_size_in_bytes": int(8536064), - "kmalloc-8_size_in_bytes": int(229376), - "kmalloc-8192_size_in_bytes": int(1048576), - "kmalloc-96_size_in_bytes": int(12378240), - "kmem_cache_size_in_bytes": int(81920), - "kmem_cache_node_size_in_bytes": int(36864), + "ext4_allocation_context_size": int(16384), + "ext4_extent_status_size": int(8160), + "ext4_free_data_size": int(0), + "ext4_inode_cache_size": int(491520), + "ext4_io_end_size": int(4032), + "ext4_xattr_size": int(0), + "kmalloc_1024_size": int(239927296), + "kmalloc_128_size": int(5586944), + "kmalloc_16_size": int(17002496), + "kmalloc_192_size": int(4015872), + "kmalloc_2048_size": int(3309568), + "kmalloc_256_size": int(5423104), + "kmalloc_32_size": int(3657728), + "kmalloc_4096_size": int(2359296), + "kmalloc_512_size": int(41435136), + "kmalloc_64_size": int(8536064), + "kmalloc_8_size": int(229376), + "kmalloc_8192_size": int(1048576), + "kmalloc_96_size": int(12378240), + "kmem_cache_size": int(81920), + "kmem_cache_node_size": int(36864), } acc.AssertContainsFields(t, "slab", fields) From 9cd9e1c62c4f6f8c83118940314f29a2897c2b4d Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 11 May 2022 16:43:07 +0900 Subject: [PATCH 05/16] fix doc Signed-off-by: Nobuhiro MIKI --- etc/telegraf.conf | 4 +++- plugins/inputs/slab/README.md | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/etc/telegraf.conf b/etc/telegraf.conf index 11a9a16f54639..ad35538803f59 100644 --- a/etc/telegraf.conf +++ b/etc/telegraf.conf @@ -6920,7 +6920,9 @@ # # Get slab statistics from procfs # [[inputs.slab]] -# # no configuration +# ## /proc/slabinfo is usually restricted to read as root user. +# ## Enable `use_sudo` option if necessary. +# # use_sudo = false # # Get synproxy counter statistics from procfs # [[inputs.synproxy]] diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md index ddbc15296286c..12a304073f46f 100644 --- a/plugins/inputs/slab/README.md +++ b/plugins/inputs/slab/README.md @@ -15,7 +15,8 @@ equivalent to the `CACHE_SIZE` column of `slabtop` command. ```toml # Get slab statistics from procfs [[inputs.slab]] - ## Use sudo to run LVM commands + ## /proc/slabinfo is usually restricted to read as root user. + ## Enable `use_sudo` option if necessary. use_sudo = false ``` From 4c330b55632bdaaa3090f842f4c84d8276ed28fd Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 11 May 2022 16:44:31 +0900 Subject: [PATCH 06/16] fix typo Signed-off-by: Nobuhiro MIKI --- plugins/inputs/slab/README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md index 12a304073f46f..50dd69e792602 100644 --- a/plugins/inputs/slab/README.md +++ b/plugins/inputs/slab/README.md @@ -28,16 +28,16 @@ Each field with `_size` suffix indicates memory consumption in bytes. - mem - fields: - _ kmalloc_8_size (integer) - _ kmalloc_16_size (integer) - _ kmalloc_32_size (integer) - _ kmalloc_64_size (integer) - _ kmalloc_96_size (integer) - _ kmalloc_128_size (integer) - _ kmalloc_256_size (integer) - _ kmalloc_512_size (integer) - _ xfs_ili_size (integer) - _ xfs_inode_size (integer) + - kmalloc_8_size (integer) + - kmalloc_16_size (integer) + - kmalloc_32_size (integer) + - kmalloc_64_size (integer) + - kmalloc_96_size (integer) + - kmalloc_128_size (integer) + - kmalloc_256_size (integer) + - kmalloc_512_size (integer) + - xfs_ili_size (integer) + - xfs_inode_size (integer) ## Example Output From 3b88f109dd68f37c3f87e5814f3003ead7b81266 Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 11 May 2022 16:48:36 +0900 Subject: [PATCH 07/16] add err checking Signed-off-by: Nobuhiro MIKI --- plugins/inputs/slab/slab_linux.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/inputs/slab/slab_linux.go b/plugins/inputs/slab/slab_linux.go index 17056d96bcc53..8c7d9c3abaeca 100644 --- a/plugins/inputs/slab/slab_linux.go +++ b/plugins/inputs/slab/slab_linux.go @@ -35,6 +35,10 @@ func (ss *SlabStats) getSlabStats() (map[string]interface{}, error) { fields := map[string]interface{}{} out, err := ss.runCmd("/bin/cat", []string{ss.statFile}) + if err != nil { + return nil, err + } + bytesReader := bytes.NewReader(out) scanner := bufio.NewScanner(bytesReader) From 2ac75380d9cb86cf7b7dc7381c681dc2377f95aa Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 11 May 2022 17:07:15 +0900 Subject: [PATCH 08/16] fix docs Signed-off-by: Nobuhiro MIKI --- plugins/inputs/slab/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md index 50dd69e792602..3f2b6146cd982 100644 --- a/plugins/inputs/slab/README.md +++ b/plugins/inputs/slab/README.md @@ -16,7 +16,7 @@ equivalent to the `CACHE_SIZE` column of `slabtop` command. # Get slab statistics from procfs [[inputs.slab]] ## /proc/slabinfo is usually restricted to read as root user. - ## Enable `use_sudo` option if necessary. + ## Enable use_sudo option if necessary. use_sudo = false ``` From 6a20b15b549eeddf8e6c00d042043832769dff57 Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Tue, 17 May 2022 10:25:35 +0900 Subject: [PATCH 09/16] add linux only build tags & remove unused files Signed-off-by: Nobuhiro MIKI --- plugins/inputs/slab/slab.go | 100 ++++++++++++++++++++-- plugins/inputs/slab/slab_linux.go | 94 -------------------- plugins/inputs/slab/slab_nonlinux.go | 4 + plugins/inputs/slab/slab_notlinux.go | 15 ---- plugins/inputs/slab/slab_sample_config.go | 3 + 5 files changed, 101 insertions(+), 115 deletions(-) delete mode 100644 plugins/inputs/slab/slab_linux.go create mode 100644 plugins/inputs/slab/slab_nonlinux.go delete mode 100644 plugins/inputs/slab/slab_notlinux.go diff --git a/plugins/inputs/slab/slab.go b/plugins/inputs/slab/slab.go index f502d401aa78f..06352dd52d2f4 100644 --- a/plugins/inputs/slab/slab.go +++ b/plugins/inputs/slab/slab.go @@ -1,13 +1,33 @@ +//go:build linux +// +build linux + package slab import ( + "bufio" + "bytes" + "errors" + "fmt" "os" + "os/exec" "path" + "strconv" + "strings" + "time" "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/plugins/inputs" ) +func init() { + inputs.Add("slab", func() telegraf.Input { + return &SlabStats{ + statFile: path.Join(getHostProc(), "/slabinfo"), + } + }) +} + type SlabStats struct { Log telegraf.Logger `toml:"-"` @@ -15,6 +35,78 @@ type SlabStats struct { UseSudo bool `toml:"use_sudo"` } +func (ss *SlabStats) Init() error { + return nil +} + +func (ss *SlabStats) Gather(acc telegraf.Accumulator) error { + fields, err := ss.getSlabStats() + if err != nil { + return err + } + + acc.AddGauge("slab", fields, nil) + return nil +} + +func (ss *SlabStats) getSlabStats() (map[string]interface{}, error) { + fields := map[string]interface{}{} + + out, err := ss.runCmd("/bin/cat", []string{ss.statFile}) + if err != nil { + return nil, err + } + + bytesReader := bytes.NewReader(out) + scanner := bufio.NewScanner(bytesReader) + + // Read header rows + scanner.Scan() // for "slabinfo - version: 2.1" + scanner.Scan() // for "# name ..." + + // Read data rows + for scanner.Scan() { + line := scanner.Text() + cols := strings.Fields(line) + + if len(cols) < 4 { + return nil, errors.New("the content of /proc/slabinfo is invalid") + } + + var numObj, sizObj int + + numObj, err = strconv.Atoi(cols[2]) + if err != nil { + return nil, err + } + + sizObj, err = strconv.Atoi(cols[3]) + if err != nil { + return nil, err + } + + fields[normalizeName(cols[0])] = numObj * sizObj + } + return fields, nil +} + +func (ss *SlabStats) runCmd(cmd string, args []string) ([]byte, error) { + execCmd := exec.Command(cmd, args...) + if ss.UseSudo { + execCmd = exec.Command("sudo", append([]string{"-n", cmd}, args...)...) + } + + out, err := internal.StdOutputTimeout(execCmd, 5*time.Second) + if err != nil { + return nil, fmt.Errorf( + "failed to run command %s: %s - %s", + strings.Join(execCmd.Args, " "), err, string(out), + ) + } + + return out, nil +} + func getHostProc() string { procPath := "/proc" if os.Getenv("HOST_PROC") != "" { @@ -23,10 +115,6 @@ func getHostProc() string { return procPath } -func init() { - inputs.Add("slab", func() telegraf.Input { - return &SlabStats{ - statFile: path.Join(getHostProc(), "/slabinfo"), - } - }) +func normalizeName(name string) string { + return strings.ReplaceAll(strings.ToLower(name), "-", "_") + "_size" } diff --git a/plugins/inputs/slab/slab_linux.go b/plugins/inputs/slab/slab_linux.go deleted file mode 100644 index 8c7d9c3abaeca..0000000000000 --- a/plugins/inputs/slab/slab_linux.go +++ /dev/null @@ -1,94 +0,0 @@ -//go:build linux -// +build linux - -package slab - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "os/exec" - "strconv" - "strings" - "time" - - "github.com/influxdata/telegraf" - "github.com/influxdata/telegraf/internal" -) - -func (ss *SlabStats) Init() error { - return nil -} - -func (ss *SlabStats) Gather(acc telegraf.Accumulator) error { - fields, err := ss.getSlabStats() - if err != nil { - return err - } - - acc.AddGauge("slab", fields, nil) - return nil -} - -func (ss *SlabStats) getSlabStats() (map[string]interface{}, error) { - fields := map[string]interface{}{} - - out, err := ss.runCmd("/bin/cat", []string{ss.statFile}) - if err != nil { - return nil, err - } - - bytesReader := bytes.NewReader(out) - scanner := bufio.NewScanner(bytesReader) - - // Read header rows - scanner.Scan() // for "slabinfo - version: 2.1" - scanner.Scan() // for "# name ..." - - // Read data rows - for scanner.Scan() { - line := scanner.Text() - cols := strings.Fields(line) - - if len(cols) < 4 { - return nil, errors.New("the content of /proc/slabinfo is invalid") - } - - var numObj, sizObj int - - numObj, err = strconv.Atoi(cols[2]) - if err != nil { - return nil, err - } - - sizObj, err = strconv.Atoi(cols[3]) - if err != nil { - return nil, err - } - - fields[normalizeName(cols[0])] = numObj * sizObj - } - return fields, nil -} - -func (ss *SlabStats) runCmd(cmd string, args []string) ([]byte, error) { - execCmd := exec.Command(cmd, args...) - if ss.UseSudo { - execCmd = exec.Command("sudo", append([]string{"-n", cmd}, args...)...) - } - - out, err := internal.StdOutputTimeout(execCmd, 5*time.Second) - if err != nil { - return nil, fmt.Errorf( - "failed to run command %s: %s - %s", - strings.Join(execCmd.Args, " "), err, string(out), - ) - } - - return out, nil -} - -func normalizeName(name string) string { - return strings.ReplaceAll(strings.ToLower(name), "-", "_") + "_size" -} diff --git a/plugins/inputs/slab/slab_nonlinux.go b/plugins/inputs/slab/slab_nonlinux.go new file mode 100644 index 0000000000000..77ec3e6e6a170 --- /dev/null +++ b/plugins/inputs/slab/slab_nonlinux.go @@ -0,0 +1,4 @@ +//go:build !linux +// +build !linux + +package slab diff --git a/plugins/inputs/slab/slab_notlinux.go b/plugins/inputs/slab/slab_notlinux.go deleted file mode 100644 index 95047ea2e5c86..0000000000000 --- a/plugins/inputs/slab/slab_notlinux.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !linux -// +build !linux - -package slab - -import "github.com/influxdata/telegraf" - -func (ss *SlabStats) Init() error { - ss.Log.Warn("Current platform is not supported") - return nil -} - -func (ss *SlabStats) Gather(acc telegraf.Accumulator) error { - return nil -} diff --git a/plugins/inputs/slab/slab_sample_config.go b/plugins/inputs/slab/slab_sample_config.go index b45c9b259fc02..eb4da02542bf4 100644 --- a/plugins/inputs/slab/slab_sample_config.go +++ b/plugins/inputs/slab/slab_sample_config.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + //go:generate go run ../../../tools/generate_plugindata/main.go //go:generate go run ../../../tools/generate_plugindata/main.go --clean // DON'T EDIT; This file is used as a template by tools/generate_plugindata From 7f17585b191cd685fc33a6f44f871bdefdf87bcd Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Tue, 17 May 2022 10:31:54 +0900 Subject: [PATCH 10/16] fix typo Signed-off-by: Nobuhiro MIKI --- plugins/inputs/slab/{slab_nonlinux.go => slab_notlinux.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/inputs/slab/{slab_nonlinux.go => slab_notlinux.go} (100%) diff --git a/plugins/inputs/slab/slab_nonlinux.go b/plugins/inputs/slab/slab_notlinux.go similarity index 100% rename from plugins/inputs/slab/slab_nonlinux.go rename to plugins/inputs/slab/slab_notlinux.go From 4b9e2384c5ca55cca949f49c03f2e428da749a5d Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 18 May 2022 10:49:51 +0900 Subject: [PATCH 11/16] rm use_sudo flag Signed-off-by: Nobuhiro MIKI --- etc/telegraf.conf | 4 +--- plugins/inputs/slab/README.md | 6 ++---- plugins/inputs/slab/slab.go | 6 +----- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/etc/telegraf.conf b/etc/telegraf.conf index ad35538803f59..11a9a16f54639 100644 --- a/etc/telegraf.conf +++ b/etc/telegraf.conf @@ -6920,9 +6920,7 @@ # # Get slab statistics from procfs # [[inputs.slab]] -# ## /proc/slabinfo is usually restricted to read as root user. -# ## Enable `use_sudo` option if necessary. -# # use_sudo = false +# # no configuration # # Get synproxy counter statistics from procfs # [[inputs.synproxy]] diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md index 3f2b6146cd982..5fcceec9c86c9 100644 --- a/plugins/inputs/slab/README.md +++ b/plugins/inputs/slab/README.md @@ -8,16 +8,14 @@ not changed since [Linux v2.6.12 (April 2005)](https://github.com/torvalds/linux so it can be regarded as sufficiently stable. The memory usage is equivalent to the `CACHE_SIZE` column of `slabtop` command. -**Note: `/proc/slabinfo` is usually restricted to read as root user. Enable `use_sudo` option if necessary.** +**Note: `/proc/slabinfo` is usually restricted to read as root user. Make sure telegraf can execute `sudo` without password.** ## Configuration ```toml # Get slab statistics from procfs [[inputs.slab]] - ## /proc/slabinfo is usually restricted to read as root user. - ## Enable use_sudo option if necessary. - use_sudo = false + # no configuration ``` ## Metrics diff --git a/plugins/inputs/slab/slab.go b/plugins/inputs/slab/slab.go index 06352dd52d2f4..1e0fda87d2081 100644 --- a/plugins/inputs/slab/slab.go +++ b/plugins/inputs/slab/slab.go @@ -32,7 +32,6 @@ type SlabStats struct { Log telegraf.Logger `toml:"-"` statFile string - UseSudo bool `toml:"use_sudo"` } func (ss *SlabStats) Init() error { @@ -91,10 +90,7 @@ func (ss *SlabStats) getSlabStats() (map[string]interface{}, error) { } func (ss *SlabStats) runCmd(cmd string, args []string) ([]byte, error) { - execCmd := exec.Command(cmd, args...) - if ss.UseSudo { - execCmd = exec.Command("sudo", append([]string{"-n", cmd}, args...)...) - } + execCmd := exec.Command("sudo", append([]string{"-n", cmd}, args...)...) out, err := internal.StdOutputTimeout(execCmd, 5*time.Second) if err != nil { From 7c2294b4d0bfed3076e10702e4d085c645be4697 Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 18 May 2022 11:16:10 +0900 Subject: [PATCH 12/16] fix runCmd Signed-off-by: Nobuhiro MIKI --- plugins/inputs/slab/slab.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/inputs/slab/slab.go b/plugins/inputs/slab/slab.go index 1e0fda87d2081..a18513df98789 100644 --- a/plugins/inputs/slab/slab.go +++ b/plugins/inputs/slab/slab.go @@ -90,7 +90,10 @@ func (ss *SlabStats) getSlabStats() (map[string]interface{}, error) { } func (ss *SlabStats) runCmd(cmd string, args []string) ([]byte, error) { - execCmd := exec.Command("sudo", append([]string{"-n", cmd}, args...)...) + execCmd := exec.Command(cmd, args...) + if os.Geteuid() != 0 { + execCmd = exec.Command("sudo", append([]string{"-n", cmd}, args...)...) + } out, err := internal.StdOutputTimeout(execCmd, 5*time.Second) if err != nil { From 3fd0a46b797f5a8e4bea79e10721026ca16d3ad3 Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 18 May 2022 12:13:59 +0900 Subject: [PATCH 13/16] Update plugins/inputs/slab/README.md Co-authored-by: reimda --- plugins/inputs/slab/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md index 5fcceec9c86c9..9075654b9b310 100644 --- a/plugins/inputs/slab/README.md +++ b/plugins/inputs/slab/README.md @@ -7,6 +7,7 @@ file, only Linux is supported. The specification of `/proc/slabinfo` has not changed since [Linux v2.6.12 (April 2005)](https://github.com/torvalds/linux/blob/1da177e4/mm/slab.c#L2848-L2861), so it can be regarded as sufficiently stable. The memory usage is equivalent to the `CACHE_SIZE` column of `slabtop` command. +If the HOST_PROC environment variable is set, Telegraf will use its value instead of `/proc` **Note: `/proc/slabinfo` is usually restricted to read as root user. Make sure telegraf can execute `sudo` without password.** From 4034fadc741945aef70ddba640cdc090498eb5c2 Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 18 May 2022 12:14:23 +0900 Subject: [PATCH 14/16] Update plugins/inputs/slab/README.md Co-authored-by: reimda --- plugins/inputs/slab/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md index 9075654b9b310..f81caf08bbef0 100644 --- a/plugins/inputs/slab/README.md +++ b/plugins/inputs/slab/README.md @@ -18,7 +18,12 @@ If the HOST_PROC environment variable is set, Telegraf will use its value instea [[inputs.slab]] # no configuration ``` +## Sudo configuration +Since the slabinfo file is only readable by root, the plugin runs `sudo /bin/cat` to read the file. + +Sudo can be configured to allow telegraf to run just the command needed to read the slabinfo file. For example, if telegraf is running as the user 'telegraf' and HOST_PROC is not used, add this to the sudoers file: +`telegraf ALL = (root) NOPASSWD: /bin/cat /proc/slabinfo` ## Metrics Metrics include generic ones such as `kmalloc_*` as well as those of kernel From d44ded479ed0c6ac1a09679701a1d8780ab30d67 Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Wed, 18 May 2022 14:10:18 +0900 Subject: [PATCH 15/16] fix for markdownlint Signed-off-by: Nobuhiro MIKI --- plugins/inputs/slab/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md index f81caf08bbef0..8c3c2e11242c8 100644 --- a/plugins/inputs/slab/README.md +++ b/plugins/inputs/slab/README.md @@ -18,12 +18,14 @@ If the HOST_PROC environment variable is set, Telegraf will use its value instea [[inputs.slab]] # no configuration ``` + ## Sudo configuration Since the slabinfo file is only readable by root, the plugin runs `sudo /bin/cat` to read the file. Sudo can be configured to allow telegraf to run just the command needed to read the slabinfo file. For example, if telegraf is running as the user 'telegraf' and HOST_PROC is not used, add this to the sudoers file: `telegraf ALL = (root) NOPASSWD: /bin/cat /proc/slabinfo` + ## Metrics Metrics include generic ones such as `kmalloc_*` as well as those of kernel From fe8fd4bc59272266a60a80e201997d10b899cc4a Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Thu, 19 May 2022 10:07:37 +0900 Subject: [PATCH 16/16] Update plugins/inputs/slab/README.md Co-authored-by: Joshua Powers --- plugins/inputs/slab/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/inputs/slab/README.md b/plugins/inputs/slab/README.md index 8c3c2e11242c8..18512fbf42b86 100644 --- a/plugins/inputs/slab/README.md +++ b/plugins/inputs/slab/README.md @@ -16,7 +16,8 @@ If the HOST_PROC environment variable is set, Telegraf will use its value instea ```toml # Get slab statistics from procfs [[inputs.slab]] - # no configuration + # no configuration - please see the plugin's README for steps to configure + # sudo properly ``` ## Sudo configuration