113 lines
2.4 KiB
Go
113 lines
2.4 KiB
Go
// Copyright (C) 2020 Marius Schellenberger
|
|
|
|
package rcctl
|
|
|
|
import (
|
|
"github.com/go-kit/kit/log"
|
|
"github.com/go-kit/kit/log/level"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"os/exec"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
specialSvcs = map[string]struct{}{
|
|
"accounting": struct{}{},
|
|
"check_quotas": struct{}{},
|
|
"ipsec": struct{}{},
|
|
"library_aslr": struct{}{},
|
|
"multicast": struct{}{},
|
|
"pf": struct{}{},
|
|
"spamd_black": struct{}{},
|
|
}
|
|
)
|
|
|
|
const (
|
|
namespace = "rcctl"
|
|
rcctl = "/usr/sbin/rcctl"
|
|
statusOK = "(ok)"
|
|
statusFailed = "(failed)"
|
|
|
|
serviceUpdateInterval = time.Second * 30
|
|
)
|
|
|
|
type Collector struct {
|
|
sync.RWMutex
|
|
state *prometheus.Desc
|
|
logger log.Logger
|
|
|
|
services []string
|
|
}
|
|
|
|
// NewCollector returns a new Collector exposing rcctl statistics.
|
|
func NewCollector(logger log.Logger) (*Collector, error) {
|
|
c := &Collector{
|
|
state: prometheus.NewDesc(
|
|
prometheus.BuildFQName(namespace, "", "state"),
|
|
"State of rcctl service.",
|
|
[]string{"service"}, prometheus.Labels{"supervisor": "rcctl"},
|
|
),
|
|
logger: logger,
|
|
}
|
|
go c.getServices()
|
|
return c, nil
|
|
}
|
|
|
|
func (c *Collector) getServices() {
|
|
for {
|
|
var svcs []string
|
|
cmd := exec.Command(rcctl, "ls", "on")
|
|
on, err := cmd.Output()
|
|
if err != nil {
|
|
level.Debug(c.logger).Log("msg", "rcctl list services", "error", err)
|
|
time.Sleep(serviceUpdateInterval)
|
|
continue
|
|
}
|
|
for _, s := range strings.Split(string(on), "\n") {
|
|
if s == "" {
|
|
continue
|
|
}
|
|
if _, ok := specialSvcs[s]; ok {
|
|
continue
|
|
}
|
|
svcs = append(svcs, s)
|
|
}
|
|
c.Lock()
|
|
c.services = svcs
|
|
c.Unlock()
|
|
time.Sleep(serviceUpdateInterval)
|
|
}
|
|
}
|
|
|
|
func (c *Collector) Collect(ch chan<- prometheus.Metric) {
|
|
c.RLock()
|
|
args := append([]string{"check"}, c.services...)
|
|
c.RUnlock()
|
|
cmd := exec.Command(rcctl, args...)
|
|
states, err := cmd.Output()
|
|
if err != nil {
|
|
level.Debug(c.logger).Log("msg", "rcctl check services", "error", err)
|
|
}
|
|
for _, s := range strings.Split(string(states), "\n") {
|
|
if s == "" {
|
|
continue
|
|
}
|
|
state := 0.0
|
|
if strings.Contains(s, statusOK) {
|
|
state = 1.0
|
|
s = strings.TrimSuffix(s, statusOK)
|
|
} else {
|
|
s = strings.TrimSuffix(s, statusFailed)
|
|
}
|
|
level.Debug(c.logger).Log("msg", "Current status", "Service", s, "Status", state)
|
|
ch <- prometheus.MustNewConstMetric(
|
|
c.state, prometheus.GaugeValue, state, s)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (c *Collector) Describe(desc chan<- *prometheus.Desc) {
|
|
desc <- c.state
|
|
}
|