未验证 提交 6440645c 编写于 作者: Q qinyening 提交者: GitHub

feat: alert rule api fill users and groups (#723)

上级 45855199
package cache
import (
"sync"
"github.com/didi/nightingale/v5/models"
)
type UserGroupMap struct {
sync.RWMutex
Data map[int64]*models.UserGroup
}
var UserGroupCache = &UserGroupMap{Data: make(map[int64]*models.UserGroup)}
func (s *UserGroupMap) GetBy(id int64) *models.UserGroup {
s.RLock()
defer s.RUnlock()
return s.Data[id]
}
func (s *UserGroupMap) GetByIds(ids []int64) []*models.UserGroup {
s.RLock()
defer s.RUnlock()
var userGroups []*models.UserGroup
for _, id := range ids {
if s.Data[id] == nil {
continue
}
userGroups = append(userGroups, s.Data[id])
}
return userGroups
}
func (s *UserGroupMap) SetAll(userGroups map[int64]*models.UserGroup) {
s.Lock()
defer s.Unlock()
s.Data = userGroups
}
...@@ -3,16 +3,21 @@ package http ...@@ -3,16 +3,21 @@ package http
import ( import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"strconv"
"strings"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/cache"
"github.com/didi/nightingale/v5/config" "github.com/didi/nightingale/v5/config"
"github.com/didi/nightingale/v5/models" "github.com/didi/nightingale/v5/models"
) )
func alertRuleGet(c *gin.Context) { func alertRuleGet(c *gin.Context) {
renderData(c, AlertRule(urlParamInt64(c, "id")), nil) alertRule := AlertRule(urlParamInt64(c, "id"))
alertRuleFillUserAndGroups(alertRule)
renderData(c, alertRule, nil)
} }
type alertRuleForm struct { type alertRuleForm struct {
...@@ -163,3 +168,22 @@ func alertRuleDel(c *gin.Context) { ...@@ -163,3 +168,22 @@ func alertRuleDel(c *gin.Context) {
func notifyChannelsGet(c *gin.Context) { func notifyChannelsGet(c *gin.Context) {
renderData(c, config.Config.NotifyChannels, nil) renderData(c, config.Config.NotifyChannels, nil)
} }
func alertRuleFillUserAndGroups(alertRule *models.AlertRule) {
uidStrs := strings.Fields(alertRule.NotifyUsers)
var uids []int64
for _, uidStr := range uidStrs {
uid, _ := strconv.ParseInt(uidStr, 10, 64)
uids = append(uids, uid)
}
alertRule.NotifyUsersDetail = cache.UserCache.GetByIds(uids)
gidStrs := strings.Fields(alertRule.NotifyGroups)
var gids []int64
for _, gidStr := range gidStrs {
gid, _ := strconv.ParseInt(gidStr, 10, 64)
gids = append(gids, gid)
}
alertRule.NotifyGroupsDetail = cache.UserGroupCache.GetByIds(gids)
}
...@@ -68,6 +68,10 @@ func alertRuleGroupGet(c *gin.Context) { ...@@ -68,6 +68,10 @@ func alertRuleGroupGet(c *gin.Context) {
func alertRuleOfGroupGet(c *gin.Context) { func alertRuleOfGroupGet(c *gin.Context) {
ars, err := models.AlertRulesOfGroup(urlParamInt64(c, "id")) ars, err := models.AlertRulesOfGroup(urlParamInt64(c, "id"))
for i := range ars {
alertRuleFillUserAndGroups(&ars[i])
}
renderData(c, ars, err) renderData(c, ars, err)
} }
......
...@@ -71,6 +71,7 @@ func main() { ...@@ -71,6 +71,7 @@ func main() {
timer.SyncResourceTags() timer.SyncResourceTags()
timer.SyncUsers() timer.SyncUsers()
timer.SyncUserGroups()
timer.SyncUserGroupMember() timer.SyncUserGroupMember()
timer.SyncClasspathReses() timer.SyncClasspathReses()
timer.SyncCollectRules() timer.SyncCollectRules()
......
...@@ -19,32 +19,34 @@ const ALERT_RULE_ACTIVE = 0 ...@@ -19,32 +19,34 @@ const ALERT_RULE_ACTIVE = 0
const ALERT_RULE_DISABLED = 1 const ALERT_RULE_DISABLED = 1
type AlertRule struct { type AlertRule struct {
Id int64 `json:"id"` Id int64 `json:"id"`
GroupId int64 `json:"group_id"` GroupId int64 `json:"group_id"`
Name string `json:"name"` Name string `json:"name"`
Type int `json:"type"` // 0: nightingale, 1: prometheus Type int `json:"type"` // 0: nightingale, 1: prometheus
Expression json.RawMessage `json:"expression"` Expression json.RawMessage `json:"expression"`
Status int `json:"status"` // 0: active, 1: disabled Status int `json:"status"` // 0: active, 1: disabled
AppendTags string `json:"append_tags"` AppendTags string `json:"append_tags"`
EnableStime string `json:"enable_stime"` EnableStime string `json:"enable_stime"`
EnableEtime string `json:"enable_etime"` EnableEtime string `json:"enable_etime"`
EnableDaysOfWeek string `json:"enable_days_of_week"` EnableDaysOfWeek string `json:"enable_days_of_week"`
RecoveryNotify int `json:"recovery_notify"` RecoveryNotify int `json:"recovery_notify"`
Priority int `json:"priority"` Priority int `json:"priority"`
NotifyChannels string `json:"notify_channels"` NotifyChannels string `json:"notify_channels"`
NotifyGroups string `json:"notify_groups"` NotifyGroups string `json:"notify_groups"`
NotifyUsers string `json:"notify_users"` NotifyUsers string `json:"notify_users"`
Callbacks string `json:"callbacks"` Callbacks string `json:"callbacks"`
RunbookUrl string `json:"runbook_url"` RunbookUrl string `json:"runbook_url"`
Note string `json:"note"` Note string `json:"note"`
CreateAt int64 `json:"create_at"` CreateAt int64 `json:"create_at"`
CreateBy string `json:"create_by"` CreateBy string `json:"create_by"`
UpdateAt int64 `json:"update_at"` UpdateAt int64 `json:"update_at"`
UpdateBy string `json:"update_by"` UpdateBy string `json:"update_by"`
AlertDuration int `json:"alert_duration"` // 告警统计周期,PULL模型会当做P8S的for时间 AlertDuration int `json:"alert_duration"` // 告警统计周期,PULL模型会当做P8S的for时间
PushExpr PushExpression `xorm:"-" json:"-"` PushExpr PushExpression `xorm:"-" json:"-"`
PullExpr PullExpression `xorm:"-" json:"-"` PullExpr PullExpression `xorm:"-" json:"-"`
FirstMetric string `xorm:"-" json:"-"` // Exps里可能有多个metric,只取第一个,给后续制作map使用 FirstMetric string `xorm:"-" json:"-"` // Exps里可能有多个metric,只取第一个,给后续制作map使用
NotifyUsersDetail []*User `xorm:"-" json:"notify_users_detail"`
NotifyGroupsDetail []*UserGroup `xorm:"-" json:"notify_groups_detail"`
} }
type PushExpression struct { type PushExpression struct {
......
...@@ -204,3 +204,19 @@ func (ug *UserGroup) Del() error { ...@@ -204,3 +204,19 @@ func (ug *UserGroup) Del() error {
return session.Commit() return session.Commit()
} }
func UserGroupGetAll() ([]UserGroup, error) {
var userGroups []UserGroup
err := DB.Find(&userGroups)
if err != nil {
logger.Errorf("mysql.error: select user_group fail: %v", err)
return userGroups, internalServerError
}
if len(userGroups) == 0 {
return []UserGroup{}, nil
}
return userGroups, nil
}
package timer
import (
"fmt"
"math/rand"
"time"
"github.com/didi/nightingale/v5/cache"
"github.com/didi/nightingale/v5/models"
"github.com/toolkits/pkg/logger"
)
// user_group_id->user_group 将数据库中的用户信息缓存在内存里,
// 在生成告警事件的时候,根据用户ID快速找到用户的详情
func SyncUserGroups() {
err := syncUserGroups()
if err != nil {
fmt.Println("timer: sync users fail:", err)
exit(1)
}
go loopSyncUserGroups()
}
func loopSyncUserGroups() {
randtime := rand.Intn(9000)
fmt.Printf("timer: sync users: random sleep %dms\n", randtime)
time.Sleep(time.Duration(randtime) * time.Millisecond)
for {
time.Sleep(time.Second * time.Duration(9))
err := syncUserGroups()
if err != nil {
logger.Warning("timer: sync users fail:", err)
}
}
}
func syncUserGroups() error {
start := time.Now()
userGroups, err := models.UserGroupGetAll()
if err != nil {
return err
}
userGroupsMap := make(map[int64]*models.UserGroup)
for i := range userGroups {
userGroupsMap[userGroups[i].Id] = &userGroups[i]
}
cache.UserGroupCache.SetAll(userGroupsMap)
logger.Debugf("timer: sync userGroups done, cost: %dms", time.Since(start).Milliseconds())
return nil
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册