Alerting: Refactor Evaluator (#51673)
* AlertRule to return condition * update ConditionEval to not return an error because it's always nil * make getExprRequest private * refactor executeCondition to just converter and move execution to the ConditionEval as this makes code more readable. * log error if results have errors * change signature of evaluate function to not return an error
This commit is contained in:
@@ -28,7 +28,7 @@ import (
|
||||
//go:generate mockery --name Evaluator --structname FakeEvaluator --inpackage --filename evaluator_mock.go --with-expecter
|
||||
type Evaluator interface {
|
||||
// ConditionEval executes conditions and evaluates the result.
|
||||
ConditionEval(condition *models.Condition, now time.Time) (Results, error)
|
||||
ConditionEval(condition models.Condition, now time.Time) Results
|
||||
// QueriesAndExpressionsEval executes queries and expressions and returns the result.
|
||||
QueriesAndExpressionsEval(orgID int64, data []models.AlertQuery, now time.Time) (*backend.QueryDataResponse, error)
|
||||
}
|
||||
@@ -89,6 +89,15 @@ type ExecutionResults struct {
|
||||
// Results is a slice of evaluated alert instances states.
|
||||
type Results []Result
|
||||
|
||||
func (evalResults Results) HasErrors() bool {
|
||||
for _, r := range evalResults {
|
||||
if r.State == Error {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Result contains the evaluated State of an alert instance
|
||||
// identified by its labels.
|
||||
type Result struct {
|
||||
@@ -153,8 +162,8 @@ type AlertExecCtx struct {
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
// GetExprRequest validates the condition, gets the datasource information and creates an expr.Request from it.
|
||||
func GetExprRequest(ctx AlertExecCtx, data []models.AlertQuery, now time.Time, dsCacheService datasources.CacheService, secretsService secrets.Service) (*expr.Request, error) {
|
||||
// getExprRequest validates the condition, gets the datasource information and creates an expr.Request from it.
|
||||
func getExprRequest(ctx AlertExecCtx, data []models.AlertQuery, now time.Time, dsCacheService datasources.CacheService, secretsService secrets.Service) (*expr.Request, error) {
|
||||
req := &expr.Request{
|
||||
OrgId: ctx.OrgID,
|
||||
Headers: map[string]string{
|
||||
@@ -166,8 +175,7 @@ func GetExprRequest(ctx AlertExecCtx, data []models.AlertQuery, now time.Time, d
|
||||
|
||||
datasources := make(map[string]*datasources.DataSource, len(data))
|
||||
|
||||
for i := range data {
|
||||
q := data[i]
|
||||
for _, q := range data {
|
||||
model, err := q.GetModel()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get query model: %w", err)
|
||||
@@ -259,12 +267,7 @@ type NumberValueCapture struct {
|
||||
Value *float64
|
||||
}
|
||||
|
||||
func executeCondition(ctx AlertExecCtx, c *models.Condition, now time.Time, exprService *expr.Service, dsCacheService datasources.CacheService, secretsService secrets.Service) ExecutionResults {
|
||||
execResp, err := executeQueriesAndExpressions(ctx, c.Data, now, exprService, dsCacheService, secretsService)
|
||||
if err != nil {
|
||||
return ExecutionResults{Error: err}
|
||||
}
|
||||
|
||||
func queryDataResponseToExecutionResults(c models.Condition, execResp *backend.QueryDataResponse) ExecutionResults {
|
||||
// eval captures for the '__value_string__' annotation and the Value property of the API response.
|
||||
captures := make([]NumberValueCapture, 0, len(execResp.Responses))
|
||||
captureVal := func(refID string, labels data.Labels, value *float64) {
|
||||
@@ -356,7 +359,7 @@ func executeQueriesAndExpressions(ctx AlertExecCtx, data []models.AlertQuery, no
|
||||
}
|
||||
}()
|
||||
|
||||
queryDataReq, err := GetExprRequest(ctx, data, now, dsCacheService, secretsService)
|
||||
queryDataReq, err := getExprRequest(ctx, data, now, dsCacheService, secretsService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -564,8 +567,6 @@ func (evalResults Results) AsDataFrame() data.Frame {
|
||||
labelColumns = append(labelColumns, k)
|
||||
}
|
||||
|
||||
labelColumns = sort.StringSlice(labelColumns)
|
||||
|
||||
frame := data.NewFrame("evaluation results")
|
||||
for _, lKey := range labelColumns {
|
||||
frame.Fields = append(frame.Fields, data.NewField(lKey, nil, make([]string, fieldLen)))
|
||||
@@ -591,16 +592,15 @@ func (evalResults Results) AsDataFrame() data.Frame {
|
||||
}
|
||||
|
||||
// ConditionEval executes conditions and evaluates the result.
|
||||
func (e *evaluatorImpl) ConditionEval(condition *models.Condition, now time.Time) (Results, error) {
|
||||
alertCtx, cancelFn := context.WithTimeout(context.Background(), e.cfg.UnifiedAlerting.EvaluationTimeout)
|
||||
defer cancelFn()
|
||||
|
||||
alertExecCtx := AlertExecCtx{OrgID: condition.OrgID, Ctx: alertCtx, ExpressionsEnabled: e.cfg.ExpressionsEnabled, Log: e.log}
|
||||
|
||||
execResult := executeCondition(alertExecCtx, condition, now, e.expressionService, e.dataSourceCache, e.secretsService)
|
||||
|
||||
evalResults := evaluateExecutionResult(execResult, now)
|
||||
return evalResults, nil
|
||||
func (e *evaluatorImpl) ConditionEval(condition models.Condition, now time.Time) Results {
|
||||
execResp, err := e.QueriesAndExpressionsEval(condition.OrgID, condition.Data, now)
|
||||
var execResults ExecutionResults
|
||||
if err != nil {
|
||||
execResults = ExecutionResults{Error: err}
|
||||
} else {
|
||||
execResults = queryDataResponseToExecutionResults(condition, execResp)
|
||||
}
|
||||
return evaluateExecutionResult(execResults, now)
|
||||
}
|
||||
|
||||
// QueriesAndExpressionsEval executes queries and expressions and returns the result.
|
||||
|
||||
Reference in New Issue
Block a user