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
ソースの最終更新活動
2026年7月1日 04:20
検出された SKILL.md の言語
英語
スター
13,359
フォーク
1,786

インストール方法

デフォルトでは、最初にソースを確認する 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で見る