2016-07-27 09:18:10 -05:00
|
|
|
package conditions
|
2016-07-19 09:15:26 -05:00
|
|
|
|
2016-07-19 10:45:37 -05:00
|
|
|
import (
|
2016-07-20 07:28:02 -05:00
|
|
|
"fmt"
|
2016-07-19 09:15:26 -05:00
|
|
|
|
2016-07-20 07:28:02 -05:00
|
|
|
"github.com/grafana/grafana/pkg/bus"
|
2016-07-19 10:45:37 -05:00
|
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
2016-07-20 07:28:02 -05:00
|
|
|
m "github.com/grafana/grafana/pkg/models"
|
2016-07-27 09:18:10 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/alerting"
|
2016-07-20 07:28:02 -05:00
|
|
|
"github.com/grafana/grafana/pkg/tsdb"
|
2016-07-19 10:45:37 -05:00
|
|
|
)
|
2016-07-19 09:15:26 -05:00
|
|
|
|
2016-07-27 09:18:10 -05:00
|
|
|
func init() {
|
2016-07-27 09:29:28 -05:00
|
|
|
alerting.RegisterCondition("query", func(model *simplejson.Json, index int) (alerting.Condition, error) {
|
2016-07-27 09:18:10 -05:00
|
|
|
return NewQueryCondition(model, index)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-07-19 09:15:26 -05:00
|
|
|
type QueryCondition struct {
|
2016-07-21 14:54:12 -05:00
|
|
|
Index int
|
2016-07-20 07:28:02 -05:00
|
|
|
Query AlertQuery
|
|
|
|
Reducer QueryReducer
|
|
|
|
Evaluator AlertEvaluator
|
|
|
|
HandleRequest tsdb.HandleRequestFunc
|
2016-07-19 09:15:26 -05:00
|
|
|
}
|
|
|
|
|
2016-07-27 09:18:10 -05:00
|
|
|
type AlertQuery struct {
|
|
|
|
Model *simplejson.Json
|
|
|
|
DatasourceId int64
|
|
|
|
From string
|
|
|
|
To string
|
|
|
|
}
|
|
|
|
|
2016-07-27 09:29:28 -05:00
|
|
|
func (c *QueryCondition) Eval(context *alerting.EvalContext) {
|
2016-07-20 07:28:02 -05:00
|
|
|
seriesList, err := c.executeQuery(context)
|
|
|
|
if err != nil {
|
|
|
|
context.Error = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-09-08 07:33:10 -05:00
|
|
|
emptySerieCount := 0
|
2016-07-20 07:28:02 -05:00
|
|
|
for _, series := range seriesList {
|
|
|
|
reducedValue := c.Reducer.Reduce(series)
|
2016-09-06 13:40:12 -05:00
|
|
|
evalMatch := c.Evaluator.Eval(reducedValue)
|
2016-07-21 14:54:12 -05:00
|
|
|
|
2016-09-16 07:58:10 -05:00
|
|
|
if reducedValue == nil {
|
|
|
|
emptySerieCount++
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2016-07-21 14:54:12 -05:00
|
|
|
if context.IsTestRun {
|
2016-07-27 09:29:28 -05:00
|
|
|
context.Logs = append(context.Logs, &alerting.ResultLogEntry{
|
2016-09-06 13:40:12 -05:00
|
|
|
Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %1.3f", c.Index, evalMatch, series.Name, *reducedValue),
|
2016-07-21 14:54:12 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-08-15 08:12:43 -05:00
|
|
|
if evalMatch {
|
|
|
|
context.EvalMatches = append(context.EvalMatches, &alerting.EvalMatch{
|
2016-07-21 14:54:12 -05:00
|
|
|
Metric: series.Name,
|
2016-09-06 13:40:12 -05:00
|
|
|
Value: *reducedValue,
|
2016-07-21 14:54:12 -05:00
|
|
|
})
|
2016-07-20 07:28:02 -05:00
|
|
|
}
|
|
|
|
}
|
2016-09-08 06:28:41 -05:00
|
|
|
|
2016-09-08 07:33:10 -05:00
|
|
|
context.NoDataFound = emptySerieCount == len(seriesList)
|
2016-09-08 06:28:41 -05:00
|
|
|
context.Firing = len(context.EvalMatches) > 0
|
2016-07-20 07:28:02 -05:00
|
|
|
}
|
|
|
|
|
2016-07-27 09:29:28 -05:00
|
|
|
func (c *QueryCondition) executeQuery(context *alerting.EvalContext) (tsdb.TimeSeriesSlice, error) {
|
2016-07-20 07:28:02 -05:00
|
|
|
getDsInfo := &m.GetDataSourceByIdQuery{
|
|
|
|
Id: c.Query.DatasourceId,
|
|
|
|
OrgId: context.Rule.OrgId,
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := bus.Dispatch(getDsInfo); err != nil {
|
|
|
|
return nil, fmt.Errorf("Could not find datasource")
|
|
|
|
}
|
|
|
|
|
|
|
|
req := c.getRequestForAlertRule(getDsInfo.Result)
|
|
|
|
result := make(tsdb.TimeSeriesSlice, 0)
|
|
|
|
|
|
|
|
resp, err := c.HandleRequest(req)
|
|
|
|
if err != nil {
|
2016-07-21 06:09:12 -05:00
|
|
|
return nil, fmt.Errorf("tsdb.HandleRequest() error %v", err)
|
2016-07-20 07:28:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range resp.Results {
|
|
|
|
if v.Error != nil {
|
2016-07-21 06:09:12 -05:00
|
|
|
return nil, fmt.Errorf("tsdb.HandleRequest() response error %v", v)
|
2016-07-20 07:28:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
result = append(result, v.Series...)
|
2016-07-21 06:09:12 -05:00
|
|
|
|
|
|
|
if context.IsTestRun {
|
2016-07-27 09:29:28 -05:00
|
|
|
context.Logs = append(context.Logs, &alerting.ResultLogEntry{
|
2016-07-21 14:54:12 -05:00
|
|
|
Message: fmt.Sprintf("Condition[%d]: Query Result", c.Index),
|
2016-07-21 06:09:12 -05:00
|
|
|
Data: v.Series,
|
|
|
|
})
|
|
|
|
}
|
2016-07-20 07:28:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource) *tsdb.Request {
|
|
|
|
req := &tsdb.Request{
|
|
|
|
TimeRange: tsdb.TimeRange{
|
|
|
|
From: c.Query.From,
|
|
|
|
To: c.Query.To,
|
|
|
|
},
|
|
|
|
Queries: []*tsdb.Query{
|
|
|
|
{
|
|
|
|
RefId: "A",
|
|
|
|
Query: c.Query.Model.Get("target").MustString(),
|
|
|
|
DataSource: &tsdb.DataSourceInfo{
|
2016-08-29 08:49:25 -05:00
|
|
|
Id: datasource.Id,
|
|
|
|
Name: datasource.Name,
|
|
|
|
PluginId: datasource.Type,
|
|
|
|
Url: datasource.Url,
|
|
|
|
User: datasource.User,
|
|
|
|
Password: datasource.Password,
|
|
|
|
Database: datasource.Database,
|
|
|
|
BasicAuth: datasource.BasicAuth,
|
|
|
|
BasicAuthUser: datasource.BasicAuthUser,
|
|
|
|
BasicAuthPassword: datasource.BasicAuthPassword,
|
2016-07-20 07:28:02 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
return req
|
2016-07-19 09:15:26 -05:00
|
|
|
}
|
|
|
|
|
2016-07-21 14:54:12 -05:00
|
|
|
func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, error) {
|
2016-07-19 10:45:37 -05:00
|
|
|
condition := QueryCondition{}
|
2016-07-21 14:54:12 -05:00
|
|
|
condition.Index = index
|
2016-07-20 07:28:02 -05:00
|
|
|
condition.HandleRequest = tsdb.HandleRequest
|
2016-07-19 10:45:37 -05:00
|
|
|
|
|
|
|
queryJson := model.Get("query")
|
|
|
|
|
2016-07-20 07:28:02 -05:00
|
|
|
condition.Query.Model = queryJson.Get("model")
|
2016-07-19 10:45:37 -05:00
|
|
|
condition.Query.From = queryJson.Get("params").MustArray()[1].(string)
|
|
|
|
condition.Query.To = queryJson.Get("params").MustArray()[2].(string)
|
|
|
|
condition.Query.DatasourceId = queryJson.Get("datasourceId").MustInt64()
|
|
|
|
|
|
|
|
reducerJson := model.Get("reducer")
|
|
|
|
condition.Reducer = NewSimpleReducer(reducerJson.Get("type").MustString())
|
|
|
|
|
|
|
|
evaluatorJson := model.Get("evaluator")
|
2016-08-16 05:34:54 -05:00
|
|
|
evaluator, err := NewAlertEvaluator(evaluatorJson)
|
2016-07-19 10:45:37 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
condition.Evaluator = evaluator
|
|
|
|
return &condition, nil
|
2016-07-19 09:15:26 -05:00
|
|
|
}
|