From fb62660df79b30f29c7866c6420767d3d66c6068 Mon Sep 17 00:00:00 2001 From: Alex Moreno Date: Thu, 27 Oct 2022 16:12:14 +0200 Subject: [PATCH] Alerting: Add title and description to VictorOps contact point (#57458) * Add title and description to VictorOps contact point * Update pkg/services/ngalert/notifier/channels_config/available_channels.go Co-authored-by: Santiago Co-authored-by: Santiago --- .../ngalert/notifier/channels/victorops.go | 33 ++++++++++++------- .../notifier/channels/victorops_test.go | 25 ++++++++++++++ .../channels_config/available_channels.go | 16 +++++++++ 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/pkg/services/ngalert/notifier/channels/victorops.go b/pkg/services/ngalert/notifier/channels/victorops.go index e71d01552d8..f8b5066a4cf 100644 --- a/pkg/services/ngalert/notifier/channels/victorops.go +++ b/pkg/services/ngalert/notifier/channels/victorops.go @@ -31,6 +31,8 @@ const ( type victorOpsSettings struct { URL string `json:"url,omitempty" yaml:"url,omitempty"` MessageType string `json:"messageType,omitempty" yaml:"messageType,omitempty"` + Title string `json:"title,omitempty" yaml:"title,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` } func buildVictorOpsSettings(fc FactoryConfig) (victorOpsSettings, error) { @@ -45,6 +47,12 @@ func buildVictorOpsSettings(fc FactoryConfig) (victorOpsSettings, error) { if settings.MessageType == "" { settings.MessageType = victoropsAlertStateCritical } + if settings.Title == "" { + settings.Title = DefaultMessageTitleEmbed + } + if settings.Description == "" { + settings.Description = DefaultMessageEmbed + } return settings, nil } @@ -101,15 +109,7 @@ func (vn *VictoropsNotifier) Notify(ctx context.Context, as ...*types.Alert) (bo var tmplErr error tmpl, _ := TmplText(ctx, vn.tmpl, as, vn.log, &tmplErr) - messageType := strings.ToUpper(tmpl(vn.settings.MessageType)) - if messageType == "" { - vn.log.Warn("expansion of message type template resulted in an empty string. Using fallback", "fallback", victoropsAlertStateCritical, "template", vn.settings.MessageType) - messageType = victoropsAlertStateCritical - } - alerts := types.Alerts(as...) - if alerts.Status() == model.AlertResolved { - messageType = victoropsAlertStateRecovery - } + messageType := buildMessageType(vn.log, tmpl, vn.settings.MessageType, as...) groupKey, err := notify.ExtractGroupKey(ctx) if err != nil { @@ -119,9 +119,9 @@ func (vn *VictoropsNotifier) Notify(ctx context.Context, as ...*types.Alert) (bo bodyJSON := map[string]interface{}{ "message_type": messageType, "entity_id": groupKey.Hash(), - "entity_display_name": tmpl(DefaultMessageTitleEmbed), + "entity_display_name": tmpl(vn.settings.Title), "timestamp": time.Now().Unix(), - "state_message": tmpl(DefaultMessageEmbed), + "state_message": tmpl(vn.settings.Description), "monitoring_tool": "Grafana v" + setting.BuildVersion, } @@ -169,3 +169,14 @@ func (vn *VictoropsNotifier) Notify(ctx context.Context, as ...*types.Alert) (bo func (vn *VictoropsNotifier) SendResolved() bool { return !vn.GetDisableResolveMessage() } + +func buildMessageType(l log.Logger, tmpl func(string) string, msgType string, as ...*types.Alert) string { + if types.Alerts(as...).Status() == model.AlertResolved { + return victoropsAlertStateRecovery + } + if messageType := strings.ToUpper(tmpl(msgType)); messageType != "" { + return messageType + } + l.Warn("expansion of message type template resulted in an empty string. Using fallback", "fallback", victoropsAlertStateCritical, "template", msgType) + return victoropsAlertStateCritical +} diff --git a/pkg/services/ngalert/notifier/channels/victorops_test.go b/pkg/services/ngalert/notifier/channels/victorops_test.go index a85eb7c659a..7b7574d7cc6 100644 --- a/pkg/services/ngalert/notifier/channels/victorops_test.go +++ b/pkg/services/ngalert/notifier/channels/victorops_test.go @@ -104,6 +104,31 @@ func TestVictoropsNotifier(t *testing.T) { "state_message": "**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\n\nValue: [no value]\nLabels:\n - alertname = alert1\n - lbl1 = val2\nAnnotations:\n - ann1 = annv2\nSilence: http://localhost/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dalert1&matcher=lbl1%3Dval2\n", }, expMsgError: nil, + }, { + name: "Custom title and description", + settings: `{"url": "http://localhost", "title": "Alerts firing: {{ len .Alerts.Firing }}", "description": "customDescription"}`, + alerts: []*types.Alert{ + { + Alert: model.Alert{ + Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"}, + Annotations: model.LabelSet{"ann1": "annv1"}, + }, + }, { + Alert: model.Alert{ + Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val2"}, + Annotations: model.LabelSet{"ann1": "annv2"}, + }, + }, + }, + expMsg: map[string]interface{}{ + "alert_url": "http://localhost/alerting/list", + "entity_display_name": "Alerts firing: 2", + "entity_id": "6e3538104c14b583da237e9693b76debbc17f0f8058ef20492e5853096cf8733", + "message_type": "CRITICAL", + "monitoring_tool": "Grafana v" + setting.BuildVersion, + "state_message": "customDescription", + }, + expMsgError: nil, }, { name: "Missing field in template", settings: `{"url": "http://localhost", "messageType": "custom template {{ .NotAField }} bad template"}`, diff --git a/pkg/services/ngalert/notifier/channels_config/available_channels.go b/pkg/services/ngalert/notifier/channels_config/available_channels.go index bbf333b5caf..622dc0b0ae2 100644 --- a/pkg/services/ngalert/notifier/channels_config/available_channels.go +++ b/pkg/services/ngalert/notifier/channels_config/available_channels.go @@ -311,6 +311,22 @@ func GetAvailableNotifiers() []*NotifierPlugin { }, }, }, + { // New in 9.3. + Label: "Title", + Element: ElementTypeInput, + InputType: InputTypeText, + Description: "Templated title to display", + PropertyName: "title", + Placeholder: channels.DefaultMessageTitleEmbed, + }, + { // New in 9.3. + Label: "Description", + Element: ElementTypeInput, + InputType: InputTypeText, + Description: "Templated description of the message", + PropertyName: "description", + Placeholder: channels.DefaultMessageEmbed, + }, }, }, {