executor.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package alerting
  2. import (
  3. "fmt"
  4. "github.com/grafana/grafana/pkg/bus"
  5. "github.com/grafana/grafana/pkg/log"
  6. m "github.com/grafana/grafana/pkg/models"
  7. "github.com/grafana/grafana/pkg/services/alerting/alertstates"
  8. "github.com/grafana/grafana/pkg/tsdb"
  9. )
  10. var (
  11. descriptionFmt = "Actual value: %1.2f for %s"
  12. )
  13. type ExecutorImpl struct {
  14. log log.Logger
  15. }
  16. func NewExecutor() *ExecutorImpl {
  17. return &ExecutorImpl{
  18. log: log.New("alerting.executor"),
  19. }
  20. }
  21. func (e *ExecutorImpl) Execute(job *AlertJob, resultQueue chan *AlertResult) {
  22. timeSeries, err := e.executeQuery(job)
  23. if err != nil {
  24. resultQueue <- &AlertResult{
  25. Error: err,
  26. State: alertstates.Pending,
  27. AlertJob: job,
  28. }
  29. }
  30. result := e.evaluateRule(job.Rule, timeSeries)
  31. result.AlertJob = job
  32. resultQueue <- result
  33. }
  34. func (e *ExecutorImpl) executeQuery(job *AlertJob) (tsdb.TimeSeriesSlice, error) {
  35. getDsInfo := &m.GetDataSourceByIdQuery{
  36. Id: job.Rule.Query.DatasourceId,
  37. OrgId: job.Rule.OrgId,
  38. }
  39. if err := bus.Dispatch(getDsInfo); err != nil {
  40. return nil, fmt.Errorf("Could not find datasource")
  41. }
  42. req := e.GetRequestForAlertRule(job.Rule, getDsInfo.Result)
  43. result := make(tsdb.TimeSeriesSlice, 0)
  44. resp, err := tsdb.HandleRequest(req)
  45. if err != nil {
  46. return nil, fmt.Errorf("Alerting: GetSeries() tsdb.HandleRequest() error %v", err)
  47. }
  48. for _, v := range resp.Results {
  49. if v.Error != nil {
  50. return nil, fmt.Errorf("Alerting: GetSeries() tsdb.HandleRequest() response error %v", v)
  51. }
  52. result = append(result, v.Series...)
  53. }
  54. return result, nil
  55. }
  56. func (e *ExecutorImpl) GetRequestForAlertRule(rule *AlertRule, datasource *m.DataSource) *tsdb.Request {
  57. e.log.Debug("GetRequest", "query", rule.Query.Query, "from", rule.Query.From, "datasourceId", datasource.Id)
  58. req := &tsdb.Request{
  59. TimeRange: tsdb.TimeRange{
  60. From: "-" + rule.Query.From,
  61. To: rule.Query.To,
  62. },
  63. Queries: []*tsdb.Query{
  64. {
  65. RefId: "A",
  66. Query: rule.Query.Query,
  67. DataSource: &tsdb.DataSourceInfo{
  68. Id: datasource.Id,
  69. Name: datasource.Name,
  70. PluginId: datasource.Type,
  71. Url: datasource.Url,
  72. },
  73. },
  74. },
  75. }
  76. return req
  77. }
  78. func (e *ExecutorImpl) evaluateRule(rule *AlertRule, series tsdb.TimeSeriesSlice) *AlertResult {
  79. e.log.Debug("Evaluating Alerting Rule", "seriesCount", len(series), "ruleName", rule.Name)
  80. for _, serie := range series {
  81. e.log.Debug("Evaluating series", "series", serie.Name)
  82. transformedValue, _ := rule.Transformer.Transform(serie)
  83. critResult := evalCondition(rule.Critical, transformedValue)
  84. e.log.Debug("Alert execution Crit", "name", serie.Name, "transformedValue", transformedValue, "operator", rule.Critical.Operator, "level", rule.Critical.Level, "result", critResult)
  85. if critResult {
  86. return &AlertResult{
  87. State: alertstates.Critical,
  88. ActualValue: transformedValue,
  89. Description: fmt.Sprintf(descriptionFmt, transformedValue, serie.Name),
  90. }
  91. }
  92. warnResult := evalCondition(rule.Warning, transformedValue)
  93. e.log.Debug("Alert execution Warn", "name", serie.Name, "transformedValue", transformedValue, "operator", rule.Warning.Operator, "level", rule.Warning.Level, "result", warnResult)
  94. if warnResult {
  95. return &AlertResult{
  96. State: alertstates.Warn,
  97. Description: fmt.Sprintf(descriptionFmt, transformedValue, serie.Name),
  98. ActualValue: transformedValue,
  99. }
  100. }
  101. }
  102. return &AlertResult{State: alertstates.Ok, Description: "Alert is OK!"}
  103. }