news 2026/9/19 16:42:59

OneUptime 监控告警模板引擎:用 `{{variable}}` 占位符动态生成 Incident 与 Alert

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OneUptime 监控告警模板引擎:用 `{{variable}}` 占位符动态生成 Incident 与 Alert

OneUptime 监控告警模板引擎:用{{variable}}占位符动态生成 Incident 与 Alert

【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime

当监控条件(Criteria)命中并自动创建 Incident(事件)或 Alert(告警)时,如果标题、描述与修复备注(Remediation Notes)是固定文案,排查效率会大打折扣——你需要在几千条告警里逐条打开才能知道哪台机器、哪个接口、什么状态码出了问题。OneUptime 提供了一套与监控 Criteria 中 JavaScript 表达式同源的{{variable}}占位符模板语法,在事件/告警自动创建时动态填充真实的监控数据(响应码、响应时间、CPU 使用率、SSL 证书信息、OID 值等)。读完本文,你将掌握每种监控类型可用的模板变量、基础与进阶模板写法(含{{#each}}数组循环)、以及模板底层的存储映射与渲染实现原理。

模板语法概览

OneUptime 的模板语法复用了监控 Criteria 中 JavaScript 表达式所使用的{{variable}}占位符标记。在监控条件实例(Criteria Instance)内的Incident/Alerta 表单中,你可以把标题(Title)、描述(Description)和修复备注(Remediation Notes)写成模板字符串,当条件触发并自动创建事件/告警时,系统会以该次监控的真实结果填充占位符。

从源码结构看,这一能力由 Common/Server/Utils/Monitor/MonitorTemplateUtil.ts 的processTemplateString承载,其内部调用 Common/Server/Utils/VM/VMAPI.ts 的replaceValueInPlace完成替换:

  • buildTemplateStorageMap根据监控类型,把监控响应数据组装成一个扁平/嵌套的存储映射(Storage Map,JSON 对象),例如 API 监控得到responseBodyresponseStatusCoderesponseTimeInMs等键;
  • processTemplateString把模板字符串与存储映射交给VMUtil.replaceValueInPlace,用正则/{{(.*?)}}/g逐个匹配占位符,通过deepFind按点分路径取值并回填。

Incident 侧的实际调用位于 Common/Server/Utils/Monitor/MonitorIncident.ts,它先buildTemplateStorageMap生成存储映射,再对criteriaIncident.titlecriteriaIncident.description执行processTemplateString,最后由SeriesContextEnricher补充序列标签信息后落库。Alert 侧的渲染逻辑与 Incident 完全对齐(源码注释明确指出二者必须一致,否则同一告警会因触发对象不同而呈现出不同描述)。

支持模板的监控类型与变量全集

以下监控类型支持动态模板,各自暴露不同的变量集合:

  • 网站与 API 监控:响应数据、响应头、状态码、响应时间
  • 请求入站(Incoming Request)监控:请求数据、请求头、请求方法、时间
  • Ping 监控:连通性状态、响应时间、失败原因
  • 端口监控:端口连通性、响应时间、超时状态
  • IP 监控:IP 可达性、Ping 时间、失败信息
  • SSL 证书监控:证书详情、校验状态、过期信息
  • 服务器/VM 监控:系统指标(CPU、内存、磁盘)、进程、主机名
  • 合成(Synthetic)监控:脚本执行结果、截图、浏览器详情
  • 自定义 JavaScript 代码监控:执行结果、耗时、错误消息
  • SNMP 监控:设备状态、响应时间、OID 值

注意:日志(Logs)、链路(Traces)与指标(Metrics)监控目前不支持Incident/Alert 模板,因为它们使用不同的触发机制。

网站与 API 监控变量

变量说明类型
responseBody响应体对象;HTML/XML 时为字符串,JSON 时为 JSON 对象stringJSON
responseHeaders响应头对象(键为小写)Dictionary<string>
responseStatusCode响应的 HTTP 状态码number
responseTimeInMs响应时间(毫秒)number
isOnline监控是否被认为在线boolean

对应的存储映射构建逻辑见 MonitorTemplateUtil.ts:其中responseBody会优先尝试JSON.parse解析为对象,解析失败则保留原始字符串;responseStatusCode取自responseCode字段。

请求入站(Incoming Request)监控变量

变量说明类型
requestBody请求体对象stringJSON
requestHeaders请求头对象(键为小写)Dictionary<string>
requestMethod入站请求的 HTTP 方法(GET、POST 等)string
incomingRequestReceivedAt收到入站请求的日期时间Date

按负载字段分组(Group incidents and alerts by a payload field):当 Criteria 启用了按负载字段分组的选项后,提取出的分组键也会作为模板变量可用,变量名取自分组路径的最后一个段。例如按requestBody.alerts[*].labels.alertname分组,你会得到{{alertname}};按requestBody.alerts[*].fingerprint分组,会得到{{fingerprint}}。完整requestBody仍然可用。

注意[*]只在分组路径字段本身中可理解——这里不会解析它,因此该标记会被原样打印(含花括号)。在标题或描述中,{{requestBody.alerts[0].annotations.summary}}始终读取负载中的第一条告警,而非为它创建 Incident 的那一条。请改用分组变量以及负载的共享字段(commonLabelscommonAnnotations)。可参考 入站请求监控文档。

Ping 监控变量

变量说明类型
isOnlinePing 目标是否被认为在线boolean
responseTimeInMsPing 响应时间(毫秒)number
failureCausePing 失败的原因string
isTimeoutPing 请求是否超时boolean

端口监控变量

变量说明类型
isOnline端口是否在线/可访问boolean
responseTimeInMs连接响应时间(毫秒)number
failureCause端口检查失败的原因string
isTimeout端口连接是否超时boolean

IP 监控变量

变量说明类型
isOnlineIP 地址是否被认为在线boolean
responseTimeInMsPing 响应时间(毫秒)number
failureCauseIP 检查失败的原因string
isTimeoutIP Ping 请求是否超时boolean

SSL 证书监控变量

变量说明类型
isOnlineSSL 证书校验是否成功boolean
isSelfSigned证书是否自签名boolean
createdAt证书创建日期Date
expiresAt证书过期日期Date
commonName证书通用名(CN)string
organizationalUnit组织单位(OU)string
organization组织(O)string
locality地点(L)string
state州/省(ST)string
country国家(C)string
serialNumber证书序列号string
fingerprint证书 SHA-1 指纹string
fingerprint256证书 SHA-256 指纹string
failureCauseSSL 校验失败的原因string

这些字段直接取自探针返回的sslResponse对象(见 MonitorTemplateUtil.ts)。

服务器/VM 监控变量

变量说明类型
hostname被监控服务器的主机名string
requestReceivedAt收到服务器监控请求的日期时间Date
cpuUsagePercentCPU 使用率(百分比)number
cpuCoresCPU 核心数number
memoryUsagePercent内存使用率(百分比)number
memoryFreePercent空闲内存百分比number
memoryTotalBytes总内存(字节)number
diskMetrics所有挂载磁盘的磁盘指标数组Array<Object>
diskMetrics[].diskPath磁盘挂载点路径string
diskMetrics[].usagePercent该挂载点磁盘使用率number
diskMetrics[].freePercent该挂载点磁盘空闲率number
diskMetrics[].totalBytes该挂载点磁盘总空间(字节)number
processes服务器上运行的进程数组Array<Object>
processes[].pid进程 IDnumber
processes[].name进程名称string
processes[].command启动进程的命令string
failureCause服务器检查失败的原因string

CPU 与内存指标在basicInfrastructureMetrics.cpuMetricsbasicInfrastructureMetrics.memoryMetrics可用时才会被注入存储映射(见 MonitorTemplateUtil.ts),磁盘与进程数组同理。

合成(Synthetic)监控变量

合成监控会在多个浏览器(Chromium、Firefox、Webkit)与多种屏幕尺寸(移动端、平板、桌面)上运行同一个脚本,每种组合产生一条响应。每次执行通过syntheticResponses数组暴露;你可以用索引访问某次特定执行({{syntheticResponses[0].browserType}}),或用{{#each syntheticResponses}}迭代。

变量说明类型
failureCause合成检查失败的原因string
syntheticResponses每条浏览器/屏幕尺寸组合一条执行记录的数组Array<Object>
syntheticResponses[].executionTimeInMs本次执行耗时(毫秒)number
syntheticResponses[].result本次执行返回的结果stringnumberbooleanJSON
syntheticResponses[].scriptError本次执行中发生的错误string
syntheticResponses[].logMessages本次执行产生的日志消息Array<string>
syntheticResponses[].screenshots本次执行中截取的截图Object
syntheticResponses[].browserType本次执行使用的浏览器string
syntheticResponses[].screenSizeType本次执行使用的屏幕尺寸string

自定义 JavaScript 代码监控变量

变量说明类型
executionTimeInMs自定义代码执行耗时(毫秒)number
result自定义代码返回的结果stringnumberbooleanJSON
scriptError代码执行中发生的错误string
logMessages执行过程中产生的日志消息数组Array<string>

SNMP 监控变量

变量说明类型
isOnlineSNMP 设备是否在线并响应boolean
responseTimeInMsSNMP 查询响应时间(毫秒)number
failureCauseSNMP 查询失败的原因string
isTimeoutSNMP 查询是否超时boolean
oidResponsesOID 响应对象数组(含 oid、name、value、type)Array<Object>
oidResponses[].oid被查询的 OIDstring
oidResponses[].nameOID 的描述性名称(若提供)string
oidResponses[].valueOID 返回的值stringnumber
oidResponses[].type值的 SNMP 数据类型string
{{OID_NAME}}按名称直接访问 OID 值(如{{sysUpTime}}stringnumber

基础用法

在监控条件实例的Incident/Alert 表单中,你可以直接书写模板字符串。例如:

API devolvió {{responseStatusCode}} en {{responseTimeInMs}}ms

如果监控响应状态码为502、耗时为842,则存储的标题会变成:

API devolvió 502 en 842ms

嵌套 JSON 访问与 JavaScript 表达式一致:

ID del problema: {{responseBody.error.id}} Mensaje: {{responseBody.error.message}}

数组索引同样受支持:

Primer usuario: {{responseBody.users[0].name}}

未解析占位符的兜底行为:如果某条路径不存在,占位符会原样保留在输出中——{{responseBody.error.id}}会带着花括号逐字出现在 Incident 标题里。唯一例外是{{#each}}块:若其目标路径不存在,整个块会被删除。这与底层实现一致:VMUtil.replaceValueInPlacedeepFind找不到变量时直接continue跳过替换(见 VMAPI.ts),这是刻意的“静默失败”设计,避免因一个字段缺失而丢掉整条告警。

进阶用法

数组元素访问

Uso del primer disco: {{diskMetrics[0].usagePercent}}% Último proceso: {{processes[-1].name}}

注意索引-1并不是传统“从尾部数”的语义——底层deepFind在解析[]之间的内容时,只有字面量last会映射到数组最后一个元素(见 VMAPI.ts)。数组越界或目标不是数组时返回undefined,占位符保持原样。

嵌套对象访问

Mensaje de error: {{responseBody.error.details.message}} Ubicación del servidor: {{sslCertificate.locality}} {{sslCertificate.country}}

deepFind会把路径按.切分逐级下钻,每个段先剥离[索引]后缀再取键;空段(如路径中出现连续两个点)会直接返回undefined

使用{{#each}}迭代数组

你可以用块语法{{#each path}}...{{/each}}遍历数组,适合把列表中的每一项都写进 Incident/Alert 描述。

语法:

{{#each arrayPath}} ...cuerpo usando {{property}} de cada elemento... {{/each}}

在循环体内:

  • {{propertyName}}相对于当前数组元素解析
  • {{nested.property}}点分访问作用于当前元素
  • {{@index}}解析为当前迭代的 0 基索引
  • {{this}}解析为当前元素的值(对字符串/数字等原始类型数组很有用)
  • 在当前元素中找不到的变量,会回退到父级存储映射查找

这些行为与 VMAPI.ts 中expandEachLoops的实现一一对应:循环体以当前元素属性合并父级存储映射构造作用域后再递归展开,{{@index}}被替换为数字下标,原始类型数组则替换{{this}};若解析路径不是数组,整个块被替换为空字符串;每个循环最多迭代 100 次作为防死循环的安全上限。

示例:带告警数组的入站请求(如 Grafana webhook)

假设入站请求体如下:

{ "status": "firing", "alerts": [ { "status": "firing", "labels": { "label": "Coralpay" } }, { "status": "firing", "labels": { "label": "capitecpay" } }, { "status": "resolved", "labels": { "label": "capricorn" } } ] }

可以写这样的模板:

Etiquetas de alerta: {{#each requestBody.alerts}} - {{labels.label}} ({{status}}) {{/each}}

渲染结果:

Etiquetas de alerta: - Coralpay (firing) - capitecpay (firing) - capricorn (resolved)

示例:服务器磁盘指标

Uso del disco: {{#each diskMetrics}} - {{diskPath}}: {{usagePercent}}% usado {{/each}}

示例:使用{{@index}}

Procesos: {{#each processes}} {{@index}}. {{name}} (PID: {{pid}}) {{/each}}

示例:原始类型数组配合{{this}}

Mensajes de registro: {{#each logMessages}} - {{this}} {{/each}}

示例:嵌套循环

多级数组可以嵌套{{#each}}块:

{{#each requestBody.groups}} Grupo: {{name}} {{#each members}} - {{id}}: {{role}} {{/each}} {{/each}}

注意:如果路径未解析为数组,整个{{#each}}...{{/each}}块会从输出中删除;空数组不会为块产生任何输出。模板表达式的分类解析(#each开标签、/each闭标签、@indexthis与其他引用)在 Common/Types/Workflow/TemplateSyntax.ts 中有完整的枚举与解析实现,可作为理解该语法的权威参考。

各监控类型实战示例

网站/API 监控 Incident 标题

Alta latencia: {{responseTimeInMs}}ms (> umbral)

网站/API 监控 Incident 描述

### Error de API Estado: **{{responseStatusCode}}** Latencia: **{{responseTimeInMs}}ms** Fragmento del cuerpo: `{{responseBody.error.message}}`

入站请求 Alert 标题

Solicitud entrante defectuosa: method={{requestMethod}} auth={{requestHeaders.authorization}}

SSL 证书 Alert 标题

Certificado SSL a punto de expirar: {{commonName}} caduca {{expiresAt}}

服务器监控 Alert 描述

### Alerta del servidor: {{hostname}} Uso de CPU: **{{cpuUsagePercent}}%** Uso de memoria: **{{memoryUsagePercent}}%** Uso del primer disco: **{{diskMetrics[0].usagePercent}}%** Última verificación: {{requestReceivedAt}}

Ping 监控 Alert 标题

Ping fallido para el destino: {{failureCause}} ({{responseTimeInMs}}ms)

端口监控 Alert 描述

Problema de conectividad del puerto Estado del puerto de destino: {{isOnline}} Tiempo de respuesta: {{responseTimeInMs}}ms Causa del fallo: {{failureCause}}

合成监控 Alert

按索引访问特定浏览器/屏幕尺寸组合的执行:

Primera ejecución: {{syntheticResponses[0].browserType}} / {{syntheticResponses[0].screenSizeType}} Resultado: {{syntheticResponses[0].result}} en {{syntheticResponses[0].executionTimeInMs}}ms

{{#each}}迭代每种浏览器/屏幕尺寸组合:

### Resultados del monitor sintético {{#each syntheticResponses}} - **{{browserType}} / {{screenSizeType}}**: {{result}} en {{executionTimeInMs}}ms - Error del script: {{scriptError}} - Primer registro: {{logMessages[0]}} {{/each}}

自定义代码监控 Alert

Ejecución del código personalizado: {{executionTimeInMs}}ms Salida del registro: {{logMessages[0]}}

SNMP 监控 Alert 标题

Dispositivo SNMP fuera de línea: {{failureCause}} ({{responseTimeInMs}}ms)

SNMP 监控 Alert 描述

### Alerta del dispositivo SNMP Estado: **{{isOnline}}** Tiempo de respuesta: **{{responseTimeInMs}}ms** Tiempo de actividad del sistema: {{sysUpTime}} Nombre del sistema: {{sysName}} Valor del primer OID: {{oidResponses[0].value}}

入站请求 + 数组循环(Grafana webhook)

标题:

[{{requestBody.status}}] {{requestBody.receiver}}

描述:

### Alertas de {{requestBody.receiver}} {{#each requestBody.alerts}} **Alerta {{@index}}**: {{labels.alertname}} - Etiqueta: {{labels.label}} - Estado: {{status}} - Valores: {{valueString}} - Fuente: {{generatorURL}} {{/each}}

服务器监控 + 磁盘循环

描述:

### Alerta del servidor: {{hostname}} Uso de CPU: **{{cpuUsagePercent}}%** Uso de memoria: **{{memoryUsagePercent}}%** **Uso del disco:** {{#each diskMetrics}} - {{diskPath}}: {{usagePercent}}% usado ({{freePercent}}% libre) {{/each}} **Procesos en ejecución:** {{#each processes}} - [{{pid}}] {{name}}: {{command}} {{/each}}

SNMP 监控 + OID 循环

描述:

### Estado del dispositivo SNMP En línea: {{isOnline}} Respuesta: {{responseTimeInMs}}ms **Valores OID:** {{#each oidResponses}} - {{name}} ({{oid}}): {{value}} {{/each}}

模板引擎的底层原理

理解模板引擎的实现细节,有助于写出稳定、可预期的模板:

  1. 存储映射构建(数据侧)MonitorTemplateUtil.buildTemplateStorageMap按监控类型(MonitorType.APIMonitorType.WebsiteMonitorType.IncomingRequestMonitorType.PingMonitorType.IPMonitorType.PortMonitorType.SSLCertificateMonitorType.ServerMonitorType.SyntheticMonitorType.CustomCodeMonitorType.Snmp)分别从ProbeMonitorResponseIncomingMonitorRequestServerMonitorResponseSslMonitorResponseSyntheticMonitorResponseCustomCodeMonitorResponseSnmpMonitorResponse等类型中抽取字段。这也是文档中“不同监控类型暴露不同变量”的根本原因。
  2. 模板渲染(字符串侧)processTemplateString调用VMUtil.replaceValueInPlace(storageMap, value, false)。渲染分两阶段:先调用expandEachLoops展开所有{{#each}}循环(嵌套循环按作用域递归),再对剩余的{{variable}}deepFind在存储映射中逐条查找替换。未找到的变量被跳过、保留原文。
  3. JSON 值序列化:当解析出的值是对象时,会被JSON.stringify(缩进 2 空格)后插入;替换使用函数形式而非字符串形式,避免值中$&$1等字符被误当作正则替换模式。
  4. Incident/Alert 创建时的调用链:MonitorIncident.ts 在创建 Incident 时构建存储映射并对标题/描述做模板渲染,Alert 侧逻辑与之镜像对齐,保证同一阈值触发事件与告警时文案口径一致。

常见陷阱与最佳实践

  • 路径不存在时占位符原样保留{{responseBody.error.id}}会在标题中带花括号出现。若希望整段文案消失,应使用{{#each}}块包裹(仅当路径解析为数组时生效)。
  • [*]不会被解析:它只在“按负载字段分组”的路径字段中有意义,模板正文里请用[0][1]这类具体索引。
  • 入站请求数组请优先用分组变量{{requestBody.alerts[0].annotations.summary}}永远读第一条告警,而非触发 Incident 的那一条;正确做法是使用分组键变量与commonLabelscommonAnnotations等共享字段。
  • 循环体中优先相对路径{{labels.label}}先相对于当前数组元素解析,找不到再回退父级存储映射——这既是便利也是隐患,注意字段名冲突。
  • 明确不支持的监控类型:日志、链路、指标监控目前不参与模板渲染,请勿在其 Criteria 中依赖本机制。
  • 充分利用代码内核对变量名:遇到不确定的字段,可对照 MonitorTemplateUtil.ts 中buildTemplateStorageMap的实际注入键名(如服务器监控只在basicInfrastructureMetrics存在时注入 CPU/内存/磁盘键),避免引用永远不会存在的变量。

掌握以上语法与实现细节后,你可以为每种监控类型定制信息密度恰到好处的 Incident/Alert 文案,让值班人员在通知到达的瞬间即可定位故障源,而无需逐条打开详情页。

【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 16:37:52

基于Matlab的矩量法二维金属体散射RCS计算全流程解析

简介&#xff1a;资源围绕矩量法在二维金属体散射计算中的应用展开&#xff0c;以MATLAB为实现工具&#xff0c;面向电磁场与微波技术、计算电磁学方向的学生和科研人员&#xff0c;尤其适合正在做课程设计或需要快速上手矩量法编程的读者。文档从电场积分方程和磁场积分方程入…

作者头像 李华
网站建设 2026/9/19 16:35:07

Windows18-HD19下Keil安装失败全解析与修复指南

换了新系统之后装 Keil&#xff0c;我遇到过太多“明明按教程走的&#xff0c;却死活装不上”的兄弟了。这段时间后台和群里问得最多的就是 Windows18-HD19 这套环境下 Keil 安装失败的问题&#xff0c;有人装到一半提示回滚&#xff0c;有人装完了一启动就闪退&#xff0c;还有…

作者头像 李华
网站建设 2026/9/19 16:29:18

VSCode local history 备份太多?TaoToken 这样改 Codex 的 config.toml

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 16:28:56

高层建筑供配电系统设计:负荷建模、主接线与短路保护全链路实践

简介&#xff1a;本资源是一份面向电气工程专业本科生及供配电设计初学者的课程设计实践文档&#xff0c;聚焦26层商业办公楼供配电系统全流程设计&#xff0c;解决负荷分级、设备选型、短路校验与主接线优化等核心工程问题。压缩包含1个4.12MB的Word文档&#xff08;.doc&…

作者头像 李华
网站建设 2026/9/19 16:28:44

读 plugin-database 驱动切换,把会话存储旁路的 Token 计量接到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华