From 632c8e13c1921b859de7a95dd09bb13705025d33 Mon Sep 17 00:00:00 2001 From: ston1th Date: Mon, 31 Aug 2020 17:49:38 +0200 Subject: [PATCH] added syspatch exporter --- main.go | 17 +++++++++-- syspatch/syspatch.go | 72 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 syspatch/syspatch.go diff --git a/main.go b/main.go index 1bacc90..203e79e 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "os" "git.giftfish.de/ston1th/rcctl_exporter/rcctl" + "git.giftfish.de/ston1th/rcctl_exporter/syspatch" "github.com/go-kit/kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -56,18 +57,30 @@ func main() { r := prometheus.NewRegistry() r.MustRegister(version.NewCollector("rcctl_exporter")) + r.MustRegister(version.NewCollector("syspatch_exporter")) - collector, err := rcctl.NewCollector(logger) + rcctlCollector, err := rcctl.NewCollector(logger) if err != nil { level.Error(logger).Log("msg", "couldn't create collector", "err", err) os.Exit(1) } - if err := r.Register(collector); err != nil { + if err := r.Register(rcctlCollector); err != nil { level.Error(logger).Log("msg", "couldn't register rcctl collector", "err", err) os.Exit(1) } + syspatchCollector, err := syspatch.NewCollector(logger) + if err != nil { + level.Error(logger).Log("msg", "couldn't create collector", "err", err) + os.Exit(1) + } + + if err := r.Register(syspatchCollector); err != nil { + level.Error(logger).Log("msg", "couldn't register syspatch collector", "err", err) + os.Exit(1) + } + handler := promhttp.HandlerFor( prometheus.Gatherers{exporterMetricsRegistry, r}, promhttp.HandlerOpts{ diff --git a/syspatch/syspatch.go b/syspatch/syspatch.go new file mode 100644 index 0000000..f62c0e5 --- /dev/null +++ b/syspatch/syspatch.go @@ -0,0 +1,72 @@ +// Copyright (C) 2020 Marius Schellenberger + +package syspatch + +import ( + "bytes" + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" + "github.com/prometheus/client_golang/prometheus" + "os/exec" + "sync" + "time" +) + +const ( + namespace = "syspatch" + syspatch = "/usr/sbin/syspatch" + + errUpdateInterval = time.Second * 30 + updateInterval = time.Hour * 2 +) + +type Collector struct { + sync.RWMutex + patches *prometheus.Desc + logger log.Logger + + num float64 +} + +// NewCollector returns a new Collector exposing rcctl statistics. +func NewCollector(logger log.Logger) (*Collector, error) { + c := &Collector{ + patches: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "", "patches_available"), + "Number of syspatch patches available.", + nil, nil, + ), + logger: logger, + } + go c.getPatches() + return c, nil +} + +func (c *Collector) getPatches() { + for { + cmd := exec.Command(syspatch, "-c") + out, err := cmd.Output() + if err != nil { + level.Debug(c.logger).Log("msg", "syspatch list patches", "error", err) + time.Sleep(errUpdateInterval) + continue + } + num := float64(bytes.Count(out, []byte("\n"))) + c.Lock() + c.num = num + c.Unlock() + time.Sleep(updateInterval) + } +} + +func (c *Collector) Collect(ch chan<- prometheus.Metric) { + c.RLock() + num := c.num + c.RUnlock() + ch <- prometheus.MustNewConstMetric( + c.patches, prometheus.GaugeValue, num) +} + +func (c *Collector) Describe(desc chan<- *prometheus.Desc) { + desc <- c.patches +}