package zfs import ( "io/ioutil" "os" "testing" "github.com/influxdata/telegraf/testutil" "github.com/stretchr/testify/require" ) const arcstatsContents = `5 1 0x01 86 4128 23617128247 12081618582809582 name type data hits 4 5968846374 misses 4 1659178751 demand_data_hits 4 4860247322 demand_data_misses 4 501499535 demand_metadata_hits 4 708608325 demand_metadata_misses 4 156591375 prefetch_data_hits 4 367047144 prefetch_data_misses 4 974529898 prefetch_metadata_hits 4 32943583 prefetch_metadata_misses 4 26557943 mru_hits 4 301176811 mru_ghost_hits 4 47066067 mfu_hits 4 5520612438 mfu_ghost_hits 4 45784009 deleted 4 1718937704 recycle_miss 4 481222994 mutex_miss 4 20575623 evict_skip 4 14655903906543 evict_l2_cached 4 145310202998272 evict_l2_eligible 4 16345402777088 evict_l2_ineligible 4 7437226893312 hash_elements 4 36617980 hash_elements_max 4 36618318 hash_collisions 4 554145157 hash_chains 4 4187651 hash_chain_max 4 26 p 4 13963222064 c 4 16381258376 c_min 4 4194304 c_max 4 16884125696 size 4 16319887096 hdr_size 4 42567864 data_size 4 60066304 meta_size 4 1701534208 other_size 4 1661543168 anon_size 4 94720 anon_evict_data 4 0 anon_evict_metadata 4 0 mru_size 4 973099008 mru_evict_data 4 9175040 mru_evict_metadata 4 32768 mru_ghost_size 4 32768 mru_ghost_evict_data 4 0 mru_ghost_evict_metadata 4 32768 mfu_size 4 788406784 mfu_evict_data 4 50881024 mfu_evict_metadata 4 81920 mfu_ghost_size 4 0 mfu_ghost_evict_data 4 0 mfu_ghost_evict_metadata 4 0 l2_hits 4 573868618 l2_misses 4 1085309718 l2_feeds 4 12182087 l2_rw_clash 4 9610 l2_read_bytes 4 32695938336768 l2_write_bytes 4 2826774778880 l2_writes_sent 4 4267687 l2_writes_done 4 4267687 l2_writes_error 4 0 l2_writes_hdr_miss 4 164 l2_evict_lock_retry 4 5 l2_evict_reading 4 0 l2_free_on_write 4 1606914 l2_cdata_free_on_write 4 1775 l2_abort_lowmem 4 83462 l2_cksum_bad 4 393860640 l2_io_error 4 53881460 l2_size 4 2471466648576 l2_asize 4 2461690072064 l2_hdr_size 4 12854175552 l2_compress_successes 4 12184849 l2_compress_zeros 4 0 l2_compress_failures 4 0 memory_throttle_count 4 0 duplicate_buffers 4 0 duplicate_buffers_size 4 0 duplicate_reads 4 0 memory_direct_count 4 5159942 memory_indirect_count 4 3034640 arc_no_grow 4 0 arc_tempreserve 4 0 arc_loaned_bytes 4 0 arc_prune 4 114554259559 arc_meta_used 4 16259820792 arc_meta_limit 4 12663094272 arc_meta_max 4 18327165696 ` const zfetchstatsContents = `3 1 0x01 11 528 23607270446 12081656848148208 name type data hits 4 7812959060 misses 4 4154484207 colinear_hits 4 1366368 colinear_misses 4 4153117839 stride_hits 4 7309776732 stride_misses 4 222766182 reclaim_successes 4 107788388 reclaim_failures 4 4045329451 streams_resets 4 20989756 streams_noresets 4 503182328 bogus_streams 4 0 ` const vdev_cache_statsContents = `7 1 0x01 3 144 23617323692 12081684236238879 name type data delegations 4 0 hits 4 0 misses 4 0 ` const pool_ioContents = `11 3 0x00 1 80 2225326830828 32953476980628 nread nwritten reads writes wtime wlentime wupdate rtime rlentime rupdate wcnt rcnt 1884160 6450688 22 978 272187126 2850519036 2263669418655 424226814 2850519036 2263669871823 0 0 ` var testKstatPath = os.TempDir() + "/telegraf/proc/spl/kstat/zfs" func TestZfsPoolMetrics(t *testing.T) { err := os.MkdirAll(testKstatPath, 0755) require.NoError(t, err) err = os.MkdirAll(testKstatPath+"/HOME", 0755) require.NoError(t, err) err = ioutil.WriteFile(testKstatPath+"/HOME/io", []byte(pool_ioContents), 0644) require.NoError(t, err) err = ioutil.WriteFile(testKstatPath+"/arcstats", []byte(arcstatsContents), 0644) require.NoError(t, err) poolMetrics := getPoolMetrics() var acc testutil.Accumulator z := &Zfs{KstatPath: testKstatPath, KstatMetrics: []string{"arcstats"}} err = z.Gather(&acc) require.NoError(t, err) require.False(t, acc.HasMeasurement("zfs_pool")) acc.Metrics = nil z = &Zfs{KstatPath: testKstatPath, KstatMetrics: []string{"arcstats"}, PoolMetrics: true} err = z.Gather(&acc) require.NoError(t, err) //one pool, all metrics tags := map[string]string{ "pool": "HOME", } acc.AssertContainsTaggedFields(t, "zfs_pool", poolMetrics, tags) err = os.RemoveAll(os.TempDir() + "/telegraf") require.NoError(t, err) } func TestZfsGeneratesMetrics(t *testing.T) { err := os.MkdirAll(testKstatPath, 0755) require.NoError(t, err) err = os.MkdirAll(testKstatPath+"/HOME", 0755) require.NoError(t, err) err = ioutil.WriteFile(testKstatPath+"/HOME/io", []byte(""), 0644) require.NoError(t, err) err = ioutil.WriteFile(testKstatPath+"/arcstats", []byte(arcstatsContents), 0644) require.NoError(t, err) err = ioutil.WriteFile(testKstatPath+"/zfetchstats", []byte(zfetchstatsContents), 0644) require.NoError(t, err) err = ioutil.WriteFile(testKstatPath+"/vdev_cache_stats", []byte(vdev_cache_statsContents), 0644) require.NoError(t, err) intMetrics := getKstatMetricsAll() var acc testutil.Accumulator //one pool, all metrics tags := map[string]string{ "pools": "HOME", } z := &Zfs{KstatPath: testKstatPath} err = z.Gather(&acc) require.NoError(t, err) acc.AssertContainsTaggedFields(t, "zfs", intMetrics, tags) acc.Metrics = nil //two pools, all metrics err = os.MkdirAll(testKstatPath+"/STORAGE", 0755) require.NoError(t, err) err = ioutil.WriteFile(testKstatPath+"/STORAGE/io", []byte(""), 0644) require.NoError(t, err) tags = map[string]string{ "pools": "HOME::STORAGE", } z = &Zfs{KstatPath: testKstatPath} acc2 := testutil.Accumulator{} err = z.Gather(&acc2) require.NoError(t, err) acc2.AssertContainsTaggedFields(t, "zfs", intMetrics, tags) acc2.Metrics = nil intMetrics = getKstatMetricsArcOnly() //two pools, one metric z = &Zfs{KstatPath: testKstatPath, KstatMetrics: []string{"arcstats"}} acc3 := testutil.Accumulator{} err = z.Gather(&acc3) require.NoError(t, err) acc3.AssertContainsTaggedFields(t, "zfs", intMetrics, tags) err = os.RemoveAll(os.TempDir() + "/telegraf") require.NoError(t, err) } func getKstatMetricsArcOnly() map[string]interface{} { return map[string]interface{}{ "arcstats_hits": int64(5968846374), "arcstats_misses": int64(1659178751), "arcstats_demand_data_hits": int64(4860247322), "arcstats_demand_data_misses": int64(501499535), "arcstats_demand_metadata_hits": int64(708608325), "arcstats_demand_metadata_misses": int64(156591375), "arcstats_prefetch_data_hits": int64(367047144), "arcstats_prefetch_data_misses": int64(974529898), "arcstats_prefetch_metadata_hits": int64(32943583), "arcstats_prefetch_metadata_misses": int64(26557943), "arcstats_mru_hits": int64(301176811), "arcstats_mru_ghost_hits": int64(47066067), "arcstats_mfu_hits": int64(5520612438), "arcstats_mfu_ghost_hits": int64(45784009), "arcstats_deleted": int64(1718937704), "arcstats_recycle_miss": int64(481222994), "arcstats_mutex_miss": int64(20575623), "arcstats_evict_skip": int64(14655903906543), "arcstats_evict_l2_cached": int64(145310202998272), "arcstats_evict_l2_eligible": int64(16345402777088), "arcstats_evict_l2_ineligible": int64(7437226893312), "arcstats_hash_elements": int64(36617980), "arcstats_hash_elements_max": int64(36618318), "arcstats_hash_collisions": int64(554145157), "arcstats_hash_chains": int64(4187651), "arcstats_hash_chain_max": int64(26), "arcstats_p": int64(13963222064), "arcstats_c": int64(16381258376), "arcstats_c_min": int64(4194304), "arcstats_c_max": int64(16884125696), "arcstats_size": int64(16319887096), "arcstats_hdr_size": int64(42567864), "arcstats_data_size": int64(60066304), "arcstats_meta_size": int64(1701534208), "arcstats_other_size": int64(1661543168), "arcstats_anon_size": int64(94720), "arcstats_anon_evict_data": int64(0), "arcstats_anon_evict_metadata": int64(0), "arcstats_mru_size": int64(973099008), "arcstats_mru_evict_data": int64(9175040), "arcstats_mru_evict_metadata": int64(32768), "arcstats_mru_ghost_size": int64(32768), "arcstats_mru_ghost_evict_data": int64(0), "arcstats_mru_ghost_evict_metadata": int64(32768), "arcstats_mfu_size": int64(788406784), "arcstats_mfu_evict_data": int64(50881024), "arcstats_mfu_evict_metadata": int64(81920), "arcstats_mfu_ghost_size": int64(0), "arcstats_mfu_ghost_evict_data": int64(0), "arcstats_mfu_ghost_evict_metadata": int64(0), "arcstats_l2_hits": int64(573868618), "arcstats_l2_misses": int64(1085309718), "arcstats_l2_feeds": int64(12182087), "arcstats_l2_rw_clash": int64(9610), "arcstats_l2_read_bytes": int64(32695938336768), "arcstats_l2_write_bytes": int64(2826774778880), "arcstats_l2_writes_sent": int64(4267687), "arcstats_l2_writes_done": int64(4267687), "arcstats_l2_writes_error": int64(0), "arcstats_l2_writes_hdr_miss": int64(164), "arcstats_l2_evict_lock_retry": int64(5), "arcstats_l2_evict_reading": int64(0), "arcstats_l2_free_on_write": int64(1606914), "arcstats_l2_cdata_free_on_write": int64(1775), "arcstats_l2_abort_lowmem": int64(83462), "arcstats_l2_cksum_bad": int64(393860640), "arcstats_l2_io_error": int64(53881460), "arcstats_l2_size": int64(2471466648576), "arcstats_l2_asize": int64(2461690072064), "arcstats_l2_hdr_size": int64(12854175552), "arcstats_l2_compress_successes": int64(12184849), "arcstats_l2_compress_zeros": int64(0), "arcstats_l2_compress_failures": int64(0), "arcstats_memory_throttle_count": int64(0), "arcstats_duplicate_buffers": int64(0), "arcstats_duplicate_buffers_size": int64(0), "arcstats_duplicate_reads": int64(0), "arcstats_memory_direct_count": int64(5159942), "arcstats_memory_indirect_count": int64(3034640), "arcstats_arc_no_grow": int64(0), "arcstats_arc_tempreserve": int64(0), "arcstats_arc_loaned_bytes": int64(0), "arcstats_arc_prune": int64(114554259559), "arcstats_arc_meta_used": int64(16259820792), "arcstats_arc_meta_limit": int64(12663094272), "arcstats_arc_meta_max": int64(18327165696), } } func getKstatMetricsAll() map[string]interface{} { otherMetrics := map[string]interface{}{ "zfetchstats_hits": int64(7812959060), "zfetchstats_misses": int64(4154484207), "zfetchstats_colinear_hits": int64(1366368), "zfetchstats_colinear_misses": int64(4153117839), "zfetchstats_stride_hits": int64(7309776732), "zfetchstats_stride_misses": int64(222766182), "zfetchstats_reclaim_successes": int64(107788388), "zfetchstats_reclaim_failures": int64(4045329451), "zfetchstats_streams_resets": int64(20989756), "zfetchstats_streams_noresets": int64(503182328), "zfetchstats_bogus_streams": int64(0), "vdev_cache_stats_delegations": int64(0), "vdev_cache_stats_hits": int64(0), "vdev_cache_stats_misses": int64(0), } arcMetrics := getKstatMetricsArcOnly() for k, v := range otherMetrics { arcMetrics[k] = v } return arcMetrics } func getPoolMetrics() map[string]interface{} { return map[string]interface{}{ "nread": int64(1884160), "nwritten": int64(6450688), "reads": int64(22), "writes": int64(978), "wtime": int64(272187126), "wlentime": int64(2850519036), "wupdate": int64(2263669418655), "rtime": int64(424226814), "rlentime": int64(2850519036), "rupdate": int64(2263669871823), "wcnt": int64(0), "rcnt": int64(0), } }