2020-09-26 16:53:10 +08:00
|
|
|
|
package http
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"regexp"
|
|
|
|
|
"strings"
|
2021-06-28 00:42:39 +08:00
|
|
|
|
"time"
|
2020-09-26 16:53:10 +08:00
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
2021-06-28 00:42:39 +08:00
|
|
|
|
|
|
|
|
|
"github.com/didi/nightingale/v5/cache"
|
|
|
|
|
"github.com/didi/nightingale/v5/models"
|
2020-09-26 16:53:10 +08:00
|
|
|
|
)
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
type collectRuleForm struct {
|
|
|
|
|
ClasspathId int64 `json:"classpath_id"`
|
|
|
|
|
PrefixMatch int `json:"prefix_match"`
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
Note string `json:"note"`
|
|
|
|
|
Step int `json:"step"`
|
|
|
|
|
Type string `json:"type"`
|
|
|
|
|
Data string `json:"data"`
|
|
|
|
|
AppendTags string `json:"append_tags"`
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
func collectRuleAdd(c *gin.Context) {
|
|
|
|
|
var f collectRuleForm
|
|
|
|
|
bind(c, &f)
|
|
|
|
|
|
|
|
|
|
me := loginUser(c).MustPerm("collect_rule_create")
|
|
|
|
|
|
|
|
|
|
cr := models.CollectRule{
|
|
|
|
|
ClasspathId: f.ClasspathId,
|
|
|
|
|
PrefixMatch: f.PrefixMatch,
|
|
|
|
|
Name: f.Name,
|
|
|
|
|
Note: f.Note,
|
|
|
|
|
Step: f.Step,
|
|
|
|
|
Type: f.Type,
|
|
|
|
|
Data: f.Data,
|
|
|
|
|
AppendTags: f.AppendTags,
|
|
|
|
|
CreateBy: me.Username,
|
|
|
|
|
UpdateBy: me.Username,
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
renderMessage(c, cr.Add())
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
func collectRulePut(c *gin.Context) {
|
|
|
|
|
var f collectRuleForm
|
|
|
|
|
bind(c, &f)
|
|
|
|
|
|
|
|
|
|
me := loginUser(c).MustPerm("collect_rule_modify")
|
|
|
|
|
cr := CollectRule(urlParamInt64(c, "id"))
|
|
|
|
|
|
|
|
|
|
cr.PrefixMatch = f.PrefixMatch
|
|
|
|
|
cr.Name = f.Name
|
|
|
|
|
cr.Note = f.Note
|
|
|
|
|
cr.Step = f.Step
|
|
|
|
|
cr.Type = f.Type
|
|
|
|
|
cr.Data = f.Data
|
|
|
|
|
cr.AppendTags = f.AppendTags
|
|
|
|
|
cr.UpdateAt = time.Now().Unix()
|
|
|
|
|
cr.UpdateBy = me.Username
|
|
|
|
|
|
|
|
|
|
renderMessage(c, cr.Update(
|
|
|
|
|
"prefix_match",
|
|
|
|
|
"name",
|
|
|
|
|
"note",
|
|
|
|
|
"step",
|
|
|
|
|
"type",
|
|
|
|
|
"data",
|
|
|
|
|
"update_at",
|
|
|
|
|
"update_by",
|
|
|
|
|
"append_tags",
|
|
|
|
|
))
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
func collectRuleDel(c *gin.Context) {
|
|
|
|
|
var f idsForm
|
|
|
|
|
bind(c, &f)
|
|
|
|
|
f.Validate()
|
|
|
|
|
loginUser(c).MustPerm("collect_rule_delete")
|
|
|
|
|
renderMessage(c, models.CollectRulesDel(f.Ids))
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
func collectRuleGets(c *gin.Context) {
|
|
|
|
|
classpathId := urlParamInt64(c, "id")
|
2020-09-26 16:53:10 +08:00
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
where := "classpath_id = ?"
|
|
|
|
|
param := []interface{}{classpathId}
|
2021-01-01 10:41:30 +08:00
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
typ := queryStr(c, "type", "")
|
|
|
|
|
if typ != "" {
|
|
|
|
|
where += " and type = ?"
|
|
|
|
|
param = append(param, typ)
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
objs, err := models.CollectRuleGets(where, param...)
|
|
|
|
|
renderData(c, objs, err)
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
func collectRuleGetsByIdent(c *gin.Context) {
|
|
|
|
|
ident := queryStr(c, "ident")
|
2021-01-18 19:25:47 +08:00
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
objs := cache.CollectRulesOfIdent.GetBy(ident)
|
|
|
|
|
renderData(c, objs, nil)
|
2021-01-18 19:25:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
type Summary struct {
|
|
|
|
|
LatestUpdatedAt int64 `json:"latestUpdatedAt"`
|
|
|
|
|
Total int `json:"total"`
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
func collectRuleSummaryGetByIdent(c *gin.Context) {
|
|
|
|
|
ident := queryStr(c, "ident")
|
|
|
|
|
var summary Summary
|
|
|
|
|
objs := cache.CollectRulesOfIdent.GetBy(ident)
|
|
|
|
|
total := len(objs)
|
|
|
|
|
if total > 0 {
|
|
|
|
|
summary.Total = total
|
|
|
|
|
var latestUpdatedAt int64
|
|
|
|
|
for _, obj := range objs {
|
|
|
|
|
if latestUpdatedAt < obj.UpdateAt {
|
|
|
|
|
latestUpdatedAt = obj.UpdateAt
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-28 00:42:39 +08:00
|
|
|
|
summary.LatestUpdatedAt = latestUpdatedAt
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
renderData(c, summary, nil)
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
type RegExpCheck struct {
|
2020-09-26 16:53:10 +08:00
|
|
|
|
Success bool `json:"success"`
|
|
|
|
|
Data []map[string]string `json:"tags"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func regExpCheck(c *gin.Context) {
|
2021-06-28 00:42:39 +08:00
|
|
|
|
param := make(map[string]string)
|
|
|
|
|
dangerous(c.ShouldBind(¶m))
|
2020-09-26 16:53:10 +08:00
|
|
|
|
|
2021-06-28 00:42:39 +08:00
|
|
|
|
ret := &RegExpCheck{
|
2020-09-26 16:53:10 +08:00
|
|
|
|
Success: true,
|
|
|
|
|
Data: make([]map[string]string, 0),
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 20:09:40 +08:00
|
|
|
|
calcMethod := param["func"]
|
|
|
|
|
if calcMethod == "" {
|
|
|
|
|
tmp := map[string]string{"func": "is empty"}
|
2020-09-26 16:53:10 +08:00
|
|
|
|
ret.Data = append(ret.Data, tmp)
|
2021-06-29 20:09:40 +08:00
|
|
|
|
renderData(c, ret, nil)
|
|
|
|
|
return
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 20:09:40 +08:00
|
|
|
|
// 处理主正则
|
2020-09-26 16:53:10 +08:00
|
|
|
|
if re, ok := param["re"]; !ok || re == "" {
|
2021-06-29 20:09:40 +08:00
|
|
|
|
tmp := map[string]string{"re": "regex does not exist or is empty"}
|
2020-09-26 16:53:10 +08:00
|
|
|
|
ret.Data = append(ret.Data, tmp)
|
2021-06-29 20:09:40 +08:00
|
|
|
|
renderData(c, ret, nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
2020-09-26 16:53:10 +08:00
|
|
|
|
|
2021-06-29 20:09:40 +08:00
|
|
|
|
// 匹配主正则
|
|
|
|
|
suc, reRes, isSub := checkRegex(param["re"], param["log"])
|
|
|
|
|
if !suc {
|
|
|
|
|
ret.Success = false
|
2021-07-16 08:30:48 +08:00
|
|
|
|
reRes = genErrMsg(param["re"])
|
2021-06-29 20:09:40 +08:00
|
|
|
|
ret.Data = append(ret.Data, map[string]string{"re": reRes})
|
|
|
|
|
renderData(c, ret, nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if calcMethod == "histogram" && !isSub {
|
|
|
|
|
ret.Success = false
|
2021-07-16 08:30:48 +08:00
|
|
|
|
reRes = genSubErrMsg(param["re"])
|
2021-06-29 20:09:40 +08:00
|
|
|
|
ret.Data = append(ret.Data, map[string]string{"re": reRes})
|
|
|
|
|
renderData(c, ret, nil)
|
|
|
|
|
return
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 20:09:40 +08:00
|
|
|
|
ret.Data = append(ret.Data, map[string]string{"re": reRes})
|
2020-09-26 16:53:10 +08:00
|
|
|
|
// 处理tags
|
|
|
|
|
var nonTagKey = map[string]bool{
|
2021-06-29 20:09:40 +08:00
|
|
|
|
"re": true,
|
|
|
|
|
"log": true,
|
|
|
|
|
"func": true,
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for tagk, pat := range param {
|
|
|
|
|
// 如果不是tag,就继续循环
|
|
|
|
|
if _, ok := nonTagKey[tagk]; ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-06-29 20:09:40 +08:00
|
|
|
|
suc, tagRes, isSub := checkRegex(pat, param["log"])
|
2020-09-26 16:53:10 +08:00
|
|
|
|
if !suc {
|
|
|
|
|
// 正则错误
|
|
|
|
|
ret.Success = false
|
2021-07-16 08:30:48 +08:00
|
|
|
|
tagRes = genErrMsg(pat)
|
2020-09-26 16:53:10 +08:00
|
|
|
|
} else if !isSub {
|
|
|
|
|
// 未匹配出子串
|
|
|
|
|
ret.Success = false
|
2021-07-16 08:30:48 +08:00
|
|
|
|
tagRes = genSubErrMsg(pat)
|
2020-09-26 16:53:10 +08:00
|
|
|
|
} else if includeIllegalChar(tagRes) || includeIllegalChar(tagk) {
|
|
|
|
|
// 保留字报错
|
|
|
|
|
ret.Success = false
|
|
|
|
|
tagRes = genIllegalCharErrMsg()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tmp := map[string]string{tagk: tagRes}
|
|
|
|
|
ret.Data = append(ret.Data, tmp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
renderData(c, ret, nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 出错信息直接放在body里
|
2021-06-29 20:09:40 +08:00
|
|
|
|
func checkRegex(pat string, log string) (succ bool, result string, isSub bool) {
|
2020-09-26 16:53:10 +08:00
|
|
|
|
if pat == "" {
|
|
|
|
|
return false, "", false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reg, err := regexp.Compile(pat)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false, "", false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res := reg.FindStringSubmatch(log)
|
|
|
|
|
switch len(res) {
|
|
|
|
|
// 没查到
|
|
|
|
|
case 0:
|
|
|
|
|
return false, "", false
|
|
|
|
|
// 没查到括号内的串,返回整个匹配串
|
|
|
|
|
case 1:
|
|
|
|
|
return true, res[0], false
|
|
|
|
|
// 查到了,默认取第一个串
|
|
|
|
|
default:
|
2021-06-29 20:09:40 +08:00
|
|
|
|
return true, res[1], true
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func includeIllegalChar(s string) bool {
|
|
|
|
|
illegalChars := ":,=\r\n\t"
|
|
|
|
|
return strings.ContainsAny(s, illegalChars)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成返回错误信息
|
2021-07-16 08:30:48 +08:00
|
|
|
|
func genErrMsg(pattern string) string {
|
|
|
|
|
return _s("Regexp[%s] matching failed", pattern)
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成子串匹配错误信息
|
2021-07-16 08:30:48 +08:00
|
|
|
|
func genSubErrMsg(pattern string) string {
|
|
|
|
|
return _s("Regexp[%s] matched, but cannot get substring()", pattern)
|
2020-09-26 16:53:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成子串匹配错误信息
|
|
|
|
|
func genIllegalCharErrMsg() string {
|
2021-07-16 08:30:48 +08:00
|
|
|
|
return _s(`TagKey or TagValue contains illegal characters[:,/=\r\n\t]`)
|
2021-04-13 11:38:40 +08:00
|
|
|
|
}
|