go-common/app/interface/openplatform/monitor-end/service/alert.go

413 lines
9.1 KiB
Go
Raw Normal View History

2019-04-22 10:49:16 +00:00
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"
}