handler.go 3.9 KB

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