handler.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. e.log.Debug("Alert execution Crit", "name", serie.Name, "transformedValue", transformedValue, "operator", rule.Critical.Operator, "level", rule.Critical.Value, "result", critResult)
  86. if critResult {
  87. triggeredAlert = append(triggeredAlert, &TriggeredAlert{
  88. State: alertstates.Critical,
  89. ActualValue: transformedValue,
  90. Name: serie.Name,
  91. })
  92. }
  93. warnResult := evalCondition(rule.Warning, transformedValue)
  94. e.log.Debug("Alert execution Warn", "name", serie.Name, "transformedValue", transformedValue, "operator", rule.Warning.Operator, "level", rule.Warning.Value, "result", warnResult)
  95. if warnResult {
  96. triggeredAlert = append(triggeredAlert, &TriggeredAlert{
  97. State: alertstates.Warn,
  98. ActualValue: transformedValue,
  99. Name: serie.Name,
  100. })
  101. }
  102. }
  103. executionState := alertstates.Ok
  104. description := ""
  105. for _, raised := range triggeredAlert {
  106. if raised.State == alertstates.Critical {
  107. executionState = alertstates.Critical
  108. }
  109. if executionState != alertstates.Critical && raised.State == alertstates.Warn {
  110. executionState = alertstates.Warn
  111. }
  112. description += fmt.Sprintf(descriptionFmt, raised.ActualValue, raised.Name)
  113. }
  114. return &AlertResult{State: executionState, Description: description, TriggeredAlerts: triggeredAlert}
  115. }