// 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 }