Skip to content

Commit

Permalink
system/zfs: Add ARC statistics
Browse files Browse the repository at this point in the history
  • Loading branch information
ppmathis committed Jun 22, 2019
1 parent 0d7358e commit ba3adb7
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 3 deletions.
19 changes: 16 additions & 3 deletions mod-system/zfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ type zfsSummarizer struct {
nagocheck.Summarizer
}

type zfsGlobalStats struct{}
type zfsGlobalStats struct {
arcSize uint64
arcHits uint64
arcMisses uint64
}

type zfsPoolStats struct {
state string
Expand All @@ -56,7 +60,7 @@ type zfsPoolIOStats struct {
func newZfsPlugin() *zfsPlugin {
return &zfsPlugin{
Plugin: nagocheck.NewPlugin("zfs",
nagocheck.PluginDescription("ZFS Statistics"),
nagocheck.PluginDescription("ZFS Pool Statistics"),
nagocheck.PluginForceVerbose(true),
),
}
Expand All @@ -66,6 +70,10 @@ func (p *zfsPlugin) DefineCheck() nagopher.Check {
check := nagopher.NewCheck("zfs", newZfsSummarizer(p))
check.AttachResources(newZfsResource(p))
check.AttachContexts(
nagopher.NewScalarContext("arc_size", nil, nil),
nagopher.NewScalarContext("arc_hits", nil, nil),
nagopher.NewScalarContext("arc_misses", nil, nil),

nagopher.NewStringMatchContext("pool_state", nagopher.StateCritical(), []string{"ONLINE"}),
nagopher.NewStringInfoContext("pool"),
)
Expand All @@ -84,10 +92,15 @@ func (r *zfsResource) Probe(warnings nagopher.WarningCollection) (metrics []nago
return metrics, err
}

metrics = append(metrics,
nagopher.MustNewNumericMetric("arc_size", float64(r.globalStats.arcSize), "B", nil, ""),
nagopher.MustNewNumericMetric("arc_hits", float64(r.globalStats.arcHits), "c", nil, ""),
nagopher.MustNewNumericMetric("arc_misses", float64(r.globalStats.arcMisses), "c", nil, ""),
)

for poolName, pool := range r.poolStats {
metrics = append(metrics,
nagopher.MustNewStringMetric(fmt.Sprintf("pool_%s_state", poolName), pool.state, "pool_state"),

nagopher.MustNewStringMetric(
fmt.Sprintf("pool_%s", poolName),
fmt.Sprintf("%s is %s - %s read, %s written",
Expand Down
62 changes: 62 additions & 0 deletions mod-system/zfs_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,82 @@ import (
)

const zfsProcBasePath = "/proc/spl/kstat/zfs"
const zfsProcArcStats = "arcstats"
const zfsPoolPathPattern = "/*/io"

const (
zfsTypeUint64 = "4"
)

func (r *zfsResource) Collect(warnings nagopher.WarningCollection) error {
if err := r.collectGlobal(zfsProcBasePath, warnings); err != nil {
return err
}

if err := r.collectPools(zfsProcBasePath); err != nil {
return err
}

return nil
}

func (r *zfsResource) collectGlobal(basePath string, warnings nagopher.WarningCollection) error {
if file, err := os.Open(filepath.Join(basePath, zfsProcArcStats)); err == nil {
if metrics, err := r.parseGlobalStats(file, warnings); err == nil {
if value, ok := metrics["size"]; ok {
r.globalStats.arcSize = value
}
if value, ok := metrics["hits"]; ok {
r.globalStats.arcHits = value
}
if value, ok := metrics["misses"]; ok {
r.globalStats.arcMisses = value
}
} else {
warnings.Add(nagopher.NewWarning("could not parse arc statistics: %s", err.Error()))
}
} else {
warnings.Add(nagopher.NewWarning("could not gather arc statistics: %s", err.Error()))
}

return nil
}

func (r *zfsResource) parseGlobalStats(reader io.Reader, warnings nagopher.WarningCollection) (metrics map[string]uint64, _ error) {
skipParsing := true
scanner := bufio.NewScanner(reader)
metrics = make(map[string]uint64)

for scanner.Scan() {
parts := strings.Fields(scanner.Text())

if skipParsing && len(parts) == 3 && parts[0] == "name" && parts[1] == "type" && parts[2] == "data" {
skipParsing = false
continue
} else if skipParsing || len(parts) < 3 {
continue
}

metricKey, metricType, metricValue := parts[0], parts[1], parts[2]
switch metricType {
case zfsTypeUint64:
value, err := strconv.ParseUint(metricValue, 10, 64)
if err != nil {
warnings.Add(nagopher.NewWarning("could not parse metric [%s] as uint64: %s", metricKey, metricValue))
continue
}

metrics[metricKey] = value
}
}

if skipParsing {
return metrics, fmt.Errorf("no global statistics have been parsed")
}

return metrics, nil
}

func (r *zfsResource) collectPools(basePath string) error {
globMatches, err := filepath.Glob(filepath.Join(zfsProcBasePath, zfsPoolPathPattern))
if err != nil {
Expand Down

0 comments on commit ba3adb7

Please sign in to comment.