413 lines
9.1 KiB
Go
413 lines
9.1 KiB
Go
|
package service
|
|||
|
|
|||
|
import (
|
|||
|
"context"
|
|||
|
"errors"
|
|||
|
"fmt"
|
|||
|
"reflect"
|
|||
|
"strings"
|
|||
|
|
|||
|
"go-common/app/interface/openplatform/monitor-end/model"
|
|||
|
"go-common/app/interface/openplatform/monitor-end/model/monitor"
|
|||
|
"go-common/library/ecode"
|
|||
|
)
|
|||
|
|
|||
|
var (
|
|||
|
_duplicateNameErr = errors.New("组名已经存在!")
|
|||
|
_duplicateTargetErr = errors.New("已经存在该告警sub_event!")
|
|||
|
_invalidTargetIDErr = errors.New("无效的id!")
|
|||
|
_duplicateProductErr = errors.New("重复的product name")
|
|||
|
)
|
|||
|
|
|||
|
func targetKey(t *model.Target) string {
|
|||
|
if t.Source == "" || t.Product == "" || t.Event == "" || t.SubEvent == "" {
|
|||
|
return ""
|
|||
|
}
|
|||
|
return fmt.Sprintf("%s_%s_%s_%s", t.Source, t.Product, t.Event, t.SubEvent)
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
func productKey(p string) string {
|
|||
|
if p == "" {
|
|||
|
return ""
|
|||
|
}
|
|||
|
return fmt.Sprintf("%s", p)
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) loadalertsettings() {
|
|||
|
var (
|
|||
|
c = context.Background()
|
|||
|
gm = make(map[int64]*model.Group)
|
|||
|
tm = make(map[int64]*model.Target)
|
|||
|
tmk = make(map[string]*model.Target)
|
|||
|
tmn = make(map[string]*model.Target)
|
|||
|
pm = make(map[int64]*model.Product)
|
|||
|
pmk = make(map[string]*model.Product)
|
|||
|
)
|
|||
|
if gs, err := s.dao.AllGroups(c); err == nil {
|
|||
|
for _, g := range gs {
|
|||
|
gm[g.ID] = g
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ts, err := s.dao.AllTargets(c, 1); err == nil {
|
|||
|
for _, t := range ts {
|
|||
|
tm[t.ID] = t
|
|||
|
if key := targetKey(t); key != "" {
|
|||
|
tmk[key] = t
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if ts, err := s.dao.AllTargets(c, 0); err == nil {
|
|||
|
for _, t := range ts {
|
|||
|
if key := targetKey(t); key != "" {
|
|||
|
tmn[key] = t
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if ps, err := s.dao.AllProducts(c); err == nil {
|
|||
|
for _, p := range ps {
|
|||
|
pm[p.ID] = p
|
|||
|
if key := productKey(p.Name); err == nil {
|
|||
|
pmk[key] = p
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
s.mapMutex.Lock()
|
|||
|
s.groups = gm
|
|||
|
s.targets = tm
|
|||
|
s.products = pm
|
|||
|
s.targetKeys = tmk
|
|||
|
s.productKeys = pmk
|
|||
|
s.newTargets = tmn
|
|||
|
s.mapMutex.Unlock()
|
|||
|
}
|
|||
|
|
|||
|
// AddGroup add a new group.
|
|||
|
func (s *Service) AddGroup(c context.Context, group *model.Group) (id int64, err error) {
|
|||
|
var g *model.Group
|
|||
|
if group.Name == "" || group.Receivers == "" || group.Interval < 0 {
|
|||
|
err = ecode.RequestErr
|
|||
|
return
|
|||
|
}
|
|||
|
if g, err = s.GroupByName(c, group.Name); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
if g.ID > 0 {
|
|||
|
err = _duplicateNameErr
|
|||
|
return
|
|||
|
}
|
|||
|
if group.Interval == 0 {
|
|||
|
group.Interval = 30
|
|||
|
}
|
|||
|
return s.dao.AddGroup(c, group)
|
|||
|
}
|
|||
|
|
|||
|
// UpdateGroup update group.
|
|||
|
func (s *Service) UpdateGroup(c context.Context, group *model.Group) (err error) {
|
|||
|
var g *model.Group
|
|||
|
if group.ID == 0 || group.Name == "" || group.Receivers == "" || group.Interval < 0 {
|
|||
|
err = ecode.RequestErr
|
|||
|
return
|
|||
|
}
|
|||
|
if g, err = s.GroupByName(c, group.Name); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
if g.ID != 0 && g.ID != group.ID {
|
|||
|
err = _duplicateNameErr
|
|||
|
return
|
|||
|
}
|
|||
|
if group.Interval == 0 {
|
|||
|
group.Interval = 30
|
|||
|
}
|
|||
|
_, err = s.dao.UpdateGroup(c, group)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// DeleteGroup delete group.
|
|||
|
func (s *Service) DeleteGroup(c context.Context, id int64) (err error) {
|
|||
|
if id == 0 {
|
|||
|
err = ecode.RequestErr
|
|||
|
return
|
|||
|
}
|
|||
|
_, err = s.dao.DeleteGroup(c, id)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// GroupList return all groups.
|
|||
|
func (s *Service) GroupList(c context.Context, params *model.GroupListParams) (res *model.Groups, err error) {
|
|||
|
res = &model.Groups{}
|
|||
|
if res.Groups, err = s.dao.AllGroups(c); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
res.Total = len(res.Groups)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// GroupByName get group by name.
|
|||
|
func (s *Service) GroupByName(c context.Context, name string) (res *model.Group, err error) {
|
|||
|
return s.dao.GroupByName(c, name)
|
|||
|
}
|
|||
|
|
|||
|
// Target get target by id.
|
|||
|
func (s *Service) Target(c context.Context, id int64) (res *model.Target, err error) {
|
|||
|
return s.dao.Target(c, id)
|
|||
|
}
|
|||
|
|
|||
|
// AddTarget add a new target.
|
|||
|
func (s *Service) AddTarget(c context.Context, t *model.Target) (id int64, err error) {
|
|||
|
if t.SubEvent == "" || t.Event == "" || t.Product == "" || t.Source == "" {
|
|||
|
err = ecode.RequestErr
|
|||
|
return
|
|||
|
}
|
|||
|
if err = s.checkTarget(c, t, true); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
return s.dao.AddTarget(c, t)
|
|||
|
}
|
|||
|
|
|||
|
// UpdateTarget update target.
|
|||
|
func (s *Service) UpdateTarget(c context.Context, t *model.Target) (err error) {
|
|||
|
var (
|
|||
|
oldTarget *model.Target
|
|||
|
)
|
|||
|
if oldTarget, err = s.Target(c, t.ID); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
if oldTarget == nil {
|
|||
|
err = _invalidTargetIDErr
|
|||
|
return
|
|||
|
}
|
|||
|
mergeTarget(t, oldTarget)
|
|||
|
if err = s.checkTarget(c, t, false); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
_, err = s.dao.UpdateTarget(c, t)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// TargetList .
|
|||
|
func (s *Service) TargetList(c context.Context, t *model.Target, pn int, ps int, sort string) (res *model.Targets, err error) {
|
|||
|
// query := "SELECT id, sub_event, event, product, source, group_id, threshold, duration, state FROM target"
|
|||
|
var (
|
|||
|
where = ""
|
|||
|
order = ""
|
|||
|
empty struct{}
|
|||
|
sortFields = map[string]struct{}{
|
|||
|
"sub_event": empty,
|
|||
|
"mtime": empty,
|
|||
|
"ctime": empty,
|
|||
|
"state": empty,
|
|||
|
}
|
|||
|
sortOrder = map[string]string{
|
|||
|
"0": "DESC",
|
|||
|
"1": "ASC",
|
|||
|
}
|
|||
|
)
|
|||
|
if t.SubEvent != "" {
|
|||
|
where += " sub_event LIKE '%" + t.SubEvent + "%'"
|
|||
|
}
|
|||
|
if t.Event != "" {
|
|||
|
where += " event = '" + t.Event + "'"
|
|||
|
}
|
|||
|
if t.Product != "" {
|
|||
|
where += " product = '" + t.Product + "'"
|
|||
|
}
|
|||
|
if t.Source != "" {
|
|||
|
where += " source = '" + t.Source + "'"
|
|||
|
}
|
|||
|
if t.States != "" {
|
|||
|
where += " state in (" + t.States + ")"
|
|||
|
}
|
|||
|
if where == "" {
|
|||
|
where = " WHERE" + where + " deleted_time = 0"
|
|||
|
} else {
|
|||
|
where = " WHERE" + where + " AND deleted_time = 0"
|
|||
|
}
|
|||
|
countWhere := where
|
|||
|
pn = (pn - 1) * ps
|
|||
|
sorts := strings.Split(sort, ",")
|
|||
|
if len(sorts) == 2 {
|
|||
|
_, ok1 := sortFields[sorts[0]]
|
|||
|
d, ok2 := sortOrder[sorts[1]]
|
|||
|
if ok1 && ok2 {
|
|||
|
order = " ORDER BY " + sorts[0] + " " + d
|
|||
|
}
|
|||
|
}
|
|||
|
where += order
|
|||
|
where += fmt.Sprintf(" LIMIT %d, %d", pn, ps)
|
|||
|
res = &model.Targets{}
|
|||
|
if res.Targets, err = s.dao.TargetsByQuery(c, where); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
if res.Total, err = s.dao.CountTargets(c, countWhere); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
res.Page = pn
|
|||
|
res.PageSize = ps
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// TargetSync sync target state.
|
|||
|
func (s *Service) TargetSync(c context.Context, id int64, state int) (err error) {
|
|||
|
return s.dao.TargetSync(c, id, state)
|
|||
|
}
|
|||
|
|
|||
|
// DeleteTarget delete target by id.
|
|||
|
func (s *Service) DeleteTarget(c context.Context, id int64) (err error) {
|
|||
|
_, err = s.dao.DeleteTarget(c, id)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
func (s *Service) checkTarget(c context.Context, t *model.Target, isNew bool) (err error) {
|
|||
|
var id int64
|
|||
|
t.SubEvent = induceSubEvent(t.SubEvent)
|
|||
|
if id, err = s.dao.IsExisted(c, t); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
if isNew && id != 0 {
|
|||
|
fmt.Println("id", id)
|
|||
|
err = _duplicateTargetErr
|
|||
|
}
|
|||
|
if !isNew && id != 0 && t.ID != id {
|
|||
|
err = _duplicateTargetErr
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
func mergeTarget(t *model.Target, o *model.Target) {
|
|||
|
te := reflect.ValueOf(t).Elem()
|
|||
|
oe := reflect.ValueOf(o).Elem()
|
|||
|
for i := 0; i < te.NumField()-2; i++ {
|
|||
|
switch v := te.Field(i).Interface().(type) {
|
|||
|
case int, int64:
|
|||
|
if v == 0 {
|
|||
|
te.Field(i).Set(oe.Field(i))
|
|||
|
}
|
|||
|
case string:
|
|||
|
if v == "" {
|
|||
|
te.Field(i).Set(oe.Field(i))
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// AddProduct add a new group.
|
|||
|
func (s *Service) AddProduct(c context.Context, p *model.Product) (id int64, err error) {
|
|||
|
if p.Name == "" || p.GroupIDs == "" {
|
|||
|
err = ecode.RequestErr
|
|||
|
return
|
|||
|
}
|
|||
|
var a *model.Product
|
|||
|
if a, err = s.dao.ProductByName(c, p.Name); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
if a != nil {
|
|||
|
err = _duplicateProductErr
|
|||
|
return
|
|||
|
}
|
|||
|
id, err = s.dao.AddProduct(c, p)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// UpdateProduct update product.
|
|||
|
func (s *Service) UpdateProduct(c context.Context, p *model.Product) (err error) {
|
|||
|
if p.ID == 0 || p.Name == "" || p.GroupIDs == "" {
|
|||
|
err = ecode.RequestErr
|
|||
|
return
|
|||
|
}
|
|||
|
var a *model.Product
|
|||
|
if a, err = s.dao.ProductByName(c, p.Name); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
if a != nil && a.ID != p.ID {
|
|||
|
err = _duplicateProductErr
|
|||
|
return
|
|||
|
}
|
|||
|
_, err = s.dao.UpdateProduct(c, p)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// DeleteProduct delete product.
|
|||
|
func (s *Service) DeleteProduct(c context.Context, id int64) (err error) {
|
|||
|
_, err = s.dao.DeleteProduct(c, id)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// AllProducts return all products.
|
|||
|
func (s *Service) AllProducts(c context.Context) (res *model.Products, err error) {
|
|||
|
res = &model.Products{}
|
|||
|
if res.Products, err = s.dao.AllProducts(c); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
res.Total = len(res.Products)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// Collect collect.
|
|||
|
func (s *Service) Collect(c context.Context, p *monitor.Log) {
|
|||
|
var (
|
|||
|
curr int
|
|||
|
key string
|
|||
|
t *model.Target
|
|||
|
)
|
|||
|
target := &model.Target{
|
|||
|
Source: sourceFromLog(p),
|
|||
|
Product: p.Product,
|
|||
|
Event: p.Event,
|
|||
|
SubEvent: induceSubEvent(p.SubEvent),
|
|||
|
State: 0,
|
|||
|
}
|
|||
|
s.infoCh <- p
|
|||
|
//TODO 获取buvid, ip等信息,过滤重复请求
|
|||
|
if key = targetKey(target); key == "" {
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
if t = s.targetKeys[key]; t == nil {
|
|||
|
if s.newTargets[key] == nil {
|
|||
|
// 添加新的target
|
|||
|
s.AddTarget(c, target)
|
|||
|
}
|
|||
|
s.mapMutex.Lock()
|
|||
|
s.newTargets[key] = t
|
|||
|
s.mapMutex.Unlock()
|
|||
|
return
|
|||
|
}
|
|||
|
if t.Threshold == 0 {
|
|||
|
return
|
|||
|
}
|
|||
|
p.CalCode()
|
|||
|
code := codeFromLog(p)
|
|||
|
curr = s.dao.TargetIncr(c, t, code)
|
|||
|
if curr > t.Threshold {
|
|||
|
go s.mail(c, p, t, curr, code)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func sourceFromLog(l *monitor.Log) string {
|
|||
|
if l.Type == "web/h5" {
|
|||
|
return l.Type
|
|||
|
}
|
|||
|
if l.RequestURI == "" {
|
|||
|
return "app"
|
|||
|
}
|
|||
|
if res := strings.Split(l.RequestURI, "?"); len(res) > 1 {
|
|||
|
return res[1]
|
|||
|
}
|
|||
|
return l.RequestURI
|
|||
|
}
|
|||
|
|
|||
|
func codeFromLog(l *monitor.Log) string {
|
|||
|
if l.Codes == "" {
|
|||
|
return "999"
|
|||
|
}
|
|||
|
if l.HTTPCode != "" && l.HTTPCode != "200" {
|
|||
|
return l.HTTPCode
|
|||
|
}
|
|||
|
if l.BusinessCode != "" && l.BusinessCode != "0" {
|
|||
|
return l.BusinessCode
|
|||
|
}
|
|||
|
return "-999"
|
|||
|
}
|