rule.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package alerting
  2. import (
  3. "fmt"
  4. "regexp"
  5. "strconv"
  6. "time"
  7. "github.com/grafana/grafana/pkg/components/simplejson"
  8. m "github.com/grafana/grafana/pkg/models"
  9. )
  10. type Rule struct {
  11. Id int64
  12. OrgId int64
  13. DashboardId int64
  14. PanelId int64
  15. Frequency int64
  16. Name string
  17. Message string
  18. LastStateChange time.Time
  19. For time.Duration
  20. NoDataState m.NoDataOption
  21. ExecutionErrorState m.ExecutionErrorOption
  22. State m.AlertStateType
  23. Conditions []Condition
  24. Notifications []int64
  25. StateChanges int64
  26. }
  27. type ValidationError struct {
  28. Reason string
  29. Err error
  30. Alertid int64
  31. DashboardId int64
  32. PanelId int64
  33. }
  34. func (e ValidationError) Error() string {
  35. extraInfo := e.Reason
  36. if e.Alertid != 0 {
  37. extraInfo = fmt.Sprintf("%s AlertId: %v", extraInfo, e.Alertid)
  38. }
  39. if e.PanelId != 0 {
  40. extraInfo = fmt.Sprintf("%s PanelId: %v", extraInfo, e.PanelId)
  41. }
  42. if e.DashboardId != 0 {
  43. extraInfo = fmt.Sprintf("%s DashboardId: %v", extraInfo, e.DashboardId)
  44. }
  45. if e.Err != nil {
  46. return fmt.Sprintf("Alert validation error: %s%s", e.Err.Error(), extraInfo)
  47. }
  48. return fmt.Sprintf("Alert validation error: %s", extraInfo)
  49. }
  50. var (
  51. ValueFormatRegex = regexp.MustCompile(`^\d+`)
  52. UnitFormatRegex = regexp.MustCompile(`\w{1}$`)
  53. )
  54. var unitMultiplier = map[string]int{
  55. "s": 1,
  56. "m": 60,
  57. "h": 3600,
  58. }
  59. func getTimeDurationStringToSeconds(str string) (int64, error) {
  60. multiplier := 1
  61. matches := ValueFormatRegex.FindAllString(str, 1)
  62. if len(matches) <= 0 {
  63. return 0, fmt.Errorf("Frequency could not be parsed")
  64. }
  65. value, err := strconv.Atoi(matches[0])
  66. if err != nil {
  67. return 0, err
  68. }
  69. unit := UnitFormatRegex.FindAllString(str, 1)[0]
  70. if val, ok := unitMultiplier[unit]; ok {
  71. multiplier = val
  72. }
  73. return int64(value * multiplier), nil
  74. }
  75. func NewRuleFromDBAlert(ruleDef *m.Alert) (*Rule, error) {
  76. model := &Rule{}
  77. model.Id = ruleDef.Id
  78. model.OrgId = ruleDef.OrgId
  79. model.DashboardId = ruleDef.DashboardId
  80. model.PanelId = ruleDef.PanelId
  81. model.Name = ruleDef.Name
  82. model.Message = ruleDef.Message
  83. model.Frequency = ruleDef.Frequency
  84. model.State = ruleDef.State
  85. model.LastStateChange = ruleDef.NewStateDate
  86. model.For = ruleDef.For
  87. model.NoDataState = m.NoDataOption(ruleDef.Settings.Get("noDataState").MustString("no_data"))
  88. model.ExecutionErrorState = m.ExecutionErrorOption(ruleDef.Settings.Get("executionErrorState").MustString("alerting"))
  89. model.StateChanges = ruleDef.StateChanges
  90. for _, v := range ruleDef.Settings.Get("notifications").MustArray() {
  91. jsonModel := simplejson.NewFromAny(v)
  92. id, err := jsonModel.Get("id").Int64()
  93. if err != nil {
  94. return nil, ValidationError{Reason: "Invalid notification schema", DashboardId: model.DashboardId, Alertid: model.Id, PanelId: model.PanelId}
  95. }
  96. model.Notifications = append(model.Notifications, id)
  97. }
  98. for index, condition := range ruleDef.Settings.Get("conditions").MustArray() {
  99. conditionModel := simplejson.NewFromAny(condition)
  100. conditionType := conditionModel.Get("type").MustString()
  101. factory, exist := conditionFactories[conditionType]
  102. if !exist {
  103. return nil, ValidationError{Reason: "Unknown alert condition: " + conditionType, DashboardId: model.DashboardId, Alertid: model.Id, PanelId: model.PanelId}
  104. }
  105. queryCondition, err := factory(conditionModel, index)
  106. if err != nil {
  107. return nil, ValidationError{Err: err, DashboardId: model.DashboardId, Alertid: model.Id, PanelId: model.PanelId}
  108. }
  109. model.Conditions = append(model.Conditions, queryCondition)
  110. }
  111. if len(model.Conditions) == 0 {
  112. return nil, ValidationError{Reason: "Alert is missing conditions"}
  113. }
  114. return model, nil
  115. }
  116. type ConditionFactory func(model *simplejson.Json, index int) (Condition, error)
  117. var conditionFactories = make(map[string]ConditionFactory)
  118. func RegisterCondition(typeName string, factory ConditionFactory) {
  119. conditionFactories[typeName] = factory
  120. }