Merge branch 'develop'
This commit is contained in:
commit
794ea5369d
13 changed files with 207 additions and 72 deletions
|
@ -5,7 +5,7 @@ Cross platform command line application to run health checks against sensor stat
|
||||||
This tool lets you automatically check if senseBoxes are still runnning correctly,
|
This tool lets you automatically check if senseBoxes are still runnning correctly,
|
||||||
and when that's not the case, notifies you.
|
and when that's not the case, notifies you.
|
||||||
Currently, email notifications are implemented, but other transports can be added easily.
|
Currently, email notifications are implemented, but other transports can be added easily.
|
||||||
Implemented health checks are [described below](#possible-values-for-defaulthealthchecksevents), and new ones can be added just as easily (given some knowledge of programming).
|
Implemented health checks are [described below](#available-healthchecks), and new ones can be added just as easily (given some knowledge of programming).
|
||||||
|
|
||||||
The tool has multiple modes of operation:
|
The tool has multiple modes of operation:
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ Contributions are welcome!
|
||||||
Check out the following locations for plugging in new functionality:
|
Check out the following locations for plugging in new functionality:
|
||||||
|
|
||||||
- new notification transports: [core/notifiers.go](core/notifiers.go)
|
- new notification transports: [core/notifiers.go](core/notifiers.go)
|
||||||
- new health checks: [core/healthcheck*.go](core/healtchecks.go)
|
- new health checks: [core/healthcheck*.go](core/healthchecks.go)
|
||||||
- new commands: [cmd/](cmd/)
|
- new commands: [cmd/](cmd/)
|
||||||
|
|
||||||
Before committing and submitting a pull request, please run `go fmt ./ cmd/ core/`.
|
Before committing and submitting a pull request, please run `go fmt ./ cmd/ core/`.
|
||||||
|
|
|
@ -12,8 +12,14 @@ import (
|
||||||
"github.com/noerw/osem_notify/utils"
|
"github.com/noerw/osem_notify/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
clearCache bool
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
debugCmd.AddCommand(debugNotificationsCmd)
|
debugCmd.AddCommand(debugNotificationsCmd)
|
||||||
|
debugCacheCmd.PersistentFlags().BoolVarP(&clearCache, "clear", "", false, "reset the notifications cache")
|
||||||
|
debugCmd.AddCommand(debugCacheCmd)
|
||||||
rootCmd.AddCommand(debugCmd)
|
rootCmd.AddCommand(debugCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,13 +38,28 @@ var debugCmd = &cobra.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var debugCacheCmd = &cobra.Command{
|
||||||
|
Use: "cache",
|
||||||
|
Short: "Print or clear the notifications cache",
|
||||||
|
Long: "osem_notify debug cache prints the contents of the notifications cache",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if clearCache {
|
||||||
|
return core.ClearCache()
|
||||||
|
}
|
||||||
|
core.PrintCache()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var debugNotificationsCmd = &cobra.Command{
|
var debugNotificationsCmd = &cobra.Command{
|
||||||
Use: "notifications",
|
Use: "notifications",
|
||||||
Short: "Verify that notifications are working",
|
Short: "Verify that notifications are working",
|
||||||
Long: "osem_notify debug <feature> tests the functionality of the given feature",
|
Long: `osem_notify debug notifications sends a test notification according
|
||||||
|
to healthchecks.default.notifications.options as defined in the config file`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
defaultNotifyConf := &core.NotifyConfig{}
|
defaultNotifyConf := &core.NotifyConfig{}
|
||||||
err := viper.UnmarshalKey("defaultHealthchecks", defaultNotifyConf)
|
err := viper.UnmarshalKey("healthchecks.default", defaultNotifyConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -55,11 +76,11 @@ var debugNotificationsCmd = &cobra.Command{
|
||||||
|
|
||||||
host, _ := os.Hostname()
|
host, _ := os.Hostname()
|
||||||
err = n.Submit(core.Notification{
|
err = n.Submit(core.Notification{
|
||||||
Subject: "Test notification from opeSenseMap notifier",
|
Subject: "Test notification from openSenseMap notifier",
|
||||||
Body: fmt.Sprintf("Your notification set up on %s is working fine!", host),
|
Body: fmt.Sprintf("Your notification set up on %s is working fine!", host),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
notLog.Warnf("could not submit test notification for %s notifier!", transport)
|
notLog.Warnf("could not submit test notification for %s notifier: %s", transport, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
notLog.Info("Test notification (successfully?) submitted, check the specified inbox")
|
notLog.Info("Test notification (successfully?) submitted, check the specified inbox")
|
|
@ -23,21 +23,32 @@ var configHelpCmd = &cobra.Command{
|
||||||
|
|
||||||
> Example configuration:
|
> Example configuration:
|
||||||
|
|
||||||
# override default health checks:
|
healthchecks:
|
||||||
defaultHealthchecks:
|
# override default health checks for all boxes
|
||||||
notifications:
|
default:
|
||||||
transport: email
|
notifications:
|
||||||
options:
|
transport: email
|
||||||
recipients:
|
options:
|
||||||
- fridolina@example.com
|
recipients:
|
||||||
- ruth.less@example.com
|
- fridolina@example.com
|
||||||
events:
|
events:
|
||||||
- type: "measurement_age"
|
- type: "measurement_age"
|
||||||
target: "all" # all sensors
|
target: "all" # all sensors
|
||||||
threshold: "15m" # any duration
|
threshold: "15m" # any duration
|
||||||
- type: "measurement_faulty"
|
- type: "measurement_faulty"
|
||||||
target: "all"
|
target: "all"
|
||||||
threshold: ""
|
threshold: ""
|
||||||
|
|
||||||
|
# set health checks per box
|
||||||
|
593bcd656ccf3b0011791f5a:
|
||||||
|
notifications:
|
||||||
|
options:
|
||||||
|
recipients:
|
||||||
|
- ruth.less@example.com
|
||||||
|
events:
|
||||||
|
- type: "measurement_max"
|
||||||
|
target: "593bcd656ccf3b0011791f5b"
|
||||||
|
threshold: "40"
|
||||||
|
|
||||||
# only needed when sending notifications via email
|
# only needed when sending notifications via email
|
||||||
email:
|
email:
|
||||||
|
@ -48,14 +59,14 @@ var configHelpCmd = &cobra.Command{
|
||||||
from: hildegunst@example.com
|
from: hildegunst@example.com
|
||||||
|
|
||||||
|
|
||||||
> possible values for defaultHealthchecks.notifications:
|
> possible values for healthchecks.*.notifications:
|
||||||
|
|
||||||
transport | options
|
transport | options
|
||||||
----------|-------------------------------------
|
----------|-------------------------------------
|
||||||
email | recipients: list of email addresses
|
email | recipients: list of email addresses
|
||||||
|
|
||||||
|
|
||||||
> possible values for defaultHealthchecks.events[]:
|
> possible values for healthchecks.*.events[]:
|
||||||
|
|
||||||
type | description
|
type | description
|
||||||
-------------------|---------------------------------------------------
|
-------------------|---------------------------------------------------
|
||||||
|
@ -105,8 +116,9 @@ var cfgFile string
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var (
|
var (
|
||||||
shouldNotify bool
|
|
||||||
debug bool
|
debug bool
|
||||||
|
noCache bool
|
||||||
|
shouldNotify string
|
||||||
logFormat string
|
logFormat string
|
||||||
api string
|
api string
|
||||||
)
|
)
|
||||||
|
@ -117,14 +129,16 @@ func init() {
|
||||||
rootCmd.PersistentFlags().StringVarP(&api, "api", "a", "https://api.opensensemap.org", "openSenseMap API to query against")
|
rootCmd.PersistentFlags().StringVarP(&api, "api", "a", "https://api.opensensemap.org", "openSenseMap API to query against")
|
||||||
rootCmd.PersistentFlags().StringVarP(&logFormat, "logformat", "l", "plain", "log format, can be plain or json")
|
rootCmd.PersistentFlags().StringVarP(&logFormat, "logformat", "l", "plain", "log format, can be plain or json")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "enable verbose logging")
|
rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "enable verbose logging")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&shouldNotify, "notify", "n", false, `if set, will send out notifications,
|
rootCmd.PersistentFlags().StringVarP(&shouldNotify, "notify", "n", "", `If set, will send out notifications for the specified type of check result,
|
||||||
Otherwise results are printed to stdout only.
|
otherwise results are printed to stdout only.
|
||||||
|
Allowed values are "all", "error", "ok".
|
||||||
You might want to run 'osem_notify debug notifications' first to verify everything works.
|
You might want to run 'osem_notify debug notifications' first to verify everything works.
|
||||||
|
|
||||||
Notifications for failing checks are sent only once,
|
Notifications for failing checks are sent only once, and then cached until the issue got
|
||||||
and then cached until the issue got resolved.
|
resolved, unless --no-cache is set.
|
||||||
To clear the cache, delete the file ~/.osem_notify_cache.yaml.
|
To clear the cache, run 'osem_notify debug cache --clear'.
|
||||||
`)
|
`)
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&noCache, "no-cache", "", false, "send all notifications, ignoring results from previous runs. also don't update the cache.")
|
||||||
|
|
||||||
viper.BindPFlags(rootCmd.PersistentFlags()) // let flags override config
|
viper.BindPFlags(rootCmd.PersistentFlags()) // let flags override config
|
||||||
|
|
|
@ -4,9 +4,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/noerw/osem_notify/utils"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/noerw/osem_notify/core"
|
||||||
|
"github.com/noerw/osem_notify/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// initConfig reads in config file and ENV variables if set.
|
// initConfig reads in config file and ENV variables if set.
|
||||||
|
@ -58,3 +60,55 @@ func validateConfig() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getNotifyConf(boxID string) (*core.NotifyConfig, error) {
|
||||||
|
// config used when no configuration is present at all
|
||||||
|
conf := &core.NotifyConfig{
|
||||||
|
Events: []core.NotifyEvent{
|
||||||
|
core.NotifyEvent{
|
||||||
|
Type: "measurement_age",
|
||||||
|
Target: "all",
|
||||||
|
Threshold: "15m",
|
||||||
|
},
|
||||||
|
core.NotifyEvent{
|
||||||
|
Type: "measurement_faulty",
|
||||||
|
Target: "all",
|
||||||
|
Threshold: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// override with default configuration from file
|
||||||
|
// considering the case that .events may be defined but empty
|
||||||
|
// to allow to define no events, and don't leak shorter lists into
|
||||||
|
// previous longer ones
|
||||||
|
if keyDefined("healthchecks.default.events") {
|
||||||
|
conf.Events = []core.NotifyEvent{}
|
||||||
|
}
|
||||||
|
err := viper.UnmarshalKey("healthchecks.default", conf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// override with per box configuration from file
|
||||||
|
if keyDefined("healthchecks." + boxID + ".events") {
|
||||||
|
conf.Events = []core.NotifyEvent{}
|
||||||
|
}
|
||||||
|
err = viper.UnmarshalKey("healthchecks."+boxID, conf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// implement our own keyCheck, as viper.InConfig() does not work
|
||||||
|
func keyDefined(key string) bool {
|
||||||
|
allConfKeys := viper.AllKeys()
|
||||||
|
for _, k := range allConfKeys {
|
||||||
|
if k == key {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package cmd
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
@ -33,21 +34,38 @@ func BoxIdValidator(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkAndNotify(boxIds []string) error {
|
func checkAndNotify(boxIds []string) error {
|
||||||
defaultNotifyConf := &core.NotifyConfig{}
|
boxLocalConfig := map[string]*core.NotifyConfig{}
|
||||||
err := viper.UnmarshalKey("defaultHealthchecks", defaultNotifyConf)
|
for _, boxID := range boxIds {
|
||||||
if err != nil {
|
c, err := getNotifyConf(boxID)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
boxLocalConfig[boxID] = c
|
||||||
}
|
}
|
||||||
|
|
||||||
results, err := core.CheckBoxes(boxIds, defaultNotifyConf)
|
results, err := core.CheckBoxes(boxLocalConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
results.Log()
|
results.Log()
|
||||||
|
|
||||||
if viper.GetBool("notify") {
|
notify := strings.ToLower(viper.GetString("notify"))
|
||||||
return results.SendNotifications()
|
if notify != "" {
|
||||||
|
types := []string{}
|
||||||
|
switch notify {
|
||||||
|
case "all":
|
||||||
|
types = []string{core.CheckErr, core.CheckOk}
|
||||||
|
case "error", "err":
|
||||||
|
types = []string{core.CheckErr}
|
||||||
|
case "ok":
|
||||||
|
types = []string{core.CheckOk}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid value %s for \"notify\"", notify)
|
||||||
|
}
|
||||||
|
|
||||||
|
useCache := !viper.GetBool("no-cache")
|
||||||
|
return results.SendNotifications(types, useCache)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,3 +60,18 @@ func updateCache(box *Box, results []CheckResult) error {
|
||||||
}
|
}
|
||||||
return cache.WriteConfig()
|
return cache.WriteConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ClearCache() error {
|
||||||
|
fileName := utils.GetConfigFile("osem_notify_cache")
|
||||||
|
_, err := os.Stat(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return os.Remove(fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintCache() {
|
||||||
|
for key, val := range cache.AllSettings() {
|
||||||
|
log.Infof("%20s: %v", key, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@ import (
|
||||||
|
|
||||||
type BoxCheckResults map[*Box][]CheckResult
|
type BoxCheckResults map[*Box][]CheckResult
|
||||||
|
|
||||||
func (results BoxCheckResults) Size(status string) int {
|
func (results BoxCheckResults) Size(statusToCheck []string) int {
|
||||||
size := 0
|
size := 0
|
||||||
for _, boxResults := range results {
|
for _, boxResults := range results {
|
||||||
for _, result := range boxResults {
|
for _, result := range boxResults {
|
||||||
if status == result.Status || status == "" {
|
if result.HasStatus(statusToCheck) {
|
||||||
size++
|
size++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,24 +42,26 @@ func (results BoxCheckResults) Log() {
|
||||||
countErr++
|
countErr++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if countErr == 0 {
|
if len(boxResults) == 0 {
|
||||||
|
boxLog.Infof("%s: no checks defined", box.Name)
|
||||||
|
} else if countErr == 0 {
|
||||||
boxLog.Infof("%s: all is fine!", box.Name)
|
boxLog.Infof("%s: all is fine!", box.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckBoxes(boxIds []string, defaultConf *NotifyConfig) (BoxCheckResults, error) {
|
func CheckBoxes(boxLocalConfs map[string]*NotifyConfig) (BoxCheckResults, error) {
|
||||||
log.Debug("Checking notifications for ", len(boxIds), " box(es)")
|
log.Debug("Checking notifications for ", len(boxLocalConfs), " box(es)")
|
||||||
|
|
||||||
results := BoxCheckResults{}
|
results := BoxCheckResults{}
|
||||||
errs := []string{}
|
errs := []string{}
|
||||||
|
|
||||||
// TODO: check boxes in parallel, capped at 5 at once
|
// TODO: check boxes in parallel, capped at 5 at once
|
||||||
for _, boxId := range boxIds {
|
for boxId, localConf := range boxLocalConfs {
|
||||||
boxLogger := log.WithField("boxId", boxId)
|
boxLogger := log.WithField("boxId", boxId)
|
||||||
boxLogger.Info("checking box for events")
|
boxLogger.Info("checking box for events")
|
||||||
|
|
||||||
box, res, err := checkBox(boxId, defaultConf)
|
box, res, err := checkBox(boxId, localConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
boxLogger.Errorf("could not run checks on box %s: %s", boxId, err)
|
boxLogger.Errorf("could not run checks on box %s: %s", boxId, err)
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err.Error())
|
||||||
|
|
|
@ -5,8 +5,13 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
nameMin = "measurement_min"
|
||||||
|
nameMax = "measurement_max"
|
||||||
|
)
|
||||||
|
|
||||||
var checkMeasurementMin = checkType{
|
var checkMeasurementMin = checkType{
|
||||||
name: "measurement_min",
|
name: nameMin,
|
||||||
toString: func(r CheckResult) string {
|
toString: func(r CheckResult) string {
|
||||||
return fmt.Sprintf("Sensor %s (%s) reads low value of %s", r.TargetName, r.Target, r.Value)
|
return fmt.Sprintf("Sensor %s (%s) reads low value of %s", r.TargetName, r.Target, r.Value)
|
||||||
},
|
},
|
||||||
|
@ -14,7 +19,7 @@ var checkMeasurementMin = checkType{
|
||||||
}
|
}
|
||||||
|
|
||||||
var checkMeasurementMax = checkType{
|
var checkMeasurementMax = checkType{
|
||||||
name: "measurement_min",
|
name: nameMax,
|
||||||
toString: func(r CheckResult) string {
|
toString: func(r CheckResult) string {
|
||||||
return fmt.Sprintf("Sensor %s (%s) reads high value of %s", r.TargetName, r.Target, r.Value)
|
return fmt.Sprintf("Sensor %s (%s) reads high value of %s", r.TargetName, r.Target, r.Value)
|
||||||
},
|
},
|
||||||
|
@ -41,8 +46,8 @@ func validateMeasurementMinMax(e NotifyEvent, s Sensor, b Box) (CheckResult, err
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Type == eventMeasurementValMax && val > thresh ||
|
if e.Type == nameMax && val > thresh ||
|
||||||
e.Type == eventMeasurementValMin && val < thresh {
|
e.Type == nameMin && val < thresh {
|
||||||
result.Status = CheckErr
|
result.Status = CheckErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,16 +9,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CheckOk = "OK"
|
CheckOk = "OK"
|
||||||
CheckErr = "FAILED"
|
CheckErr = "FAILED"
|
||||||
eventMeasurementAge = "measurement_age"
|
eventTargetAll = "all" // if event.Target is this value, all sensors will be checked
|
||||||
eventMeasurementValMin = "measurement_min"
|
|
||||||
eventMeasurementValMax = "measurement_max"
|
|
||||||
eventMeasurementValFaulty = "measurement_faulty"
|
|
||||||
eventTargetAll = "all" // if event.Target is this value, all sensors will be checked
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type checkType = struct {
|
type checkType struct {
|
||||||
name string // name that is used in config
|
name string // name that is used in config
|
||||||
toString func(result CheckResult) string // error message when check failed
|
toString func(result CheckResult) string // error message when check failed
|
||||||
checkFunc func(event NotifyEvent, sensor Sensor, context Box) (CheckResult, error)
|
checkFunc func(event NotifyEvent, sensor Sensor, context Box) (CheckResult, error)
|
||||||
|
@ -41,6 +37,15 @@ type CheckResult struct {
|
||||||
Threshold string
|
Threshold string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r CheckResult) HasStatus(statusToCheck []string) bool {
|
||||||
|
for _, status := range statusToCheck {
|
||||||
|
if status == r.Status {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (r CheckResult) EventID() string {
|
func (r CheckResult) EventID() string {
|
||||||
s := fmt.Sprintf("%s%s%s", r.Event, r.Target, r.Threshold)
|
s := fmt.Sprintf("%s%s%s", r.Event, r.Target, r.Threshold)
|
||||||
hasher := sha256.New()
|
hasher := sha256.New()
|
||||||
|
|
|
@ -39,25 +39,24 @@ func (box Box) GetNotifier() (AbstractNotifier, error) {
|
||||||
return notifier.New(box.NotifyConf.Notifications.Options)
|
return notifier.New(box.NotifyConf.Notifications.Options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (results BoxCheckResults) SendNotifications() error {
|
func (results BoxCheckResults) SendNotifications(notifyTypes []string, useCache bool) error {
|
||||||
// TODO: expose flags to not use cache, and to notify for checks turned CheckOk as well
|
if useCache {
|
||||||
|
results = results.filterChangedFromCache()
|
||||||
|
}
|
||||||
|
|
||||||
results = results.filterChangedFromCache()
|
toCheck := results.Size(notifyTypes)
|
||||||
|
if toCheck == 0 {
|
||||||
nErr := results.Size(CheckErr)
|
|
||||||
if nErr == 0 {
|
|
||||||
log.Info("No notifications due.")
|
log.Info("No notifications due.")
|
||||||
} else {
|
} else {
|
||||||
log.Infof("Notifying for %v checks turned bad in total...", nErr)
|
log.Infof("Notifying for %v checks changing state to %v...", toCheck, notifyTypes)
|
||||||
}
|
}
|
||||||
log.Debugf("%v checks turned OK!", results.Size(CheckOk))
|
|
||||||
|
|
||||||
errs := []string{}
|
errs := []string{}
|
||||||
for box, resultsBox := range results {
|
for box, resultsBox := range results {
|
||||||
// only submit results which are errors
|
// only submit results which are errors
|
||||||
resultsDue := []CheckResult{}
|
resultsDue := []CheckResult{}
|
||||||
for _, result := range resultsBox {
|
for _, result := range resultsBox {
|
||||||
if result.Status != CheckOk {
|
if result.HasStatus(notifyTypes) {
|
||||||
resultsDue = append(resultsDue, result)
|
resultsDue = append(resultsDue, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,16 +90,18 @@ func (results BoxCheckResults) SendNotifications() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update cache (also with CheckOk results to reset status)
|
// update cache (with /all/ changed results to reset status)
|
||||||
notifyLog.Debug("updating cache")
|
if useCache {
|
||||||
cacheError := updateCache(box, resultsBox)
|
notifyLog.Debug("updating cache")
|
||||||
if cacheError != nil {
|
cacheError := updateCache(box, resultsBox)
|
||||||
notifyLog.Error("could not cache notification results: ", cacheError)
|
if cacheError != nil {
|
||||||
errs = append(errs, cacheError.Error())
|
notifyLog.Error("could not cache notification results: ", cacheError)
|
||||||
|
errs = append(errs, cacheError.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(resultsDue) != 0 {
|
if len(resultsDue) != 0 {
|
||||||
notifyLog.Infof("Sent notification for %s via %s with %v new issues", box.Name, transport, len(resultsDue))
|
notifyLog.Infof("Sent notification for %s via %s with %v updated issues", box.Name, transport, len(resultsDue))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue