query alerts card

This commit is contained in:
Ulric Qin 2022-03-22 14:10:10 +08:00
parent e1bd7f0267
commit 7c8c961aef
5 changed files with 229 additions and 19 deletions

View File

@ -1,6 +1,7 @@
package models
import (
"fmt"
"strconv"
"strings"
"time"
@ -50,6 +51,62 @@ func (e *AlertCurEvent) Add() error {
return Insert(e)
}
type AggrRule struct {
Type string
Value string
}
func (e *AlertCurEvent) GenCardTitle(rules []*AggrRule) string {
arr := make([]string, len(rules))
for i := 0; i < len(rules); i++ {
rule := rules[i]
if rule.Type == "field" {
arr[i] = e.GetField(rule.Value)
}
if rule.Type == "tagkey" {
arr[i] = e.GetTagValue(rule.Value)
}
}
return strings.Join(arr, "::")
}
func (e *AlertCurEvent) GetTagValue(tagkey string) string {
for _, tag := range e.TagsJSON {
i := strings.Index(tag, tagkey+"=")
if i >= 0 {
return tag[len(tagkey+"="):]
}
}
return ""
}
func (e *AlertCurEvent) GetField(field string) string {
switch field {
case "cluster":
return e.Cluster
case "group_id":
return fmt.Sprint(e.GroupId)
case "group_name":
return e.GroupName
case "rule_id":
return fmt.Sprint(e.RuleId)
case "rule_name":
return e.RuleName
case "severity":
return fmt.Sprintf("S%d", e.Severity)
case "runbook_url":
return e.RunbookUrl
case "target_ident":
return e.TargetIdent
case "target_note":
return e.TargetNote
default:
return ""
}
}
func (e *AlertCurEvent) IncRepeatStep(step int64) error {
return DB().Model(e).Where("id=?", e.Id).Update("notify_repeat_next", time.Now().Unix()+step).Error
}
@ -155,7 +212,11 @@ func (e *AlertCurEvent) FillNotifyGroups(cache map[int64]*UserGroup) error {
}
func AlertCurEventTotal(bgid, stime, etime int64, severity int, clusters []string, query string) (int64, error) {
session := DB().Model(&AlertCurEvent{}).Where("trigger_time between ? and ? and group_id = ?", stime, etime, bgid)
session := DB().Model(&AlertCurEvent{}).Where("trigger_time between ? and ?", stime, etime)
if bgid > 0 {
session = session.Where("group_id = ?", bgid)
}
if severity >= 0 {
session = session.Where("severity = ?", severity)
@ -177,7 +238,11 @@ func AlertCurEventTotal(bgid, stime, etime int64, severity int, clusters []strin
}
func AlertCurEventGets(bgid, stime, etime int64, severity int, clusters []string, query string, limit, offset int) ([]AlertCurEvent, error) {
session := DB().Where("trigger_time between ? and ? and group_id = ?", stime, etime, bgid)
session := DB().Where("trigger_time between ? and ?", stime, etime)
if bgid > 0 {
session = session.Where("group_id = ?", bgid)
}
if severity >= 0 {
session = session.Where("severity = ?", severity)

View File

@ -88,7 +88,11 @@ func (e *AlertHisEvent) FillNotifyGroups(cache map[int64]*UserGroup) error {
}
func AlertHisEventTotal(bgid, stime, etime int64, severity int, recovered int, clusters []string, query string) (int64, error) {
session := DB().Model(&AlertHisEvent{}).Where("last_eval_time between ? and ? and group_id = ?", stime, etime, bgid)
session := DB().Model(&AlertHisEvent{}).Where("last_eval_time between ? and ?", stime, etime)
if bgid > 0 {
session = session.Where("group_id = ?", bgid)
}
if severity >= 0 {
session = session.Where("severity = ?", severity)
@ -114,7 +118,11 @@ func AlertHisEventTotal(bgid, stime, etime int64, severity int, recovered int, c
}
func AlertHisEventGets(bgid, stime, etime int64, severity int, recovered int, clusters []string, query string, limit, offset int) ([]AlertHisEvent, error) {
session := DB().Where("last_eval_time between ? and ? and group_id = ?", stime, etime, bgid)
session := DB().Where("last_eval_time between ? and ?", stime, etime)
if bgid > 0 {
session = session.Where("group_id = ?", bgid)
}
if severity >= 0 {
session = session.Where("severity = ?", severity)

View File

@ -205,9 +205,10 @@ func configRoute(r *gin.Engine, version string) {
// pages.GET("/busi-group/:id/collect-rule/:crid", jwtAuth(), user(), bgro(), collectRuleGet)
// pages.PUT("/busi-group/:id/collect-rule/:crid", jwtAuth(), user(), bgrw(), collectRulePut)
// card逻辑fe改造完之后这三个方法可以删除
pages.GET("/busi-group/:id/alert-his-events", jwtAuth(), user(), bgro(), alertHisEventGets)
pages.GET("/busi-group/:id/alert-cur-events", jwtAuth(), user(), bgro(), alertCurEventGets)
pages.DELETE("/busi-group/:id/alert-cur-events", jwtAuth(), user(), perm("/alert-cur-events/del"), bgrw(), alertCurEventDel)
pages.DELETE("/busi-group/:id/alert-cur-events", jwtAuth(), user(), perm("/alert-cur-events/del"), alertCurEventDel)
if config.C.AnonymousAccess.AlertDetail {
pages.GET("/alert-cur-event/:eid", alertCurEventGet)
@ -217,6 +218,13 @@ func configRoute(r *gin.Engine, version string) {
pages.GET("/alert-his-event/:eid", jwtAuth(), alertHisEventGet)
}
// card logic
pages.GET("/alert-cur-events/list", jwtAuth(), alertCurEventsList)
pages.GET("/alert-cur-events/card", jwtAuth(), alertCurEventsCard)
pages.GET("/alert-cur-events/card/details", jwtAuth(), alertCurEventsCardDetails)
pages.GET("/alert-his-events/list", jwtAuth(), alertHisEventsList)
pages.DELETE("/alert-cur-events", jwtAuth(), user(), perm("/alert-cur-events/del"), alertCurEventDel)
pages.GET("/alert-aggr-views", jwtAuth(), alertAggrViewGets)
pages.DELETE("/alert-aggr-views", jwtAuth(), alertAggrViewDel)
pages.POST("/alert-aggr-views", jwtAuth(), alertAggrViewAdd)

View File

@ -1,7 +1,8 @@
package router
import (
"time"
"sort"
"strings"
"github.com/gin-gonic/gin"
"github.com/toolkits/pkg/ginx"
@ -9,20 +10,104 @@ import (
"github.com/didi/nightingale/v5/src/models"
)
func alertCurEventGets(c *gin.Context) {
stime := ginx.QueryInt64(c, "stime", 0)
etime := ginx.QueryInt64(c, "etime", 0)
hours := ginx.QueryInt64(c, "hours", 0)
now := time.Now().Unix()
if hours != 0 {
stime = now - 3600*hours
etime = now + 3600*24
func alertCurEventsCard(c *gin.Context) {
stime, etime := getTimeRange(c)
severity := ginx.QueryInt(c, "severity", -1)
query := ginx.QueryStr(c, "query", "")
busiGroupId := ginx.QueryInt64(c, "bgid", 0)
clusters := queryClusters(c)
aggrRules := strings.Fields(ginx.QueryStr(c, "rules", "")) // e.g. field:group_name field:severity tagkey:ident
if len(aggrRules) == 0 {
ginx.NewRender(c).Message("rules empty")
return
}
if stime != 0 && etime == 0 {
etime = now + 3600*24
rules := make([]*models.AggrRule, len(aggrRules))
for i := 0; i < len(aggrRules); i++ {
pair := strings.Split(aggrRules[i], ":")
if len(pair) != 2 {
ginx.NewRender(c).Message("rules invalid")
return
}
if !(pair[0] == "field" || pair[0] == "tagkey") {
ginx.NewRender(c).Message("rules invalid")
return
}
rules[i] = &models.AggrRule{
Type: pair[0],
Value: pair[1],
}
}
// 最多获取10000个获取太多也没啥意义
list, err := models.AlertCurEventGets(busiGroupId, stime, etime, severity, clusters, query, 10000, 0)
ginx.Dangerous(err)
cardCount := make(map[string]int)
for _, event := range list {
title := event.GenCardTitle(rules)
cardCount[title]++
}
titles := make([]string, 0, len(cardCount))
for title := range cardCount {
titles = append(titles, title)
}
sort.Strings(titles)
cards := make([]AlertCard, len(titles))
for i := 0; i < len(titles); i++ {
cards[i] = AlertCard{
Title: titles[i],
Total: cardCount[titles[i]],
}
}
ginx.NewRender(c).Data(cards, nil)
}
type AlertCard struct {
Title string `json:"title"`
Total int `json:"total"`
}
func alertCurEventsCardDetails(c *gin.Context) {
}
// 列表方式,拉取活跃告警
func alertCurEventsList(c *gin.Context) {
stime, etime := getTimeRange(c)
severity := ginx.QueryInt(c, "severity", -1)
query := ginx.QueryStr(c, "query", "")
limit := ginx.QueryInt(c, "limit", 20)
busiGroupId := ginx.QueryInt64(c, "bgid", 0)
clusters := queryClusters(c)
total, err := models.AlertCurEventTotal(busiGroupId, stime, etime, severity, clusters, query)
ginx.Dangerous(err)
list, err := models.AlertCurEventGets(busiGroupId, stime, etime, severity, clusters, query, limit, ginx.Offset(c, limit))
ginx.Dangerous(err)
cache := make(map[int64]*models.UserGroup)
for i := 0; i < len(list); i++ {
list[i].FillNotifyGroups(cache)
}
ginx.NewRender(c).Data(gin.H{
"list": list,
"total": total,
}, nil)
}
func alertCurEventGets(c *gin.Context) {
stime, etime := getTimeRange(c)
severity := ginx.QueryInt(c, "severity", -1)
query := ginx.QueryStr(c, "query", "")
limit := ginx.QueryInt(c, "limit", 20)
@ -51,6 +136,18 @@ func alertCurEventDel(c *gin.Context) {
ginx.BindJSON(c, &f)
f.Verify()
set := make(map[int64]struct{})
for i := 0; i < len(f.Ids); i++ {
event, err := models.AlertCurEventGetById(f.Ids[i])
ginx.Dangerous(err)
if _, has := set[event.GroupId]; !has {
bgrwCheck(c, event.GroupId)
set[event.GroupId] = struct{}{}
}
}
ginx.NewRender(c).Message(models.AlertCurEventDel(f.Ids))
}

View File

@ -9,9 +9,9 @@ import (
"github.com/didi/nightingale/v5/src/models"
)
func alertHisEventGets(c *gin.Context) {
stime := ginx.QueryInt64(c, "stime", 0)
etime := ginx.QueryInt64(c, "etime", 0)
func getTimeRange(c *gin.Context) (stime, etime int64) {
stime = ginx.QueryInt64(c, "stime", 0)
etime = ginx.QueryInt64(c, "etime", 0)
hours := ginx.QueryInt64(c, "hours", 0)
now := time.Now().Unix()
if hours != 0 {
@ -22,6 +22,38 @@ func alertHisEventGets(c *gin.Context) {
if stime != 0 && etime == 0 {
etime = now + 3600*24
}
return
}
func alertHisEventsList(c *gin.Context) {
stime, etime := getTimeRange(c)
severity := ginx.QueryInt(c, "severity", -1)
recovered := ginx.QueryInt(c, "is_recovered", -1)
query := ginx.QueryStr(c, "query", "")
limit := ginx.QueryInt(c, "limit", 20)
busiGroupId := ginx.QueryInt64(c, "bgid", 0)
clusters := queryClusters(c)
total, err := models.AlertHisEventTotal(busiGroupId, stime, etime, severity, recovered, clusters, query)
ginx.Dangerous(err)
list, err := models.AlertHisEventGets(busiGroupId, stime, etime, severity, recovered, clusters, query, limit, ginx.Offset(c, limit))
ginx.Dangerous(err)
cache := make(map[int64]*models.UserGroup)
for i := 0; i < len(list); i++ {
list[i].FillNotifyGroups(cache)
}
ginx.NewRender(c).Data(gin.H{
"list": list,
"total": total,
}, nil)
}
func alertHisEventGets(c *gin.Context) {
stime, etime := getTimeRange(c)
severity := ginx.QueryInt(c, "severity", -1)
recovered := ginx.QueryInt(c, "is_recovered", -1)