It is tested on FreeBSD 10.2-RELEASE and Linux (ZFS on Linux 0.6.5.4). On FreeBSD, Solaris, etc. ZFS metrics are exposed through sysctls. ZFS on Linux exposes the same metrics through procfs `/proc/spl/...`. In addition to sysctl metrics, 'computed metrics' are exposed by the collector, which are based on several sysctl values. There is some conditional logic involved in computing these metrics which cannot be easily mapped to PromQL. Not all 92 ARC sysctls are exposed right now but this can be changed with one additional LOC each.
88 lines
1.8 KiB
Go
88 lines
1.8 KiB
Go
package collector
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/common/log"
|
|
)
|
|
|
|
const (
|
|
zfsArcstatsProcpath = "spl/kstat/zfs/arcstats"
|
|
)
|
|
|
|
func (c *zfsCollector) zfsAvailable() (err error) {
|
|
file, err := c.openArcstatsFile()
|
|
if err != nil {
|
|
file.Close()
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (c *zfsCollector) openArcstatsFile() (file *os.File, err error) {
|
|
file, err = os.Open(procFilePath(zfsArcstatsProcpath))
|
|
if err != nil {
|
|
log.Debugf("Cannot open %q for reading. Is the kernel module loaded?", procFilePath(zfsArcstatsProcpath))
|
|
err = zfsNotAvailableError
|
|
}
|
|
return
|
|
}
|
|
|
|
func (c *zfsCollector) updateArcstats(ch chan<- prometheus.Metric) (err error) {
|
|
|
|
file, err := c.openArcstatsFile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
return c.parseArcstatsProcfsFile(file, func(s zfsSysctl, v zfsMetricValue) {
|
|
ch <- c.ConstSysctlMetric(arc, s, v)
|
|
})
|
|
|
|
}
|
|
|
|
func (c *zfsCollector) parseArcstatsProcfsFile(reader io.Reader, handler func(zfsSysctl, zfsMetricValue)) (err error) {
|
|
|
|
scanner := bufio.NewScanner(reader)
|
|
|
|
parseLine := false
|
|
for scanner.Scan() {
|
|
|
|
parts := strings.Fields(scanner.Text())
|
|
|
|
if !parseLine && len(parts) == 3 && parts[0] == "name" && parts[1] == "type" && parts[2] == "data" {
|
|
// Start parsing from here.
|
|
parseLine = true
|
|
continue
|
|
}
|
|
|
|
if !parseLine || len(parts) < 3 {
|
|
continue
|
|
}
|
|
|
|
key := fmt.Sprintf("kstat.zfs.misc.arcstats.%s", parts[0])
|
|
|
|
value, err := strconv.Atoi(parts[2])
|
|
if err != nil {
|
|
return fmt.Errorf("could not parse expected integer value for %q", key)
|
|
}
|
|
handler(zfsSysctl(key), zfsMetricValue(value))
|
|
|
|
}
|
|
if !parseLine {
|
|
return errors.New("did not parse a single arcstat metric")
|
|
}
|
|
|
|
return scanner.Err()
|
|
}
|
|
|
|
func (c *zfsCollector) updatePoolStats(ch chan<- prometheus.Metric) (err error) {
|
|
return nil
|
|
}
|