Add option for resolved template

This introduces a "msg_template_resolved" option, allowing a custom
template for resolved messages to be defined. If the option is not
set, the existing "msg_template" will apply as before.
This allows users to define different templates for firing and
resolved events.

Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
This commit is contained in:
Georg Pfuetzenreuter 2024-01-23 23:57:29 +01:00
parent 2cb8078717
commit 486424e8d9
Signed by untrusted user: Georg
GPG Key ID: 1ED2F138E7E6FF57
4 changed files with 40 additions and 4 deletions

View File

@ -61,6 +61,9 @@ use_privmsg: yes
# #
# The formatting is based on golang's text/template . # The formatting is based on golang's text/template .
msg_template: "Alert {{ .Labels.alertname }} on {{ .Labels.instance }} is {{ .Status }}" msg_template: "Alert {{ .Labels.alertname }} on {{ .Labels.instance }} is {{ .Status }}"
# By default, firing and resolved messages use the template defined as msg_template.
# Define msg_template_resolved to define a different template for resolved messages.
# msg_template_resolved: "Resolved: {{ .Labels.alertname }} on {{ .Labels.instance }}"
# Note: When sending only one message per alert group the default # Note: When sending only one message per alert group the default
# msg_template is set to # msg_template is set to
# "Alert {{ .GroupLabels.alertname }} for {{ .GroupLabels.job }} is {{ .Status }}" # "Alert {{ .GroupLabels.alertname }} for {{ .GroupLabels.job }} is {{ .Status }}"

View File

@ -45,6 +45,7 @@ type Config struct {
IRCVerifySSL bool `yaml:"irc_verify_ssl"` IRCVerifySSL bool `yaml:"irc_verify_ssl"`
IRCChannels []IRCChannel `yaml:"irc_channels"` IRCChannels []IRCChannel `yaml:"irc_channels"`
MsgTemplate string `yaml:"msg_template"` MsgTemplate string `yaml:"msg_template"`
MsgTemplateResolved string `yaml:"msg_template_resolved"`
MsgOnce bool `yaml:"msg_once_per_alert_group"` MsgOnce bool `yaml:"msg_once_per_alert_group"`
UsePrivmsg bool `yaml:"use_privmsg"` UsePrivmsg bool `yaml:"use_privmsg"`
AlertBufferSize int `yaml:"alert_buffer_size"` AlertBufferSize int `yaml:"alert_buffer_size"`
@ -99,6 +100,9 @@ func LoadConfig(configFile string) (*Config, error) {
config.MsgTemplate = defaultMsgTemplate config.MsgTemplate = defaultMsgTemplate
} }
} }
if config.MsgTemplateResolved == "" {
config.MsgTemplateResolved = config.MsgTemplate
}
loadedConfig, _ := yaml.Marshal(config) loadedConfig, _ := yaml.Marshal(config)
logging.Debug("Loaded config:\n%s", loadedConfig) logging.Debug("Loaded config:\n%s", loadedConfig)

View File

@ -27,6 +27,7 @@ import (
type Formatter struct { type Formatter struct {
MsgTemplate *template.Template MsgTemplate *template.Template
MsgTemplateResolved *template.Template
MsgOnce bool MsgOnce bool
} }
@ -44,16 +45,27 @@ func NewFormatter(config *Config) (*Formatter, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
tmplresolved, err := template.New("msg").Funcs(funcMap).Parse(config.MsgTemplateResolved)
if err != nil {
return nil, err
}
return &Formatter{ return &Formatter{
MsgTemplate: tmpl, MsgTemplate: tmpl,
MsgTemplateResolved: tmplresolved,
MsgOnce: config.MsgOnce, MsgOnce: config.MsgOnce,
}, nil }, nil
} }
func (f *Formatter) FormatMsg(ircChannel string, data interface{}) []string { func (f *Formatter) FormatMsg(ircChannel string, data interface{}, status string) []string {
output := bytes.Buffer{} output := bytes.Buffer{}
var msg string var msg string
if err := f.MsgTemplate.Execute(&output, data); err != nil { var msgtemplate *template.Template
if status == "resolved" {
msgtemplate = f.MsgTemplateResolved
} else {
msgtemplate = f.MsgTemplate
}
if err := msgtemplate.Execute(&output, data); err != nil {
msg_bytes, _ := json.Marshal(data) msg_bytes, _ := json.Marshal(data)
msg = string(msg_bytes) msg = string(msg_bytes)
logging.Error("Could not apply msg template on alert (%s): %s", logging.Error("Could not apply msg template on alert (%s): %s",
@ -75,13 +87,13 @@ func (f *Formatter) GetMsgsFromAlertMessage(ircChannel string,
data *promtmpl.Data) []AlertMsg { data *promtmpl.Data) []AlertMsg {
msgs := []AlertMsg{} msgs := []AlertMsg{}
if f.MsgOnce { if f.MsgOnce {
for _, msg := range f.FormatMsg(ircChannel, data) { for _, msg := range f.FormatMsg(ircChannel, data, data.Status) {
msgs = append(msgs, msgs = append(msgs,
AlertMsg{Channel: ircChannel, Alert: msg}) AlertMsg{Channel: ircChannel, Alert: msg})
} }
} else { } else {
for _, alert := range data.Alerts { for _, alert := range data.Alerts {
for _, msg := range f.FormatMsg(ircChannel, alert) { for _, msg := range f.FormatMsg(ircChannel, alert, data.Status) {
msgs = append(msgs, msgs = append(msgs,
AlertMsg{Channel: ircChannel, Alert: msg}) AlertMsg{Channel: ircChannel, Alert: msg})
} }

View File

@ -133,3 +133,20 @@ func TestMultilineTemplates(t *testing.T) {
CreateFormatterAndCheckOutput(t, &testingConfig, expectedAlertMsgs) CreateFormatterAndCheckOutput(t, &testingConfig, expectedAlertMsgs)
} }
func TestResolvedTemplate(t *testing.T) {
testingConfig := Config{
MsgTemplateResolved: "Resolved: {{ .Labels.alertname }}",
}
expectedAlertMsgs := []AlertMsg{
AlertMsg{
Channel: "#somechannel",
Alert: "Resolved: airDown",
},
AlertMsg{
Channel: "#somechannel",
Alert: "Resolved: airDown",
},
}
CreateFormatterAndCheckOutput(t, &testingConfig, expectedAlertMsgs)
}