feat(alerting): begin alert rule storage refactoring
This commit is contained in:
@@ -64,15 +64,8 @@ func GetAlerts(c *middleware.Context) Response {
|
||||
Id: alert.Id,
|
||||
DashboardId: alert.DashboardId,
|
||||
PanelId: alert.PanelId,
|
||||
Query: alert.Query,
|
||||
QueryRefId: alert.QueryRefId,
|
||||
WarnLevel: alert.WarnLevel,
|
||||
CritLevel: alert.CritLevel,
|
||||
Frequency: alert.Frequency,
|
||||
Name: alert.Name,
|
||||
Description: alert.Description,
|
||||
QueryRange: alert.QueryRange,
|
||||
Aggregator: alert.Aggregator,
|
||||
State: alert.State,
|
||||
})
|
||||
}
|
||||
|
||||
+25
-30
@@ -2,49 +2,44 @@ package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
)
|
||||
|
||||
type AlertRule struct {
|
||||
Id int64 `json:"id"`
|
||||
OrgId int64 `json:"-"`
|
||||
DatasourceId int64 `json:"datasourceId"`
|
||||
DashboardId int64 `json:"dashboardId"`
|
||||
PanelId int64 `json:"panelId"`
|
||||
Query string `json:"query"`
|
||||
QueryRefId string `json:"queryRefId"`
|
||||
WarnLevel float64 `json:"warnLevel"`
|
||||
CritLevel float64 `json:"critLevel"`
|
||||
WarnOperator string `json:"warnOperator"`
|
||||
CritOperator string `json:"critOperator"`
|
||||
Frequency int64 `json:"frequency"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
QueryRange int `json:"queryRange"`
|
||||
Aggregator string `json:"aggregator"`
|
||||
State string `json:"state"`
|
||||
Id int64
|
||||
OrgId int64
|
||||
DashboardId int64
|
||||
PanelId int64
|
||||
Name string
|
||||
Description string
|
||||
State string
|
||||
|
||||
Created time.Time `json:"created"`
|
||||
Updated time.Time `json:"updated"`
|
||||
Created time.Time
|
||||
Updated time.Time
|
||||
|
||||
Expression *simplejson.Json
|
||||
}
|
||||
|
||||
func (alertRule *AlertRule) ValidToSave() bool {
|
||||
return alertRule.Query != "" && alertRule.Frequency != 0 && alertRule.QueryRange != 0 && alertRule.Name != ""
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *AlertRule) Equals(other *AlertRule) bool {
|
||||
func (this *AlertRule) ContainsUpdates(other *AlertRule) bool {
|
||||
result := false
|
||||
|
||||
result = result || this.Aggregator != other.Aggregator
|
||||
result = result || this.CritLevel != other.CritLevel
|
||||
result = result || this.WarnLevel != other.WarnLevel
|
||||
result = result || this.WarnOperator != other.WarnOperator
|
||||
result = result || this.CritOperator != other.CritOperator
|
||||
result = result || this.Query != other.Query
|
||||
result = result || this.QueryRefId != other.QueryRefId
|
||||
result = result || this.Frequency != other.Frequency
|
||||
result = result || this.Name != other.Name
|
||||
result = result || this.Description != other.Description
|
||||
result = result || this.QueryRange != other.QueryRange
|
||||
|
||||
json1, err1 := this.Expression.MarshalJSON()
|
||||
json2, err2 := other.Expression.MarshalJSON()
|
||||
|
||||
if err1 != nil || err2 != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
result = result || string(json1) != string(json2)
|
||||
|
||||
//don't compare .State! That would be insane.
|
||||
|
||||
return result
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestAlertingModelTest(t *testing.T) {
|
||||
Convey("Testing Alerting model", t, func() {
|
||||
|
||||
json1, _ := simplejson.NewJson([]byte(`{ "field": "value" }`))
|
||||
json2, _ := simplejson.NewJson([]byte(`{ "field": "value" }`))
|
||||
|
||||
rule1 := &AlertRule{
|
||||
Expression: json1,
|
||||
Name: "Namn",
|
||||
Description: "Description",
|
||||
}
|
||||
|
||||
rule2 := &AlertRule{
|
||||
Expression: json2,
|
||||
Name: "Namn",
|
||||
Description: "Description",
|
||||
}
|
||||
|
||||
Convey("Testing AlertRule equals", func() {
|
||||
|
||||
So(rule1.ContainsUpdates(rule2), ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Changing the expression should contain update", func() {
|
||||
json2, _ := simplejson.NewJson([]byte(`{ "field": "newValue" }`))
|
||||
rule1.Expression = json2
|
||||
So(rule1.ContainsUpdates(rule2), ShouldBeTrue)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -18,54 +18,63 @@ func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRule {
|
||||
|
||||
alerting := panel.Get("alerting")
|
||||
alert := &m.AlertRule{
|
||||
DashboardId: cmd.Result.Id,
|
||||
OrgId: cmd.Result.OrgId,
|
||||
PanelId: panel.Get("id").MustInt64(),
|
||||
Id: alerting.Get("id").MustInt64(),
|
||||
QueryRefId: alerting.Get("queryRef").MustString(),
|
||||
WarnLevel: alerting.Get("warnLevel").MustFloat64(),
|
||||
CritLevel: alerting.Get("critLevel").MustFloat64(),
|
||||
WarnOperator: alerting.Get("warnOperator").MustString(),
|
||||
CritOperator: alerting.Get("critOperator").MustString(),
|
||||
Frequency: alerting.Get("frequency").MustInt64(),
|
||||
Name: alerting.Get("name").MustString(),
|
||||
Description: alerting.Get("description").MustString(),
|
||||
QueryRange: alerting.Get("queryRange").MustInt(),
|
||||
Aggregator: alerting.Get("aggregator").MustString(),
|
||||
DashboardId: cmd.Result.Id,
|
||||
OrgId: cmd.Result.OrgId,
|
||||
PanelId: panel.Get("id").MustInt64(),
|
||||
Id: alerting.Get("id").MustInt64(),
|
||||
Name: alerting.Get("name").MustString(),
|
||||
Description: alerting.Get("description").MustString(),
|
||||
}
|
||||
|
||||
log.Info("Alertrule: %v", alert.Name)
|
||||
|
||||
expression := alerting
|
||||
valueQuery := expression.Get("valueQuery")
|
||||
valueQueryRef := valueQuery.Get("queryRefId").MustString()
|
||||
for _, targetsObj := range panel.Get("targets").MustArray() {
|
||||
target := simplejson.NewFromAny(targetsObj)
|
||||
|
||||
if target.Get("refId").MustString() == alert.QueryRefId {
|
||||
targetJson, err := target.MarshalJSON()
|
||||
if err == nil {
|
||||
alert.Query = string(targetJson)
|
||||
if target.Get("refId").MustString() == valueQueryRef {
|
||||
datsourceName := ""
|
||||
if target.Get("datasource").MustString() != "" {
|
||||
datsourceName = target.Get("datasource").MustString()
|
||||
} else if panel.Get("datasource").MustString() != "" {
|
||||
datsourceName = panel.Get("datasource").MustString()
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if panel.Get("datasource").MustString() == "" {
|
||||
query := &m.GetDataSourcesQuery{OrgId: cmd.OrgId}
|
||||
if err := bus.Dispatch(query); err == nil {
|
||||
for _, ds := range query.Result {
|
||||
if ds.IsDefault {
|
||||
alert.DatasourceId = ds.Id
|
||||
if datsourceName == "" {
|
||||
query := &m.GetDataSourcesQuery{OrgId: cmd.OrgId}
|
||||
if err := bus.Dispatch(query); err == nil {
|
||||
for _, ds := range query.Result {
|
||||
if ds.IsDefault {
|
||||
valueQuery.Set("datasourceId", ds.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
query := &m.GetDataSourceByNameQuery{
|
||||
Name: panel.Get("datasource").MustString(),
|
||||
OrgId: cmd.OrgId,
|
||||
}
|
||||
bus.Dispatch(query)
|
||||
valueQuery.Set("datasourceId", query.Result.Id)
|
||||
}
|
||||
|
||||
targetQuery := target.Get("target").MustString()
|
||||
if targetQuery != "" {
|
||||
valueQuery.Set("query", targetQuery)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
query := &m.GetDataSourceByNameQuery{
|
||||
Name: panel.Get("datasource").MustString(),
|
||||
OrgId: cmd.OrgId,
|
||||
}
|
||||
bus.Dispatch(query)
|
||||
alert.DatasourceId = query.Result.Id
|
||||
}
|
||||
|
||||
if alert.ValidToSave() {
|
||||
expression.Set("valueQuery", valueQuery)
|
||||
alert.Expression = expression
|
||||
|
||||
alertRule := &AlertRule{}
|
||||
|
||||
ParseAlertRulesFromAlertModel(alert, alertRule)
|
||||
|
||||
if alert.ValidToSave() && alertRule.IsValid() {
|
||||
alerts = append(alerts, alert)
|
||||
}
|
||||
}
|
||||
@@ -73,3 +82,34 @@ func ParseAlertsFromDashboard(cmd *m.SaveDashboardCommand) []*m.AlertRule {
|
||||
|
||||
return alerts
|
||||
}
|
||||
|
||||
func (rule *AlertRule) IsValid() bool {
|
||||
return rule.ValueQuery.Query != ""
|
||||
}
|
||||
|
||||
func ParseAlertRulesFromAlertModel(ruleDef *m.AlertRule, model *AlertRule) error {
|
||||
critical := ruleDef.Expression.Get("critical")
|
||||
model.Critical = Level{
|
||||
Operator: critical.Get("operator").MustString(),
|
||||
Level: critical.Get("level").MustFloat64(),
|
||||
}
|
||||
|
||||
warning := ruleDef.Expression.Get("warning")
|
||||
model.Warning = Level{
|
||||
Operator: warning.Get("operator").MustString(),
|
||||
Level: warning.Get("level").MustFloat64(),
|
||||
}
|
||||
|
||||
model.Frequency = ruleDef.Expression.Get("frequency").MustInt64()
|
||||
|
||||
valueQuery := ruleDef.Expression.Get("valueQuery")
|
||||
model.ValueQuery = AlertQuery{
|
||||
Query: valueQuery.Get("query").MustString(),
|
||||
DatasourceId: valueQuery.Get("datasourceId").MustInt64(),
|
||||
From: valueQuery.Get("From").MustInt64(),
|
||||
Until: valueQuery.Get("until").MustInt64(),
|
||||
Aggregator: valueQuery.Get("aggregator").MustString(),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -102,12 +102,12 @@ func (e *ExecutorImpl) Execute(job *AlertJob, resultQueue chan *AlertResult) {
|
||||
|
||||
func (e *ExecutorImpl) executeQuery(job *AlertJob) (tsdb.TimeSeriesSlice, error) {
|
||||
getDsInfo := &m.GetDataSourceByIdQuery{
|
||||
Id: job.Rule.DatasourceId,
|
||||
Id: 1,
|
||||
OrgId: job.Rule.OrgId,
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(getDsInfo); err != nil {
|
||||
return nil, fmt.Errorf("Could not find datasource for %d", job.Rule.DatasourceId)
|
||||
return nil, fmt.Errorf("Could not find datasource")
|
||||
}
|
||||
|
||||
req := e.GetRequestForAlertRule(job.Rule, getDsInfo.Result)
|
||||
@@ -130,16 +130,15 @@ func (e *ExecutorImpl) executeQuery(job *AlertJob) (tsdb.TimeSeriesSlice, error)
|
||||
}
|
||||
|
||||
func (e *ExecutorImpl) GetRequestForAlertRule(rule *AlertRule, datasource *m.DataSource) *tsdb.Request {
|
||||
|
||||
req := &tsdb.Request{
|
||||
TimeRange: tsdb.TimeRange{
|
||||
From: "-" + strconv.Itoa(rule.QueryRange) + "s",
|
||||
From: "-" + strconv.Itoa(int(rule.ValueQuery.From)) + "s",
|
||||
To: "now",
|
||||
},
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
RefId: rule.QueryRefId,
|
||||
Query: rule.Query,
|
||||
RefId: "A",
|
||||
Query: "apps.fakesite.*.counters.requests.count",
|
||||
DataSource: &tsdb.DataSourceInfo{
|
||||
Id: datasource.Id,
|
||||
Name: datasource.Name,
|
||||
@@ -159,15 +158,15 @@ func (e *ExecutorImpl) evaluateRule(rule *AlertRule, series tsdb.TimeSeriesSlice
|
||||
for _, serie := range series {
|
||||
log.Debug("Evaluating series", "series", serie.Name)
|
||||
|
||||
if aggregator[rule.Aggregator] == nil {
|
||||
if aggregator["avg"] == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var aggValue = aggregator[rule.Aggregator](serie)
|
||||
var critOperartor = operators[rule.CritOperator]
|
||||
var critResult = critOperartor(aggValue, rule.CritLevel)
|
||||
var aggValue = aggregator["avg"](serie)
|
||||
var critOperartor = operators[rule.Critical.Operator]
|
||||
var critResult = critOperartor(aggValue, rule.Critical.Level)
|
||||
|
||||
log.Trace(resultLogFmt, "Crit", serie.Name, aggValue, rule.CritOperator, rule.CritLevel, critResult)
|
||||
log.Trace(resultLogFmt, "Crit", serie.Name, aggValue, rule.Critical.Operator, rule.Critical.Level, critResult)
|
||||
if critResult {
|
||||
return &AlertResult{
|
||||
State: alertstates.Critical,
|
||||
@@ -176,9 +175,9 @@ func (e *ExecutorImpl) evaluateRule(rule *AlertRule, series tsdb.TimeSeriesSlice
|
||||
}
|
||||
}
|
||||
|
||||
var warnOperartor = operators[rule.CritOperator]
|
||||
var warnResult = warnOperartor(aggValue, rule.CritLevel)
|
||||
log.Trace(resultLogFmt, "Warn", serie.Name, aggValue, rule.WarnOperator, rule.WarnLevel, warnResult)
|
||||
var warnOperartor = operators[rule.Warning.Operator]
|
||||
var warnResult = warnOperartor(aggValue, rule.Warning.Level)
|
||||
log.Trace(resultLogFmt, "Warn", serie.Name, aggValue, rule.Warning.Operator, rule.Warning.Level, warnResult)
|
||||
if warnResult {
|
||||
return &AlertResult{
|
||||
State: alertstates.Warn,
|
||||
|
||||
@@ -14,7 +14,7 @@ func TestAlertingExecutor(t *testing.T) {
|
||||
|
||||
Convey("single time serie", func() {
|
||||
Convey("Show return ok since avg is above 2", func() {
|
||||
rule := &AlertRule{CritLevel: 10, CritOperator: ">", Aggregator: "sum"}
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{2, 0}}),
|
||||
@@ -25,7 +25,7 @@ func TestAlertingExecutor(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Show return critical since below 2", func() {
|
||||
rule := &AlertRule{CritLevel: 10, CritOperator: "<", Aggregator: "sum"}
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: "<"}}
|
||||
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{2, 0}}),
|
||||
@@ -36,7 +36,7 @@ func TestAlertingExecutor(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Show return critical since sum is above 10", func() {
|
||||
rule := &AlertRule{CritLevel: 10, CritOperator: ">", Aggregator: "sum"}
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{9, 0}, {9, 0}}),
|
||||
@@ -47,7 +47,7 @@ func TestAlertingExecutor(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Show return ok since avg is below 10", func() {
|
||||
rule := &AlertRule{CritLevel: 10, CritOperator: ">", Aggregator: "avg"}
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{9, 0}, {9, 0}}),
|
||||
@@ -58,7 +58,7 @@ func TestAlertingExecutor(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Show return ok since min is below 10", func() {
|
||||
rule := &AlertRule{CritLevel: 10, CritOperator: ">", Aggregator: "min"}
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{11, 0}, {9, 0}}),
|
||||
@@ -69,7 +69,7 @@ func TestAlertingExecutor(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Show return ok since max is above 10", func() {
|
||||
rule := &AlertRule{CritLevel: 10, CritOperator: ">", Aggregator: "max"}
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{1, 0}, {11, 0}}),
|
||||
@@ -82,7 +82,7 @@ func TestAlertingExecutor(t *testing.T) {
|
||||
|
||||
Convey("muliple time series", func() {
|
||||
Convey("both are ok", func() {
|
||||
rule := &AlertRule{CritLevel: 10, CritOperator: ">", Aggregator: "sum"}
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{2, 0}}),
|
||||
@@ -94,7 +94,7 @@ func TestAlertingExecutor(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("first serie is good, second is critical", func() {
|
||||
rule := &AlertRule{CritLevel: 10, CritOperator: ">", Aggregator: "sum"}
|
||||
rule := &AlertRule{Critical: Level{Level: 10, Operator: ">"}}
|
||||
|
||||
timeSeries := []*tsdb.TimeSeries{
|
||||
tsdb.NewTimeSeries("test1", [][2]float64{{2, 0}}),
|
||||
|
||||
@@ -18,21 +18,37 @@ type AlertResult struct {
|
||||
}
|
||||
|
||||
type AlertRule struct {
|
||||
Id int64
|
||||
OrgId int64
|
||||
Id int64
|
||||
OrgId int64
|
||||
DashboardId int64
|
||||
PanelId int64
|
||||
//WarnLevel float64
|
||||
//CritLevel float64
|
||||
//WarnOperator string
|
||||
//CritOperator string
|
||||
Frequency int64
|
||||
Name string
|
||||
Description string
|
||||
State string
|
||||
|
||||
Warning Level
|
||||
Critical Level
|
||||
|
||||
ValueQuery AlertQuery
|
||||
EvalFunc string
|
||||
EvalQuery AlertQuery
|
||||
EvalParam string
|
||||
}
|
||||
|
||||
type Level struct {
|
||||
Operator string
|
||||
Level float64
|
||||
}
|
||||
|
||||
type AlertQuery struct {
|
||||
Query string
|
||||
DatasourceId int64
|
||||
DashboardId int64
|
||||
PanelId int64
|
||||
Query string
|
||||
QueryRefId string
|
||||
WarnLevel float64
|
||||
CritLevel float64
|
||||
WarnOperator string
|
||||
CritOperator string
|
||||
Frequency int64
|
||||
Name string
|
||||
Description string
|
||||
QueryRange int
|
||||
Aggregator string
|
||||
State string
|
||||
From int64
|
||||
Until int64
|
||||
}
|
||||
|
||||
@@ -52,19 +52,12 @@ func (arr *AlertRuleReader) Fetch() []*AlertRule {
|
||||
model := &AlertRule{}
|
||||
model.Id = ruleDef.Id
|
||||
model.OrgId = ruleDef.OrgId
|
||||
model.DatasourceId = ruleDef.DatasourceId
|
||||
model.Query = ruleDef.Query
|
||||
model.QueryRefId = ruleDef.QueryRefId
|
||||
model.WarnLevel = ruleDef.WarnLevel
|
||||
model.WarnOperator = ruleDef.WarnOperator
|
||||
model.CritLevel = ruleDef.CritLevel
|
||||
model.CritOperator = ruleDef.CritOperator
|
||||
model.Frequency = ruleDef.Frequency
|
||||
model.Name = ruleDef.Name
|
||||
model.Description = ruleDef.Description
|
||||
model.Aggregator = ruleDef.Aggregator
|
||||
model.State = ruleDef.State
|
||||
model.QueryRange = ruleDef.QueryRange
|
||||
|
||||
ParseAlertRulesFromAlertModel(ruleDef, model)
|
||||
|
||||
res[i] = model
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ func upsertAlerts(alerts []*m.AlertRule, posted []*m.AlertRule, sess *xorm.Sessi
|
||||
}
|
||||
|
||||
if update {
|
||||
if alertToUpdate.Equals(alert) {
|
||||
if alertToUpdate.ContainsUpdates(alert) {
|
||||
alert.Updated = time.Now()
|
||||
alert.State = alertToUpdate.State
|
||||
_, err := sess.Id(alert.Id).Update(alert)
|
||||
|
||||
@@ -22,20 +22,11 @@ func TestAlertRuleChangesDataAccess(t *testing.T) {
|
||||
Convey("When dashboard is removed", func() {
|
||||
items := []*m.AlertRule{
|
||||
{
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
Query: "Query",
|
||||
QueryRefId: "A",
|
||||
WarnLevel: 30,
|
||||
CritLevel: 50,
|
||||
WarnOperator: ">",
|
||||
CritOperator: ">",
|
||||
Frequency: 10,
|
||||
Name: "Alerting title",
|
||||
Description: "Alerting description",
|
||||
QueryRange: 3600,
|
||||
Aggregator: "avg",
|
||||
OrgId: FakeOrgId,
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
Name: "Alerting title",
|
||||
Description: "Alerting description",
|
||||
OrgId: FakeOrgId,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
)
|
||||
|
||||
func TestAlertingDataAccess(t *testing.T) {
|
||||
|
||||
Convey("Testing Alerting data access", t, func() {
|
||||
InitTestDB(t)
|
||||
|
||||
@@ -16,21 +15,11 @@ func TestAlertingDataAccess(t *testing.T) {
|
||||
|
||||
items := []*m.AlertRule{
|
||||
{
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
OrgId: testDash.OrgId,
|
||||
Query: "Query",
|
||||
QueryRefId: "A",
|
||||
WarnLevel: 30,
|
||||
CritLevel: 50,
|
||||
WarnOperator: ">",
|
||||
CritOperator: ">",
|
||||
Frequency: 10,
|
||||
Name: "Alerting title",
|
||||
Description: "Alerting description",
|
||||
QueryRange: 3600,
|
||||
Aggregator: "avg",
|
||||
DatasourceId: 42,
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
OrgId: testDash.OrgId,
|
||||
Name: "Alerting title",
|
||||
Description: "Alerting description",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -58,25 +47,15 @@ func TestAlertingDataAccess(t *testing.T) {
|
||||
|
||||
alert := alertQuery.Result[0]
|
||||
So(err2, ShouldBeNil)
|
||||
So(alert.Frequency, ShouldEqual, 10)
|
||||
So(alert.WarnLevel, ShouldEqual, 30)
|
||||
So(alert.CritLevel, ShouldEqual, 50)
|
||||
So(alert.WarnOperator, ShouldEqual, ">")
|
||||
So(alert.CritOperator, ShouldEqual, ">")
|
||||
So(alert.Query, ShouldEqual, "Query")
|
||||
So(alert.QueryRefId, ShouldEqual, "A")
|
||||
So(alert.Name, ShouldEqual, "Alerting title")
|
||||
So(alert.Description, ShouldEqual, "Alerting description")
|
||||
So(alert.QueryRange, ShouldEqual, 3600)
|
||||
So(alert.Aggregator, ShouldEqual, "avg")
|
||||
So(alert.State, ShouldEqual, "OK")
|
||||
So(alert.DatasourceId, ShouldEqual, 42)
|
||||
})
|
||||
|
||||
Convey("Alerts with same dashboard id and panel id should update", func() {
|
||||
modifiedItems := items
|
||||
modifiedItems[0].Query = "Updated Query"
|
||||
modifiedItems[0].State = "ALERT"
|
||||
modifiedItems[0].Name = "New name"
|
||||
//modifiedItems[0].State = "ALERT"
|
||||
|
||||
modifiedCmd := m.SaveAlertsCommand{
|
||||
DashboardId: testDash.Id,
|
||||
@@ -97,7 +76,7 @@ func TestAlertingDataAccess(t *testing.T) {
|
||||
|
||||
So(err2, ShouldBeNil)
|
||||
So(len(query.Result), ShouldEqual, 1)
|
||||
So(query.Result[0].Query, ShouldEqual, "Updated Query")
|
||||
So(query.Result[0].Name, ShouldEqual, "Name")
|
||||
|
||||
Convey("Alert state should not be updated", func() {
|
||||
So(query.Result[0].State, ShouldEqual, "OK")
|
||||
@@ -120,19 +99,19 @@ func TestAlertingDataAccess(t *testing.T) {
|
||||
{
|
||||
DashboardId: testDash.Id,
|
||||
PanelId: 1,
|
||||
Query: "1",
|
||||
Name: "1",
|
||||
OrgId: 1,
|
||||
},
|
||||
{
|
||||
DashboardId: testDash.Id,
|
||||
PanelId: 2,
|
||||
Query: "2",
|
||||
Name: "2",
|
||||
OrgId: 1,
|
||||
},
|
||||
{
|
||||
DashboardId: testDash.Id,
|
||||
PanelId: 3,
|
||||
Query: "3",
|
||||
Name: "3",
|
||||
OrgId: 1,
|
||||
},
|
||||
}
|
||||
@@ -180,19 +159,10 @@ func TestAlertingDataAccess(t *testing.T) {
|
||||
Convey("When dashboard is removed", func() {
|
||||
items := []*m.AlertRule{
|
||||
{
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
Query: "Query",
|
||||
QueryRefId: "A",
|
||||
WarnLevel: 30,
|
||||
CritLevel: 50,
|
||||
WarnOperator: ">",
|
||||
CritOperator: ">",
|
||||
Frequency: 10,
|
||||
Name: "Alerting title",
|
||||
Description: "Alerting description",
|
||||
QueryRange: 3600,
|
||||
Aggregator: "avg",
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
Name: "Alerting title",
|
||||
Description: "Alerting description",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -15,20 +15,11 @@ func TestAlertingStateAccess(t *testing.T) {
|
||||
|
||||
items := []*m.AlertRule{
|
||||
{
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
OrgId: testDash.OrgId,
|
||||
Query: "Query",
|
||||
QueryRefId: "A",
|
||||
WarnLevel: 30,
|
||||
CritLevel: 50,
|
||||
WarnOperator: ">",
|
||||
CritOperator: ">",
|
||||
Frequency: 10,
|
||||
Name: "Alerting title",
|
||||
Description: "Alerting description",
|
||||
QueryRange: 3600,
|
||||
Aggregator: "avg",
|
||||
PanelId: 1,
|
||||
DashboardId: testDash.Id,
|
||||
OrgId: testDash.OrgId,
|
||||
Name: "Alerting title",
|
||||
Description: "Alerting description",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -101,17 +101,45 @@ func TestAlertModel(t *testing.T) {
|
||||
"timeShift": null,
|
||||
"aliasColors": {},
|
||||
"seriesOverrides": [],
|
||||
|
||||
|
||||
"alerting": {
|
||||
"queryRef": "A",
|
||||
"warnLevel": 30,
|
||||
"critLevel": 50,
|
||||
"warnOperator": ">",
|
||||
"critOperator": ">",
|
||||
"aggregator": "sum",
|
||||
"queryRange": 3600,
|
||||
"frequency": 10,
|
||||
"name": "active desktop users",
|
||||
"description": "restart webservers"
|
||||
"warning": {
|
||||
"op": ">",
|
||||
"level": 10
|
||||
},
|
||||
"critical": {
|
||||
"op": ">",
|
||||
"level": 20
|
||||
},
|
||||
"function": "static",
|
||||
"valueQuery": {
|
||||
"queryRefId": "A",
|
||||
"from": "5m",
|
||||
"to": "now",
|
||||
"agg": "avg",
|
||||
"params": [
|
||||
"#A",
|
||||
"5m",
|
||||
"now",
|
||||
"avg"
|
||||
]
|
||||
},
|
||||
"evalQuery": {
|
||||
"queryRefId": "A",
|
||||
"from": "5m",
|
||||
"to": "now",
|
||||
"agg": "avg",
|
||||
"params": [
|
||||
"#A",
|
||||
"5m",
|
||||
"now",
|
||||
"avg"
|
||||
]
|
||||
},
|
||||
"evalStringParam1": "",
|
||||
"name": "Alerting Panel Title alert"
|
||||
},
|
||||
"links": []
|
||||
},
|
||||
@@ -189,16 +217,42 @@ func TestAlertModel(t *testing.T) {
|
||||
},
|
||||
"seriesOverrides": [],
|
||||
"alerting": {
|
||||
"queryRef": "A",
|
||||
"warnOperator": ">",
|
||||
"critOperator": ">",
|
||||
"warnLevel": 300,
|
||||
"critLevel": 500,
|
||||
"aggregator": "avg",
|
||||
"queryRange": 3600,
|
||||
"frequency": 10,
|
||||
"name": "active mobile users",
|
||||
"description": "restart itunes"
|
||||
"warning": {
|
||||
"op": ">",
|
||||
"level": 10
|
||||
},
|
||||
"critical": {
|
||||
"op": ">",
|
||||
"level": 20
|
||||
},
|
||||
"function": "static",
|
||||
"valueQuery": {
|
||||
"queryRefId": "A",
|
||||
"from": "5m",
|
||||
"to": "now",
|
||||
"agg": "avg",
|
||||
"params": [
|
||||
"#A",
|
||||
"5m",
|
||||
"now",
|
||||
"avg"
|
||||
]
|
||||
},
|
||||
"evalQuery": {
|
||||
"queryRefId": "A",
|
||||
"from": "5m",
|
||||
"to": "now",
|
||||
"agg": "avg",
|
||||
"params": [
|
||||
"#A",
|
||||
"5m",
|
||||
"now",
|
||||
"avg"
|
||||
]
|
||||
},
|
||||
"evalStringParam1": "",
|
||||
"name": "Alerting Panel Title alert"
|
||||
},
|
||||
"links": []
|
||||
}
|
||||
@@ -379,37 +433,13 @@ func TestAlertModel(t *testing.T) {
|
||||
So(v.DashboardId, ShouldEqual, 1)
|
||||
So(v.PanelId, ShouldNotEqual, 0)
|
||||
|
||||
So(v.WarnLevel, ShouldNotBeEmpty)
|
||||
So(v.CritLevel, ShouldNotBeEmpty)
|
||||
|
||||
So(v.Aggregator, ShouldNotBeEmpty)
|
||||
So(v.Query, ShouldNotBeEmpty)
|
||||
So(v.QueryRefId, ShouldNotBeEmpty)
|
||||
So(v.QueryRange, ShouldNotEqual, 0)
|
||||
So(v.Frequency, ShouldNotEqual, 0)
|
||||
So(v.Name, ShouldNotBeEmpty)
|
||||
So(v.Description, ShouldNotBeEmpty)
|
||||
|
||||
expr := simplejson.NewFromAny(v.Expression)
|
||||
So(expr.Get("valueQuery").Get("query").MustString(), ShouldNotEqual, "")
|
||||
So(expr.Get("valueQuery").Get("datsourceId").MustInt64(), ShouldNotEqual, 0)
|
||||
}
|
||||
|
||||
So(alerts[0].WarnLevel, ShouldEqual, 30)
|
||||
So(alerts[1].WarnLevel, ShouldEqual, 300)
|
||||
|
||||
So(alerts[0].Frequency, ShouldEqual, 10)
|
||||
So(alerts[1].Frequency, ShouldEqual, 10)
|
||||
|
||||
So(alerts[0].CritLevel, ShouldEqual, 50)
|
||||
So(alerts[1].CritLevel, ShouldEqual, 500)
|
||||
|
||||
So(alerts[0].CritOperator, ShouldEqual, ">")
|
||||
So(alerts[1].CritOperator, ShouldEqual, ">")
|
||||
So(alerts[0].WarnOperator, ShouldEqual, ">")
|
||||
So(alerts[1].WarnOperator, ShouldEqual, ">")
|
||||
|
||||
So(alerts[0].Query, ShouldEqual, `{"refId":"A","target":"aliasByNode(statsd.fakesite.counters.session_start.desktop.count, 4)"}`)
|
||||
So(alerts[1].Query, ShouldEqual, `{"refId":"A","target":"aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"}`)
|
||||
|
||||
So(alerts[0].DatasourceId, ShouldEqual, 2)
|
||||
So(alerts[1].DatasourceId, ShouldEqual, 1)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,21 +11,12 @@ func addAlertMigrations(mg *Migrator) {
|
||||
Columns: []*Column{
|
||||
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||
{Name: "dashboard_id", Type: DB_BigInt, Nullable: false},
|
||||
{Name: "datasource_id", Type: DB_BigInt, Nullable: false},
|
||||
{Name: "panel_id", Type: DB_BigInt, Nullable: false},
|
||||
{Name: "org_id", Type: DB_BigInt, Nullable: false},
|
||||
{Name: "query", Type: DB_Text, Nullable: false},
|
||||
{Name: "query_ref_id", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
{Name: "warn_level", Type: DB_Float, Nullable: false},
|
||||
{Name: "warn_operator", Type: DB_NVarchar, Length: 10, Nullable: false},
|
||||
{Name: "crit_level", Type: DB_Float, Nullable: false},
|
||||
{Name: "crit_operator", Type: DB_NVarchar, Length: 10, Nullable: false},
|
||||
{Name: "frequency", Type: DB_BigInt, Nullable: false},
|
||||
{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
{Name: "description", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
{Name: "query_range", Type: DB_Int, Nullable: false},
|
||||
{Name: "aggregator", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
{Name: "state", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
{Name: "expression", Type: DB_Text, Nullable: false},
|
||||
{Name: "created", Type: DB_DateTime, Nullable: false},
|
||||
{Name: "updated", Type: DB_DateTime, Nullable: false},
|
||||
},
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
)
|
||||
@@ -39,7 +38,7 @@ func (e *GraphiteExecutor) Execute(queries tsdb.QuerySlice, context *tsdb.QueryC
|
||||
|
||||
for _, query := range queries {
|
||||
params["target"] = []string{
|
||||
getTargetFromQuery(query.Query),
|
||||
query.Query,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,8 +76,3 @@ func (e *GraphiteExecutor) Execute(queries tsdb.QuerySlice, context *tsdb.QueryC
|
||||
result.QueryResults["A"] = queryRes
|
||||
return result
|
||||
}
|
||||
|
||||
func getTargetFromQuery(query string) string {
|
||||
json, _ := simplejson.NewJson([]byte(query))
|
||||
return json.Get("target").MustString()
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ export class AlertTabCtrl {
|
||||
|
||||
var defaultName = (this.panelCtrl.dashboard.title + ' ' + this.panel.title + ' alert');
|
||||
this.panel.alerting.name = this.panel.alerting.name || defaultName;
|
||||
this.panel.alerting.description = this.panel.alerting.description || defaultName;
|
||||
|
||||
this.panel.targets.map(target => {
|
||||
this.metricTargets.push(target);
|
||||
@@ -92,7 +93,7 @@ export class AlertTabCtrl {
|
||||
}
|
||||
|
||||
evalFuncChanged() {
|
||||
var evalFuncDef = _.findWhere(this.evalFuncs, { value: this.rule.expression.evalFunc });
|
||||
var evalFuncDef = _.findWhere(this.evalFuncs, { value: this.rule.evalFunc });
|
||||
console.log(evalFuncDef);
|
||||
this.secondParam = evalFuncDef.secondParam;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user