Skills Development Nightingale Alert Message Templates

Nightingale Alert Message Templates

v20261022
generate-message-template
Generate or modify Nightingale (n9e) alert notification message templates using Go text/template syntax, including variables, helper functions, and channel-specific escaping for DingTalk, Feishu, email, SMS, and voice.
Get Skill
231 downloads
Overview

Nightingale (n9e) Notification Message Template Generation

Nightingale message templates use Go text/template / html/template syntax (email uses text/template, others use html/template and then escape). Users edit them on the "Notification Management → Message Templates" page; once saved they are referenced by notification rules, and when an alert fires the variables are substituted with rendered data and sent to each channel.

This skill focuses on writing/modifying the template fragment itself, and does not cover creating notification rules or channel configuration.


Render Context

The renderData passed in when the backend executes:

keytypedescription
.events[]*AlertCurEventThe list of alert events in the current batch, usually just 1
.domainstringThe n9e site URL, used to build redirect links

Automatically injected shorthands (no need to write by hand):

{{ $events := .events }}
{{ $event := index $events 0 }}
{{ $labels := $event.TagsMap }}
{{ $value := $event.TriggerValue }}

So inside the template you can directly use $event.xxx, $labels.agent_hostname, and $value.


Available $event Fields (*AlertCurEvent)

Common Fields

fieldtypedescription
.Idint64Alert event ID (used to build the redirect link)
.RuleIdint64Alert rule ID
.RuleNamestringRule name
.RuleNotestringRule note
.SeverityintAlert severity: 1=Critical, 2=Warning, 3=Info
.PromQlstringAlert trigger expression
.RuleAlgostringRule algorithm type
.TriggerTimeint64Trigger time, unix seconds
.TriggerValuestringMetric value at trigger time (already a string)
.FirstTriggerTimeint64First abnormal time (for consecutive alerts)
.LastEvalTimeint64Most recent evaluation time, used as the recovery time on recovery
.IsRecoveredboolWhether it has recovered
.NotifyCurNumberintWhich notification number this send is
.TargetIdentstringMonitored object (usually agent_hostname)
.TargetNotestringObject note
.GroupId / .GroupNameint64 / stringBusiness group
.ClusterstringData source cluster name
.CatestringData source type (prometheus / host / mysql / ...)
.RunbookUrlstringRunbook link

Labels / Annotations / Trigger Value Objects

fieldtypedescription
.TagsMapmap[string]stringEvent labels, preferred: {{$labels.agent_hostname}}
.TagsJSON[]stringA string array like ["k=v", ...] (commonly used in early templates)
.AnnotationsJSONmap[string]stringAnnotations, commonly .AnnotationsJSON.recovery_value
.TriggerValuesJson.ValuesWithUnitmapTrigger values with units (multi-value scenarios)

Notification Objects

fieldtypedescription
.NotifyUsersObj[]*UserThe user objects to notify this time (with Username/Nickname/Phone/Email)
.NotifyGroupsObj[]*UserGroupAssociated user groups
User objects are commonly used in DingTalk/Feishu/Lark templates to build @-mentions; see the ats family of helpers below.

Available Helper Functions (tplx.TemplateFuncMap)

Time

  • timeformat <unix> — defaults to "2006-01-02 15:04:05"; pass a second argument to override: {{timeformat $event.TriggerTime "15:04:05"}}
  • timestamp — current time string
  • now.Unix — current unix seconds (now is a Go template builtin)
  • humanizeDuration <sec> — "3m15s"
  • humanizeDurationInterface <interface> — same as above but accepts an interface
  • toTime <unix> — returns a time.Time, can be chained
  • parseDuration <"5m"> — returns a time.Duration

Numbers / Formatting

  • formatDecimal <v> <n> — keep n decimal places ({{formatDecimal $event.TriggerValue 2}})
  • humanize <v> — K/M/G units (base 1000, SI)
  • humanize1024 <v> — Ki/Mi/Gi (base 1024)
  • humanizePercentage <v> / humanizePercentageH <v> — percentage
  • add / sub / mul / div <a> <b> — arithmetic
  • printf "%.2f" <v> — Go fmt.Sprintf

