Alerting: PagerDuty receiver to let user configure fields Source, Client and Client URL (#59895)

* add support for source field
* add client_url
* use real host name for source placeholder
This commit is contained in:
Yuri Tseretyan
2022-12-08 11:49:27 -05:00
committed by GitHub
parent 64ccbf0a98
commit 316870c658
3 changed files with 97 additions and 13 deletions
@@ -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())
}
@@ -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",
@@ -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",
},
},
},
{