go-common/app/interface/openplatform/monitor-end/service/alert.go
2019-04-22 18:49:16 +08:00

413 lines
9.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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"
}