Introduce TSDB service (#31520)

* Introduce TSDB service

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

Co-authored-by: Erik Sundell <erik.sundell87@gmail.com>
Co-authored-by: Will Browne <will.browne@grafana.com>
Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
This commit is contained in:
Arve Knudsen
2021-03-08 07:02:49 +01:00
committed by GitHub
co-authored by Erik Sundell Will Browne Torkel Ödegaard Will Browne Zoltán Bedi
parent c899bf3592
commit b79e61656a
203 changed files with 5269 additions and 4776 deletions
+6 -4
View File
@@ -9,6 +9,7 @@ import (
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/setting"
@@ -20,6 +21,7 @@ type apiImpl struct {
Cfg *setting.Cfg `inject:""`
DatasourceCache datasources.CacheService `inject:""`
RouteRegister routing.RouteRegister `inject:""`
DataService *tsdb.Service
schedule scheduleService
store store
}
@@ -64,13 +66,13 @@ func (api *apiImpl) conditionEvalEndpoint(c *models.ReqContext, cmd evalAlertCon
}
evaluator := eval.Evaluator{Cfg: api.Cfg}
evalResults, err := evaluator.ConditionEval(&evalCond, timeNow())
evalResults, err := evaluator.ConditionEval(&evalCond, timeNow(), api.DataService)
if err != nil {
return response.Error(400, "Failed to evaluate conditions", err)
}
frame := evalResults.AsDataFrame()
df := tsdb.NewDecodedDataFrames([]*data.Frame{&frame})
df := plugins.NewDecodedDataFrames([]*data.Frame{&frame})
instances, err := df.Encoded()
if err != nil {
return response.Error(400, "Failed to encode result dataframes", err)
@@ -95,13 +97,13 @@ func (api *apiImpl) alertDefinitionEvalEndpoint(c *models.ReqContext) response.R
}
evaluator := eval.Evaluator{Cfg: api.Cfg}
evalResults, err := evaluator.ConditionEval(condition, timeNow())
evalResults, err := evaluator.ConditionEval(condition, timeNow(), api.DataService)
if err != nil {
return response.Error(400, "Failed to evaluate alert", err)
}
frame := evalResults.AsDataFrame()
df := tsdb.NewDecodedDataFrames([]*data.Frame{&frame})
df := plugins.NewDecodedDataFrames([]*data.Frame{&frame})
if err != nil {
return response.Error(400, "Failed to instantiate Dataframes from the decoded frames", err)
}
+8 -4
View File
@@ -8,6 +8,7 @@ import (
"time"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
@@ -100,7 +101,7 @@ type AlertExecCtx struct {
}
// execute runs the Condition's expressions or queries.
func (c *Condition) execute(ctx AlertExecCtx, now time.Time) (*ExecutionResults, error) {
func (c *Condition) execute(ctx AlertExecCtx, now time.Time, dataService *tsdb.Service) (*ExecutionResults, error) {
result := ExecutionResults{}
if !c.IsValid() {
return nil, fmt.Errorf("invalid conditions")
@@ -140,7 +141,10 @@ func (c *Condition) execute(ctx AlertExecCtx, now time.Time) (*ExecutionResults,
})
}
exprService := expr.Service{Cfg: &setting.Cfg{ExpressionsEnabled: ctx.ExpressionsEnabled}}
exprService := expr.Service{
Cfg: &setting.Cfg{ExpressionsEnabled: ctx.ExpressionsEnabled},
DataService: dataService,
}
pbRes, err := exprService.TransformData(ctx.Ctx, queryDataReq)
if err != nil {
return &result, err
@@ -218,13 +222,13 @@ func (evalResults Results) AsDataFrame() data.Frame {
}
// ConditionEval executes conditions and evaluates the result.
func (e *Evaluator) ConditionEval(condition *Condition, now time.Time) (Results, error) {
func (e *Evaluator) ConditionEval(condition *Condition, now time.Time, dataService *tsdb.Service) (Results, error) {
alertCtx, cancelFn := context.WithTimeout(context.Background(), alertingEvaluationTimeout)
defer cancelFn()
alertExecCtx := AlertExecCtx{OrgID: condition.OrgID, Ctx: alertCtx, ExpressionsEnabled: e.Cfg.ExpressionsEnabled}
execResult, err := condition.execute(alertExecCtx, now)
execResult, err := condition.execute(alertExecCtx, now, dataService)
if err != nil {
return nil, fmt.Errorf("failed to execute conditions: %w", err)
}
+6 -2
View File
@@ -7,6 +7,7 @@ import (
"github.com/benbjohnson/clock"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
@@ -34,6 +35,7 @@ type AlertNG struct {
DatasourceCache datasources.CacheService `inject:""`
RouteRegister routing.RouteRegister `inject:""`
SQLStore *sqlstore.SQLStore `inject:""`
DataService *tsdb.Service `inject:""`
log log.Logger
schedule scheduleService
}
@@ -57,14 +59,16 @@ func (ng *AlertNG) Init() error {
evaluator: eval.Evaluator{Cfg: ng.Cfg},
store: store,
}
ng.schedule = newScheduler(schedCfg)
ng.schedule = newScheduler(schedCfg, ng.DataService)
api := apiImpl{
Cfg: ng.Cfg,
DatasourceCache: ng.DatasourceCache,
RouteRegister: ng.RouteRegister,
DataService: ng.DataService,
schedule: ng.schedule,
store: store}
store: store,
}
api.registerAPIEndpoints()
return nil
+10 -4
View File
@@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
"github.com/grafana/grafana/pkg/tsdb"
"golang.org/x/sync/errgroup"
)
@@ -24,7 +25,8 @@ type scheduleService interface {
overrideCfg(cfg schedulerCfg)
}
func (sch *schedule) definitionRoutine(grafanaCtx context.Context, key alertDefinitionKey, evalCh <-chan *evalContext, stopCh <-chan struct{}) error {
func (sch *schedule) definitionRoutine(grafanaCtx context.Context, key alertDefinitionKey,
evalCh <-chan *evalContext, stopCh <-chan struct{}) error {
sch.log.Debug("alert definition routine started", "key", key)
evalRunning := false
@@ -58,11 +60,12 @@ func (sch *schedule) definitionRoutine(grafanaCtx context.Context, key alertDefi
OrgID: alertDefinition.OrgID,
QueriesAndExpressions: alertDefinition.Data,
}
results, err := sch.evaluator.ConditionEval(&condition, ctx.now)
results, err := sch.evaluator.ConditionEval(&condition, ctx.now, sch.dataService)
end = timeNow()
if err != nil {
// consider saving alert instance on error
sch.log.Error("failed to evaluate alert definition", "title", alertDefinition.Title, "key", key, "attempt", attempt, "now", ctx.now, "duration", end.Sub(start), "error", err)
sch.log.Error("failed to evaluate alert definition", "title", alertDefinition.Title,
"key", key, "attempt", attempt, "now", ctx.now, "duration", end.Sub(start), "error", err)
return err
}
for _, r := range results {
@@ -129,6 +132,8 @@ type schedule struct {
evaluator eval.Evaluator
store store
dataService *tsdb.Service
}
type schedulerCfg struct {
@@ -142,7 +147,7 @@ type schedulerCfg struct {
}
// newScheduler returns a new schedule.
func newScheduler(cfg schedulerCfg) *schedule {
func newScheduler(cfg schedulerCfg, dataService *tsdb.Service) *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)},
@@ -155,6 +160,7 @@ func newScheduler(cfg schedulerCfg) *schedule {
stopAppliedFunc: cfg.stopAppliedFunc,
evaluator: cfg.evaluator,
store: cfg.store,
dataService: dataService,
}
return &sch
}