update alerting api

This commit is contained in:
liugq 2022-05-13 12:27:06 +08:00
parent c5727f331f
commit 8926460150
6 changed files with 72 additions and 40 deletions

View File

@ -35,6 +35,7 @@ type ActionExecutionResult struct {
LastExecutionTime int `json:"last_execution_time"` LastExecutionTime int `json:"last_execution_time"`
Error string `json:"error"` Error string `json:"error"`
Result string `json:"result"` Result string `json:"result"`
Message string `json:"message"`
} }
const ( const (

View File

@ -75,6 +75,10 @@ func (tr *TimeRange) Include( t time.Time) bool {
return tr.Start <= currentTimeStr && currentTimeStr <= tr.End return tr.Start <= currentTimeStr && currentTimeStr <= tr.End
} }
type FilterParam struct {
Start interface{} `json:"start"`
End interface{} `json:"end"`
}
//ctx //ctx
//rule expression, rule_id, resource_id, resource_name, event_id, condition_name, preset_value,[group_tags, check_values], //rule expression, rule_id, resource_id, resource_name, event_id, condition_name, preset_value,[group_tags, check_values],
//check_status ,timestamp, //check_status ,timestamp,

View File

@ -6,13 +6,13 @@ package alerting
import ( import (
"fmt" "fmt"
log "github.com/cihub/seelog"
"infini.sh/console/model/alerting" "infini.sh/console/model/alerting"
httprouter "infini.sh/framework/core/api/router" httprouter "infini.sh/framework/core/api/router"
"infini.sh/framework/core/elastic" "infini.sh/framework/core/elastic"
"infini.sh/framework/core/orm" "infini.sh/framework/core/orm"
"infini.sh/framework/core/util" "infini.sh/framework/core/util"
"net/http" "net/http"
log "src/github.com/cihub/seelog"
"strconv" "strconv"
"strings" "strings"
) )

View File

@ -431,6 +431,9 @@ func (alertAPI *AlertAPI) sendTestMessage(w http.ResponseWriter, req *http.Reque
}, http.StatusInternalServerError) }, http.StatusInternalServerError)
return return
} }
if rule.ID == "" {
rule.ID = util.GetUUID()
}
eng := alerting2.GetEngine(rule.Resource.Type) eng := alerting2.GetEngine(rule.Resource.Type)
actionResults, err := eng.Test(&rule) actionResults, err := eng.Test(&rule)
if err != nil { if err != nil {
@ -483,7 +486,7 @@ func (alertAPI *AlertAPI) getMetricData(w http.ResponseWriter, req *http.Request
return return
} }
eng := alerting2.GetEngine(rule.Resource.Type) eng := alerting2.GetEngine(rule.Resource.Type)
metricData, err := eng.GetTargetMetricData(&rule, true) metricData, err := eng.GetTargetMetricData(&rule, true, nil)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
alertAPI.WriteJSON(w, util.MapStr{ alertAPI.WriteJSON(w, util.MapStr{

View File

@ -35,8 +35,8 @@ type Engine struct {
//auto generate elasticsearch aggregations by metrics of rule //auto generate elasticsearch aggregations by metrics of rule
//group of metric item converted to terms aggregation and TimeField of rule converted to date_histogram aggregation //group of metric item converted to terms aggregation and TimeField of rule converted to date_histogram aggregation
//convert statistic of metric item to elasticsearch aggregation //convert statistic of metric item to elasticsearch aggregation
func (engine *Engine) GenerateQuery(rule *alerting.Rule) (interface{}, error) { func (engine *Engine) GenerateQuery(rule *alerting.Rule, filterParam *alerting.FilterParam) (interface{}, error) {
filter, err := engine.GenerateRawFilter(rule) filter, err := engine.GenerateRawFilter(rule, filterParam)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -258,7 +258,7 @@ func (engine *Engine) ConvertFilterQueryToDsl(fq *alerting.FilterQuery) (map[str
return resultQuery, nil return resultQuery, nil
} }
func (engine *Engine) GenerateRawFilter(rule *alerting.Rule) (map[string]interface{}, error) { func (engine *Engine) GenerateRawFilter(rule *alerting.Rule, filterParam *alerting.FilterParam) (map[string]interface{}, error) {
query := map[string]interface{}{} query := map[string]interface{}{}
var err error var err error
if rule.Resource.RawFilter != nil { if rule.Resource.RawFilter != nil {
@ -271,14 +271,22 @@ func (engine *Engine) GenerateRawFilter(rule *alerting.Rule) (map[string]interfa
} }
} }
} }
intervalDuration, err := time.ParseDuration(rule.Metrics.PeriodInterval) var (
if err != nil { timeStart interface{}
return nil, err timeEnd interface{}
} )
if filterParam != nil {
timeStart = filterParam.Start
timeEnd = filterParam.End
}else{
var ( var (
units string units string
value int value int
) )
intervalDuration, err := time.ParseDuration(rule.Metrics.PeriodInterval)
if err != nil {
return nil, err
}
if intervalDuration / time.Hour >= 1 { if intervalDuration / time.Hour >= 1 {
units = "h" units = "h"
value = int(intervalDuration / time.Hour) value = int(intervalDuration / time.Hour)
@ -291,10 +299,19 @@ func (engine *Engine) GenerateRawFilter(rule *alerting.Rule) (map[string]interfa
}else{ }else{
return nil, fmt.Errorf("period interval: %s is too small", rule.Metrics.PeriodInterval) return nil, fmt.Errorf("period interval: %s is too small", rule.Metrics.PeriodInterval)
} }
duration, err := time.ParseDuration(fmt.Sprintf("%d%s", value * 15, units))
if err != nil {
return nil, err
}
timeStart = time.Now().Add(-duration).Format(time.RFC3339Nano)
timeEnd = time.Now().Format(time.RFC3339Nano)
}
timeQuery := util.MapStr{ timeQuery := util.MapStr{
"range": util.MapStr{ "range": util.MapStr{
rule.Resource.TimeField: util.MapStr{ rule.Resource.TimeField: util.MapStr{
"gte": fmt.Sprintf("now-%d%s", value * 15, units), "gte": timeStart,
"lte": timeEnd,
}, },
}, },
} }
@ -331,12 +348,12 @@ func (engine *Engine) GenerateRawFilter(rule *alerting.Rule) (map[string]interfa
return query, nil return query, nil
} }
func (engine *Engine) ExecuteQuery(rule *alerting.Rule)(*alerting.QueryResult, error){ func (engine *Engine) ExecuteQuery(rule *alerting.Rule, filterParam *alerting.FilterParam)(*alerting.QueryResult, error){
esClient := elastic.GetClient(rule.Resource.ID) esClient := elastic.GetClient(rule.Resource.ID)
queryResult := &alerting.QueryResult{} queryResult := &alerting.QueryResult{}
indexName := strings.Join(rule.Resource.Objects, ",") indexName := strings.Join(rule.Resource.Objects, ",")
//todo cache queryDsl //todo cache queryDsl
queryDsl, err := engine.GenerateQuery(rule) queryDsl, err := engine.GenerateQuery(rule, filterParam)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -363,8 +380,8 @@ func (engine *Engine) ExecuteQuery(rule *alerting.Rule)(*alerting.QueryResult, e
queryResult.MetricData = metricData queryResult.MetricData = metricData
return queryResult, nil return queryResult, nil
} }
func (engine *Engine) GetTargetMetricData(rule *alerting.Rule, isFilterNaN bool)([]alerting.MetricData, error){ func (engine *Engine) GetTargetMetricData(rule *alerting.Rule, isFilterNaN bool, filterParam *alerting.FilterParam)([]alerting.MetricData, error){
queryResult, err := engine.ExecuteQuery(rule) queryResult, err := engine.ExecuteQuery(rule, filterParam)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -429,7 +446,7 @@ func (engine *Engine) GetTargetMetricData(rule *alerting.Rule, isFilterNaN bool)
//if triggered returns an array of ConditionResult //if triggered returns an array of ConditionResult
//sort conditions by severity desc before check , and then if condition is true, then continue check another group //sort conditions by severity desc before check , and then if condition is true, then continue check another group
func (engine *Engine) CheckCondition(rule *alerting.Rule)(*alerting.ConditionResult, error){ func (engine *Engine) CheckCondition(rule *alerting.Rule)(*alerting.ConditionResult, error){
queryResult, err := engine.ExecuteQuery(rule) queryResult, err := engine.ExecuteQuery(rule, nil)
conditionResult := &alerting.ConditionResult{ conditionResult := &alerting.ConditionResult{
QueryResult: queryResult, QueryResult: queryResult,
} }
@ -438,7 +455,7 @@ func (engine *Engine) CheckCondition(rule *alerting.Rule)(*alerting.ConditionRes
} }
var resultItems []alerting.ConditionResultItem var resultItems []alerting.ConditionResultItem
targetMetricData, err := engine.GetTargetMetricData(rule, false) targetMetricData, err := engine.GetTargetMetricData(rule, false, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -542,7 +559,7 @@ func (engine *Engine) Do(rule *alerting.Rule) error {
} }
}() }()
log.Tracef("start check condition of rule %s", rule.ID) log.Tracef("start check condition of rule %s", rule.ID)
checkResults, err := engine.CheckCondition(rule)
alertItem = &alerting.Alert{ alertItem = &alerting.Alert{
ID: util.GetUUID(), ID: util.GetUUID(),
Created: time.Now(), Created: time.Now(),
@ -552,10 +569,11 @@ func (engine *Engine) Do(rule *alerting.Rule) error {
ResourceName: rule.Resource.Name, ResourceName: rule.Resource.Name,
Expression: rule.Metrics.Expression, Expression: rule.Metrics.Expression,
Objects: rule.Resource.Objects, Objects: rule.Resource.Objects,
ConditionResult: checkResults,
Conditions: rule.Conditions, Conditions: rule.Conditions,
State: alerting.AlertStateNormal, State: alerting.AlertStateNormal,
} }
checkResults, err := engine.CheckCondition(rule)
alertItem.ConditionResult = checkResults
if err != nil { if err != nil {
return err return err
} }
@ -716,7 +734,7 @@ func performChannels(channels []alerting.Channel, ctx map[string]interface{}) ([
var errCount int var errCount int
var actionResults []alerting.ActionExecutionResult var actionResults []alerting.ActionExecutionResult
for _, channel := range channels { for _, channel := range channels {
resBytes, err := performChannel(&channel, ctx) resBytes, err, messageBytes := performChannel(&channel, ctx)
var errStr string var errStr string
if err != nil { if err != nil {
errCount++ errCount++
@ -725,6 +743,7 @@ func performChannels(channels []alerting.Channel, ctx map[string]interface{}) ([
actionResults = append(actionResults, alerting.ActionExecutionResult{ actionResults = append(actionResults, alerting.ActionExecutionResult{
Result: string(resBytes), Result: string(resBytes),
Error: errStr, Error: errStr,
Message: string(messageBytes),
LastExecutionTime: int(time.Now().UnixNano()/1e6), LastExecutionTime: int(time.Now().UnixNano()/1e6),
}) })
} }
@ -744,23 +763,28 @@ func resolveMessage(messageTemplate string, ctx map[string]interface{}) ([]byte,
return msgBuffer.Bytes(), err return msgBuffer.Bytes(), err
} }
func performChannel(channel *alerting.Channel, ctx map[string]interface{}) ([]byte, error) { func performChannel(channel *alerting.Channel, ctx map[string]interface{}) ([]byte, error, []byte) {
var act action.Action var (
act action.Action
message []byte
err error
)
switch channel.Type { switch channel.Type {
case alerting.ChannelWebhook: case alerting.ChannelWebhook:
message, err := resolveMessage(channel.Webhook.Body, ctx) message, err = resolveMessage(channel.Webhook.Body, ctx)
if err != nil { if err != nil {
return nil, err return nil, err, message
} }
act = &action.WebhookAction{ act = &action.WebhookAction{
Data: channel.Webhook, Data: channel.Webhook,
Message: string(message), Message: string(message),
} }
default: default:
return nil, fmt.Errorf("unsupported action type: %s", channel.Type) return nil, fmt.Errorf("unsupported action type: %s", channel.Type), message
} }
return act.Execute() executeResult, err := act.Execute()
return executeResult, err, message
} }
func (engine *Engine) GenerateTask(rule *alerting.Rule) func(ctx context.Context) { func (engine *Engine) GenerateTask(rule *alerting.Rule) func(ctx context.Context) {
return func(ctx context.Context) { return func(ctx context.Context) {

View File

@ -12,12 +12,12 @@ import (
) )
type Engine interface { type Engine interface {
GenerateQuery(rule *alerting.Rule) (interface{}, error) GenerateQuery(rule *alerting.Rule, filterParam *alerting.FilterParam) (interface{}, error)
ExecuteQuery(rule *alerting.Rule)(*alerting.QueryResult, error) ExecuteQuery(rule *alerting.Rule, filterParam *alerting.FilterParam)(*alerting.QueryResult, error)
CheckCondition(rule *alerting.Rule)(*alerting.ConditionResult, error) CheckCondition(rule *alerting.Rule)(*alerting.ConditionResult, error)
GenerateTask(rule *alerting.Rule) func(ctx context.Context) GenerateTask(rule *alerting.Rule) func(ctx context.Context)
Test(rule *alerting.Rule) ([]alerting.ActionExecutionResult, error) Test(rule *alerting.Rule) ([]alerting.ActionExecutionResult, error)
GetTargetMetricData(rule *alerting.Rule, isFilterNaN bool)([]alerting.MetricData, error) GetTargetMetricData(rule *alerting.Rule, isFilterNaN bool, filterParam *alerting.FilterParam)([]alerting.MetricData, error)
} }
var ( var (