150 lines
4.0 KiB
Go
150 lines
4.0 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type Event struct {
|
|
Status string `json:"status"`
|
|
TimeNow time.Time `json:"timeNow"`
|
|
StartsAt time.Time `json:"startsAt"`
|
|
Node string `json:"node"`
|
|
DeltaLastSeconds float64 `json:"deltaLastSeconds"`
|
|
DeltaStartSeconds float64 `json:"deltaStartSeconds"`
|
|
}
|
|
|
|
type Notification struct {
|
|
Alerts []Alert `json:"alerts"`
|
|
CommonAnnotations map[string]string `json:"commonAnnotations"`
|
|
CommonLabels map[string]string `json:"commonLabels"`
|
|
ExternalURL string `json:"externalURL"`
|
|
GroupKey string `json:"groupKey"`
|
|
GroupLabels map[string]string `json:"groupLabels"`
|
|
Message string `json:"message"`
|
|
OrgID int `json:"orgId"`
|
|
Receiver string `json:"receiver"`
|
|
State string `json:"state"`
|
|
Status string `json:"status"`
|
|
Title string `json:"title"`
|
|
TruncatedAlerts int `json:"truncatedAlerts"`
|
|
Version string `json:"version"`
|
|
}
|
|
|
|
type Alert struct {
|
|
Annotations map[string]string `json:"annotations"`
|
|
DashboardURL string `json:"dashboardURL"`
|
|
StartsAt time.Time `json:"startsAt"`
|
|
EndsAt time.Time `json:"endsAt"`
|
|
Fingerprint string `json:"fingerprint"`
|
|
GeneratorURL string `json:"generatorURL"`
|
|
Labels map[string]string `json:"labels"`
|
|
PanelURL string `json:"panelURL"`
|
|
SilenceURL string `json:"silenceURL"`
|
|
Status string `json:"status"`
|
|
ValueString string `json:"valueString"`
|
|
Values map[string]any `json:"values"`
|
|
}
|
|
|
|
type NotificationHandler struct {
|
|
startedAt time.Time
|
|
stats map[string]int
|
|
hist []Event
|
|
m sync.Mutex
|
|
}
|
|
|
|
func NewNotificationHandler() *NotificationHandler {
|
|
return &NotificationHandler{
|
|
startedAt: time.Now(),
|
|
stats: make(map[string]int),
|
|
hist: make([]Event, 0),
|
|
}
|
|
}
|
|
|
|
func (ah *NotificationHandler) Notify(w http.ResponseWriter, r *http.Request) {
|
|
b, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
log.Println(err)
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
return
|
|
}
|
|
n := Notification{}
|
|
if err := json.Unmarshal(b, &n); err != nil {
|
|
log.Println(err)
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
return
|
|
}
|
|
log.Printf("got notification from: %s. a: %v", r.RemoteAddr, n)
|
|
|
|
ah.m.Lock()
|
|
defer ah.m.Unlock()
|
|
|
|
addr := r.RemoteAddr
|
|
if split := strings.Split(r.RemoteAddr, ":"); len(split) > 0 {
|
|
addr = split[0]
|
|
}
|
|
|
|
a := n.Alerts[0]
|
|
|
|
timeNow := time.Now()
|
|
|
|
ah.stats[n.Status]++
|
|
|
|
var d time.Duration
|
|
if len(ah.hist) > 0 {
|
|
last := ah.hist[len(ah.hist)-1]
|
|
d = timeNow.Sub(last.TimeNow)
|
|
}
|
|
|
|
ah.hist = append(ah.hist, Event{
|
|
Status: n.Status,
|
|
StartsAt: a.StartsAt,
|
|
TimeNow: timeNow,
|
|
Node: addr,
|
|
DeltaLastSeconds: d.Seconds(),
|
|
DeltaStartSeconds: timeNow.Sub(ah.startedAt).Seconds(),
|
|
})
|
|
}
|
|
|
|
func (ah *NotificationHandler) GetNotifications(w http.ResponseWriter, _ *http.Request) {
|
|
ah.m.Lock()
|
|
defer ah.m.Unlock()
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
res, err := json.MarshalIndent(map[string]any{"stats": ah.stats, "history": ah.hist}, "", "\t")
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
//nolint:errcheck
|
|
w.Write([]byte(`{"error":"failed to marshal alerts"}`))
|
|
log.Printf("failed to marshal alerts: %v\n", err)
|
|
return
|
|
}
|
|
|
|
log.Printf("requested current state\n%v\n", string(res))
|
|
|
|
_, err = w.Write(res)
|
|
if err != nil {
|
|
log.Printf("failed to write response: %v\n", err)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
ah := NewNotificationHandler()
|
|
|
|
http.HandleFunc("/ready", func(w http.ResponseWriter, _ *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
http.HandleFunc("/notify", ah.Notify)
|
|
http.HandleFunc("/notifications", ah.GetNotifications)
|
|
|
|
log.Println("Listening")
|
|
//nolint:errcheck
|
|
http.ListenAndServe("0.0.0.0:8080", nil)
|
|
}
|