|
|
@@ -3,25 +3,97 @@ package alerting
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
"errors"
|
|
|
+ "fmt"
|
|
|
|
|
|
+ "github.com/grafana/grafana/pkg/bus"
|
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
|
+ m "github.com/grafana/grafana/pkg/models"
|
|
|
+ "github.com/grafana/grafana/pkg/tsdb"
|
|
|
)
|
|
|
|
|
|
type QueryCondition struct {
|
|
|
- Query AlertQuery
|
|
|
- Reducer QueryReducer
|
|
|
- Evaluator AlertEvaluator
|
|
|
+ Query AlertQuery
|
|
|
+ Reducer QueryReducer
|
|
|
+ Evaluator AlertEvaluator
|
|
|
+ HandleRequest tsdb.HandleRequestFunc
|
|
|
}
|
|
|
|
|
|
func (c *QueryCondition) Eval(context *AlertResultContext) {
|
|
|
+ seriesList, err := c.executeQuery(context)
|
|
|
+ if err != nil {
|
|
|
+ context.Error = err
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, series := range seriesList {
|
|
|
+ reducedValue := c.Reducer.Reduce(series)
|
|
|
+ pass := c.Evaluator.Eval(series, reducedValue)
|
|
|
+ if pass {
|
|
|
+ context.Triggered = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (c *QueryCondition) executeQuery(context *AlertResultContext) (tsdb.TimeSeriesSlice, error) {
|
|
|
+ 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 {
|
|
|
+ return nil, fmt.Errorf("Alerting: GetSeries() tsdb.HandleRequest() error %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, v := range resp.Results {
|
|
|
+ if v.Error != nil {
|
|
|
+ return nil, fmt.Errorf("Alerting: GetSeries() tsdb.HandleRequest() response error %v", v)
|
|
|
+ }
|
|
|
+
|
|
|
+ result = append(result, v.Series...)
|
|
|
+ }
|
|
|
+
|
|
|
+ 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{
|
|
|
+ Id: datasource.Id,
|
|
|
+ Name: datasource.Name,
|
|
|
+ PluginId: datasource.Type,
|
|
|
+ Url: datasource.Url,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ return req
|
|
|
}
|
|
|
|
|
|
func NewQueryCondition(model *simplejson.Json) (*QueryCondition, error) {
|
|
|
condition := QueryCondition{}
|
|
|
+ condition.HandleRequest = tsdb.HandleRequest
|
|
|
|
|
|
queryJson := model.Get("query")
|
|
|
|
|
|
- condition.Query.Query = queryJson.Get("query").MustString()
|
|
|
+ condition.Query.Model = queryJson.Get("model")
|
|
|
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()
|
|
|
@@ -43,8 +115,18 @@ type SimpleReducer struct {
|
|
|
Type string
|
|
|
}
|
|
|
|
|
|
-func (s *SimpleReducer) Reduce() float64 {
|
|
|
- return 0
|
|
|
+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 {
|
|
|
@@ -56,8 +138,15 @@ type DefaultAlertEvaluator struct {
|
|
|
Threshold float64
|
|
|
}
|
|
|
|
|
|
-func (e *DefaultAlertEvaluator) Eval() bool {
|
|
|
- return true
|
|
|
+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) {
|