eval_handler.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package alerting
  2. import (
  3. "strconv"
  4. "strings"
  5. "time"
  6. "github.com/grafana/grafana/pkg/log"
  7. "github.com/grafana/grafana/pkg/metrics"
  8. "github.com/grafana/grafana/pkg/models"
  9. )
  10. type DefaultEvalHandler struct {
  11. log log.Logger
  12. alertJobTimeout time.Duration
  13. }
  14. func NewEvalHandler() *DefaultEvalHandler {
  15. return &DefaultEvalHandler{
  16. log: log.New("alerting.evalHandler"),
  17. alertJobTimeout: time.Second * 5,
  18. }
  19. }
  20. func (e *DefaultEvalHandler) Eval(context *EvalContext) {
  21. firing := true
  22. noDataFound := true
  23. conditionEvals := ""
  24. for i := 0; i < len(context.Rule.Conditions); i++ {
  25. condition := context.Rule.Conditions[i]
  26. cr, err := condition.Eval(context)
  27. if err != nil {
  28. context.Error = err
  29. }
  30. // break if condition could not be evaluated
  31. if context.Error != nil {
  32. break
  33. }
  34. if i == 0 {
  35. firing = cr.Firing
  36. noDataFound = cr.NoDataFound
  37. }
  38. // calculating Firing based on operator
  39. if cr.Operator == "or" {
  40. firing = firing || cr.Firing
  41. noDataFound = noDataFound || cr.NoDataFound
  42. } else {
  43. firing = firing && cr.Firing
  44. noDataFound = noDataFound && cr.NoDataFound
  45. }
  46. if i > 0 {
  47. conditionEvals = "[" + conditionEvals + " " + strings.ToUpper(cr.Operator) + " " + strconv.FormatBool(cr.Firing) + "]"
  48. } else {
  49. conditionEvals = strconv.FormatBool(firing)
  50. }
  51. context.EvalMatches = append(context.EvalMatches, cr.EvalMatches...)
  52. }
  53. context.ConditionEvals = conditionEvals + " = " + strconv.FormatBool(firing)
  54. context.Firing = firing
  55. context.NoDataFound = noDataFound
  56. context.EndTime = time.Now()
  57. context.Rule.State = e.getNewState(context)
  58. elapsedTime := context.EndTime.Sub(context.StartTime).Nanoseconds() / int64(time.Millisecond)
  59. metrics.M_Alerting_Execution_Time.Observe(float64(elapsedTime))
  60. }
  61. // This should be move into evalContext once its been refactored. (Carl Bergquist)
  62. func (handler *DefaultEvalHandler) getNewState(evalContext *EvalContext) models.AlertStateType {
  63. if evalContext.Error != nil {
  64. handler.log.Error("Alert Rule Result Error",
  65. "ruleId", evalContext.Rule.Id,
  66. "name", evalContext.Rule.Name,
  67. "error", evalContext.Error,
  68. "changing state to", evalContext.Rule.ExecutionErrorState.ToAlertState())
  69. if evalContext.Rule.ExecutionErrorState == models.ExecutionErrorKeepState {
  70. return evalContext.PrevAlertState
  71. } else {
  72. return evalContext.Rule.ExecutionErrorState.ToAlertState()
  73. }
  74. } else if evalContext.Firing {
  75. return models.AlertStateAlerting
  76. } else if evalContext.NoDataFound {
  77. handler.log.Info("Alert Rule returned no data",
  78. "ruleId", evalContext.Rule.Id,
  79. "name", evalContext.Rule.Name,
  80. "changing state to", evalContext.Rule.NoDataState.ToAlertState())
  81. if evalContext.Rule.NoDataState == models.NoDataKeepState {
  82. return evalContext.PrevAlertState
  83. } else {
  84. return evalContext.Rule.NoDataState.ToAlertState()
  85. }
  86. }
  87. return models.AlertStateOK
  88. }