ZFS Collector: Refactor to use maps/slices and fewer globals

Removed all global types that were unnecessary, and refactored to use constructor-created values and inline values instead of globals.

Signed-Off-By: Joe Handzik <joseph.t.handzik@hpe.com>
This commit is contained in:
Joe Handzik 2017-01-25 21:47:48 -06:00
parent 1dde3ec31b
commit e213ccbc57
3 changed files with 48 additions and 169 deletions

View File

@ -24,30 +24,14 @@ import (
"github.com/prometheus/common/log"
)
type zfsMetricValue int
const zfsErrorValue = zfsMetricValue(-1)
var zfsNotAvailableError = errors.New("ZFS / ZFS statistics are not available")
type zfsSysctl string
type zfsSubsystemName string
const (
arc = zfsSubsystemName("zfsArc")
dmuTx = zfsSubsystemName("zfsDmuTx")
fm = zfsSubsystemName("zfsFm")
vdevCache = zfsSubsystemName("zfsVdevCache")
xuio = zfsSubsystemName("zfsXuio")
zfetch = zfsSubsystemName("zfsFetch")
zil = zfsSubsystemName("zfsZil")
zpoolSubsystem = zfsSubsystemName("zfsPool")
)
// Metrics
type zfsMetric struct {
subsystem zfsSubsystemName // The Prometheus subsystem name.
subsystem string // The Prometheus subsystem name.
name string // The Prometheus name of the metric.
sysctl zfsSysctl // The sysctl of the ZFS metric.
}
@ -60,15 +44,28 @@ func init() {
type zfsCollector struct {
zfsMetrics []zfsMetric
linuxProcpathBase string
linuxPathMap map[string]string
}
func NewZFSCollector() (Collector, error) {
return &zfsCollector{}, nil
var z zfsCollector
z.linuxProcpathBase = "spl/kstat/zfs"
z.linuxPathMap = map[string]string{
"zfsArc": "arcstats",
"zfsDmuTx": "dmu_tx",
"zfsFm": "fm",
"zfsFetch": "zfetchstats",
"zfsVdevCache": "vdev_cache_stats",
"zfsXuio": "xuio_stats",
"zfsZil": "zil",
}
return &z, nil
}
func (c *zfsCollector) Update(ch chan<- prometheus.Metric) (err error) {
// Arcstats
err = c.updateArcstats(ch)
for subsystem := range c.linuxPathMap {
err = c.updateZfsStats(subsystem, ch)
switch {
case err == zfsNotAvailableError:
log.Debug(err)
@ -76,41 +73,6 @@ func (c *zfsCollector) Update(ch chan<- prometheus.Metric) (err error) {
case err != nil:
return err
}
// Zfetchstats
err = c.updateZfetchstats(ch)
if err != nil {
return err
}
// Zil
err = c.updateZil(ch)
if err != nil {
return err
}
// VdevCacheStats
err = c.updateVdevCacheStats(ch)
if err != nil {
return err
}
// XuioStats
err = c.updateXuioStats(ch)
if err != nil {
return err
}
// Fm
err = c.updateFm(ch)
if err != nil {
return err
}
// DmuTx
err = c.updateDmuTx(ch)
if err != nil {
return err
}
// Pool stats
@ -122,7 +84,7 @@ func (s zfsSysctl) metricName() string {
return parts[len(parts)-1]
}
func (c *zfsCollector) constSysctlMetric(subsystem zfsSubsystemName, sysctl zfsSysctl, value zfsMetricValue) prometheus.Metric {
func (c *zfsCollector) constSysctlMetric(subsystem string, sysctl zfsSysctl, value int) prometheus.Metric {
metricName := sysctl.metricName()
return prometheus.MustNewConstMetric(

View File

@ -26,17 +26,6 @@ import (
"github.com/prometheus/common/log"
)
const (
zfsProcpathBase = "spl/kstat/zfs/"
zfsArcstatsExt = "arcstats"
zfsDmuTxExt = "dmu_tx"
zfsFmExt = "fm"
zfsFetchstatsExt = "zfetchstats"
zfsVdevCacheStatsExt = "vdev_cache_stats"
zfsXuioStatsExt = "xuio_stats"
zfsZilExt = "zil"
)
func (c *zfsCollector) openProcFile(path string) (file *os.File, err error) {
file, err = os.Open(procFilePath(path))
if err != nil {
@ -46,91 +35,19 @@ func (c *zfsCollector) openProcFile(path string) (file *os.File, err error) {
return
}
func (c *zfsCollector) updateArcstats(ch chan<- prometheus.Metric) (err error) {
file, err := c.openProcFile(filepath.Join(zfsProcpathBase, zfsArcstatsExt))
func (c *zfsCollector) updateZfsStats(subsystem string, ch chan<- prometheus.Metric) (err error) {
file, err := c.openProcFile(filepath.Join(c.linuxProcpathBase, c.linuxPathMap[subsystem]))
if err != nil {
return err
}
defer file.Close()
return c.parseProcfsFile(file, zfsArcstatsExt, func(s zfsSysctl, v zfsMetricValue) {
ch <- c.constSysctlMetric(arc, s, v)
return c.parseProcfsFile(file, c.linuxPathMap[subsystem], func(s zfsSysctl, v int) {
ch <- c.constSysctlMetric(subsystem, s, v)
})
}
func (c *zfsCollector) updateZfetchstats(ch chan<- prometheus.Metric) (err error) {
file, err := c.openProcFile(filepath.Join(zfsProcpathBase, zfsFetchstatsExt))
if err != nil {
return err
}
defer file.Close()
return c.parseProcfsFile(file, zfsFetchstatsExt, func(s zfsSysctl, v zfsMetricValue) {
ch <- c.constSysctlMetric(zfetch, s, v)
})
}
func (c *zfsCollector) updateZil(ch chan<- prometheus.Metric) (err error) {
file, err := c.openProcFile(filepath.Join(zfsProcpathBase, zfsZilExt))
if err != nil {
return err
}
defer file.Close()
return c.parseProcfsFile(file, zfsZilExt, func(s zfsSysctl, v zfsMetricValue) {
ch <- c.constSysctlMetric(zil, s, v)
})
}
func (c *zfsCollector) updateVdevCacheStats(ch chan<- prometheus.Metric) (err error) {
file, err := c.openProcFile(filepath.Join(zfsProcpathBase, zfsVdevCacheStatsExt))
if err != nil {
return err
}
defer file.Close()
return c.parseProcfsFile(file, zfsVdevCacheStatsExt, func(s zfsSysctl, v zfsMetricValue) {
ch <- c.constSysctlMetric(vdevCache, s, v)
})
}
func (c *zfsCollector) updateXuioStats(ch chan<- prometheus.Metric) (err error) {
file, err := c.openProcFile(filepath.Join(zfsProcpathBase, zfsXuioStatsExt))
if err != nil {
return err
}
defer file.Close()
return c.parseProcfsFile(file, zfsXuioStatsExt, func(s zfsSysctl, v zfsMetricValue) {
ch <- c.constSysctlMetric(xuio, s, v)
})
}
func (c *zfsCollector) updateFm(ch chan<- prometheus.Metric) (err error) {
file, err := c.openProcFile(filepath.Join(zfsProcpathBase, zfsFmExt))
if err != nil {
return err
}
defer file.Close()
return c.parseProcfsFile(file, zfsFmExt, func(s zfsSysctl, v zfsMetricValue) {
ch <- c.constSysctlMetric(fm, s, v)
})
}
func (c *zfsCollector) updateDmuTx(ch chan<- prometheus.Metric) (err error) {
file, err := c.openProcFile(filepath.Join(zfsProcpathBase, zfsDmuTxExt))
if err != nil {
return err
}
defer file.Close()
return c.parseProcfsFile(file, zfsDmuTxExt, func(s zfsSysctl, v zfsMetricValue) {
ch <- c.constSysctlMetric(dmuTx, s, v)
})
}
func (c *zfsCollector) parseProcfsFile(reader io.Reader, fmtExt string, handler func(zfsSysctl, zfsMetricValue)) (err error) {
func (c *zfsCollector) parseProcfsFile(reader io.Reader, fmtExt string, handler func(zfsSysctl, int)) (err error) {
scanner := bufio.NewScanner(reader)
parseLine := false
@ -154,7 +71,7 @@ func (c *zfsCollector) parseProcfsFile(reader io.Reader, fmtExt string, handler
if err != nil {
return fmt.Errorf("could not parse expected integer value for %q", key)
}
handler(zfsSysctl(key), zfsMetricValue(value))
handler(zfsSysctl(key), value)
}
if !parseLine {

View File

@ -31,7 +31,7 @@ func TestArcstatsParsing(t *testing.T) {
}
handlerCalled := false
err = c.parseProcfsFile(arcstatsFile, "arcstats", func(s zfsSysctl, v zfsMetricValue) {
err = c.parseProcfsFile(arcstatsFile, "arcstats", func(s zfsSysctl, v int) {
if s != zfsSysctl("kstat.zfs.misc.arcstats.hits") {
return
@ -39,7 +39,7 @@ func TestArcstatsParsing(t *testing.T) {
handlerCalled = true
if v != zfsMetricValue(8772612) {
if v != int(8772612) {
t.Fatalf("Incorrect value parsed from procfs data")
}
@ -67,7 +67,7 @@ func TestZfetchstatsParsing(t *testing.T) {
}
handlerCalled := false
err = c.parseProcfsFile(zfetchstatsFile, "zfetchstats", func(s zfsSysctl, v zfsMetricValue) {
err = c.parseProcfsFile(zfetchstatsFile, "zfetchstats", func(s zfsSysctl, v int) {
if s != zfsSysctl("kstat.zfs.misc.zfetchstats.hits") {
return
@ -75,7 +75,7 @@ func TestZfetchstatsParsing(t *testing.T) {
handlerCalled = true
if v != zfsMetricValue(7067992) {
if v != int(7067992) {
t.Fatalf("Incorrect value parsed from procfs data")
}
@ -103,7 +103,7 @@ func TestZilParsing(t *testing.T) {
}
handlerCalled := false
err = c.parseProcfsFile(zilFile, "zil", func(s zfsSysctl, v zfsMetricValue) {
err = c.parseProcfsFile(zilFile, "zil", func(s zfsSysctl, v int) {
if s != zfsSysctl("kstat.zfs.misc.zil.zil_commit_count") {
return
@ -111,7 +111,7 @@ func TestZilParsing(t *testing.T) {
handlerCalled = true
if v != zfsMetricValue(10) {
if v != int(10) {
t.Fatalf("Incorrect value parsed from procfs data")
}
@ -139,7 +139,7 @@ func TestVdevCacheStatsParsing(t *testing.T) {
}
handlerCalled := false
err = c.parseProcfsFile(vdevCacheStatsFile, "vdev_cache_stats", func(s zfsSysctl, v zfsMetricValue) {
err = c.parseProcfsFile(vdevCacheStatsFile, "vdev_cache_stats", func(s zfsSysctl, v int) {
if s != zfsSysctl("kstat.zfs.misc.vdev_cache_stats.delegations") {
return
@ -147,7 +147,7 @@ func TestVdevCacheStatsParsing(t *testing.T) {
handlerCalled = true
if v != zfsMetricValue(40) {
if v != int(40) {
t.Fatalf("Incorrect value parsed from procfs data")
}
@ -175,7 +175,7 @@ func TestXuioStatsParsing(t *testing.T) {
}
handlerCalled := false
err = c.parseProcfsFile(xuioStatsFile, "xuio_stats", func(s zfsSysctl, v zfsMetricValue) {
err = c.parseProcfsFile(xuioStatsFile, "xuio_stats", func(s zfsSysctl, v int) {
if s != zfsSysctl("kstat.zfs.misc.xuio_stats.onloan_read_buf") {
return
@ -183,7 +183,7 @@ func TestXuioStatsParsing(t *testing.T) {
handlerCalled = true
if v != zfsMetricValue(32) {
if v != int(32) {
t.Fatalf("Incorrect value parsed from procfs data")
}
@ -211,7 +211,7 @@ func TestFmParsing(t *testing.T) {
}
handlerCalled := false
err = c.parseProcfsFile(fmFile, "fm", func(s zfsSysctl, v zfsMetricValue) {
err = c.parseProcfsFile(fmFile, "fm", func(s zfsSysctl, v int) {
if s != zfsSysctl("kstat.zfs.misc.fm.erpt-dropped") {
return
@ -219,7 +219,7 @@ func TestFmParsing(t *testing.T) {
handlerCalled = true
if v != zfsMetricValue(18) {
if v != int(18) {
t.Fatalf("Incorrect value parsed from procfs data")
}
@ -247,7 +247,7 @@ func TestDmuTxParsing(t *testing.T) {
}
handlerCalled := false
err = c.parseProcfsFile(dmuTxFile, "dmu_tx", func(s zfsSysctl, v zfsMetricValue) {
err = c.parseProcfsFile(dmuTxFile, "dmu_tx", func(s zfsSysctl, v int) {
if s != zfsSysctl("kstat.zfs.misc.dmu_tx.dmu_tx_assigned") {
return
@ -255,7 +255,7 @@ func TestDmuTxParsing(t *testing.T) {
handlerCalled = true
if v != zfsMetricValue(3532844) {
if v != int(3532844) {
t.Fatalf("Incorrect value parsed from procfs data")
}