update rule expression
This commit is contained in:
parent
6ac22f53a3
commit
2461773428
|
@ -42,4 +42,13 @@ const (
|
|||
AlertStateAcknowledge = "acknowledge"
|
||||
AlertStateNormal = "normal"
|
||||
AlertStateError = "error"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
/*
|
||||
{
|
||||
RuleID
|
||||
ResourceID
|
||||
ResourceName
|
||||
}
|
||||
*/
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
package alerting
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Condition struct {
|
||||
Operator string `json:"operator"`
|
||||
Items []ConditionItem `json:"items"`
|
||||
|
@ -17,6 +19,32 @@ type ConditionItem struct {
|
|||
Severity string `json:"severity"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
func (cond *ConditionItem) GenerateConditionExpression()(conditionExpression string, err error){
|
||||
valueLength := len(cond.Values)
|
||||
if valueLength == 0 {
|
||||
return conditionExpression, fmt.Errorf("condition values: %v should not be empty", cond.Values)
|
||||
}
|
||||
switch cond.Operator {
|
||||
case "equals":
|
||||
conditionExpression = fmt.Sprintf("result == %v", cond.Values[0])
|
||||
case "gte":
|
||||
conditionExpression = fmt.Sprintf("result >= %v", cond.Values[0])
|
||||
case "lte":
|
||||
conditionExpression = fmt.Sprintf("result <= %v", cond.Values[0])
|
||||
case "gt":
|
||||
conditionExpression = fmt.Sprintf("result > %v", cond.Values[0])
|
||||
case "lt":
|
||||
conditionExpression = fmt.Sprintf("result < %v", cond.Values[0])
|
||||
case "range":
|
||||
if len(cond.Values) != 2 {
|
||||
return conditionExpression, fmt.Errorf("length of %s condition values should be 2", cond.Operator)
|
||||
}
|
||||
conditionExpression = fmt.Sprintf("result >= %v && result <= %v", cond.Values[0], cond.Values[1])
|
||||
default:
|
||||
return conditionExpression, fmt.Errorf("unsupport condition operator: %s", cond.Operator)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type ConditionResult struct {
|
||||
ResultItems []ConditionResultItem `json:"result_items"`
|
||||
|
|
|
@ -16,13 +16,12 @@ type Metric struct {
|
|||
Formula string `json:"formula,omitempty"`
|
||||
Expression string `json:"expression" elastic_mapping:"expression:{type:keyword,copy_to:search_text}"` //告警表达式,自动生成 eg: avg(cpu) > 80
|
||||
}
|
||||
func (m *Metric) RefreshExpression() error{
|
||||
func (m *Metric) GenerateExpression() (string, error){
|
||||
if len(m.Items) == 1 {
|
||||
m.Expression = fmt.Sprintf("%s(%s)", m.Items[0].Statistic, m.Items[0].Field)
|
||||
return nil
|
||||
return fmt.Sprintf("%s(%s)", m.Items[0].Statistic, m.Items[0].Field), nil
|
||||
}
|
||||
if m.Formula == "" {
|
||||
return fmt.Errorf("formula should not be empty since there are %d metrics", len(m.Items))
|
||||
return "", fmt.Errorf("formula should not be empty since there are %d metrics", len(m.Items))
|
||||
}
|
||||
var (
|
||||
expressionBytes = []byte(m.Formula)
|
||||
|
@ -32,13 +31,12 @@ func (m *Metric) RefreshExpression() error{
|
|||
metricExpression = fmt.Sprintf("%s(%s)", item.Statistic, item.Field)
|
||||
reg, err := regexp.Compile(item.Name+`([^\w]|$)`)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
expressionBytes = reg.ReplaceAll(expressionBytes, []byte(metricExpression+"$1"))
|
||||
}
|
||||
|
||||
m.Expression = string(expressionBytes)
|
||||
return nil
|
||||
return string(expressionBytes), nil
|
||||
}
|
||||
|
||||
type MetricItem struct {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package alerting
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -23,6 +24,31 @@ type Rule struct {
|
|||
LastTermStartTime time.Time `json:"-"` //标识最近一轮告警的开始时间
|
||||
LastEscalationTime time.Time `json:"-"` //标识最近一次告警升级发送通知的时间
|
||||
SearchText string `json:"-" elastic_mapping:"search_text:{type:text,index_prefixes:{},index_phrases:true, analyzer:suggest_text_search }"`
|
||||
Expression string `json:"-"`
|
||||
}
|
||||
|
||||
func (rule *Rule) GetOrInitExpression() (string, error){
|
||||
if rule.Expression != ""{
|
||||
return rule.Expression, nil
|
||||
}
|
||||
sb := strings.Builder{}
|
||||
for i, cond := range rule.Conditions.Items {
|
||||
condExp, err := cond.GenerateConditionExpression()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sb.WriteString(condExp)
|
||||
|
||||
if i < len(rule.Conditions.Items)-1 {
|
||||
sb.WriteString(" or ")
|
||||
}
|
||||
}
|
||||
metricExp, err := rule.Metrics.GenerateExpression()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
rule.Expression = strings.ReplaceAll(sb.String(), "result", metricExp)
|
||||
return rule.Expression, nil
|
||||
}
|
||||
|
||||
type RuleChannel struct {
|
||||
|
|
|
@ -25,7 +25,7 @@ func TestCreateRule( t *testing.T) {
|
|||
Type: "elasticsearch",
|
||||
Objects: []string{".infini_metrics*"},
|
||||
TimeField: "timestamp",
|
||||
Filter: Filter{
|
||||
Filter: FilterQuery{
|
||||
And: []FilterQuery{
|
||||
//{Field: "timestamp", Operator: "gte", Values: []string{"now-15m"}},
|
||||
//{Field: "payload.elasticsearch.cluster_health.status", Operator: "equals", Values: []string{"red"}},
|
||||
|
@ -106,13 +106,17 @@ func TestCreateRule( t *testing.T) {
|
|||
EscalationThrottlePeriod: "30m",
|
||||
},
|
||||
}
|
||||
//err := rule.Metrics.RefreshExpression()
|
||||
//err := rule.Metrics.GenerateExpression()
|
||||
//if err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
exp, err := rule.GetOrInitExpression()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(util.MustToJSON(rule))
|
||||
//fmt.Println(rule.Metrics.Expression)
|
||||
//fmt.Println(util.MustToJSON(rule))
|
||||
fmt.Println(exp)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ func (alertAPI *AlertAPI) createRule(w http.ResponseWriter, req *http.Request, p
|
|||
}, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = rule.Metrics.RefreshExpression()
|
||||
rule.Metrics.Expression, err = rule.Metrics.GenerateExpression()
|
||||
if err != nil {
|
||||
alertAPI.WriteJSON(w, util.MapStr{
|
||||
"error": err.Error(),
|
||||
|
@ -135,7 +135,7 @@ func (alertAPI *AlertAPI) updateRule(w http.ResponseWriter, req *http.Request, p
|
|||
obj.ID = id
|
||||
obj.Created = create
|
||||
obj.Updated = time.Now()
|
||||
err = obj.Metrics.RefreshExpression()
|
||||
obj.Metrics.Expression, err = obj.Metrics.GenerateExpression()
|
||||
if err != nil {
|
||||
alertAPI.WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||
log.Error(err)
|
||||
|
|
|
@ -424,29 +424,9 @@ func (engine *Engine) CheckCondition(rule *alerting.Rule)(*alerting.ConditionRes
|
|||
})
|
||||
LoopCondition:
|
||||
for _, cond := range rule.Conditions.Items {
|
||||
conditionExpression := ""
|
||||
valueLength := len(cond.Values)
|
||||
if valueLength == 0 {
|
||||
return conditionResult, fmt.Errorf("condition values: %v should not be empty", cond.Values)
|
||||
}
|
||||
switch cond.Operator {
|
||||
case "equals":
|
||||
conditionExpression = fmt.Sprintf("result == %v", cond.Values[0])
|
||||
case "gte":
|
||||
conditionExpression = fmt.Sprintf("result >= %v", cond.Values[0])
|
||||
case "lte":
|
||||
conditionExpression = fmt.Sprintf("result <= %v", cond.Values[0])
|
||||
case "gt":
|
||||
conditionExpression = fmt.Sprintf("result > %v", cond.Values[0])
|
||||
case "lt":
|
||||
conditionExpression = fmt.Sprintf("result < %v", cond.Values[0])
|
||||
case "range":
|
||||
if valueLength != 2 {
|
||||
return conditionResult, fmt.Errorf("length of %s condition values should be 2", cond.Operator)
|
||||
}
|
||||
conditionExpression = fmt.Sprintf("result >= %v && result <= %v", cond.Values[0], cond.Values[1])
|
||||
default:
|
||||
return conditionResult, fmt.Errorf("unsupport condition operator: %s", cond.Operator)
|
||||
conditionExpression, err := cond.GenerateConditionExpression()
|
||||
if err != nil {
|
||||
return conditionResult, err
|
||||
}
|
||||
expression, err := govaluate.NewEvaluableExpression(conditionExpression)
|
||||
if err != nil {
|
||||
|
@ -882,4 +862,4 @@ func readTimeFromKV(bucketKey string, key []byte)(time.Time, error){
|
|||
return time.ParseInLocation(time.RFC3339, string(timeBytes), time.UTC)
|
||||
}
|
||||
return zeroTime, nil
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue