本文介紹夜鶯開源項目(Nightingale)的模板函數,夜鶯內置了很多模板函數,可以對告警事件做一些渲染調整,方便 On-call 人員根據告警事件處理告警。
本文大綱:
- 夜鶯開源項目簡介
- 夜鶯模板函數用途場景
- 夜鶯模板函數分類
- 附加查詢函數
- 格式化函數
- 字符串處理函數
- 時間處理函數
- 數學運算函數
- 數據處理函數
夜鶯項目簡介
夜鶯監控(Nightingale)是一款側重告警的監控類開源項目。類似 Grafana 的數據源集成方式,夜鶯也是對接多種既有的數據源,不過 Grafana 側重在可視化,夜鶯是側重在告警引擎、告警事件的處理和分發。
夜鶯監控項目,最初由滴滴開發和開源,並於 2022 年 5 月 11 日,捐贈予中國計算機學會開源發展委員會(CCF ODC),為 CCF ODC 成立後接受捐贈的第一個開源項目。
其開源倉庫地址:
- 代碼:https://github.com/ccfos/nightingale
- 文檔:https://n9e.github.io/
夜鶯模板函數用途場景
夜鶯項目中有兩個地方會用到模板:
- 告警規則。在告警規則的備註、附加信息等字段裏可以使用 go template 自定義字段內容
- 消息模板。在把告警發給各個通知媒介時,不同的媒介會有不同的要求,比如郵件內容是 HTML 格式,釘釘機器人是 Markdown,此時也需要使用 go template 模板來渲染內容
這兩個地方支持的模板函數是相同的。只是可以引用的字段略有差異。這裏我們以告警規則為例,説明各個模板函數的用途。
夜鶯模板函數分類
夜鶯模板函數大致可以分為:
- 附加查詢函數
- 格式化函數
- 字符串處理函數
- 時間處理函數
- 數學運算函數
- 數據處理函數
附加查詢函數
query
功能描述:執行 Prometheus 查詢並返回結果。這是一個特殊的模板函數,用於在告警註解中動態查詢指標數據。
函數簽名:
func(promql string, param ...int64) QueryResult
參數説明:
promql: Prometheus 查詢語句param: 可選參數,指定數據源 ID。如果不指定,使用當前告警規則的數據源
返回值:QueryResult 類型,包含查詢結果的樣本數據,每個樣本包含:
Labels: map[string]string 類型的標籤集合Value: float64 類型的數值
使用示例:
-
查詢監控指標
{{ $metrics := query "mem_available_percent" }} {{ range $metrics }} 機器: {{ .Labels.ident }} 內存使用率: {{ .Value }} {{ end }}可以在告警規則的附加信息中,使用此模板函數來實現告警時查詢額外信息的需求
-
查詢監控指標時,使用告警事件某個標籤過濾
{{ $memMetrics := query (printf "mem_available_percent{ident=\"%s\"}" .TagsMap.ident) }} {{ range $memMetrics }} 機器: {{ .Labels.ident }} 內存使用率: {{ .Value }} {{ end }}
格式化函數
humanize
功能描述:將數字格式化為人類可讀的形式,使用 SI 前綴(k, M, G, T 等)
使用示例:
{{ "1234567" | humanize }} // 輸出: 1.23M
{{ "0.00123" | humanize }} // 輸出: 1.23m
{{ "1000000000" | humanize }} // 輸出: 1.00G
humanize1024
功能描述:將數字格式化為人類可讀的形式,使用二進制前綴(Ki, Mi, Gi, Ti 等)
使用示例:
{{ "1048576" | humanize1024 }} // 輸出: 1Mi
{{ "1073741824" | humanize1024 }} // 輸出: 1Gi
{{ "2048" | humanize1024 }} // 輸出: 2ki
humanizeDuration
功能描述:將秒數轉換為人類可讀的時間格式
使用示例:
{{ "3661" | humanizeDuration }} // 輸出: 1h 1m 1s
{{ "86400" | humanizeDuration }} // 輸出: 1d 0h 0m 0s
{{ "0.5" | humanizeDuration }} // 輸出: 500ms
humanizePercentage
功能描述:將小數轉換為百分比格式(乘以100)
使用示例:
{{ "0.8567" | humanizePercentage }} // 輸出: 85.67%
{{ "0.05" | humanizePercentage }} // 輸出: 5.00%
{{ "1" | humanizePercentage }} // 輸出: 100.00%
humanizePercentageH
功能描述:直接格式化為百分比(不乘以100)
使用示例:
{{ "85.67" | humanizePercentageH }} // 輸出: 85.67%
{{ "5" | humanizePercentageH }} // 輸出: 5.00%
{{ "100" | humanizePercentageH }} // 輸出: 100.00%
formatDecimal
功能描述:格式化數字為指定小數位數
使用示例:
{{ formatDecimal "3.14159" 2 }} // 輸出: 3.14
{{ formatDecimal "10.5" 3 }} // 輸出: 10.500
{{ formatDecimal "0.123456" 4 }} // 輸出: 0.1235
printf
功能描述:格式化輸出字符串,特別優化了對字符串數字的處理(會自動嘗試將字符串轉換為浮點數)
函數簽名:
func Printf(format string, value interface{}) string
特點:
- 如果傳入的是字符串類型的數字,會自動轉換為浮點數進行格式化
- 支持標準的 Go 格式化佔位符
使用示例:
// 格式化浮點數(字符串會自動轉換)
{{ printf "%.2f" "3.14159" }} // 輸出: 3.14
{{ printf "%.2f" .TriggerValue }} // 將觸發值格式化為2位小數
// 百分比格式化
{{ printf "%.1f%%" "85.67" }} // 輸出: 85.7%
{{ printf "使用率: %.2f%%" .TriggerValue }} // 輸出: 使用率: 85.67%
// 科學計數法
{{ printf "%e" "1234567" }} // 輸出: 1.234567e+06
{{ printf "%.2e" .TriggerValue }} // 輸出: 8.57e+01
// 整數格式化(需要注意類型)
{{ printf "%d" 42 }} // 輸出: 42
// 字符串格式化
{{ printf "主機 %s 告警" .TagsMap.hostname }} // 輸出: 主機 server01 告警
// 組合使用
{{ printf "[%s] %.2f%% (閾值: %.0f%%)" .RuleName .TriggerValue 80.0 }}
// 輸出: [CPU告警] 85.67% (閾值: 80%)
字符串處理函數
escape
功能描述:URL 路徑轉義
使用示例:
{{ "hello world" | escape }} // 輸出: hello%20world
{{ "a/b/c" | escape }} // 輸出: a%2Fb%2Fc
unescaped
功能描述:將字符串作為 HTML 輸出(不轉義)
使用示例:
{{ "<b>Bold Text</b>" | unescaped }} // 輸出原始HTML: <b>Bold Text</b>
{{ "<script>alert('hi')</script>" | unescaped }} // 輸出原始腳本標籤
urlconvert
功能描述:將字符串轉換為 URL 類型
使用示例:
{{ "http://example.com" | urlconvert }} // 轉換為URL類型
toUpper
功能描述:轉換為大寫
使用示例:
{{ "hello world" | toUpper }} // 輸出: HELLO WORLD
{{ .TagsMap.env | toUpper }} // 將標籤值轉為大寫
toLower
功能描述:轉換為小寫
使用示例:
{{ "HELLO WORLD" | toLower }} // 輸出: hello world
{{ .TagsMap.DC | toLower }} // 將標籤值轉為小寫
title
功能描述:將字符串轉換為標題格式(首字母大寫)
使用示例:
{{ "hello world" | title }} // 輸出: Hello World
{{ "api_server" | title }} // 輸出: Api_Server
contains
功能描述:檢查字符串是否包含子串
使用示例:
{{ if contains "hello world" "world" }}包含{{ end }} // 輸出: 包含
{{ if contains .TagsMap.service "api" }}是API服務{{ end }}
match
功能描述:正則表達式匹配
使用示例:
{{ if match "^prod-.*" .TagsMap.env }}生產環境{{ end }}
{{ if match "[0-9]+" "abc123" }}包含數字{{ end }}
reReplaceAll
功能描述:正則表達式替換
使用示例:
{{ reReplaceAll "[0-9]+" "X" "abc123def456" }} // 輸出: abcXdefX
{{ reReplaceAll "\\s+" "-" "hello world" }} // 輸出: hello-world
split
功能描述:字符串分割
使用示例:
{{ split "a,b,c" "," }} // 返回: ["a", "b", "c"]
{{ range .TagsJSON }}
標籤: {{ . }}
{{ end }}
join
功能描述:字符串連接
使用示例:
{{ join (split "a,b,c" ",") "-" }} // 輸出: a-b-c
{{ $arr := args "hello" "world" }}
{{ join $arr " " }} // 輸出: hello world
toString
功能描述:將任意類型轉換為字符串
使用示例:
{{ toString 123 }} // 輸出: "123"
{{ toString 3.14 }} // 輸出: "3.14"
{{ toString .Value }} // 將數值轉為字符串
時間處理函數
timeformat
功能描述:格式化 Unix 時間戳
使用示例:
{{ timeformat 1609459200 }} // 輸出: 2021-01-01 00:00:00
{{ timeformat 1609459200 "2006-01-02" }} // 輸出: 2021-01-01
{{ timeformat .Timestamp "15:04:05" }} // 輸出時間部分
timestamp
功能描述:獲取當前時間的格式化字符串
使用示例:
{{ timestamp }} // 輸出: 2024-01-15 10:30:45
{{ timestamp "2006-01-02" }} // 輸出: 2024-01-15
{{ timestamp "15:04:05" }} // 輸出: 10:30:45
now
功能描述:獲取當前時間對象
使用示例:
{{ now }} // 返回當前時間對象
{{ now.Format "2006-01-02" }} // 格式化當前時間
{{ now.Unix }} // 獲取Unix時間戳
toTime
功能描述:將時間戳轉換為時間對象
使用示例:
{{ $t := toTime 1609459200 }}
{{ $t.Format "2006-01-02" }} // 輸出: 2021-01-01
parseDuration
功能描述:解析時間持續時間字符串
使用示例:
{{ parseDuration "1h30m" }} // 返回: 5400 (秒)
{{ parseDuration "24h" }} // 返回: 86400 (秒)
{{ parseDuration "5m" }} // 返回: 300 (秒)
數學運算函數
add
功能描述:加法運算
使用示例:
{{ add 10 20 }} // 輸出: 30
sub
功能描述:減法運算
使用示例:
{{ sub 100 30 }} // 輸出: 70
mul
功能描述:乘法運算
使用示例:
{{ mul 10 5 }} // 輸出: 50
div
功能描述:除法運算
使用示例:
{{ div 100 5 }} // 輸出: 20
數據處理函數
first
功能描述:獲取查詢結果的第一個元素
函數簽名:
func(v QueryResult) (*sample, error)
使用示例:
{{ $result := query "up" }}
{{ with first $result }}
第一個實例: {{ label "instance" . }} 狀態: {{ value . }}
{{ end }}
// 注意:在 AlertCurEvent 上下文中訪問標籤應使用 TagsMap
第一個觸發的主機: {{ .TagsMap.hostname }}
label
功能描述:獲取查詢結果樣本的標籤值(用於 query 函數返回的 QueryResult的單個 sample )
函數簽名:
func(label string, s *sample) string
使用示例:
{{ $result := query "up" }}
{{ range $result }}
主機名: {{ label "hostname" . }}
環境: {{ label "env" . }}
{{ end }}
value
功能描述:獲取查詢結果樣本的數值(用於 query 函數返回的 QueryResult 的單個 sample)
函數簽名:
func(s *sample) float64
使用示例:
{{ $result := query "cpu_usage" }}
{{ range $result }}
CPU使用率: {{ value . }}%
{{ end }}
模板渲染上下文(AlertCurEvent)
在告警規則的註解和通知模板渲染時,模板引擎會傳入 AlertCurEvent 對象作為上下文。你可以直接訪問該對象的所有字段。
預定義變量
模板開始時會自動定義以下便捷變量:
$labels: 等同於.TagsMap,包含所有標籤的鍵值對$value: 等同於.TriggerValue,觸發告警的值$annotations: 等同於.AnnotationsJSON,註解的鍵值對(僅在某些場景可用)
AlertCurEvent 主要字段
| 字段 | 類型 | 説明 | 使用示例 | |
|---|---|---|---|---|
.Id |
int64 | 告警事件ID | 告警ID: {{ .Id }} |
|
.Cate |
string | 告警類別 | 類別: {{ .Cate }} |
|
.Cluster |
string | 集羣名稱 | 集羣: {{ .Cluster }} |
|
.DatasourceId |
int64 | 數據源ID | 數據源: {{ .DatasourceId }} |
|
.GroupId |
int64 | 業務組ID | 業務組ID: {{ .GroupId }} |
|
.GroupName |
string | 業務組名稱 | 業務組: {{ .GroupName }} |
|
.RuleId |
int64 | 規則ID | 規則ID: {{ .RuleId }} |
|
.RuleName |
string | 規則名稱 | 規則: {{ .RuleName }} |
|
.RuleNote |
string | 規則備註 | 備註: {{ .RuleNote }} |
|
.RuleProd |
string | 規則產品線 | 產品線: {{ .RuleProd }} |
|
.RuleAlgo |
string | 規則算法 | 算法: {{ .RuleAlgo }} |
|
.Severity |
int | 告警級別(1-3) | {{ if eq .Severity 1 }}P1級告警{{ end }} |
|
.PromQl |
string | PromQL查詢語句 | 查詢: {{ .PromQl }} |
|
.PromForDuration |
int | 持續時間閾值(秒) | 持續: {{ .PromForDuration }}秒 |
|
.PromEvalInterval |
int | 評估間隔(秒) | 評估間隔: {{ .PromEvalInterval }}秒 |
|
.RunbookUrl |
string | 運維手冊URL | <a href="{{ .RunbookUrl }}">運維手冊</a> |
|
.TargetIdent |
string | 目標標識 | 目標: {{ .TargetIdent }} |
|
.TargetNote |
string | 目標備註 | {{ .TargetNote }} |
|
.TriggerTime |
int64 | 觸發時間戳 | {{ .TriggerTime \ | timeformat }} |
.TriggerValue |
string | 觸發值 | 當前值: {{ .TriggerValue }} |
|
.TagsMap |
map[string]string | 標籤鍵值對 | 主機: {{ .TagsMap.hostname }} |
|
.TagsJSON |
[]string | 標籤數組 | {{ range .TagsJSON }}{{ . }} {{ end }} |
|
.AnnotationsJSON |
map[string]string | 註解鍵值對 | {{ .AnnotationsJSON.description }} |
|
.NotifyChannels |
[]string | 通知渠道 | {{ range .NotifyChannelsJSON }}{{ . }}{{ end }} |
|
.NotifyGroups |
[]string | 通知組 | {{ range .NotifyGroupsJSON }}{{ . }}{{ end }} |
|
.NotifyCurNumber |
int | 當前通知次數 | 第{{ .NotifyCurNumber }}次通知 |
|
.FirstTriggerTime |
int64 | 首次觸發時間 | 首次告警: {{ .FirstTriggerTime \ timeformat }} | |
.Claimant |
string | 認領人 | 認領人: {{ .Claimant }} |
使用示例
// 基礎信息訪問
告警名稱:{{ .RuleName }}
告警級別:{{ if eq .Severity 1 }}P1{{ else if eq .Severity 2 }}P2{{ else }}P3{{ end }}
業務組:{{ .GroupName }}
觸發時間:{{ .TriggerTime | timeformat "2006-01-02 15:04:05" }}
當前值:{{ .TriggerValue | humanize }}
// 使用預定義變量
主機名:{{ $labels.ident }}
當前值:{{ $value | humanizePercentage }}
// 條件判斷
{{ if gt (toFloat64 .TriggerValue) 80 }}
嚴重:使用率超過80%
{{ else if gt (toFloat64 .TriggerValue) 60 }}
警告:使用率超過60%
{{ end }}
// 遍歷標籤
{{ range $k, $v := .TagsMap }}
{{ $k }}: {{ $v }}
{{ end }}
// 訪問註解
描述:{{ .AnnotationsJSON.description }}
摘要:{{ .AnnotationsJSON.summary }}