mirror of https://github.com/grafana/grafana.git
feat(alerting): refactoring conditions out to seperate package
This commit is contained in:
parent
ae5f8a76d9
commit
6aaf4c97a2
|
|
@ -79,13 +79,15 @@ func NewAlertRuleFromDBModel(ruleDef *m.Alert) (*AlertRule, error) {
|
||||||
|
|
||||||
for index, condition := range ruleDef.Settings.Get("conditions").MustArray() {
|
for index, condition := range ruleDef.Settings.Get("conditions").MustArray() {
|
||||||
conditionModel := simplejson.NewFromAny(condition)
|
conditionModel := simplejson.NewFromAny(condition)
|
||||||
switch conditionModel.Get("type").MustString() {
|
conditionType := conditionModel.Get("type").MustString()
|
||||||
case "query":
|
if factory, exist := conditionFactories[conditionType]; !exist {
|
||||||
queryCondition, err := NewQueryCondition(conditionModel, index)
|
return nil, AlertValidationError{Reason: "Unknown alert condition: " + conditionType}
|
||||||
if err != nil {
|
} else {
|
||||||
|
if queryCondition, err := factory(conditionModel, index); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else {
|
||||||
|
model.Conditions = append(model.Conditions, queryCondition)
|
||||||
}
|
}
|
||||||
model.Conditions = append(model.Conditions, queryCondition)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,3 +97,11 @@ func NewAlertRuleFromDBModel(ruleDef *m.Alert) (*AlertRule, error) {
|
||||||
|
|
||||||
return model, nil
|
return model, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConditionFactory func(model *simplejson.Json, index int) (AlertCondition, error)
|
||||||
|
|
||||||
|
var conditionFactories map[string]ConditionFactory = make(map[string]ConditionFactory)
|
||||||
|
|
||||||
|
func RegisterCondition(typeName string, factory ConditionFactory) {
|
||||||
|
conditionFactories[typeName] = factory
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,17 @@ import (
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type FakeCondition struct{}
|
||||||
|
|
||||||
|
func (f *FakeCondition) Eval(context *AlertResultContext) {}
|
||||||
|
|
||||||
func TestAlertRuleModel(t *testing.T) {
|
func TestAlertRuleModel(t *testing.T) {
|
||||||
Convey("Testing alert rule", t, func() {
|
Convey("Testing alert rule", t, func() {
|
||||||
|
|
||||||
|
RegisterCondition("test", func(model *simplejson.Json, index int) (AlertCondition, error) {
|
||||||
|
return &FakeCondition{}, nil
|
||||||
|
})
|
||||||
|
|
||||||
Convey("Can parse seconds", func() {
|
Convey("Can parse seconds", func() {
|
||||||
seconds := getTimeDurationStringToSeconds("10s")
|
seconds := getTimeDurationStringToSeconds("10s")
|
||||||
So(seconds, ShouldEqual, 10)
|
So(seconds, ShouldEqual, 10)
|
||||||
|
|
@ -41,14 +49,8 @@ func TestAlertRuleModel(t *testing.T) {
|
||||||
"frequency": "60s",
|
"frequency": "60s",
|
||||||
"conditions": [
|
"conditions": [
|
||||||
{
|
{
|
||||||
"type": "query",
|
"type": "test",
|
||||||
"query": {
|
"prop": 123
|
||||||
"params": ["A", "5m", "now"],
|
|
||||||
"datasourceId": 1,
|
|
||||||
"model": {"target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"}
|
|
||||||
},
|
|
||||||
"reducer": {"type": "avg", "params": []},
|
|
||||||
"evaluator": {"type": ">", "params": [100]}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"notifications": [
|
"notifications": [
|
||||||
|
|
@ -75,27 +77,6 @@ func TestAlertRuleModel(t *testing.T) {
|
||||||
|
|
||||||
So(alertRule.Conditions, ShouldHaveLength, 1)
|
So(alertRule.Conditions, ShouldHaveLength, 1)
|
||||||
|
|
||||||
Convey("Can read query condition from json model", func() {
|
|
||||||
queryCondition, ok := alertRule.Conditions[0].(*QueryCondition)
|
|
||||||
So(ok, ShouldBeTrue)
|
|
||||||
|
|
||||||
So(queryCondition.Query.From, ShouldEqual, "5m")
|
|
||||||
So(queryCondition.Query.To, ShouldEqual, "now")
|
|
||||||
So(queryCondition.Query.DatasourceId, ShouldEqual, 1)
|
|
||||||
|
|
||||||
Convey("Can read query reducer", func() {
|
|
||||||
reducer, ok := queryCondition.Reducer.(*SimpleReducer)
|
|
||||||
So(ok, ShouldBeTrue)
|
|
||||||
So(reducer.Type, ShouldEqual, "avg")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Can read evaluator", func() {
|
|
||||||
evaluator, ok := queryCondition.Evaluator.(*DefaultAlertEvaluator)
|
|
||||||
So(ok, ShouldBeTrue)
|
|
||||||
So(evaluator.Type, ShouldEqual, ">")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Can read notifications", func() {
|
Convey("Can read notifications", func() {
|
||||||
So(len(alertRule.Notifications), ShouldEqual, 2)
|
So(len(alertRule.Notifications), ShouldEqual, 2)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package conditions
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package conditions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
"github.com/grafana/grafana/pkg/services/alerting"
|
||||||
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AlertEvaluator interface {
|
||||||
|
Eval(timeSeries *tsdb.TimeSeries, reducedValue float64) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultAlertEvaluator struct {
|
||||||
|
Type string
|
||||||
|
Threshold float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DefaultAlertEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool {
|
||||||
|
switch e.Type {
|
||||||
|
case ">":
|
||||||
|
return reducedValue > e.Threshold
|
||||||
|
case "<":
|
||||||
|
return reducedValue < e.Threshold
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultAlertEvaluator(model *simplejson.Json) (*DefaultAlertEvaluator, error) {
|
||||||
|
evaluator := &DefaultAlertEvaluator{}
|
||||||
|
|
||||||
|
evaluator.Type = model.Get("type").MustString()
|
||||||
|
if evaluator.Type == "" {
|
||||||
|
return nil, alerting.AlertValidationError{Reason: "Evaluator missing type property"}
|
||||||
|
}
|
||||||
|
|
||||||
|
params := model.Get("params").MustArray()
|
||||||
|
if len(params) == 0 {
|
||||||
|
return nil, alerting.AlertValidationError{Reason: "Evaluator missing threshold parameter"}
|
||||||
|
}
|
||||||
|
|
||||||
|
threshold, ok := params[0].(json.Number)
|
||||||
|
if !ok {
|
||||||
|
return nil, alerting.AlertValidationError{Reason: "Evaluator has invalid threshold parameter"}
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluator.Threshold, _ = threshold.Float64()
|
||||||
|
return evaluator, nil
|
||||||
|
}
|
||||||
|
|
@ -1,15 +1,21 @@
|
||||||
package alerting
|
package conditions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/alerting"
|
||||||
"github.com/grafana/grafana/pkg/tsdb"
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
alerting.RegisterCondition("query", func(model *simplejson.Json, index int) (alerting.AlertCondition, error) {
|
||||||
|
return NewQueryCondition(model, index)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type QueryCondition struct {
|
type QueryCondition struct {
|
||||||
Index int
|
Index int
|
||||||
Query AlertQuery
|
Query AlertQuery
|
||||||
|
|
@ -18,7 +24,14 @@ type QueryCondition struct {
|
||||||
HandleRequest tsdb.HandleRequestFunc
|
HandleRequest tsdb.HandleRequestFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QueryCondition) Eval(context *AlertResultContext) {
|
type AlertQuery struct {
|
||||||
|
Model *simplejson.Json
|
||||||
|
DatasourceId int64
|
||||||
|
From string
|
||||||
|
To string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *QueryCondition) Eval(context *alerting.AlertResultContext) {
|
||||||
seriesList, err := c.executeQuery(context)
|
seriesList, err := c.executeQuery(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
context.Error = err
|
context.Error = err
|
||||||
|
|
@ -30,13 +43,13 @@ func (c *QueryCondition) Eval(context *AlertResultContext) {
|
||||||
pass := c.Evaluator.Eval(series, reducedValue)
|
pass := c.Evaluator.Eval(series, reducedValue)
|
||||||
|
|
||||||
if context.IsTestRun {
|
if context.IsTestRun {
|
||||||
context.Logs = append(context.Logs, &AlertResultLogEntry{
|
context.Logs = append(context.Logs, &alerting.AlertResultLogEntry{
|
||||||
Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %1.3f", c.Index, pass, series.Name, reducedValue),
|
Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %1.3f", c.Index, pass, series.Name, reducedValue),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if pass {
|
if pass {
|
||||||
context.Events = append(context.Events, &AlertEvent{
|
context.Events = append(context.Events, &alerting.AlertEvent{
|
||||||
Metric: series.Name,
|
Metric: series.Name,
|
||||||
Value: reducedValue,
|
Value: reducedValue,
|
||||||
})
|
})
|
||||||
|
|
@ -46,7 +59,7 @@ func (c *QueryCondition) Eval(context *AlertResultContext) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *QueryCondition) executeQuery(context *AlertResultContext) (tsdb.TimeSeriesSlice, error) {
|
func (c *QueryCondition) executeQuery(context *alerting.AlertResultContext) (tsdb.TimeSeriesSlice, error) {
|
||||||
getDsInfo := &m.GetDataSourceByIdQuery{
|
getDsInfo := &m.GetDataSourceByIdQuery{
|
||||||
Id: c.Query.DatasourceId,
|
Id: c.Query.DatasourceId,
|
||||||
OrgId: context.Rule.OrgId,
|
OrgId: context.Rule.OrgId,
|
||||||
|
|
@ -72,7 +85,7 @@ func (c *QueryCondition) executeQuery(context *AlertResultContext) (tsdb.TimeSer
|
||||||
result = append(result, v.Series...)
|
result = append(result, v.Series...)
|
||||||
|
|
||||||
if context.IsTestRun {
|
if context.IsTestRun {
|
||||||
context.Logs = append(context.Logs, &AlertResultLogEntry{
|
context.Logs = append(context.Logs, &alerting.AlertResultLogEntry{
|
||||||
Message: fmt.Sprintf("Condition[%d]: Query Result", c.Index),
|
Message: fmt.Sprintf("Condition[%d]: Query Result", c.Index),
|
||||||
Data: v.Series,
|
Data: v.Series,
|
||||||
})
|
})
|
||||||
|
|
@ -129,63 +142,3 @@ func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, erro
|
||||||
condition.Evaluator = evaluator
|
condition.Evaluator = evaluator
|
||||||
return &condition, nil
|
return &condition, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type SimpleReducer struct {
|
|
||||||
Type string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SimpleReducer) Reduce(series *tsdb.TimeSeries) float64 {
|
|
||||||
var value float64 = 0
|
|
||||||
|
|
||||||
switch s.Type {
|
|
||||||
case "avg":
|
|
||||||
for _, point := range series.Points {
|
|
||||||
value += point[0]
|
|
||||||
}
|
|
||||||
value = value / float64(len(series.Points))
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSimpleReducer(typ string) *SimpleReducer {
|
|
||||||
return &SimpleReducer{Type: typ}
|
|
||||||
}
|
|
||||||
|
|
||||||
type DefaultAlertEvaluator struct {
|
|
||||||
Type string
|
|
||||||
Threshold float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *DefaultAlertEvaluator) Eval(series *tsdb.TimeSeries, reducedValue float64) bool {
|
|
||||||
switch e.Type {
|
|
||||||
case ">":
|
|
||||||
return reducedValue > e.Threshold
|
|
||||||
case "<":
|
|
||||||
return reducedValue < e.Threshold
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefaultAlertEvaluator(model *simplejson.Json) (*DefaultAlertEvaluator, error) {
|
|
||||||
evaluator := &DefaultAlertEvaluator{}
|
|
||||||
|
|
||||||
evaluator.Type = model.Get("type").MustString()
|
|
||||||
if evaluator.Type == "" {
|
|
||||||
return nil, AlertValidationError{Reason: "Evaluator missing type property"}
|
|
||||||
}
|
|
||||||
|
|
||||||
params := model.Get("params").MustArray()
|
|
||||||
if len(params) == 0 {
|
|
||||||
return nil, AlertValidationError{Reason: "Evaluator missing threshold parameter"}
|
|
||||||
}
|
|
||||||
|
|
||||||
threshold, ok := params[0].(json.Number)
|
|
||||||
if !ok {
|
|
||||||
return nil, AlertValidationError{Reason: "Evaluator has invalid threshold parameter"}
|
|
||||||
}
|
|
||||||
|
|
||||||
evaluator.Threshold, _ = threshold.Float64()
|
|
||||||
return evaluator, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package alerting
|
package conditions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/alerting"
|
||||||
"github.com/grafana/grafana/pkg/tsdb"
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
)
|
)
|
||||||
|
|
@ -19,6 +20,26 @@ func TestQueryCondition(t *testing.T) {
|
||||||
ctx.reducer = `{"type": "avg"}`
|
ctx.reducer = `{"type": "avg"}`
|
||||||
ctx.evaluator = `{"type": ">", "params": [100]}`
|
ctx.evaluator = `{"type": ">", "params": [100]}`
|
||||||
|
|
||||||
|
Convey("Can read query condition from json model", func() {
|
||||||
|
ctx.exec()
|
||||||
|
|
||||||
|
So(ctx.condition.Query.From, ShouldEqual, "5m")
|
||||||
|
So(ctx.condition.Query.To, ShouldEqual, "now")
|
||||||
|
So(ctx.condition.Query.DatasourceId, ShouldEqual, 1)
|
||||||
|
|
||||||
|
Convey("Can read query reducer", func() {
|
||||||
|
reducer, ok := ctx.condition.Reducer.(*SimpleReducer)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
So(reducer.Type, ShouldEqual, "avg")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Can read evaluator", func() {
|
||||||
|
evaluator, ok := ctx.condition.Evaluator.(*DefaultAlertEvaluator)
|
||||||
|
So(ok, ShouldBeTrue)
|
||||||
|
So(evaluator.Type, ShouldEqual, ">")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Convey("should fire when avg is above 100", func() {
|
Convey("should fire when avg is above 100", func() {
|
||||||
ctx.series = tsdb.TimeSeriesSlice{tsdb.NewTimeSeries("test1", [][2]float64{{120, 0}})}
|
ctx.series = tsdb.TimeSeriesSlice{tsdb.NewTimeSeries("test1", [][2]float64{{120, 0}})}
|
||||||
ctx.exec()
|
ctx.exec()
|
||||||
|
|
@ -42,7 +63,8 @@ type queryConditionTestContext struct {
|
||||||
reducer string
|
reducer string
|
||||||
evaluator string
|
evaluator string
|
||||||
series tsdb.TimeSeriesSlice
|
series tsdb.TimeSeriesSlice
|
||||||
result *AlertResultContext
|
result *alerting.AlertResultContext
|
||||||
|
condition *QueryCondition
|
||||||
}
|
}
|
||||||
|
|
||||||
type queryConditionScenarioFunc func(c *queryConditionTestContext)
|
type queryConditionScenarioFunc func(c *queryConditionTestContext)
|
||||||
|
|
@ -63,6 +85,8 @@ func (ctx *queryConditionTestContext) exec() {
|
||||||
condition, err := NewQueryCondition(jsonModel, 0)
|
condition, err := NewQueryCondition(jsonModel, 0)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
ctx.condition = condition
|
||||||
|
|
||||||
condition.HandleRequest = func(req *tsdb.Request) (*tsdb.Response, error) {
|
condition.HandleRequest = func(req *tsdb.Request) (*tsdb.Response, error) {
|
||||||
return &tsdb.Response{
|
return &tsdb.Response{
|
||||||
Results: map[string]*tsdb.QueryResult{
|
Results: map[string]*tsdb.QueryResult{
|
||||||
|
|
@ -83,8 +107,8 @@ func queryConditionScenario(desc string, fn queryConditionScenarioFunc) {
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx := &queryConditionTestContext{}
|
ctx := &queryConditionTestContext{}
|
||||||
ctx.result = &AlertResultContext{
|
ctx.result = &alerting.AlertResultContext{
|
||||||
Rule: &AlertRule{},
|
Rule: &alerting.AlertRule{},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn(ctx)
|
fn(ctx)
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package conditions
|
||||||
|
|
||||||
|
import "github.com/grafana/grafana/pkg/tsdb"
|
||||||
|
|
||||||
|
type QueryReducer interface {
|
||||||
|
Reduce(timeSeries *tsdb.TimeSeries) float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type SimpleReducer struct {
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleReducer) Reduce(series *tsdb.TimeSeries) float64 {
|
||||||
|
var value float64 = 0
|
||||||
|
|
||||||
|
switch s.Type {
|
||||||
|
case "avg":
|
||||||
|
for _, point := range series.Points {
|
||||||
|
value += point[0]
|
||||||
|
}
|
||||||
|
value = value / float64(len(series.Points))
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSimpleReducer(typ string) *SimpleReducer {
|
||||||
|
return &SimpleReducer{Type: typ}
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,11 @@ import (
|
||||||
func TestAlertRuleExtraction(t *testing.T) {
|
func TestAlertRuleExtraction(t *testing.T) {
|
||||||
|
|
||||||
Convey("Parsing alert rules from dashboard json", t, func() {
|
Convey("Parsing alert rules from dashboard json", t, func() {
|
||||||
|
|
||||||
|
RegisterCondition("query", func(model *simplejson.Json, index int) (AlertCondition, error) {
|
||||||
|
return &FakeCondition{}, nil
|
||||||
|
})
|
||||||
|
|
||||||
Convey("Parsing and validating alerts from dashboards", func() {
|
Convey("Parsing and validating alerts from dashboards", func() {
|
||||||
json := `{
|
json := `{
|
||||||
"id": 57,
|
"id": 57,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package init
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/grafana/grafana/pkg/services/alerting"
|
"github.com/grafana/grafana/pkg/services/alerting"
|
||||||
|
_ "github.com/grafana/grafana/pkg/services/alerting/conditions"
|
||||||
_ "github.com/grafana/grafana/pkg/services/alerting/notifiers"
|
_ "github.com/grafana/grafana/pkg/services/alerting/notifiers"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
_ "github.com/grafana/grafana/pkg/tsdb/graphite"
|
_ "github.com/grafana/grafana/pkg/tsdb/graphite"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
package alerting
|
package alerting
|
||||||
|
|
||||||
import (
|
import "time"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/tsdb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AlertHandler interface {
|
type AlertHandler interface {
|
||||||
Execute(context *AlertResultContext)
|
Execute(context *AlertResultContext)
|
||||||
|
|
@ -23,11 +19,3 @@ type Notifier interface {
|
||||||
type AlertCondition interface {
|
type AlertCondition interface {
|
||||||
Eval(result *AlertResultContext)
|
Eval(result *AlertResultContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueryReducer interface {
|
|
||||||
Reduce(timeSeries *tsdb.TimeSeries) float64
|
|
||||||
}
|
|
||||||
|
|
||||||
type AlertEvaluator interface {
|
|
||||||
Eval(timeSeries *tsdb.TimeSeries, reducedValue float64) bool
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package alerting
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -61,10 +60,3 @@ type Level struct {
|
||||||
Operator string
|
Operator string
|
||||||
Value float64
|
Value float64
|
||||||
}
|
}
|
||||||
|
|
||||||
type AlertQuery struct {
|
|
||||||
Model *simplejson.Json
|
|
||||||
DatasourceId int64
|
|
||||||
From string
|
|
||||||
To string
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue