eval_handler.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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. // calculating Firing based on operator
  35. if cr.Operator == "or" {
  36. firing = firing || cr.Firing
  37. noDataFound = noDataFound || cr.NoDataFound
  38. } else {
  39. firing = firing && cr.Firing
  40. noDataFound = noDataFound && cr.NoDataFound
  41. }
  42. if i > 0 {
  43. conditionEvals = "[" + conditionEvals + " " + strings.ToUpper(cr.Operator) + " " + strconv.FormatBool(cr.Firing) + "]"
  44. } else {
  45. conditionEvals = strconv.FormatBool(firing)
  46. }
  47. context.EvalMatches = append(context.EvalMatches, cr.EvalMatches...)
  48. }
  49. context.ConditionEvals = conditionEvals + " = " + strconv.FormatBool(firing)
  50. context.Firing = firing
  51. context.NoDataFound = noDataFound
  52. context.EndTime = time.Now()
  53. context.Rule.State = e.getNewState(context)
  54. elapsedTime := context.EndTime.Sub(context.StartTime).Nanoseconds() / int64(time.Millisecond)
  55. metrics.M_Alerting_Execution_Time.Observe(float64(elapsedTime))
  56. }
  57. // This should be move into evalContext once its been refactored.
  58. func (handler *DefaultEvalHandler) getNewState(evalContext *EvalContext) models.AlertStateType {
  59. if evalContext.Error != nil {
  60. handler.log.Error("Alert Rule Result Error",
  61. "ruleId", evalContext.Rule.Id,
  62. "name", evalContext.Rule.Name,
  63. "error", evalContext.Error,
  64. "changing state to", evalContext.Rule.ExecutionErrorState.ToAlertState())
  65. if evalContext.Rule.ExecutionErrorState == models.ExecutionErrorKeepState {
  66. return evalContext.PrevAlertState
  67. } else {
  68. return evalContext.Rule.ExecutionErrorState.ToAlertState()
  69. }
  70. } else if evalContext.Firing {
  71. return models.AlertStateAlerting
  72. } else if evalContext.NoDataFound {
  73. handler.log.Info("Alert Rule returned no data",
  74. "ruleId", evalContext.Rule.Id,
  75. "name", evalContext.Rule.Name,
  76. "changing state to", evalContext.Rule.NoDataState.ToAlertState())
  77. if evalContext.Rule.NoDataState == models.NoDataKeepState {
  78. return evalContext.PrevAlertState
  79. } else {
  80. return evalContext.Rule.NoDataState.ToAlertState()
  81. }
  82. }
  83. return models.AlertStateOK
  84. }