mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
Fixes #104 @status filter was added to the master branch to support new status key from Alertmanager >=0.6.1 status ended up being nested in Alertmanager (it was added to solve AM issue 609 and that was a long PR with lots of changes), current unsee implementation ended being slightly off with how Alertmanager is naming this, it should actually be @state rather than @status.
141 lines
3.8 KiB
Go
141 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"path"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/cloudflare/unsee/config"
|
|
"github.com/cloudflare/unsee/transform"
|
|
|
|
"github.com/DeanThompson/ginpprof"
|
|
log "github.com/Sirupsen/logrus"
|
|
raven "github.com/getsentry/raven-go"
|
|
"github.com/gin-contrib/static"
|
|
"github.com/gin-gonic/contrib/sentry"
|
|
"github.com/gin-gonic/gin"
|
|
ginprometheus "github.com/mcuadros/go-gin-prometheus"
|
|
"github.com/patrickmn/go-cache"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
)
|
|
|
|
var (
|
|
version = "dev"
|
|
|
|
// ticker is a timer used by background loop that will keep pulling
|
|
// data from Alertmanager
|
|
ticker *time.Ticker
|
|
|
|
// apiCache will be used to keep short lived copy of JSON reponses generated for the UI
|
|
// If there are requests with the same filter we should respond from cache
|
|
// rather than do all the filtering every time
|
|
apiCache *cache.Cache
|
|
|
|
// errorLock holds a mutex used to synchronize updates to AlertmanagerError
|
|
// to avoid any race between readers and writers
|
|
errorLock = sync.RWMutex{}
|
|
// alertManagerError holds the description of last error raised when pulling data
|
|
// from Alertmanager, if there was any error
|
|
// This error will be returned in UnseeAlertsResponse and presented by Ui
|
|
alertManagerError string
|
|
|
|
metricAlerts = prometheus.NewGaugeVec(
|
|
prometheus.GaugeOpts{
|
|
Name: "unsee_collected_alerts",
|
|
Help: "Total number of alerts collected from Alertmanager API",
|
|
},
|
|
[]string{"state"},
|
|
)
|
|
metricAlertGroups = prometheus.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "unsee_collected_groups",
|
|
Help: "Total number of alert groups collected from Alertmanager API",
|
|
},
|
|
)
|
|
metricAlertmanagerErrors = prometheus.NewGaugeVec(
|
|
prometheus.GaugeOpts{
|
|
Name: "unsee_alertmanager_errors_total",
|
|
Help: "Total number of errors encounter when requesting data from Alertmanager API",
|
|
},
|
|
[]string{"endpoint"},
|
|
)
|
|
)
|
|
|
|
func init() {
|
|
prometheus.MustRegister(metricAlerts)
|
|
prometheus.MustRegister(metricAlertGroups)
|
|
prometheus.MustRegister(metricAlertmanagerErrors)
|
|
|
|
metricAlertmanagerErrors.With(prometheus.Labels{"endpoint": "alerts"}).Set(0)
|
|
metricAlertmanagerErrors.With(prometheus.Labels{"endpoint": "silences"}).Set(0)
|
|
}
|
|
|
|
func getViewURL(sub string) string {
|
|
u := path.Join(config.Config.WebPrefix, sub)
|
|
if strings.HasSuffix(sub, "/") {
|
|
// if sub path had trailing slash then add it here, since path.Join will
|
|
// skip it
|
|
return u + "/"
|
|
}
|
|
return u
|
|
}
|
|
|
|
func setupRouter(router *gin.Engine) {
|
|
router.Use(static.Serve(getViewURL("/static"), newBinaryFileSystem("static")))
|
|
|
|
router.GET(getViewURL("/favicon.ico"), favicon)
|
|
router.GET(getViewURL("/"), index)
|
|
router.GET(getViewURL("/help"), help)
|
|
router.GET(getViewURL("/alerts.json"), alerts)
|
|
router.GET(getViewURL("/autocomplete.json"), autocomplete)
|
|
}
|
|
|
|
func main() {
|
|
log.Infof("Version: %s", version)
|
|
|
|
config.Config.Read()
|
|
config.Config.LogValues()
|
|
transform.ParseRules(config.Config.JiraRegexp)
|
|
|
|
apiCache = cache.New(cache.NoExpiration, 10*time.Second)
|
|
|
|
// before we start try to fetch data from Alertmanager
|
|
log.Infof("Initial Alertmanager query, this can delay startup up to %s", 3*config.Config.AlertmanagerTimeout)
|
|
PullFromAlertmanager()
|
|
log.Info("Done, starting HTTP server")
|
|
|
|
// background loop that will fetch updates from Alertmanager
|
|
ticker = time.NewTicker(config.Config.AlertmanagerTTL)
|
|
go Tick()
|
|
|
|
switch config.Config.Debug {
|
|
case true:
|
|
gin.SetMode(gin.DebugMode)
|
|
case false:
|
|
gin.SetMode(gin.ReleaseMode)
|
|
}
|
|
|
|
router := gin.New()
|
|
router.SetHTMLTemplate(loadTemplates("templates"))
|
|
|
|
prom := ginprometheus.NewPrometheus("gin")
|
|
prom.MetricsPath = getViewURL("/metrics")
|
|
prom.Use(router)
|
|
|
|
if config.Config.Debug {
|
|
ginpprof.Wrapper(router)
|
|
}
|
|
|
|
if config.Config.SentryDSN != "" {
|
|
raven.SetRelease(version)
|
|
router.Use(sentry.Recovery(raven.DefaultClient, false))
|
|
}
|
|
|
|
setupRouter(router)
|
|
err := router.Run()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|