Select Git revision
-
Janne Mareike Koschinski authoredJanne Mareike Koschinski authored
monitor.go 2.96 KiB
package main
import (
"github.com/sirupsen/logrus"
"strconv"
"sync"
"time"
)
type Datapoint struct {
Time time.Time
Up bool
Latency int
}
type MonitorWrapper struct {
api *ConfigApi
storage *Storage
monitor Monitor
config *ConfigComponent
thresholdDuration time.Duration
// Closed when mon.Stop() is called
stopC chan bool
}
func NewMonitorWrapper(api *ConfigApi, storage *Storage, monitor Monitor) MonitorWrapper {
config := monitor.Config()
threshold, err := time.ParseDuration(config.ThresholdDuration)
if err != nil {
panic(err)
}
return MonitorWrapper{
api: api,
storage: storage,
monitor: monitor,
config: config,
thresholdDuration: threshold,
}
}
func (w *MonitorWrapper) Name() string {
return w.config.Name
}
func (w *MonitorWrapper) ClockStart(immediate bool, wg *sync.WaitGroup) {
wg.Add(1)
w.stopC = make(chan bool)
if immediate {
w.tick()
}
ticker := time.NewTicker(Interval(w.config))
for {
select {
case <-ticker.C:
w.tick()
case <-w.stopC:
wg.Done()
return
}
}
}
func (w *MonitorWrapper) tick() {
datapoint, err := w.monitor.Measure()
if err != nil {
logrus.Errorf("Monitor %s encountered error: %s\n", w.config.Name, err.Error())
return
}
if w.config.ComponentId != 0 {
status := DetermineStatus(w.config, w.storage.Store(w.config.ComponentId, datapoint, w.thresholdDuration))
_, err = w.api.Components().Save(w.config.ComponentId, ApiComponentBody{
Status: status,
})
if err != nil {
logrus.Error(err.Error())
}
}
if w.config.MetricId != 0 {
_, err = w.api.MetricPoints(w.config.MetricId).Create(ApiMetricPointBody{
Metric: w.config.MetricId,
Value: datapoint.Latency,
Timestamp: strconv.FormatInt(datapoint.Time.Unix(), 10),
})
if err != nil {
logrus.Error(err.Error())
}
}
}
func (w *MonitorWrapper) ClockStop() {
select {
case <-w.stopC:
return
default:
close(w.stopC)
}
}
type Monitor interface {
Config() *ConfigComponent
Measure() (Datapoint, error)
}
func Interval(component *ConfigComponent) time.Duration {
interval, err := time.ParseDuration(component.Interval)
if err != nil {
panic(err)
}
return interval
}
func DetermineStatus(component *ConfigComponent, datapoints []Datapoint) int {
countSlow := 0
countDown := 0
for _, datapoint := range datapoints {
if !datapoint.Up {
countDown++
} else if datapoint.Latency >= component.LatencyThresholds.Down {
countDown++
} else if datapoint.Latency >= component.LatencyThresholds.Slow {
countSlow++
}
}
percentageSlow := countSlow * 100 / len(datapoints)
percentageDown := countDown * 100 / len(datapoints)
if percentageDown > component.OutageThresholds.Major {
return ComponentStatusMajorOutage
} else if percentageDown > component.OutageThresholds.Partial {
return ComponentStatusPartialOutage
} else if percentageSlow > component.OutageThresholds.Performance {
return ComponentStatusPerformanceIssues
} else {
return ComponentStatusOperational
}
}