Skip to main content

generate-message-template

Generate or modify Nightingale (n9e) alert notification message templates. Use when the user asks to write a notification template, change the message format, add hostname/recovery value/severity, or create DingTalk/Feishu/Lark/email/SMS/voice templates.

معلومات المصدر

المستودع
ccfos/nightingale
آخر نشاط في المصدر
١ يوليو ٢٠٢٦ في ٠٤:٢٠
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١٣٬٣٢٨
التفرعات
١٬٧٨٤

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
generate-message-template
description
Generate or modify Nightingale (n9e) alert notification message templates. Use when the user asks to write a notification template, change the message format, add hostname/recovery value/severity, or create DingTalk/Feishu/Lark/email/SMS/voice templates.
tags
["internal"]
# 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: | key | type | description | |---|---|---| | `.events` | `[]*AlertCurEvent` | The list of alert events in the current batch, usually just 1 | | `.domain` | `string` | The n9e site URL, used to build redirect links | **Automatically injected shorthands** (no need to write by hand): ```gotemplate {{ $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 | field | type | description | |---|---|---| | `.Id` | int64 | Alert event ID (used to build the redirect link) | | `.RuleId` | int64 | Alert rule ID | | `.RuleName` | string | Rule name | | `.RuleNote` | string | Rule note | | `.Severity` | int | Alert severity: 1=Critical, 2=Warning, 3=Info | | `.PromQl` | string | Alert trigger expression | | `.RuleAlgo` | string | Rule algorithm type | | `.TriggerTime` | int64 | Trigger time, unix seconds | | `.TriggerValue` | string | Metric value at trigger time (already a string) | | `.FirstTriggerTime` | int64 | First abnormal time (for consecutive alerts) | | `.LastEvalTime` | int64 | Most recent evaluation time, **used as the recovery time on recovery** | | `.IsRecovered` | bool | Whether it has recovered | | `.NotifyCurNumber` | int | Which notification number this send is | | `.TargetIdent` | string | Monitored object (usually agent_hostname) | | `.TargetNote` | string | Object note | | `.GroupId` / `.GroupName` | int64 / string | Business group | | `.Cluster` | string | Data source cluster name | | `.Cate` | string | Data source type (prometheus / host / mysql / ...) | | `.RunbookUrl` | string | Runbook link | ### Labels / Annotations / Trigger Value Objects | field | type | description | |---|---|---| | `.TagsMap` | `map[string]string` | Event labels, preferred: `{{$labels.agent_hostname}}` | | `.TagsJSON` | `[]string` | A string array like `["k=v", ...]` (commonly used in early templates) | | `.AnnotationsJSON` | `map[string]string` | Annotations, commonly `.AnnotationsJSON.recovery_value` | | `.TriggerValuesJson.ValuesWithUnit` | map | Trigger values with units (multi-value scenarios) | ### Notification Objects | field | type | description | |---|---|---| | `.NotifyUsersObj` | `[]*User` | The user objects to notify this time (with Username/Nickname/Phone/Email) | | `.NotifyGroupsObj` | `[]*UserGroup` | Associated 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: | Ident | Engine | Description | |---|---|---| | `email` | `text/template` | No re-escaping; HTML templates can write tags directly | | `slackwebhook` / `slackbot` | `html/template` | After rendering, `"` / `\n` are escaped and wrapped into `template.HTML`; usually written in Markdown | | Others (`dingtalk` / `feishu` / `feishucard` / `larkcard` / `wecom` / `tx-sms` / `ali-voice` …) | `html/template` | After 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}}`. 4. **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` 5. **@-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. 6. **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 <template content> ``` 3. `**Variable explanation**`: list the non-trivial fields and functions used in the template (such as `$event.TargetIdent`, `formatDecimal`, `timeformat`), one per line. 4. If the user's request is ambiguous (for example "add the hostname" — is it `target_ident` or some tag), **state directly in the introduction what assumption you made**, rather than asking back. The language follows the user's input (use Chinese if the input is Chinese). --- ## Built-in Reference Templates (Starting Points for Customization) ### DingTalk markdown (full version) ```gotemplate #### {{if $event.IsRecovered}}<font color="#008800">💚{{$event.RuleName}}</font>{{else}}<font color="#FF0000">💔{{$event.RuleName}}</font>{{end}} --- {{$duration := sub now.Unix $event.FirstTriggerTime}}{{if $event.IsRecovered}}{{$duration = sub $event.LastEvalTime $event.FirstTriggerTime}}{{end}} - **Alert Level**: S{{$event.Severity}} {{- if $event.RuleNote}} - **Rule Note**: {{$event.RuleNote}} {{- end}} {{- if $event.TargetIdent}} - **Target**: {{$event.TargetIdent}} {{- end}} {{- if not $event.IsRecovered}} - **Trigger Value**: {{$event.TriggerValue}} - **Trigger Time**: {{timeformat $event.TriggerTime}} - **Duration**: {{humanizeDurationInterface $duration}} {{- else}} - **Recovery Time**: {{timeformat $event.LastEvalTime}} - **Duration**: {{humanizeDurationInterface $duration}} {{- end}} - **Event Tags**: {{- range $k, $v := $labels}} {{- if ne $k "rulename"}} - {{$k}}: {{$v}} {{- end}} {{- end}} [Event Detail]({{.domain}}/share/alert-his-events/{{$event.Id}}) | [Mute 1h]({{.domain}}/alert-mutes/add?__event_id={{$event.Id}}) ``` ### Feishu card (concise version) ```gotemplate {{- if $event.IsRecovered}} **Severity/State:** S{{$event.Severity}} Recovered **Alert Name:** {{$event.RuleName}} **Event Tags:** {{$event.TagsJSON}} **Recovery Time:** {{timeformat $event.LastEvalTime}} {{- else}} **Severity/State:** S{{$event.Severity}} Triggered **Alert Name:** {{$event.RuleName}} **Event Tags:** {{$event.TagsJSON}} **Trigger Time:** {{timeformat $event.TriggerTime}} **Trigger Value:** {{$event.TriggerValue}} {{- if $event.RuleNote}} **Alert Description:** {{$event.RuleNote}} {{- end}} {{- end}}
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub