handler.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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 HandlerImpl struct {
  14. log log.Logger
  15. }
  16. func NewHandler() *HandlerImpl {
  17. return &HandlerImpl{
  18. log: log.New("alerting.executor"),
  19. }
  20. }
  21. func (e *HandlerImpl) 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 *HandlerImpl) 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 *HandlerImpl) 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 *HandlerImpl) evaluateRule(rule *AlertRule, series tsdb.TimeSeriesSlice) *AlertResult {
  79. e.log.Debug("Evaluating Alerting Rule", "seriesCount", len(series), "ruleName", rule.Name)
  80. triggeredAlert := make([]*TriggeredAlert, 0)
  81. for _, serie := range series {
  82. e.log.Debug("Evaluating series", "series", serie.Name)
  83. transformedValue, _ := rule.Transformer.Transform(serie)
  84. critResult := evalCondition(rule.Critical, transformedValue)
  85. condition2 := fmt.Sprintf("%v %s %v ", transformedValue, rule.Critical.Operator, rule.Critical.Value)
  86. e.log.Debug("Alert execution Crit", "name", serie.Name, "condition", condition2, "result", critResult)
  87. if critResult {
  88. triggeredAlert = append(triggeredAlert, &TriggeredAlert{
  89. State: alertstates.Critical,
  90. ActualValue: transformedValue,
  91. Name: serie.Name,
  92. })
  93. continue
  94. }
  95. warnResult := evalCondition(rule.Warning, transformedValue)
  96. condition := fmt.Sprintf("%v %s %v ", transformedValue, rule.Warning.Operator, rule.Warning.Value)
  97. e.log.Debug("Alert execution Warn", "name", serie.Name, "condition", condition, "result", warnResult)
  98. if warnResult {
  99. triggeredAlert = append(triggeredAlert, &TriggeredAlert{
  100. State: alertstates.Warn,
  101. ActualValue: transformedValue,
  102. Name: serie.Name,
  103. })
  104. }
  105. }
  106. executionState := alertstates.Ok
  107. description := ""
  108. for _, raised := range triggeredAlert {
  109. if raised.State == alertstates.Critical {
  110. executionState = alertstates.Critical
  111. }
  112. if executionState != alertstates.Critical && raised.State == alertstates.Warn {
  113. executionState = alertstates.Warn
  114. }
  115. description += fmt.Sprintf(descriptionFmt, raised.ActualValue, raised.Name)
  116. }
  117. return &AlertResult{State: executionState, Description: description, TriggeredAlerts: triggeredAlert}
  118. }