Strings

  • toUpper / toLower / title — case conversion
  • contains <s> <sub> — substring
  • match <regex> <s> — regex match (bool)
  • reReplaceAll <regex> <repl> <s> — regex replace
  • split <s> <sep> / join <slice> <sep>
  • stripPort <host:port> / stripDomain <host.domain>
  • b64enc / b64dec — base64

Links / Escaping

  • escape <s> — URL path escape
  • unescaped <s> — output raw HTML (no escaping)
  • safeHtml <s> — same as above
  • urlconvert <s>

Labels / Trigger Values

  • label <key> <labelMap> / value <key> <m> / strvalue <v>
  • first <slice> — take the first
  • tagsMapToStr <map> — join labels into k=v,k=v
  • sortByLabel <items> <key> — sort by label

@-mention (DingTalk/Feishu/Lark only)

  • ats <users> <platform> — generate an at fragment
  • batchContactsAts <contacts> <platform> — batch at
  • batchContactsAtsInFeishuEmail <contacts> / batchContactsAtsInFeishuId <contacts> — Feishu only
  • batchContactsJoinComma <contacts> / batchContactsJsonMarshal <contacts>
  • mappingAndJoin <map> <kvSep> <itemSep>

Others

  • jsonMarshal <v> — serialize to a JSON string
  • mapDifference <a> <b> — set difference

Syntax Differences Across Channels (notify_channel_ident)

A message template is bound to a specific channel; the channel ident determines the text engine and escaping behavior:

IdentEngineDescription
emailtext/templateNo re-escaping; HTML templates can write tags directly
slackwebhook / slackbothtml/templateAfter rendering, " / \n are escaped and wrapped into template.HTML; usually written in Markdown
Others (dingtalk / feishu / feishucard / larkcard / wecom / tx-sms / ali-voice …)html/templateAfter rendering, " \n \r are JSON-string-escaped, suitable for stuffing directly into a webhook payload
Important: html/template automatically escapes < > &. Where you don't want escaping, use {{unescaped "…"}} or {{safeHtml .X}}, otherwise DingTalk will render a literal &lt;.

Template Writing Workflow

  1. Confirm the channel ident: when the user says "DingTalk" it is dingtalk, "Feishu card" is feishucard, "email" is email. Different channels differ significantly in style.
  2. Decide whether to render the recovery state: by default you should split into two branches on $event.IsRecovered. Only SMS/voice may omit it.
  3. Pick fields:
  • For labels, prefer $labels.<key> rather than $event.TagsJSON.
  • For the trigger value use $event.TriggerValue; for two decimal places use {{formatDecimal $event.TriggerValue 2}}.
  • Always pass timestamps through timeformat.
  • Build the redirect link as {{.domain}}/share/alert-his-events/{{$event.Id}}.
  1. Severity display:
  • Number: {{$event.Severity}}
  • Worded: {{if eq $event.Severity 1}}Critical{{else if eq $event.Severity 2}}Warning{{else}}Info{{end}}
  • English: Critical / Warning / Info
  1. @-mention (DingTalk/Feishu):
  • DingTalk @everyone: add a line @all at the end of the template (DingTalk matches by splitting on spaces). To at an exact phone number: {{range $event.NotifyUsersObj}}@{{.Phone}} {{end}}.
  • Feishu card: use {{batchContactsAtsInFeishuEmail $event.NotifyUsersObj}} to build <at email=...></at> fragments.
  1. Output: wrap the template body in a markdown `` `gotemplate `` code block, and at the end provide a variable/function explanation with each non-trivial variable/function on its own line.

Output Format

When replying to the user:

  1. One or two sentences of introduction explaining what the template is for and which channel it fits.
  2. ```gotemplate