Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add slab metrics input plugin #11075

Merged
merged 16 commits into from
May 19, 2022
3 changes: 3 additions & 0 deletions etc/telegraf.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand Down
1 change: 1 addition & 0 deletions plugins/inputs/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
42 changes: 42 additions & 0 deletions plugins/inputs/slab/README.md
Original file line number Diff line number Diff line change
@@ -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.

bobuhiro11 marked this conversation as resolved.
Show resolved Hide resolved
## Configuration

```toml
# Get slab statistics from procfs
[[inputs.slab]]
# no configuration
bobuhiro11 marked this conversation as resolved.
Show resolved Hide resolved
```
bobuhiro11 marked this conversation as resolved.
Show resolved Hide resolved

bobuhiro11 marked this conversation as resolved.
Show resolved Hide resolved
## 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)
powersj marked this conversation as resolved.
Show resolved Hide resolved

## Example Output

```shel
slab
kmalloc-1024_size_in_bytes=239927296i,kmalloc-512_size_in_bytes=5582848i 1651049129000000000
```
32 changes: 32 additions & 0 deletions plugins/inputs/slab/slab.go
Original file line number Diff line number Diff line change
@@ -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)
bobuhiro11 marked this conversation as resolved.
Show resolved Hide resolved
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"),
}
})
}
bobuhiro11 marked this conversation as resolved.
Show resolved Hide resolved
69 changes: 69 additions & 0 deletions plugins/inputs/slab/slab_linux.go
Original file line number Diff line number Diff line change
@@ -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 <active_objs> <num_objs> <objsize> ..."

// 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
}
15 changes: 15 additions & 0 deletions plugins/inputs/slab/slab_notlinux.go
Original file line number Diff line number Diff line change
@@ -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
}
8 changes: 8 additions & 0 deletions plugins/inputs/slab/slab_sample_config.go
Original file line number Diff line number Diff line change
@@ -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 }}`
}
89 changes: 89 additions & 0 deletions plugins/inputs/slab/slab_test.go
Original file line number Diff line number Diff line change
@@ -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 <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
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
`