rule.go 3.8 KB

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