Initial structure
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
package alerts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/jasper/quptime/internal/checks"
|
||||
"github.com/jasper/quptime/internal/config"
|
||||
)
|
||||
|
||||
// Dispatcher fans an aggregator transition out to every alert listed
|
||||
// on the check. Errors are logged but never propagated: alerting must
|
||||
// not block the aggregation pipeline.
|
||||
type Dispatcher struct {
|
||||
cluster *config.ClusterConfig
|
||||
selfID string
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// New constructs a Dispatcher.
|
||||
func New(cluster *config.ClusterConfig, selfID string, logger *log.Logger) *Dispatcher {
|
||||
if logger == nil {
|
||||
logger = log.Default()
|
||||
}
|
||||
return &Dispatcher{cluster: cluster, selfID: selfID, logger: logger}
|
||||
}
|
||||
|
||||
// OnTransition is wired as checks.TransitionFn.
|
||||
func (d *Dispatcher) OnTransition(check *config.Check, from, to checks.State, snap checks.Snapshot) {
|
||||
if to == checks.StateUnknown {
|
||||
return
|
||||
}
|
||||
msg := Render(d.selfID, check, from, to, snap)
|
||||
for _, alertID := range check.AlertIDs {
|
||||
alert, _ := d.cluster.FindAlert(alertID)
|
||||
if alert == nil {
|
||||
d.logger.Printf("alerts: check %q references unknown alert %q", check.Name, alertID)
|
||||
continue
|
||||
}
|
||||
if err := d.dispatchOne(alert, msg); err != nil {
|
||||
d.logger.Printf("alerts: %q via %s: %v", alert.Name, alert.Type, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test sends a one-shot test message to the named alert. Returns an
|
||||
// error so the CLI can surface failures interactively.
|
||||
func (d *Dispatcher) Test(alertID string) error {
|
||||
alert, _ := d.cluster.FindAlert(alertID)
|
||||
if alert == nil {
|
||||
return fmt.Errorf("alert %q not found", alertID)
|
||||
}
|
||||
msg := Message{
|
||||
Subject: "[quptime] test alert",
|
||||
Body: fmt.Sprintf("This is a test of alert %q from node %s.\nIf you see this, the alert channel is wired correctly.\n", alert.Name, d.selfID),
|
||||
}
|
||||
return d.dispatchOne(alert, msg)
|
||||
}
|
||||
|
||||
func (d *Dispatcher) dispatchOne(a *config.Alert, msg Message) error {
|
||||
switch a.Type {
|
||||
case config.AlertSMTP:
|
||||
return sendSMTP(a, msg)
|
||||
case config.AlertDiscord:
|
||||
return sendDiscord(a, msg)
|
||||
default:
|
||||
return fmt.Errorf("unknown alert type %q", a.Type)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user