Expressions: Add option to disable feature (#30541)

* Expressions: Add option to disable feature

* Apply suggestions from code review

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
This commit is contained in:
Sofia Papagiannaki
2021-01-22 19:27:33 +02:00
committed by GitHub
co-authored by achatterjee-grafana
parent 5d52e50f6f
commit 9ada4b6052
15 changed files with 99 additions and 28 deletions
+4 -2
View File
@@ -39,7 +39,8 @@ func (ng *AlertNG) conditionEvalEndpoint(c *models.ReqContext, dto evalAlertCond
return response.Error(400, "invalid condition", err)
}
evalResults, err := eval.ConditionEval(&dto.Condition, timeNow())
evaluator := eval.Evaluator{Cfg: ng.Cfg}
evalResults, err := evaluator.ConditionEval(&dto.Condition, timeNow())
if err != nil {
return response.Error(400, "Failed to evaluate conditions", err)
}
@@ -69,7 +70,8 @@ func (ng *AlertNG) alertDefinitionEvalEndpoint(c *models.ReqContext) response.Re
return response.Error(400, "invalid condition", err)
}
evalResults, err := eval.ConditionEval(condition, timeNow())
evaluator := eval.Evaluator{Cfg: ng.Cfg}
evalResults, err := evaluator.ConditionEval(condition, timeNow())
if err != nil {
return response.Error(400, "Failed to evaluate alert", err)
}
+12 -4
View File
@@ -7,6 +7,8 @@ import (
"fmt"
"time"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/expr"
@@ -14,6 +16,10 @@ import (
const alertingEvaluationTimeout = 30 * time.Second
type Evaluator struct {
Cfg *setting.Cfg
}
// invalidEvalResultFormatError is an error for invalid format of the alert definition evaluation results.
type invalidEvalResultFormatError struct {
refID string
@@ -87,7 +93,8 @@ func (c Condition) IsValid() bool {
// AlertExecCtx is the context provided for executing an alert condition.
type AlertExecCtx struct {
OrgID int64
OrgID int64
ExpressionsEnabled bool
Ctx context.Context
}
@@ -133,7 +140,8 @@ func (c *Condition) execute(ctx AlertExecCtx, now time.Time) (*ExecutionResults,
})
}
pbRes, err := expr.TransformData(ctx.Ctx, queryDataReq)
exprService := expr.Service{Cfg: &setting.Cfg{ExpressionsEnabled: ctx.ExpressionsEnabled}}
pbRes, err := exprService.TransformData(ctx.Ctx, queryDataReq)
if err != nil {
return &result, err
}
@@ -210,11 +218,11 @@ func (evalResults Results) AsDataFrame() data.Frame {
}
// ConditionEval executes conditions and evaluates the result.
func ConditionEval(condition *Condition, now time.Time) (Results, error) {
func (e *Evaluator) ConditionEval(condition *Condition, now time.Time) (Results, error) {
alertCtx, cancelFn := context.WithTimeout(context.Background(), alertingEvaluationTimeout)
defer cancelFn()
alertExecCtx := AlertExecCtx{OrgID: condition.OrgID, Ctx: alertCtx}
alertExecCtx := AlertExecCtx{OrgID: condition.OrgID, Ctx: alertCtx, ExpressionsEnabled: e.Cfg.ExpressionsEnabled}
execResult, err := condition.execute(alertExecCtx, now)
if err != nil {
+7 -1
View File
@@ -47,7 +47,13 @@ func (ng *AlertNG) Init() error {
ng.log = log.New("ngalert")
ng.registerAPIEndpoints()
ng.schedule = newScheduler(clock.New(), baseIntervalSeconds*time.Second, ng.log, nil)
schedCfg := schedulerCfg{
c: clock.New(),
baseInterval: baseIntervalSeconds * time.Second,
logger: ng.log,
evaluator: eval.Evaluator{Cfg: ng.Cfg},
}
ng.schedule = newScheduler(schedCfg)
return nil
}
+18 -7
View File
@@ -47,7 +47,7 @@ func (ng *AlertNG) definitionRoutine(grafanaCtx context.Context, key alertDefini
OrgID: alertDefinition.OrgID,
QueriesAndExpressions: alertDefinition.Data,
}
results, err := eval.ConditionEval(&condition, ctx.now)
results, err := ng.schedule.evaluator.ConditionEval(&condition, ctx.now)
end = timeNow()
if err != nil {
// consider saving alert instance on error
@@ -118,19 +118,30 @@ type schedule struct {
stopApplied func(alertDefinitionKey)
log log.Logger
evaluator eval.Evaluator
}
type schedulerCfg struct {
c clock.Clock
baseInterval time.Duration
logger log.Logger
evalApplied func(alertDefinitionKey, time.Time)
evaluator eval.Evaluator
}
// newScheduler returns a new schedule.
func newScheduler(c clock.Clock, baseInterval time.Duration, logger log.Logger, evalApplied func(alertDefinitionKey, time.Time)) *schedule {
ticker := alerting.NewTicker(c.Now(), time.Second*0, c, int64(baseInterval.Seconds()))
func newScheduler(cfg schedulerCfg) *schedule {
ticker := alerting.NewTicker(cfg.c.Now(), time.Second*0, cfg.c, int64(cfg.baseInterval.Seconds()))
sch := schedule{
registry: alertDefinitionRegistry{alertDefinitionInfo: make(map[alertDefinitionKey]alertDefinitionInfo)},
maxAttempts: maxAttempts,
clock: c,
baseInterval: baseInterval,
log: logger,
clock: cfg.c,
baseInterval: cfg.baseInterval,
log: cfg.logger,
heartbeat: ticker,
evalApplied: evalApplied,
evalApplied: cfg.evalApplied,
evaluator: cfg.evaluator,
}
return &sch
}
+8 -1
View File
@@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -26,7 +27,13 @@ func TestAlertingTicker(t *testing.T) {
t.Cleanup(registry.ClearOverrides)
mockedClock := clock.NewMock()
ng.schedule = newScheduler(mockedClock, time.Second, log.New("ngalert.schedule.test"), nil)
schefCfg := schedulerCfg{
c: mockedClock,
baseInterval: time.Second,
logger: log.New("ngalert.schedule.test"),
evaluator: eval.Evaluator{Cfg: ng.Cfg},
}
ng.schedule = newScheduler(schefCfg)
alerts := make([]*AlertDefinition, 0)