您最多选择25个主题
主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
162 行
4.0 KiB
Go
162 行
4.0 KiB
Go
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var Notifiers = map[string]AbstractNotifier{
|
|
"email": EmailNotifier{},
|
|
"slack": SlackNotifier{},
|
|
"xmpp": XmppNotifier{},
|
|
}
|
|
|
|
type AbstractNotifier interface {
|
|
New(config TransportConfig) (AbstractNotifier, error)
|
|
Submit(notification Notification) error
|
|
}
|
|
|
|
type Notification struct {
|
|
Status string // one of CheckOk | CheckErr
|
|
Body string
|
|
Subject string
|
|
}
|
|
|
|
//////
|
|
|
|
func (box Box) GetNotifier() (AbstractNotifier, error) {
|
|
return GetNotifier(&box.NotifyConf.Notifications)
|
|
}
|
|
|
|
func GetNotifier(config *TransportConfig) (AbstractNotifier, error) {
|
|
transport := config.Transport
|
|
|
|
if transport == "" {
|
|
return nil, fmt.Errorf("No notification transport provided")
|
|
}
|
|
|
|
notifier := Notifiers[transport]
|
|
if notifier == nil {
|
|
return nil, fmt.Errorf("%s is not a supported notification transport", transport)
|
|
}
|
|
|
|
return notifier.New(*config)
|
|
}
|
|
|
|
func (results BoxCheckResults) SendNotifications(notifyTypes []string, useCache bool) error {
|
|
if useCache {
|
|
results = results.filterChangedFromCache()
|
|
}
|
|
|
|
toCheck := results.Size(notifyTypes)
|
|
if toCheck == 0 {
|
|
log.Info("No notifications due.")
|
|
} else {
|
|
log.Infof("Notifying for %v checks changing state to %v...", toCheck, notifyTypes)
|
|
}
|
|
|
|
errs := []string{}
|
|
for box, resultsBox := range results {
|
|
// only submit results which are errors
|
|
resultsDue := []CheckResult{}
|
|
for _, result := range resultsBox {
|
|
if result.HasStatus(notifyTypes) {
|
|
resultsDue = append(resultsDue, result)
|
|
}
|
|
}
|
|
|
|
transport := box.NotifyConf.Notifications.Transport
|
|
notifyLog := log.WithFields(log.Fields{
|
|
"boxId": box.Id,
|
|
"transport": transport,
|
|
})
|
|
|
|
if len(resultsDue) != 0 {
|
|
notifier, err := box.GetNotifier()
|
|
if err != nil {
|
|
notifyLog.Error(err)
|
|
errs = append(errs, err.Error())
|
|
continue
|
|
}
|
|
|
|
notification := ComposeNotification(box, resultsDue)
|
|
|
|
var submitErr error
|
|
submitErr = notifier.Submit(notification)
|
|
for retry := 0; submitErr != nil && retry < 2; retry++ {
|
|
notifyLog.Warnf("sending notification failed (retry %v): %v", retry, submitErr)
|
|
time.Sleep(10 * time.Second)
|
|
submitErr = notifier.Submit(notification)
|
|
}
|
|
if submitErr != nil {
|
|
notifyLog.Error(submitErr)
|
|
errs = append(errs, submitErr.Error())
|
|
continue
|
|
}
|
|
}
|
|
|
|
// update cache (with /all/ changed results to reset status)
|
|
if useCache {
|
|
notifyLog.Debug("updating cache")
|
|
updateCache(box, resultsBox)
|
|
}
|
|
|
|
if len(resultsDue) != 0 {
|
|
notifyLog.Infof("Sent notification for %s via %s with %v updated issues", box.Name, transport, len(resultsDue))
|
|
}
|
|
}
|
|
|
|
// persist changes to cache
|
|
if useCache {
|
|
err := writeCache()
|
|
if err != nil {
|
|
log.Error("could not write cache of notification results: ", err)
|
|
errs = append(errs, err.Error())
|
|
}
|
|
}
|
|
|
|
if len(errs) != 0 {
|
|
return fmt.Errorf(strings.Join(errs, "\n"))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ComposeNotification(box *Box, checks []CheckResult) Notification {
|
|
errTexts := []string{}
|
|
resolvedTexts := []string{}
|
|
for _, check := range checks {
|
|
if check.Status == CheckErr {
|
|
errTexts = append(errTexts, check.String())
|
|
} else {
|
|
resolvedTexts = append(resolvedTexts, check.String())
|
|
}
|
|
}
|
|
|
|
var (
|
|
resolved string
|
|
resolvedList string
|
|
errList string
|
|
status string
|
|
)
|
|
if len(resolvedTexts) != 0 {
|
|
resolvedList = fmt.Sprintf("Resolved issue(s):\n\n%s\n\n", strings.Join(resolvedTexts, "\n"))
|
|
}
|
|
if len(errTexts) != 0 {
|
|
errList = fmt.Sprintf("New issue(s):\n\n%s\n\n", strings.Join(errTexts, "\n"))
|
|
status = CheckErr
|
|
} else {
|
|
resolved = "resolved "
|
|
status = CheckOk
|
|
}
|
|
|
|
return Notification{
|
|
Status: status,
|
|
Subject: fmt.Sprintf("Issues %swith your box \"%s\" on opensensemap.org!", resolved, box.Name),
|
|
Body: fmt.Sprintf("A check at %s identified the following updates for your box \"%s\":\n\n%s%sYou may visit https://opensensemap.org/explore/%s for more details.",
|
|
time.Now().Round(time.Minute), box.Name, errList, resolvedList, box.Id),
|
|
}
|
|
}
|