diff --git a/pkg/services/ngalert/notifier/channels/pagerduty.go b/pkg/services/ngalert/notifier/channels/pagerduty.go index a84347bb1d1..7d69b35634e 100644 --- a/pkg/services/ngalert/notifier/channels/pagerduty.go +++ b/pkg/services/ngalert/notifier/channels/pagerduty.go @@ -26,6 +26,7 @@ const ( defaultSeverity = "critical" defaultClass = "default" defaultGroup = "default" + defaultClient = "Grafana" ) var ( @@ -52,6 +53,9 @@ type pagerdutySettings struct { Component string `json:"component,omitempty" yaml:"component,omitempty"` Group string `json:"group,omitempty" yaml:"group,omitempty"` Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Source string `json:"source,omitempty" yaml:"source,omitempty"` + Client string `json:"client,omitempty" yaml:"client,omitempty"` + ClientURL string `json:"client_url,omitempty" yaml:"client_url,omitempty"` } func buildPagerdutySettings(fc FactoryConfig) (*pagerdutySettings, error) { @@ -88,7 +92,19 @@ func buildPagerdutySettings(fc FactoryConfig) (*pagerdutySettings, error) { if settings.Summary == "" { settings.Summary = DefaultMessageTitleEmbed } - + if settings.Client == "" { + settings.Client = defaultClient + } + if settings.ClientURL == "" { + settings.ClientURL = "{{ .ExternalURL }}" + } + if settings.Source == "" { + source, err := os.Hostname() + if err != nil { + source = settings.Client + } + settings.Source = source + } return &settings, nil } @@ -190,8 +206,8 @@ func (pn *PagerdutyNotifier) buildPagerdutyMessage(ctx context.Context, alerts m } msg := &pagerDutyMessage{ - Client: "Grafana", - ClientURL: pn.tmpl.ExternalURL.String(), + Client: tmpl(pn.settings.Client), + ClientURL: tmpl(pn.settings.ClientURL), RoutingKey: pn.settings.Key, EventAction: eventType, DedupKey: key.Hash(), @@ -200,6 +216,7 @@ func (pn *PagerdutyNotifier) buildPagerdutyMessage(ctx context.Context, alerts m Text: "External URL", }}, Payload: pagerDutyPayload{ + Source: tmpl(pn.settings.Source), Component: tmpl(pn.settings.Component), Summary: tmpl(pn.settings.Summary), Severity: severity, @@ -224,11 +241,6 @@ func (pn *PagerdutyNotifier) buildPagerdutyMessage(ctx context.Context, alerts m msg.Payload.Summary = summary } - if hostname, err := os.Hostname(); err == nil { - // TODO: should this be configured like in Prometheus AM? - msg.Payload.Source = hostname - } - if tmplErr != nil { pn.log.Warn("failed to template PagerDuty message", "error", tmplErr.Error()) } diff --git a/pkg/services/ngalert/notifier/channels/pagerduty_test.go b/pkg/services/ngalert/notifier/channels/pagerduty_test.go index 21ee9c88acc..7325d81f96a 100644 --- a/pkg/services/ngalert/notifier/channels/pagerduty_test.go +++ b/pkg/services/ngalert/notifier/channels/pagerduty_test.go @@ -56,7 +56,7 @@ func TestPagerdutyNotifier(t *testing.T) { Payload: pagerDutyPayload{ Summary: "[FIRING:1] (val1)", Source: hostname, - Severity: "critical", + Severity: defaultSeverity, Class: "default", Component: "Grafana", Group: "default", @@ -108,6 +108,50 @@ func TestPagerdutyNotifier(t *testing.T) { }, expMsgError: nil, }, + { + name: "Should expand templates in fields", + settings: `{ + "integrationKey": "abcdefgh0123456789", + "severity" : "{{ .CommonLabels.severity }}", + "class": "{{ .CommonLabels.class }}", + "component": "{{ .CommonLabels.component }}", + "group" : "{{ .CommonLabels.group }}", + "source": "{{ .CommonLabels.source }}", + "client": "client-{{ .CommonLabels.source }}", + "client_url": "http://localhost:20200/{{ .CommonLabels.group }}" + }`, + alerts: []*types.Alert{ + { + Alert: model.Alert{ + Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1", "severity": "critical", "class": "test-class", "group": "test-group", "component": "test-component", "source": "test-source"}, + Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh"}, + }, + }, + }, + expMsg: &pagerDutyMessage{ + RoutingKey: "abcdefgh0123456789", + DedupKey: "6e3538104c14b583da237e9693b76debbc17f0f8058ef20492e5853096cf8733", + EventAction: "trigger", + Payload: pagerDutyPayload{ + Summary: "[FIRING:1] (test-class test-component test-group val1 critical test-source)", + Source: "test-source", + Severity: "critical", + Class: "test-class", + Component: "test-component", + Group: "test-group", + CustomDetails: map[string]string{ + "firing": "\nValue: [no value]\nLabels:\n - alertname = alert1\n - class = test-class\n - component = test-component\n - group = test-group\n - lbl1 = val1\n - severity = critical\n - source = test-source\nAnnotations:\n - ann1 = annv1\nSilence: http://localhost/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dalert1&matcher=class%3Dtest-class&matcher=component%3Dtest-component&matcher=group%3Dtest-group&matcher=lbl1%3Dval1&matcher=severity%3Dcritical&matcher=source%3Dtest-source\nDashboard: http://localhost/d/abcd\nPanel: http://localhost/d/abcd?viewPanel=efgh\n", + "num_firing": "1", + "num_resolved": "0", + "resolved": "", + }, + }, + Client: "client-test-source", + ClientURL: "http://localhost:20200/test-group", + Links: []pagerDutyLink{{HRef: "http://localhost", Text: "External URL"}}, + }, + expMsgError: nil, + }, { name: "Default config with one alert and custom summary", settings: `{"integrationKey": "abcdefgh0123456789", "summary": "Alerts firing: {{ len .Alerts.Firing }}"}`, @@ -126,7 +170,7 @@ func TestPagerdutyNotifier(t *testing.T) { Payload: pagerDutyPayload{ Summary: "Alerts firing: 1", Source: hostname, - Severity: "critical", + Severity: defaultSeverity, Class: "default", Component: "Grafana", Group: "default", @@ -206,7 +250,7 @@ func TestPagerdutyNotifier(t *testing.T) { Payload: pagerDutyPayload{ Summary: fmt.Sprintf("%s…", strings.Repeat("1", 1023)), Source: hostname, - Severity: "critical", + Severity: defaultSeverity, Class: "default", Component: "Grafana", Group: "default", diff --git a/pkg/services/ngalert/notifier/channels_config/available_channels.go b/pkg/services/ngalert/notifier/channels_config/available_channels.go index f9b063bc022..400b8f202ff 100644 --- a/pkg/services/ngalert/notifier/channels_config/available_channels.go +++ b/pkg/services/ngalert/notifier/channels_config/available_channels.go @@ -1,11 +1,15 @@ package channels_config import ( + "os" + "github.com/grafana/grafana/pkg/services/ngalert/notifier/channels" ) // GetAvailableNotifiers returns the metadata of all the notification channels that can be configured. func GetAvailableNotifiers() []*NotifierPlugin { + hostname, _ := os.Hostname() + pushoverSoundOptions := []SelectOption{ { Value: "default", @@ -242,8 +246,8 @@ func GetAvailableNotifiers() []*NotifierPlugin { Label: "Severity", Element: ElementTypeInput, InputType: InputTypeText, - Placeholder: "critical", - Description: "Severity of the event. It must be critical, error, warning, info - otherwise, the default is set which is critical. You can use templates", + Placeholder: "error", + Description: "Severity of the event. It must be critical, error, warning, info - otherwise, the default is set which is error. You can use templates", PropertyName: "severity", }, { // New in 8.0. @@ -276,6 +280,30 @@ func GetAvailableNotifiers() []*NotifierPlugin { Placeholder: channels.DefaultMessageTitleEmbed, PropertyName: "summary", }, + { // New in 9.4. + Label: "Source", + Description: "The unique location of the affected system, preferably a hostname or FQDN. You can use templates", + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: hostname, + PropertyName: "source", + }, + { // New in 9.4. + Label: "Client", + Description: "The name of the monitoring client that is triggering this event. You can use templates", + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: "Grafana", + PropertyName: "client", + }, + { // New in 9.4. + Label: "Client URL", + Description: "The URL of the monitoring client that is triggering this event. You can use templates", + Element: ElementTypeInput, + InputType: InputTypeText, + Placeholder: "{{ .ExternalURL }}", + PropertyName: "client_url", + }, }, }, {