query.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package conditions
  2. import (
  3. "fmt"
  4. "github.com/grafana/grafana/pkg/bus"
  5. "github.com/grafana/grafana/pkg/components/simplejson"
  6. m "github.com/grafana/grafana/pkg/models"
  7. "github.com/grafana/grafana/pkg/services/alerting"
  8. "github.com/grafana/grafana/pkg/tsdb"
  9. )
  10. func init() {
  11. alerting.RegisterCondition("query", func(model *simplejson.Json, index int) (alerting.Condition, error) {
  12. return NewQueryCondition(model, index)
  13. })
  14. }
  15. type QueryCondition struct {
  16. Index int
  17. Query AlertQuery
  18. Reducer QueryReducer
  19. Evaluator AlertEvaluator
  20. HandleRequest tsdb.HandleRequestFunc
  21. }
  22. type AlertQuery struct {
  23. Model *simplejson.Json
  24. DatasourceId int64
  25. From string
  26. To string
  27. }
  28. func (c *QueryCondition) Eval(context *alerting.EvalContext) {
  29. seriesList, err := c.executeQuery(context)
  30. if err != nil {
  31. context.Error = err
  32. return
  33. }
  34. for _, series := range seriesList {
  35. reducedValue := c.Reducer.Reduce(series)
  36. evalMatch := c.Evaluator.Eval(reducedValue)
  37. if context.IsTestRun {
  38. context.Logs = append(context.Logs, &alerting.ResultLogEntry{
  39. Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %1.3f", c.Index, evalMatch, series.Name, *reducedValue),
  40. })
  41. }
  42. if evalMatch {
  43. context.EvalMatches = append(context.EvalMatches, &alerting.EvalMatch{
  44. Metric: series.Name,
  45. Value: *reducedValue,
  46. })
  47. }
  48. context.Firing = evalMatch
  49. // handle no data scenario
  50. if reducedValue == nil {
  51. context.NoDataFound = true
  52. }
  53. }
  54. }
  55. func (c *QueryCondition) executeQuery(context *alerting.EvalContext) (tsdb.TimeSeriesSlice, error) {
  56. getDsInfo := &m.GetDataSourceByIdQuery{
  57. Id: c.Query.DatasourceId,
  58. OrgId: context.Rule.OrgId,
  59. }
  60. if err := bus.Dispatch(getDsInfo); err != nil {
  61. return nil, fmt.Errorf("Could not find datasource")
  62. }
  63. req := c.getRequestForAlertRule(getDsInfo.Result)
  64. result := make(tsdb.TimeSeriesSlice, 0)
  65. resp, err := c.HandleRequest(req)
  66. if err != nil {
  67. return nil, fmt.Errorf("tsdb.HandleRequest() error %v", err)
  68. }
  69. for _, v := range resp.Results {
  70. if v.Error != nil {
  71. return nil, fmt.Errorf("tsdb.HandleRequest() response error %v", v)
  72. }
  73. result = append(result, v.Series...)
  74. if context.IsTestRun {
  75. context.Logs = append(context.Logs, &alerting.ResultLogEntry{
  76. Message: fmt.Sprintf("Condition[%d]: Query Result", c.Index),
  77. Data: v.Series,
  78. })
  79. }
  80. }
  81. return result, nil
  82. }
  83. func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource) *tsdb.Request {
  84. req := &tsdb.Request{
  85. TimeRange: tsdb.TimeRange{
  86. From: c.Query.From,
  87. To: c.Query.To,
  88. },
  89. Queries: []*tsdb.Query{
  90. {
  91. RefId: "A",
  92. Query: c.Query.Model.Get("target").MustString(),
  93. DataSource: &tsdb.DataSourceInfo{
  94. Id: datasource.Id,
  95. Name: datasource.Name,
  96. PluginId: datasource.Type,
  97. Url: datasource.Url,
  98. User: datasource.User,
  99. Password: datasource.Password,
  100. Database: datasource.Database,
  101. BasicAuth: datasource.BasicAuth,
  102. BasicAuthUser: datasource.BasicAuthUser,
  103. BasicAuthPassword: datasource.BasicAuthPassword,
  104. },
  105. },
  106. },
  107. }
  108. return req
  109. }
  110. func NewQueryCondition(model *simplejson.Json, index int) (*QueryCondition, error) {
  111. condition := QueryCondition{}
  112. condition.Index = index
  113. condition.HandleRequest = tsdb.HandleRequest
  114. queryJson := model.Get("query")
  115. condition.Query.Model = queryJson.Get("model")
  116. condition.Query.From = queryJson.Get("params").MustArray()[1].(string)
  117. condition.Query.To = queryJson.Get("params").MustArray()[2].(string)
  118. condition.Query.DatasourceId = queryJson.Get("datasourceId").MustInt64()
  119. reducerJson := model.Get("reducer")
  120. condition.Reducer = NewSimpleReducer(reducerJson.Get("type").MustString())
  121. evaluatorJson := model.Get("evaluator")
  122. evaluator, err := NewAlertEvaluator(evaluatorJson)
  123. if err != nil {
  124. return nil, err
  125. }
  126. condition.Evaluator = evaluator
  127. return &condition, nil
  128. }