notifier.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package alerting
  2. import (
  3. "fmt"
  4. "github.com/grafana/grafana/pkg/bus"
  5. "github.com/grafana/grafana/pkg/components/simplejson"
  6. "github.com/grafana/grafana/pkg/log"
  7. m "github.com/grafana/grafana/pkg/models"
  8. "github.com/grafana/grafana/pkg/services/alerting/alertstates"
  9. "github.com/grafana/grafana/pkg/setting"
  10. )
  11. type NotifierImpl struct {
  12. log log.Logger
  13. }
  14. func NewNotifier() *NotifierImpl {
  15. return &NotifierImpl{
  16. log: log.New("alerting.notifier"),
  17. }
  18. }
  19. func (n *NotifierImpl) Notify(alertResult *AlertResult) {
  20. notifiers := n.getNotifiers(alertResult.AlertJob.Rule.OrgId, alertResult.AlertJob.Rule.NotificationGroups)
  21. for _, notifier := range notifiers {
  22. warn := alertResult.State == alertstates.Warn && notifier.SendWarning
  23. crit := alertResult.State == alertstates.Critical && notifier.SendCritical
  24. if (warn || crit) || alertResult.State == alertstates.Ok {
  25. n.log.Info("Sending notification", "state", alertResult.State, "type", notifier.Type)
  26. go notifier.Notifierr.Dispatch(alertResult)
  27. }
  28. }
  29. }
  30. type Notification struct {
  31. Name string
  32. Type string
  33. SendWarning bool
  34. SendCritical bool
  35. Notifierr NotificationDispatcher
  36. }
  37. type EmailNotifier struct {
  38. To string
  39. log log.Logger
  40. }
  41. func (this *EmailNotifier) Dispatch(alertResult *AlertResult) {
  42. this.log.Info("Sending email")
  43. grafanaUrl := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
  44. if setting.AppSubUrl != "" {
  45. grafanaUrl += "/" + setting.AppSubUrl
  46. }
  47. cmd := &m.SendEmailCommand{
  48. Data: map[string]interface{}{
  49. "Name": "Name",
  50. "State": alertResult.State,
  51. "Description": alertResult.Description,
  52. "TriggeredAlerts": alertResult.TriggeredAlerts,
  53. "DashboardLink": grafanaUrl + "/dashboard/db/alerting",
  54. "AlertPageUrl": grafanaUrl + "/alerting",
  55. "DashboardImage": grafanaUrl + "/render/dashboard-solo/db/alerting?from=1466169458375&to=1466171258375&panelId=1&width=1000&height=500",
  56. },
  57. To: []string{this.To},
  58. Template: "alert_notification.html",
  59. }
  60. err := bus.Dispatch(cmd)
  61. if err != nil {
  62. this.log.Error("Could not send alert notification as email", "error", err)
  63. }
  64. }
  65. type WebhookNotifier struct {
  66. Url string
  67. User string
  68. Password string
  69. log log.Logger
  70. }
  71. func (this *WebhookNotifier) Dispatch(alertResult *AlertResult) {
  72. this.log.Info("Sending webhook")
  73. bodyJSON := simplejson.New()
  74. bodyJSON.Set("name", alertResult.AlertJob.Rule.Name)
  75. bodyJSON.Set("state", alertResult.State)
  76. bodyJSON.Set("trigged", alertResult.TriggeredAlerts)
  77. body, _ := bodyJSON.MarshalJSON()
  78. cmd := &m.SendWebhook{
  79. Url: this.Url,
  80. User: this.User,
  81. Password: this.Password,
  82. Body: string(body),
  83. }
  84. bus.Dispatch(cmd)
  85. }
  86. type NotificationDispatcher interface {
  87. Dispatch(alertResult *AlertResult)
  88. }
  89. func (n *NotifierImpl) getNotifiers(orgId int64, notificationGroups []int64) []*Notification {
  90. query := &m.GetAlertNotificationQuery{
  91. OrgID: orgId,
  92. Ids: notificationGroups,
  93. IncludeAlwaysExecute: true,
  94. }
  95. err := bus.Dispatch(query)
  96. if err != nil {
  97. n.log.Error("Failed to read notifications", "error", err)
  98. }
  99. var result []*Notification
  100. n.log.Info("notifiriring", "count", len(query.Result), "groups", notificationGroups)
  101. for _, notification := range query.Result {
  102. not, err := NewNotificationFromDBModel(notification)
  103. if err == nil {
  104. result = append(result, not)
  105. } else {
  106. n.log.Error("Failed to read notification model", "error", err)
  107. }
  108. }
  109. return result
  110. }
  111. func NewNotificationFromDBModel(model *m.AlertNotification) (*Notification, error) {
  112. notifier, err := createNotifier(model.Type, model.Settings)
  113. if err != nil {
  114. return nil, err
  115. }
  116. return &Notification{
  117. Name: model.Name,
  118. Type: model.Type,
  119. Notifierr: notifier,
  120. SendCritical: !model.Settings.Get("ignoreCrit").MustBool(),
  121. SendWarning: !model.Settings.Get("ignoreWarn").MustBool(),
  122. }, nil
  123. }
  124. var createNotifier = func(notificationType string, settings *simplejson.Json) (NotificationDispatcher, error) {
  125. if notificationType == "email" {
  126. to := settings.Get("to").MustString()
  127. if to == "" {
  128. return nil, fmt.Errorf("Could not find to propertie in settings")
  129. }
  130. return &EmailNotifier{
  131. To: to,
  132. log: log.New("alerting.notification.email"),
  133. }, nil
  134. }
  135. url := settings.Get("url").MustString()
  136. if url == "" {
  137. return nil, fmt.Errorf("Could not find url propertie in settings")
  138. }
  139. return &WebhookNotifier{
  140. Url: url,
  141. User: settings.Get("user").MustString(),
  142. Password: settings.Get("password").MustString(),
  143. log: log.New("alerting.notification.webhook"),
  144. }, nil
  145. }