mirror of
https://github.com/grafana/grafana.git
synced 2024-11-21 16:38:03 -06:00
Optional custom title and description for OpsGenie (#50131)
* optional custom description for OpsGenie * custom title and message, tests * update changelog * check for empty / whitespace only strings * truncate the title to 130 characters if needed * unnecessary validation removed * truncate title to 127 characters and add three dots
This commit is contained in:
parent
c59938b235
commit
9dc7e752b7
@ -56,6 +56,7 @@ Scopes must have an order to ensure consistency and ease of search, this helps u
|
|||||||
- [ENHANCEMENT] Create folder 'General Alerting' when Grafana starts from the scratch #48866
|
- [ENHANCEMENT] Create folder 'General Alerting' when Grafana starts from the scratch #48866
|
||||||
- [ENHANCEMENT] Rule changes authorization logic to use UID folder scope instead of ID scope #48970
|
- [ENHANCEMENT] Rule changes authorization logic to use UID folder scope instead of ID scope #48970
|
||||||
- [ENHANCEMENT] Scheduler: ticker to support stopping #48142
|
- [ENHANCEMENT] Scheduler: ticker to support stopping #48142
|
||||||
|
- [ENHANCEMENT] Optional custom title and description for OpsGenie #50131
|
||||||
- [ENHANCEMENT] Scheduler: Adds new metrics to track rules that might be scheduled #49874
|
- [ENHANCEMENT] Scheduler: Adds new metrics to track rules that might be scheduled #49874
|
||||||
- `grafana_alerting_schedule_alert_rules `
|
- `grafana_alerting_schedule_alert_rules `
|
||||||
- `grafana_alerting_schedule_alert_rules_hash `
|
- `grafana_alerting_schedule_alert_rules_hash `
|
||||||
|
@ -863,6 +863,20 @@ func GetAvailableNotifiers() []*alerting.NotifierPlugin {
|
|||||||
PropertyName: "apiUrl",
|
PropertyName: "apiUrl",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Label: "Message",
|
||||||
|
Description: "Alert text limited to 130 characters.",
|
||||||
|
Element: alerting.ElementTypeInput,
|
||||||
|
InputType: alerting.InputTypeText,
|
||||||
|
Placeholder: `{{ template "default.title" . }}`,
|
||||||
|
PropertyName: "message",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Label: "Description",
|
||||||
|
Description: "A description of the incident.",
|
||||||
|
Element: alerting.ElementTypeTextArea,
|
||||||
|
PropertyName: "description",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Label: "Auto close incidents",
|
Label: "Auto close incidents",
|
||||||
Element: alerting.ElementTypeCheckbox,
|
Element: alerting.ElementTypeCheckbox,
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/prometheus/alertmanager/notify"
|
"github.com/prometheus/alertmanager/notify"
|
||||||
"github.com/prometheus/alertmanager/template"
|
"github.com/prometheus/alertmanager/template"
|
||||||
@ -36,6 +37,8 @@ type OpsgenieNotifier struct {
|
|||||||
*Base
|
*Base
|
||||||
APIKey string
|
APIKey string
|
||||||
APIUrl string
|
APIUrl string
|
||||||
|
Message string
|
||||||
|
Description string
|
||||||
AutoClose bool
|
AutoClose bool
|
||||||
OverridePriority bool
|
OverridePriority bool
|
||||||
SendTagsAs string
|
SendTagsAs string
|
||||||
@ -49,6 +52,8 @@ type OpsgenieConfig struct {
|
|||||||
*NotificationChannelConfig
|
*NotificationChannelConfig
|
||||||
APIKey string
|
APIKey string
|
||||||
APIUrl string
|
APIUrl string
|
||||||
|
Message string
|
||||||
|
Description string
|
||||||
AutoClose bool
|
AutoClose bool
|
||||||
OverridePriority bool
|
OverridePriority bool
|
||||||
SendTagsAs string
|
SendTagsAs string
|
||||||
@ -82,6 +87,8 @@ func NewOpsgenieConfig(config *NotificationChannelConfig, decryptFunc GetDecrypt
|
|||||||
APIUrl: config.Settings.Get("apiUrl").MustString(OpsgenieAlertURL),
|
APIUrl: config.Settings.Get("apiUrl").MustString(OpsgenieAlertURL),
|
||||||
AutoClose: config.Settings.Get("autoClose").MustBool(true),
|
AutoClose: config.Settings.Get("autoClose").MustBool(true),
|
||||||
OverridePriority: config.Settings.Get("overridePriority").MustBool(true),
|
OverridePriority: config.Settings.Get("overridePriority").MustBool(true),
|
||||||
|
Message: config.Settings.Get("message").MustString(`{{ template "default.title" . }}`),
|
||||||
|
Description: config.Settings.Get("description").MustString(""),
|
||||||
SendTagsAs: sendTagsAs,
|
SendTagsAs: sendTagsAs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -98,6 +105,8 @@ func NewOpsgenieNotifier(config *OpsgenieConfig, ns notifications.WebhookSender,
|
|||||||
}),
|
}),
|
||||||
APIKey: config.APIKey,
|
APIKey: config.APIKey,
|
||||||
APIUrl: config.APIUrl,
|
APIUrl: config.APIUrl,
|
||||||
|
Description: config.Description,
|
||||||
|
Message: config.Message,
|
||||||
AutoClose: config.AutoClose,
|
AutoClose: config.AutoClose,
|
||||||
OverridePriority: config.OverridePriority,
|
OverridePriority: config.OverridePriority,
|
||||||
SendTagsAs: config.SendTagsAs,
|
SendTagsAs: config.SendTagsAs,
|
||||||
@ -180,13 +189,25 @@ func (on *OpsgenieNotifier) buildOpsgenieMessage(ctx context.Context, alerts mod
|
|||||||
var tmplErr error
|
var tmplErr error
|
||||||
tmpl, data := TmplText(ctx, on.tmpl, as, on.log, &tmplErr)
|
tmpl, data := TmplText(ctx, on.tmpl, as, on.log, &tmplErr)
|
||||||
|
|
||||||
title := tmpl(DefaultMessageTitleEmbed)
|
titleTmpl := on.Message
|
||||||
description := fmt.Sprintf(
|
if strings.TrimSpace(titleTmpl) == "" {
|
||||||
"%s\n%s\n\n%s",
|
titleTmpl = `{{ template "default.title" . }}`
|
||||||
tmpl(DefaultMessageTitleEmbed),
|
}
|
||||||
ruleURL,
|
|
||||||
tmpl(`{{ template "default.message" . }}`),
|
title := tmpl(titleTmpl)
|
||||||
)
|
if len(title) > 130 {
|
||||||
|
title = title[:127] + "..."
|
||||||
|
}
|
||||||
|
|
||||||
|
description := tmpl(on.Description)
|
||||||
|
if strings.TrimSpace(description) == "" {
|
||||||
|
description = fmt.Sprintf(
|
||||||
|
"%s\n%s\n\n%s",
|
||||||
|
tmpl(DefaultMessageTitleEmbed),
|
||||||
|
ruleURL,
|
||||||
|
tmpl(`{{ template "default.message" . }}`),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
var priority string
|
var priority string
|
||||||
|
|
||||||
@ -202,6 +223,12 @@ func (on *OpsgenieNotifier) buildOpsgenieMessage(ctx context.Context, alerts mod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for templating errors
|
||||||
|
if tmplErr != nil {
|
||||||
|
on.log.Warn("failed to template Opsgenie message", "err", tmplErr.Error())
|
||||||
|
tmplErr = nil
|
||||||
|
}
|
||||||
|
|
||||||
bodyJSON.Set("message", title)
|
bodyJSON.Set("message", title)
|
||||||
bodyJSON.Set("source", "Grafana")
|
bodyJSON.Set("source", "Grafana")
|
||||||
bodyJSON.Set("alias", alias)
|
bodyJSON.Set("alias", alias)
|
||||||
@ -244,9 +271,9 @@ func (on *OpsgenieNotifier) buildOpsgenieMessage(ctx context.Context, alerts mod
|
|||||||
bodyJSON.Set("tags", tags)
|
bodyJSON.Set("tags", tags)
|
||||||
bodyJSON.Set("details", details)
|
bodyJSON.Set("details", details)
|
||||||
apiURL = tmpl(on.APIUrl)
|
apiURL = tmpl(on.APIUrl)
|
||||||
|
|
||||||
if tmplErr != nil {
|
if tmplErr != nil {
|
||||||
on.log.Warn("failed to template Opsgenie message", "err", tmplErr.Error())
|
on.log.Warn("failed to template Opsgenie URL", "err", tmplErr.Error(), "fallback", on.APIUrl)
|
||||||
|
apiURL = on.APIUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
return bodyJSON, apiURL, nil
|
return bodyJSON, apiURL, nil
|
||||||
|
@ -54,10 +54,81 @@ func TestOpsgenieNotifier(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Default config with one alert and send tags as tags",
|
name: "Default config with one alert, custom message and description",
|
||||||
|
settings: `{"apiKey": "abcdefgh0123456789", "message": "test message", "description": "test description"}`,
|
||||||
|
alerts: []*types.Alert{
|
||||||
|
{
|
||||||
|
Alert: model.Alert{
|
||||||
|
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
|
||||||
|
Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expMsg: `{
|
||||||
|
"alias": "6e3538104c14b583da237e9693b76debbc17f0f8058ef20492e5853096cf8733",
|
||||||
|
"description": "test description",
|
||||||
|
"details": {
|
||||||
|
"url": "http://localhost/alerting/list"
|
||||||
|
},
|
||||||
|
"message": "test message",
|
||||||
|
"source": "Grafana",
|
||||||
|
"tags": ["alertname:alert1", "lbl1:val1"]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Default config with one alert, message length > 130",
|
||||||
settings: `{
|
settings: `{
|
||||||
"apiKey": "abcdefgh0123456789",
|
"apiKey": "abcdefgh0123456789",
|
||||||
"sendTagsAs": "tags"
|
"message": "IyJnsW78xQoiBJ7L7NqASv31JCFf0At3r9KUykqBVxSiC6qkDhvDLDW9VImiFcq0Iw2XwFy5fX4FcbTmlkaZzUzjVwx9VUuokhzqQlJVhWDYFqhj3a5wX0LjyvNQjsqT9WaWJAWOJanwOAWon"
|
||||||
|
}`,
|
||||||
|
alerts: []*types.Alert{
|
||||||
|
{
|
||||||
|
Alert: model.Alert{
|
||||||
|
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
|
||||||
|
Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expMsg: `{
|
||||||
|
"alias": "6e3538104c14b583da237e9693b76debbc17f0f8058ef20492e5853096cf8733",
|
||||||
|
"description": "[FIRING:1] (val1)\nhttp://localhost/alerting/list\n\n**Firing**\n\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val1\nAnnotations:\n - ann1 = annv1\nSilence: http://localhost/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dalert1&matcher=lbl1%3Dval1\nDashboard: http://localhost/d/abcd\nPanel: http://localhost/d/abcd?viewPanel=efgh\n",
|
||||||
|
"details": {
|
||||||
|
"url": "http://localhost/alerting/list"
|
||||||
|
},
|
||||||
|
"message": "IyJnsW78xQoiBJ7L7NqASv31JCFf0At3r9KUykqBVxSiC6qkDhvDLDW9VImiFcq0Iw2XwFy5fX4FcbTmlkaZzUzjVwx9VUuokhzqQlJVhWDYFqhj3a5wX0LjyvNQjsq...",
|
||||||
|
"source": "Grafana",
|
||||||
|
"tags": ["alertname:alert1", "lbl1:val1"]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Default config with one alert, templated message and description",
|
||||||
|
settings: `{"apiKey": "abcdefgh0123456789", "message": "Firing: {{ len .Alerts.Firing }}", "description": "{{ len .Alerts.Firing }} firing, {{ len .Alerts.Resolved }} resolved."}`,
|
||||||
|
alerts: []*types.Alert{
|
||||||
|
{
|
||||||
|
Alert: model.Alert{
|
||||||
|
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
|
||||||
|
Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expMsg: `{
|
||||||
|
"alias": "6e3538104c14b583da237e9693b76debbc17f0f8058ef20492e5853096cf8733",
|
||||||
|
"description": "1 firing, 0 resolved.",
|
||||||
|
"details": {
|
||||||
|
"url": "http://localhost/alerting/list"
|
||||||
|
},
|
||||||
|
"message": "Firing: 1",
|
||||||
|
"source": "Grafana",
|
||||||
|
"tags": ["alertname:alert1", "lbl1:val1"]
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Default config with one alert and send tags as tags, empty description and message",
|
||||||
|
settings: `{
|
||||||
|
"apiKey": "abcdefgh0123456789",
|
||||||
|
"sendTagsAs": "tags",
|
||||||
|
"message": " ",
|
||||||
|
"description": " "
|
||||||
}`,
|
}`,
|
||||||
alerts: []*types.Alert{
|
alerts: []*types.Alert{
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user