diff --git a/pkg/services/alerting/notifiers/victorops.go b/pkg/services/alerting/notifiers/victorops.go
index a4e34a40b8a..2fbb2f64d1b 100644
--- a/pkg/services/alerting/notifiers/victorops.go
+++ b/pkg/services/alerting/notifiers/victorops.go
@@ -1,10 +1,10 @@
package notifiers
import (
- "encoding/json"
"time"
"github.com/grafana/grafana/pkg/bus"
+ "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/models"
@@ -15,6 +15,8 @@ import (
// AlertStateCritical - Victorops uses "CRITICAL" string to indicate "Alerting" state
const AlertStateCritical = "CRITICAL"
+const AlertStateRecovery = "RECOVERY"
+
func init() {
alerting.RegisterNotifier(&alerting.NotifierPlugin{
Type: "victorops",
@@ -27,6 +29,15 @@ func init() {
Url
+
+
+
+
`,
})
}
@@ -34,6 +45,7 @@ func init() {
// NewVictoropsNotifier creates an instance of VictoropsNotifier that
// handles posting notifications to Victorops REST API
func NewVictoropsNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
+ autoResolve := model.Settings.Get("autoResolve").MustBool(true)
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find victorops url property in settings"}
@@ -42,6 +54,7 @@ func NewVictoropsNotifier(model *models.AlertNotification) (alerting.Notifier, e
return &VictoropsNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
URL: url,
+ AutoResolve: autoResolve,
log: log.New("alerting.notifier.victorops"),
}, nil
}
@@ -51,8 +64,9 @@ func NewVictoropsNotifier(model *models.AlertNotification) (alerting.Notifier, e
// Victorops specifications (http://victorops.force.com/knowledgebase/articles/Integration/Alert-Ingestion-API-Documentation/)
type VictoropsNotifier struct {
NotifierBase
- URL string
- log log.Logger
+ URL string
+ AutoResolve bool
+ log log.Logger
}
// Notify sends notification to Victorops via POST to URL endpoint
@@ -66,6 +80,11 @@ func (this *VictoropsNotifier) Notify(evalContext *alerting.EvalContext) error {
return err
}
+ if evalContext.Rule.State == models.AlertStateOK && !this.AutoResolve {
+ this.log.Info("Not alerting VictorOps", "state", evalContext.Rule.State, "auto resolve", this.AutoResolve)
+ return nil
+ }
+
fields := make([]map[string]interface{}, 0)
fieldLimitCount := 4
for index, evt := range evalContext.EvalMatches {
@@ -92,20 +111,28 @@ func (this *VictoropsNotifier) Notify(evalContext *alerting.EvalContext) error {
messageType = AlertStateCritical
}
- body := map[string]interface{}{
- "message_type": messageType,
- "entity_id": evalContext.Rule.Name,
- "timestamp": time.Now().Unix(),
- "state_start_time": evalContext.StartTime.Unix(),
- "state_message": evalContext.Rule.Message + "\n" + ruleUrl,
- "monitoring_tool": "Grafana v" + setting.BuildVersion,
+ if evalContext.Rule.State == models.AlertStateOK {
+ messageType = AlertStateRecovery
}
- data, _ := json.Marshal(&body)
+ bodyJSON := simplejson.New()
+ bodyJSON.Set("message_type", messageType)
+ bodyJSON.Set("entity_id", evalContext.Rule.Name)
+ bodyJSON.Set("timestamp", time.Now().Unix())
+ bodyJSON.Set("state_start_time", evalContext.StartTime.Unix())
+ bodyJSON.Set("state_message", evalContext.Rule.Message)
+ bodyJSON.Set("monitoring_tool", "Grafana v"+setting.BuildVersion)
+ bodyJSON.Set("alert_url", ruleUrl)
+
+ if evalContext.ImagePublicUrl != "" {
+ bodyJSON.Set("image_url", evalContext.ImagePublicUrl)
+ }
+
+ data, _ := bodyJSON.MarshalJSON()
cmd := &models.SendWebhookSync{Url: this.URL, Body: string(data)}
if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
- this.log.Error("Failed to send victorops notification", "error", err, "webhook", this.Name)
+ this.log.Error("Failed to send Victorops notification", "error", err, "webhook", this.Name)
return err
}