handler.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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. startTime := time.Now()
  24. timeSeries, err := e.executeQuery(job)
  25. if err != nil {
  26. resultQueue <- &AlertResult{
  27. Error: err,
  28. State: alertstates.Pending,
  29. AlertJob: job,
  30. StartTime: time.Now(),
  31. EndTime: time.Now(),
  32. }
  33. }
  34. result := e.evaluateRule(job.Rule, timeSeries)
  35. result.AlertJob = job
  36. result.StartTime = startTime
  37. result.EndTime = time.Now()
  38. resultQueue <- result
  39. }
  40. func (e *HandlerImpl) executeQuery(job *AlertJob) (tsdb.TimeSeriesSlice, error) {
  41. getDsInfo := &m.GetDataSourceByIdQuery{
  42. Id: job.Rule.Query.DatasourceId,
  43. OrgId: job.Rule.OrgId,
  44. }
  45. if err := bus.Dispatch(getDsInfo); err != nil {
  46. return nil, fmt.Errorf("Could not find datasource")
  47. }
  48. req := e.GetRequestForAlertRule(job.Rule, getDsInfo.Result)
  49. result := make(tsdb.TimeSeriesSlice, 0)
  50. resp, err := tsdb.HandleRequest(req)
  51. if err != nil {
  52. return nil, fmt.Errorf("Alerting: GetSeries() tsdb.HandleRequest() error %v", err)
  53. }
  54. for _, v := range resp.Results {
  55. if v.Error != nil {
  56. return nil, fmt.Errorf("Alerting: GetSeries() tsdb.HandleRequest() response error %v", v)
  57. }
  58. result = append(result, v.Series...)
  59. }
  60. return result, nil
  61. }
  62. func (e *HandlerImpl) GetRequestForAlertRule(rule *AlertRule, datasource *m.DataSource) *tsdb.Request {
  63. e.log.Debug("GetRequest", "query", rule.Query.Query, "from", rule.Query.From, "datasourceId", datasource.Id)
  64. req := &tsdb.Request{
  65. TimeRange: tsdb.TimeRange{
  66. From: "-" + rule.Query.From,
  67. To: rule.Query.To,
  68. },
  69. Queries: []*tsdb.Query{
  70. {
  71. RefId: "A",
  72. Query: rule.Query.Query,
  73. DataSource: &tsdb.DataSourceInfo{
  74. Id: datasource.Id,
  75. Name: datasource.Name,
  76. PluginId: datasource.Type,
  77. Url: datasource.Url,
  78. },
  79. },
  80. },
  81. }
  82. return req
  83. }
  84. func (e *HandlerImpl) evaluateRule(rule *AlertRule, series tsdb.TimeSeriesSlice) *AlertResult {
  85. e.log.Debug("Evaluating Alerting Rule", "seriesCount", len(series), "ruleName", rule.Name)
  86. triggeredAlert := make([]*TriggeredAlert, 0)
  87. for _, serie := range series {
  88. e.log.Debug("Evaluating series", "series", serie.Name)
  89. transformedValue, _ := rule.Transformer.Transform(serie)
  90. critResult := evalCondition(rule.Critical, transformedValue)
  91. condition2 := fmt.Sprintf("%v %s %v ", transformedValue, rule.Critical.Operator, rule.Critical.Value)
  92. e.log.Debug("Alert execution Crit", "name", serie.Name, "condition", condition2, "result", critResult)
  93. if critResult {
  94. triggeredAlert = append(triggeredAlert, &TriggeredAlert{
  95. State: alertstates.Critical,
  96. Value: transformedValue,
  97. Metric: serie.Name,
  98. })
  99. continue
  100. }
  101. warnResult := evalCondition(rule.Warning, transformedValue)
  102. condition := fmt.Sprintf("%v %s %v ", transformedValue, rule.Warning.Operator, rule.Warning.Value)
  103. e.log.Debug("Alert execution Warn", "name", serie.Name, "condition", condition, "result", warnResult)
  104. if warnResult {
  105. triggeredAlert = append(triggeredAlert, &TriggeredAlert{
  106. State: alertstates.Warn,
  107. Value: transformedValue,
  108. Metric: serie.Name,
  109. })
  110. }
  111. }
  112. executionState := alertstates.Ok
  113. for _, raised := range triggeredAlert {
  114. if raised.State == alertstates.Critical {
  115. executionState = alertstates.Critical
  116. }
  117. if executionState != alertstates.Critical && raised.State == alertstates.Warn {
  118. executionState = alertstates.Warn
  119. }
  120. }
  121. return &AlertResult{State: executionState, TriggeredAlerts: triggeredAlert}
  122. }