From 0abaf7bf6a5a07c615255846c7b4868bc22e836a Mon Sep 17 00:00:00 2001 From: Jan Shim Date: Wed, 6 Apr 2016 11:35:33 -0700 Subject: [PATCH] Add kernel_vmstat input plugins --- etc/telegraf.conf | 3 + plugins/inputs/system/KERNEL_VMSTAT_README.md | 226 +++++++++++++ plugins/inputs/system/kernel_vmstat.go | 173 ++++++++++ plugins/inputs/system/kernel_vmstat_test.go | 315 ++++++++++++++++++ 4 files changed, 717 insertions(+) create mode 100644 plugins/inputs/system/KERNEL_VMSTAT_README.md create mode 100644 plugins/inputs/system/kernel_vmstat.go create mode 100644 plugins/inputs/system/kernel_vmstat_test.go diff --git a/etc/telegraf.conf b/etc/telegraf.conf index 4081cf484..bf0779d28 100644 --- a/etc/telegraf.conf +++ b/etc/telegraf.conf @@ -422,6 +422,9 @@ [[inputs.kernel]] # no configuration +# # Get kernel statistics from /proc/vmstat +# [[inputs.kernel_vmstat]] +# # no configuration # Read metrics about memory usage [[inputs.mem]] diff --git a/plugins/inputs/system/KERNEL_VMSTAT_README.md b/plugins/inputs/system/KERNEL_VMSTAT_README.md new file mode 100644 index 000000000..c16f23aab --- /dev/null +++ b/plugins/inputs/system/KERNEL_VMSTAT_README.md @@ -0,0 +1,226 @@ +# Kernel VMStat Input Plugin + +This plugin is only available on Linux. + +The kernel_vmstat plugin gathers info about the kernel that doesn't fit into other +plugins. In general, it is the statistics available in `/proc/vmstat` that are +not covered by other plugins. + +The metrics are documented in `man proc` under the `/proc/vmstat` section. + +``` +/proc/vmstat +kernel/system statistics. Common entries include (from http://www.linuxinsight.com/proc_vmstat.html): + +Number of pages that are dirty, under writeback or unstable: + +nr_dirty 1550 +nr_writeback 0 +nr_unstable 0 + +Number of pages allocated to page tables, mapped by files or allocated by the kernel slab allocator: + +nr_page_table_pages 699 +nr_mapped 139596 +nr_slab 42723 + +Number of pageins and pageouts (since the last boot): + +pgpgin 33754195 +pgpgout 38985992 + +Number of swapins and swapouts (since the last boot): + +pswpin 2473 +pswpout 2995 + +Number of page allocations per zone (since the last boot): + +pgalloc_high 0 +pgalloc_normal 110123213 +pgalloc_dma32 0 +pgalloc_dma 415219 + +Number of page frees, activations and deactivations (since the last boot): + +pgfree 110549163 +pgactivate 4509729 +pgdeactivate 2136215 + +Number of minor and major page faults (since the last boot): + +pgfault 80663722 +pgmajfault 49813 + +Number of page refills (per zone, since the last boot): + +pgrefill_high 0 +pgrefill_normal 5817500 +pgrefill_dma32 0 +pgrefill_dma 149176 + +Number of page steals (per zone, since the last boot): + +pgsteal_high 0 +pgsteal_normal 10421346 +pgsteal_dma32 0 +pgsteal_dma 142196 + +Number of pages scanned by the kswapd daemon (per zone, since the last boot): + +pgscan_kswapd_high 0 +pgscan_kswapd_normal 10491424 +pgscan_kswapd_dma32 0 +pgscan_kswapd_dma 156130 + +Number of pages reclaimed directly (per zone, since the last boot): + +pgscan_direct_high 0 +pgscan_direct_normal 11904 +pgscan_direct_dma32 0 +pgscan_direct_dma 225 + +Number of pages reclaimed via inode freeing (since the last boot): + +pginodesteal 11 + +Number of slab objects scanned (since the last boot): + +slabs_scanned 8926976 + +Number of pages reclaimed by kswapd (since the last boot): + +kswapd_steal 10551674 + +Number of pages reclaimed by kswapd via inode freeing (since the last boot): + +kswapd_inodesteal 338730 + +Number of kswapd's calls to page reclaim (since the last boot): + +pageoutrun 181908 + +Number of direct reclaim calls (since the last boot): + +allocstall 160 + +Miscellaneous statistics: + +pgrotated 3781 +nr_bounce 0 +``` + +### Configuration: + +```toml +# Get kernel statistics from /proc/vmstat +[[inputs.kernel_vmstat]] + # no configuration +``` + +### Measurements & Fields: + +- kernel_vmstat + - nr_free_pages (integer, `nr_free_pages`) + - nr_inactive_anon (integer, `nr_inactive_anon`) + - nr_active_anon (integer, `nr_active_anon`) + - nr_inactive_file (integer, `nr_inactive_file`) + - nr_active_file (integer, `nr_active_file`) + - nr_unevictable (integer, `nr_unevictable`) + - nr_mlock (integer, `nr_mlock`) + - nr_anon_pages (integer, `nr_anon_pages`) + - nr_mapped (integer, `nr_mapped`) + - nr_file_pages (integer, `nr_file_pages`) + - nr_dirty (integer, `nr_dirty`) + - nr_writeback (integer, `nr_writeback`) + - nr_slab_reclaimable (integer, `nr_slab_reclaimable`) + - nr_slab_unreclaimable (integer, `nr_slab_unreclaimable`) + - nr_page_table_pages (integer, `nr_page_table_pages`) + - nr_kernel_stack (integer, `nr_kernel_stack`) + - nr_unstable (integer, `nr_unstable`) + - nr_bounce (integer, `nr_bounce`) + - nr_vmscan_write (integer, `nr_vmscan_write`) + - nr_writeback_temp (integer, `nr_writeback_temp`) + - nr_isolated_anon (integer, `nr_isolated_anon`) + - nr_isolated_file (integer, `nr_isolated_file`) + - nr_shmem (integer, `nr_shmem`) + - numa_hit (integer, `numa_hit`) + - numa_miss (integer, `numa_miss`) + - numa_foreign (integer, `numa_foreign`) + - numa_interleave (integer, `numa_interleave`) + - numa_local (integer, `numa_local`) + - numa_other (integer, `numa_other`) + - nr_anon_transparent_hugepages (integer, `nr_anon_transparent_hugepages`) + - pgpgin (integer, `pgpgin`) + - pgpgout (integer, `pgpgout`) + - pswpin (integer, `pswpin`) + - pswpout (integer, `pswpout`) + - pgalloc_dma (integer, `pgalloc_dma`) + - pgalloc_dma32 (integer, `pgalloc_dma32`) + - pgalloc_normal (integer, `pgalloc_normal`) + - pgalloc_movable (integer, `pgalloc_movable`) + - pgfree (integer, `pgfree`) + - pgactivate (integer, `pgactivate`) + - pgdeactivate (integer, `pgdeactivate`) + - pgfault (integer, `pgfault`) + - pgmajfault (integer, `pgmajfault`) + - pgrefill_dma (integer, `pgrefill_dma`) + - pgrefill_dma32 (integer, `pgrefill_dma32`) + - pgrefill_normal (integer, `pgrefill_normal`) + - pgrefill_movable (integer, `pgrefill_movable`) + - pgsteal_dma (integer, `pgsteal_dma`) + - pgsteal_dma32 (integer, `pgsteal_dma32`) + - pgsteal_normal (integer, `pgsteal_normal`) + - pgsteal_movable (integer, `pgsteal_movable`) + - pgscan_kswapd_dma (integer, `pgscan_kswapd_dma`) + - pgscan_kswapd_dma32 (integer, `pgscan_kswapd_dma32`) + - pgscan_kswapd_normal (integer, `pgscan_kswapd_normal`) + - pgscan_kswapd_movable (integer, `pgscan_kswapd_movable`) + - pgscan_direct_dma (integer, `pgscan_direct_dma`) + - pgscan_direct_dma32 (integer, `pgscan_direct_dma32`) + - pgscan_direct_normal (integer, `pgscan_direct_normal`) + - pgscan_direct_movable (integer, `pgscan_direct_movable`) + - zone_reclaim_failed (integer, `zone_reclaim_failed`) + - pginodesteal (integer, `pginodesteal`) + - slabs_scanned (integer, `slabs_scanned`) + - kswapd_steal (integer, `kswapd_steal`) + - kswapd_inodesteal (integer, `kswapd_inodesteal`) + - kswapd_low_wmark_hit_quickly (integer, `kswapd_low_wmark_hit_quickly`) + - kswapd_high_wmark_hit_quickly (integer, `kswapd_high_wmark_hit_quickly`) + - kswapd_skip_congestion_wait (integer, `kswapd_skip_congestion_wait`) + - pageoutrun (integer, `pageoutrun`) + - allocstall (integer, `allocstall`) + - pgrotated (integer, `pgrotated`) + - compact_blocks_moved (integer, `compact_blocks_moved`) + - compact_pages_moved (integer, `compact_pages_moved`) + - compact_pagemigrate_failed (integer, `compact_pagemigrate_failed`) + - compact_stall (integer, `compact_stall`) + - compact_fail (integer, `compact_fail`) + - compact_success (integer, `compact_success`) + - htlb_buddy_alloc_success (integer, `htlb_buddy_alloc_success`) + - htlb_buddy_alloc_fail (integer, `htlb_buddy_alloc_fail`) + - unevictable_pgs_culled (integer, `unevictable_pgs_culled`) + - unevictable_pgs_scanned (integer, `unevictable_pgs_scanned`) + - unevictable_pgs_rescued (integer, `unevictable_pgs_rescued`) + - unevictable_pgs_mlocked (integer, `unevictable_pgs_mlocked`) + - unevictable_pgs_munlocked (integer, `unevictable_pgs_munlocked`) + - unevictable_pgs_cleared (integer, `unevictable_pgs_cleared`) + - unevictable_pgs_stranded (integer, `unevictable_pgs_stranded`) + - unevictable_pgs_mlockfreed (integer, `unevictable_pgs_mlockfreed`) + - thp_fault_alloc (integer, `thp_fault_alloc`) + - thp_fault_fallback (integer, `thp_fault_fallback`) + - thp_collapse_alloc (integer, `thp_collapse_alloc`) + - thp_collapse_alloc_failed (integer, `thp_collapse_alloc_failed`) + - thp_split (integer, `thp_split`) + +### Tags: + +None + +### Example Output: + +``` +$ telegraf -config ~/ws/telegraf.conf -input-filter kernel_vmstat -test +* Plugin: kernel_vmstat, Collection 1 +> kernel_vmstat allocstall=81496i,compact_blocks_moved=238196i,compact_fail=135220i,compact_pagemigrate_failed=0i,compact_pages_moved=6370588i,compact_stall=142092i,compact_success=6872i,htlb_buddy_alloc_fail=0i,htlb_buddy_alloc_success=0i,kswapd_high_wmark_hit_quickly=25439i,kswapd_inodesteal=29770874i,kswapd_low_wmark_hit_quickly=8756i,kswapd_skip_congestion_wait=0i,kswapd_steal=291534428i,nr_active_anon=2515657i,nr_active_file=2244914i,nr_anon_pages=1358675i,nr_anon_transparent_hugepages=2034i,nr_bounce=0i,nr_dirty=5690i,nr_file_pages=5153546i,nr_free_pages=78730i,nr_inactive_anon=426259i,nr_inactive_file=2366791i,nr_isolated_anon=0i,nr_isolated_file=0i,nr_kernel_stack=579i,nr_mapped=558821i,nr_mlock=0i,nr_page_table_pages=11115i,nr_shmem=541689i,nr_slab_reclaimable=459806i,nr_slab_unreclaimable=47859i,nr_unevictable=0i,nr_unstable=0i,nr_vmscan_write=6206i,nr_writeback=0i,nr_writeback_temp=0i,numa_foreign=0i,numa_hit=5113399878i,numa_interleave=35793i,numa_local=5113399878i,numa_miss=0i,numa_other=0i,pageoutrun=505006i,pgactivate=375664931i,pgalloc_dma=0i,pgalloc_dma32=122480220i,pgalloc_movable=0i,pgalloc_normal=5233176719i,pgdeactivate=122735906i,pgfault=8699921410i,pgfree=5359765021i,pginodesteal=9188431i,pgmajfault=122210i,pgpgin=219717626i,pgpgout=3495885510i,pgrefill_dma=0i,pgrefill_dma32=1180010i,pgrefill_movable=0i,pgrefill_normal=119866676i,pgrotated=60620i,pgscan_direct_dma=0i,pgscan_direct_dma32=12256i,pgscan_direct_movable=0i,pgscan_direct_normal=31501600i,pgscan_kswapd_dma=0i,pgscan_kswapd_dma32=4480608i,pgscan_kswapd_movable=0i,pgscan_kswapd_normal=287857984i,pgsteal_dma=0i,pgsteal_dma32=4466436i,pgsteal_movable=0i,pgsteal_normal=318463755i,pswpin=2092i,pswpout=6206i,slabs_scanned=93775616i,thp_collapse_alloc=24857i,thp_collapse_alloc_failed=102214i,thp_fault_alloc=346219i,thp_fault_fallback=895453i,thp_split=9817i,unevictable_pgs_cleared=0i,unevictable_pgs_culled=1531i,unevictable_pgs_mlocked=6988i,unevictable_pgs_mlockfreed=0i,unevictable_pgs_munlocked=6988i,unevictable_pgs_rescued=5426i,unevictable_pgs_scanned=0i,unevictable_pgs_stranded=0i,zone_reclaim_failed=0i 1459455200071462843 +``` diff --git a/plugins/inputs/system/kernel_vmstat.go b/plugins/inputs/system/kernel_vmstat.go new file mode 100644 index 000000000..c40a437c0 --- /dev/null +++ b/plugins/inputs/system/kernel_vmstat.go @@ -0,0 +1,173 @@ +// +build linux + +package system + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "strconv" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs" +) + +// /proc/vmstat file line prefixes to gather stats on. +// This is currently not being used as we are retrieving all the stats. Left here for references. +var ( + nr_free_pages = []byte("nr_free_pages") + nr_inactive_anon = []byte("nr_inactive_anon") + nr_active_anon = []byte("nr_active_anon") + nr_inactive_file = []byte("nr_inactive_file") + nr_active_file = []byte("nr_active_file") + nr_unevictable = []byte("nr_unevictable") + nr_mlock = []byte("nr_mlock") + nr_anon_pages = []byte("nr_anon_pages") + nr_mapped = []byte("nr_mapped") + nr_file_pages = []byte("nr_file_pages") + nr_dirty = []byte("nr_dirty") + nr_writeback = []byte("nr_writeback") + nr_slab_reclaimable = []byte("nr_slab_reclaimable") + nr_slab_unreclaimable = []byte("nr_slab_unreclaimable") + nr_page_table_pages = []byte("nr_page_table_pages") + nr_kernel_stack = []byte("nr_kernel_stack") + nr_unstable = []byte("nr_unstable") + nr_bounce = []byte("nr_bounce") + nr_vmscan_write = []byte("nr_vmscan_write") + nr_writeback_temp = []byte("nr_writeback_temp") + nr_isolated_anon = []byte("nr_isolated_anon") + nr_isolated_file = []byte("nr_isolated_file") + nr_shmem = []byte("nr_shmem") + numa_hit = []byte("numa_hit") + numa_miss = []byte("numa_miss") + numa_foreign = []byte("numa_foreign") + numa_interleave = []byte("numa_interleave") + numa_local = []byte("numa_local") + numa_other = []byte("numa_other") + nr_anon_transparent_hugepages = []byte("nr_anon_transparent_hugepages") + pgpgin = []byte("pgpgin") + pgpgout = []byte("pgpgout") + pswpin = []byte("pswpin") + pswpout = []byte("pswpout") + pgalloc_dma = []byte("pgalloc_dma") + pgalloc_dma32 = []byte("pgalloc_dma32") + pgalloc_normal = []byte("pgalloc_normal") + pgalloc_movable = []byte("pgalloc_movable") + pgfree = []byte("pgfree") + pgactivate = []byte("pgactivate") + pgdeactivate = []byte("pgdeactivate") + pgfault = []byte("pgfault") + pgmajfault = []byte("pgmajfault") + pgrefill_dma = []byte("pgrefill_dma") + pgrefill_dma32 = []byte("pgrefill_dma32") + pgrefill_normal = []byte("pgrefill_normal") + pgrefill_movable = []byte("pgrefill_movable") + pgsteal_dma = []byte("pgsteal_dma") + pgsteal_dma32 = []byte("pgsteal_dma32") + pgsteal_normal = []byte("pgsteal_normal") + pgsteal_movable = []byte("pgsteal_movable") + pgscan_kswapd_dma = []byte("pgscan_kswapd_dma") + pgscan_kswapd_dma32 = []byte("pgscan_kswapd_dma32") + pgscan_kswapd_normal = []byte("pgscan_kswapd_normal") + pgscan_kswapd_movable = []byte("pgscan_kswapd_movable") + pgscan_direct_dma = []byte("pgscan_direct_dma") + pgscan_direct_dma32 = []byte("pgscan_direct_dma32") + pgscan_direct_normal = []byte("pgscan_direct_normal") + pgscan_direct_movable = []byte("pgscan_direct_movable") + zone_reclaim_failed = []byte("zone_reclaim_failed") + pginodesteal = []byte("pginodesteal") + slabs_scanned = []byte("slabs_scanned") + kswapd_steal = []byte("kswapd_steal") + kswapd_inodesteal = []byte("kswapd_inodesteal") + kswapd_low_wmark_hit_quickly = []byte("kswapd_low_wmark_hit_quickly") + kswapd_high_wmark_hit_quickly = []byte("kswapd_high_wmark_hit_quickly") + kswapd_skip_congestion_wait = []byte("kswapd_skip_congestion_wait") + pageoutrun = []byte("pageoutrun") + allocstall = []byte("allocstall") + pgrotated = []byte("pgrotated") + compact_blocks_moved = []byte("compact_blocks_moved") + compact_pages_moved = []byte("compact_pages_moved") + compact_pagemigrate_failed = []byte("compact_pagemigrate_failed") + compact_stall = []byte("compact_stall") + compact_fail = []byte("compact_fail") + compact_success = []byte("compact_success") + htlb_buddy_alloc_success = []byte("htlb_buddy_alloc_success") + htlb_buddy_alloc_fail = []byte("htlb_buddy_alloc_fail") + unevictable_pgs_culled = []byte("unevictable_pgs_culled") + unevictable_pgs_scanned = []byte("unevictable_pgs_scanned") + unevictable_pgs_rescued = []byte("unevictable_pgs_rescued") + unevictable_pgs_mlocked = []byte("unevictable_pgs_mlocked") + unevictable_pgs_munlocked = []byte("unevictable_pgs_munlocked") + unevictable_pgs_cleared = []byte("unevictable_pgs_cleared") + unevictable_pgs_stranded = []byte("unevictable_pgs_stranded") + unevictable_pgs_mlockfreed = []byte("unevictable_pgs_mlockfreed") + thp_fault_alloc = []byte("thp_fault_alloc") + thp_fault_fallback = []byte("thp_fault_fallback") + thp_collapse_alloc = []byte("thp_collapse_alloc") + thp_collapse_alloc_failed = []byte("thp_collapse_alloc_failed") + thp_split = []byte("thp_split") +) + +type KernelVmstat struct { + statFile string +} + +func (k *KernelVmstat) Description() string { + return "Get kernel statistics from /proc/vmstat" +} + +func (k *KernelVmstat) SampleConfig() string { + return `[[inputs.kernel_vmstat]]` +} + +func (k *KernelVmstat) Gather(acc telegraf.Accumulator) error { + data, err := k.getProcVmstat() + if err != nil { + return err + } + + fields := make(map[string]interface{}) + + dataFields := bytes.Fields(data) + for i, field := range dataFields { + + // dataFields is an array of {"stat1_name", "stat1_value", "stat2_name", "stat2_value", ...} + // We only want the even number index as that contain the stat name. + if i%2 == 0 { + // Convert the stat value into an integer. + m, err := strconv.Atoi(string(dataFields[i+1])) + if err != nil { + return err + } + + fields[string(field)] = int64(m) + } + } + + acc.AddFields("kernel_vmstat", fields, map[string]string{}) + return nil +} + +func (k *KernelVmstat) getProcVmstat() ([]byte, error) { + if _, err := os.Stat(k.statFile); os.IsNotExist(err) { + return nil, fmt.Errorf("kernel_vmstat: %s does not exist!", k.statFile) + } else if err != nil { + return nil, err + } + + data, err := ioutil.ReadFile(k.statFile) + if err != nil { + return nil, err + } + + return data, nil +} + +func init() { + inputs.Add("kernel_vmstat", func() telegraf.Input { + return &KernelVmstat{ + statFile: "/proc/vmstat", + } + }) +} diff --git a/plugins/inputs/system/kernel_vmstat_test.go b/plugins/inputs/system/kernel_vmstat_test.go new file mode 100644 index 000000000..963cf7f4a --- /dev/null +++ b/plugins/inputs/system/kernel_vmstat_test.go @@ -0,0 +1,315 @@ +// +build linux + +package system + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/influxdata/telegraf/testutil" + + "github.com/stretchr/testify/assert" +) + +func TestFullVmStatProcFile(t *testing.T) { + tmpfile := makeFakeStatFile([]byte(vmStatFile_Full)) + defer os.Remove(tmpfile) + + k := KernelVmstat{ + statFile: tmpfile, + } + + acc := testutil.Accumulator{} + err := k.Gather(&acc) + assert.NoError(t, err) + + fields := map[string]interface{}{ + "nr_free_pages": int64(78730), + "nr_inactive_anon": int64(426259), + "nr_active_anon": int64(2515657), + "nr_inactive_file": int64(2366791), + "nr_active_file": int64(2244914), + "nr_unevictable": int64(0), + "nr_mlock": int64(0), + "nr_anon_pages": int64(1358675), + "nr_mapped": int64(558821), + "nr_file_pages": int64(5153546), + "nr_dirty": int64(5690), + "nr_writeback": int64(0), + "nr_slab_reclaimable": int64(459806), + "nr_slab_unreclaimable": int64(47859), + "nr_page_table_pages": int64(11115), + "nr_kernel_stack": int64(579), + "nr_unstable": int64(0), + "nr_bounce": int64(0), + "nr_vmscan_write": int64(6206), + "nr_writeback_temp": int64(0), + "nr_isolated_anon": int64(0), + "nr_isolated_file": int64(0), + "nr_shmem": int64(541689), + "numa_hit": int64(5113399878), + "numa_miss": int64(0), + "numa_foreign": int64(0), + "numa_interleave": int64(35793), + "numa_local": int64(5113399878), + "numa_other": int64(0), + "nr_anon_transparent_hugepages": int64(2034), + "pgpgin": int64(219717626), + "pgpgout": int64(3495885510), + "pswpin": int64(2092), + "pswpout": int64(6206), + "pgalloc_dma": int64(0), + "pgalloc_dma32": int64(122480220), + "pgalloc_normal": int64(5233176719), + "pgalloc_movable": int64(0), + "pgfree": int64(5359765021), + "pgactivate": int64(375664931), + "pgdeactivate": int64(122735906), + "pgfault": int64(8699921410), + "pgmajfault": int64(122210), + "pgrefill_dma": int64(0), + "pgrefill_dma32": int64(1180010), + "pgrefill_normal": int64(119866676), + "pgrefill_movable": int64(0), + "pgsteal_dma": int64(0), + "pgsteal_dma32": int64(4466436), + "pgsteal_normal": int64(318463755), + "pgsteal_movable": int64(0), + "pgscan_kswapd_dma": int64(0), + "pgscan_kswapd_dma32": int64(4480608), + "pgscan_kswapd_normal": int64(287857984), + "pgscan_kswapd_movable": int64(0), + "pgscan_direct_dma": int64(0), + "pgscan_direct_dma32": int64(12256), + "pgscan_direct_normal": int64(31501600), + "pgscan_direct_movable": int64(0), + "zone_reclaim_failed": int64(0), + "pginodesteal": int64(9188431), + "slabs_scanned": int64(93775616), + "kswapd_steal": int64(291534428), + "kswapd_inodesteal": int64(29770874), + "kswapd_low_wmark_hit_quickly": int64(8756), + "kswapd_high_wmark_hit_quickly": int64(25439), + "kswapd_skip_congestion_wait": int64(0), + "pageoutrun": int64(505006), + "allocstall": int64(81496), + "pgrotated": int64(60620), + "compact_blocks_moved": int64(238196), + "compact_pages_moved": int64(6370588), + "compact_pagemigrate_failed": int64(0), + "compact_stall": int64(142092), + "compact_fail": int64(135220), + "compact_success": int64(6872), + "htlb_buddy_alloc_success": int64(0), + "htlb_buddy_alloc_fail": int64(0), + "unevictable_pgs_culled": int64(1531), + "unevictable_pgs_scanned": int64(0), + "unevictable_pgs_rescued": int64(5426), + "unevictable_pgs_mlocked": int64(6988), + "unevictable_pgs_munlocked": int64(6988), + "unevictable_pgs_cleared": int64(0), + "unevictable_pgs_stranded": int64(0), + "unevictable_pgs_mlockfreed": int64(0), + "thp_fault_alloc": int64(346219), + "thp_fault_fallback": int64(895453), + "thp_collapse_alloc": int64(24857), + "thp_collapse_alloc_failed": int64(102214), + "thp_split": int64(9817), + } + acc.AssertContainsFields(t, "kernel_vmstat", fields) +} + +func TestPartialVmStatProcFile(t *testing.T) { + tmpfile := makeFakeStatFile([]byte(vmStatFile_Partial)) + defer os.Remove(tmpfile) + + k := KernelVmstat{ + statFile: tmpfile, + } + + acc := testutil.Accumulator{} + err := k.Gather(&acc) + assert.NoError(t, err) + + fields := map[string]interface{}{ + "unevictable_pgs_culled": int64(1531), + "unevictable_pgs_scanned": int64(0), + "unevictable_pgs_rescued": int64(5426), + "unevictable_pgs_mlocked": int64(6988), + "unevictable_pgs_munlocked": int64(6988), + "unevictable_pgs_cleared": int64(0), + "unevictable_pgs_stranded": int64(0), + "unevictable_pgs_mlockfreed": int64(0), + "thp_fault_alloc": int64(346219), + "thp_fault_fallback": int64(895453), + "thp_collapse_alloc": int64(24857), + "thp_collapse_alloc_failed": int64(102214), + "thp_split": int64(9817), + } + acc.AssertContainsFields(t, "kernel_vmstat", fields) +} + +func TestInvalidVmStatProcFile1(t *testing.T) { + tmpfile := makeFakeStatFile([]byte(vmStatFile_Invalid)) + defer os.Remove(tmpfile) + + k := KernelVmstat{ + statFile: tmpfile, + } + + acc := testutil.Accumulator{} + err := k.Gather(&acc) + assert.Error(t, err) +} + +func TestNoVmStatProcFile(t *testing.T) { + tmpfile := makeFakeStatFile([]byte(vmStatFile_Invalid)) + os.Remove(tmpfile) + + k := KernelVmstat{ + statFile: tmpfile, + } + + acc := testutil.Accumulator{} + err := k.Gather(&acc) + assert.Error(t, err) + assert.Contains(t, err.Error(), "does not exist") +} + +const vmStatFile_Full = `nr_free_pages 78730 +nr_inactive_anon 426259 +nr_active_anon 2515657 +nr_inactive_file 2366791 +nr_active_file 2244914 +nr_unevictable 0 +nr_mlock 0 +nr_anon_pages 1358675 +nr_mapped 558821 +nr_file_pages 5153546 +nr_dirty 5690 +nr_writeback 0 +nr_slab_reclaimable 459806 +nr_slab_unreclaimable 47859 +nr_page_table_pages 11115 +nr_kernel_stack 579 +nr_unstable 0 +nr_bounce 0 +nr_vmscan_write 6206 +nr_writeback_temp 0 +nr_isolated_anon 0 +nr_isolated_file 0 +nr_shmem 541689 +numa_hit 5113399878 +numa_miss 0 +numa_foreign 0 +numa_interleave 35793 +numa_local 5113399878 +numa_other 0 +nr_anon_transparent_hugepages 2034 +pgpgin 219717626 +pgpgout 3495885510 +pswpin 2092 +pswpout 6206 +pgalloc_dma 0 +pgalloc_dma32 122480220 +pgalloc_normal 5233176719 +pgalloc_movable 0 +pgfree 5359765021 +pgactivate 375664931 +pgdeactivate 122735906 +pgfault 8699921410 +pgmajfault 122210 +pgrefill_dma 0 +pgrefill_dma32 1180010 +pgrefill_normal 119866676 +pgrefill_movable 0 +pgsteal_dma 0 +pgsteal_dma32 4466436 +pgsteal_normal 318463755 +pgsteal_movable 0 +pgscan_kswapd_dma 0 +pgscan_kswapd_dma32 4480608 +pgscan_kswapd_normal 287857984 +pgscan_kswapd_movable 0 +pgscan_direct_dma 0 +pgscan_direct_dma32 12256 +pgscan_direct_normal 31501600 +pgscan_direct_movable 0 +zone_reclaim_failed 0 +pginodesteal 9188431 +slabs_scanned 93775616 +kswapd_steal 291534428 +kswapd_inodesteal 29770874 +kswapd_low_wmark_hit_quickly 8756 +kswapd_high_wmark_hit_quickly 25439 +kswapd_skip_congestion_wait 0 +pageoutrun 505006 +allocstall 81496 +pgrotated 60620 +compact_blocks_moved 238196 +compact_pages_moved 6370588 +compact_pagemigrate_failed 0 +compact_stall 142092 +compact_fail 135220 +compact_success 6872 +htlb_buddy_alloc_success 0 +htlb_buddy_alloc_fail 0 +unevictable_pgs_culled 1531 +unevictable_pgs_scanned 0 +unevictable_pgs_rescued 5426 +unevictable_pgs_mlocked 6988 +unevictable_pgs_munlocked 6988 +unevictable_pgs_cleared 0 +unevictable_pgs_stranded 0 +unevictable_pgs_mlockfreed 0 +thp_fault_alloc 346219 +thp_fault_fallback 895453 +thp_collapse_alloc 24857 +thp_collapse_alloc_failed 102214 +thp_split 9817` + +const vmStatFile_Partial = `unevictable_pgs_culled 1531 +unevictable_pgs_scanned 0 +unevictable_pgs_rescued 5426 +unevictable_pgs_mlocked 6988 +unevictable_pgs_munlocked 6988 +unevictable_pgs_cleared 0 +unevictable_pgs_stranded 0 +unevictable_pgs_mlockfreed 0 +thp_fault_alloc 346219 +thp_fault_fallback 895453 +thp_collapse_alloc 24857 +thp_collapse_alloc_failed 102214 +thp_split 9817` + +// invalid thp_split measurement +const vmStatFile_Invalid = `unevictable_pgs_culled 1531 +unevictable_pgs_scanned 0 +unevictable_pgs_rescued 5426 +unevictable_pgs_mlocked 6988 +unevictable_pgs_munlocked 6988 +unevictable_pgs_cleared 0 +unevictable_pgs_stranded 0 +unevictable_pgs_mlockfreed 0 +thp_fault_alloc 346219 +thp_fault_fallback 895453 +thp_collapse_alloc 24857 +thp_collapse_alloc_failed 102214 +thp_split abcd` + +func makeFakeVmStatFile(content []byte) string { + tmpfile, err := ioutil.TempFile("", "kernel_vmstat_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() +}