|
|
@@ -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() {
|
|
|
<span class="gf-form-label width-6">Url</span>
|
|
|
<input type="text" required class="gf-form-input max-width-30" ng-model="ctrl.model.settings.url" placeholder="VictorOps url"></input>
|
|
|
</div>
|
|
|
+ <div class="gf-form">
|
|
|
+ <gf-form-switch
|
|
|
+ class="gf-form"
|
|
|
+ label="Auto resolve incidents"
|
|
|
+ label-class="width-14"
|
|
|
+ checked="ctrl.model.settings.autoResolve"
|
|
|
+ tooltip="Resolve incidents in VictorOps once the alert goes back to ok.">
|
|
|
+ </gf-form-switch>
|
|
|
+ </div>
|
|
|
`,
|
|
|
})
|
|
|
}
|
|
|
@@ -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
|
|
|
+ }
|
|
|
+
|
|
|
+ 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, _ := json.Marshal(&body)
|
|
|
+ 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
|
|
|
}
|
|
|
|