OneUptime 与 PagerDuty 集成实战:基于 Workflow 实现事件触发、去重与自动解决
2026/9/17 3:21:11 网站建设 项目流程

OneUptime 与 PagerDuty 集成实战:基于 Workflow 实现事件触发、去重与自动解决

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

本篇技术指南以 OneUptime 的 PagerDuty 集成为主线,讲解如何借助 OneUptime 内置的Workflow(工作流)引擎,在 OneUptime 事件(Incident)创建时自动向 PagerDuty 的 Events API v2 投递trigger事件,并在事件解决时投递resolve事件实现全自动联动。读完本文,你将掌握 PagerDuty Integration Key(routing key)的保存方式、dedup_key去重与回关原理、严重级别映射方案,以及出站/入站双向集成与常见故障排查方法。

集成概览:出站方向与 Workflow 机制

这条集成是**出站(outbound)**方向的:OneUptime 作为事件的产生方,调用 PagerDuty 的 Events API v2(端点https://events.pagerduty.com/v2/enqueue),把 OneUptime 内部的事件状态同步到 PagerDuty。它并不依赖任何内置连接器,而是完全由 OneUptime 的Workflow引擎拼装而成:一个Hændelse → On Create(事件创建)触发器,加上一个API 组件

整体数据流可以概括为:

OneUptime Incident → On Create ──► API component (POST /v2/enqueue) ──► PagerDuty incident

从源码角度看,Workflow 的组件注册表(Common/Server/Types/Workflow/Components/Index.ts)动态注册了incident-on-createincident-on-update等数据库触发器组件,同时注册了ApiPostIfElse等普通组件。这意味着“事件创建时触发 → 条件判断 → HTTP POST”这套链路全部由图上的组件拼接实现,而不是硬编码的 PagerDuty 专用代码。

注意:OneUptime 自身内置了值班计划(On-Call)与升级策略(Escalation),详见 On Call 文档。只有当你的组织确实希望事件同时进入 PagerDuty 由其接管调度时,才需要这条集成。

前置条件

在开始配置前,需要准备两样东西:

  1. 一个 PagerDuty 服务,且其集成类型必须是 Events API v2。在 PagerDuty 控制台按Service → Integrations → Add integration → Events API v2添加,然后复制Integration Key(在 PagerDuty 中也称为routing key)。注意区分 v2 与已废弃的 v1:后者会导致后续请求返回invalid routing key
  2. 一个可以创建 Workflow 的 OneUptime 项目。Workflow 功能位于侧边栏「Arbejdsgange / Workflows」。

先理解 Workflow 的变量与模板语法

由于整个集成的请求体全部由模板引用({{...}})拼装而成,先弄清变量体系能让后续步骤少踩坑。依据 Workflow 变量文档 与模板语法解析实现(Common/Types/Workflow/TemplateSyntax.ts),存在三类可引用对象:

类型语法说明
全局变量(项目级){{global.variables.NAME}}项目内所有 Workflow 共用,适合存放 API Key
本地变量(工作流级){{local.variables.NAME}}仅对当前 Workflow 有效
组件输出{{local.components.COMPONENT_ID.returnValues.FIELD_ID}}上游触发器/组件在运行期产生的数据

例如事件触发器(incident-on-create-1)会把事件记录以model返回值暴露出来,于是事件的标题就是{{local.components.incident-on-create-1.returnValues.model.title}}。变量名是大小写敏感的,且{{ }}内部不允许出现多余空格——{{ global.variables.X }}{{global.variables.X}}是两个不同的查找,前者不会被解析。

值得特别强调的一点(也是 Workflow 变量文档中明确的陷阱):无法解析的引用不会被清空,而是原样发送。如果{{...}}中的路径拼错(比如把incident-on-create-1写成incident-on-create),运行时不会报错,占位符会被当作字面文本 POST 到 PagerDuty,而工作流日志仍会显示成功。这正是下文每一步都要求“在日志中确认 202 响应”的原因。

步骤一:把 routing key 保存为全局变量

  1. 打开Arbejdsgange(Workflows)→ Globale variabler(全局变量)→ Opret(创建)
  2. 命名为PAGERDUTY_ROUTING_KEY,粘贴第 1 步复制的 Integration Key,并开启Is Secret(保密)开关。

根据 Workflow 变量文档,全局变量拥有四个属性:Navn(名称)Beskrivelse(描述)Hemmelighed(保密)Indhold(内容)。其中名称至少要两个字符、不含空格,且仅允许字母、数字、连字符与下划线(对应模板代码中的命名约束/^[A-Za-z0-9_-]+$/,见 Common/Types/Workflow/Templates.ts)。PAGERDUTY_ROUTING_KEY这种UPPER_SNAKE_CASE命名方式正是推荐习惯。

开启Is Secret后,该值会被从运行日志与步骤追踪(Step Trace)中清除,防止密钥泄露给项目内其他成员(注意:它并不会在数据库中以加密形式存储,保密仅作用于日志脱敏)。之后在 API 组件的 Headers 或 Body 中引用时,就写成:

{{global.variables.PAGERDUTY_ROUTING_KEY}}

步骤二:构建"触发"工作流(Incident → PagerDuty)

  1. 打开Arbejdsgange → Opret arbejdsgang(创建工作流),命名为Incidents → PagerDuty,进入**Bygger(构建器)**画布。

  2. 添加一个Hændelse(事件)触发器,模式设为On Create,并将其重命名为Incident(该名称将出现在local.components引用路径中)。

  3. 添加一个API 组件,与触发器连线。按源码中ApiPost组件的元数据定义(Common/Types/Workflow/Components/API.ts),该组件要求以下参数:

    • Method(方法)POST

    • URLhttps://events.pagerduty.com/v2/enqueue

    • Headers(请求头)Content-Type: application/json

      源码将该字段标记为isSensitive: true(高级选项)。原因在于:请求头通常是填写Authorization之类凭证的地方,如果直接用字面量填写,解析后的值会原样写入 WorkflowLog。只有来自标记为 secret 的变量的值才会被自动脱敏——所以把密钥放进全局变量PAGERDUTY_ROUTING_KEY是必须的,而不是直接写在 Header 或 Body 里。

    • Body(请求体),完整 JSON 如下:

      { "routing_key": "{{global.variables.PAGERDUTY_ROUTING_KEY}}", "event_action": "trigger", "dedup_key": "oneuptime-{{local.components.incident-on-create-1.returnValues.model._id}}", "payload": { "summary": "{{local.components.incident-on-create-1.returnValues.model.title}}", "source": "OneUptime", "severity": "critical", "custom_details": { "description": "{{local.components.incident-on-create-1.returnValues.model.description}}" } } }

      这里的引用写法是完整形式(由构建器的值选择器自动插入)。事件触发器返回的唯一返回值是model,可继续向下钻取_idtitledescriptioncurrentIncidentState.nameincidentSeverity.name等字段——这些字段与内置模板INCIDENT_SELECT的投影一致(见 Common/Types/Workflow/Templates.ts),保证运行期一定能取到。

  4. 保存并激活,然后创建一条测试事件进行验证。若在工作流日志中看到 HTTP202响应,说明 PagerDuty 已接受该事件。

关于dedup_key:这是整个集成的关键

dedup_key把这条 PagerDuty 事件与 OneUptime 事件绑定起来,是后续resolve调用能够“对上号”的依据。使用 OneUptime 事件自身的_id作为后缀(oneuptime-<id>),可以保证 key 唯一且可预测:同一事件无论触发多少次,都对应 PagerDuty 中同一条 incident,不会重复建单。

关于 API 组件的输出

ApiPost组件在运行后会暴露以下返回值(定义于 Common/Types/Workflow/Components/API.ts),这些值可以在后续步骤中继续引用,也用于故障排查:

  • error:请求失败时的错误信息;
  • response-status:响应状态码(如 202、400);
  • response-headers:响应头;
  • response-body:响应体。

组件还提供SuccessError两个输出端口:请求成功走 Success 分支,失败走 Error 分支。你可以在 Error 分支上再接一个 Log 或 Email 组件,把失败信息({{local.components.api-post-1.returnValues.error}})记录下来,避免静默丢失。

步骤三:在 OneUptime 解决事件时自动解决 PagerDuty 事件(推荐)

同一个工作流里再加一个事件触发器?不行——一个工作流只能有一个触发器。正确做法是新建第二个工作流Resolve PagerDuty

  1. 使用Hændelse → On Update触发器。

  2. 添加Betingelser(条件)组件(即 If/Else),判断事件是否已经解决:将{{local.components.incident-on-update-1.returnValues.model.currentIncidentState.name}}与你的“已解决”状态名称做比较。根据源码定义(Common/Types/Workflow/Components/Condition.ts),If/Else 支持==!=>>=<<=containsdoes not containstarts withends with等操作符,并输出Yes/No两个分支端口。

  3. Yes分支连接一个新的API 组件,向 PagerDuty 发送相同的dedup_key,且event_action设为resolve

    { "routing_key": "{{global.variables.PAGERDUTY_ROUTING_KEY}}", "event_action": "resolve", "dedup_key": "oneuptime-{{local.components.incident-on-update-1.returnValues.model._id}}" }

PagerDuty 收到后会用dedup_key匹配原始事件并自动关闭它。dedup_key必须与触发调用完全一致(包括大小写与前后缀),这是 resolve 生效的唯一匹配依据。

需要说明的是,On Update触发器还支持listen-on字段来监听特定字段的变化(内置模板incident-state-changed-slack就是监听currentIncidentStateId的示例,见 Common/Types/Workflow/Templates.ts)。若希望只在状态字段变化时才触发,可在触发器中把监听范围收窄到该字段,减少无关运行。

严重级别映射(可选)

PagerDuty 的severity字段只接受四档取值:criticalerrorwarninginfo。如果你的 OneUptime 事件严重级别(incidentSeverity.name)与 PagerDuty 的档位不一致,可以在API 组件之前插入多个Betingelser(If/Else)分支,对{{Incident.incidentSeverity.name}}进行逐一判断,每个分支发送不同的请求体:

  • 若 OneUptime 严重级别为Critical→ PagerDutyseverity: "critical"
  • 若为High"error"
  • 若为Medium"warning"
  • 若为Low"info"

将各分支分别连到对应的 API 组件(或先在一个 JavaScript 组件里做映射,再统一发送),即可实现自定义映射规则。完整引用形式可参考变量文档中的写法{{local.components.incident-on-create-1.returnValues.model.incidentSeverity.name}}(Workflow 变量文档)。

入站集成(可选):PagerDuty → OneUptime

上面的步骤都是“OneUptime 出站调用 PagerDuty”。如果你想走反方向——由 PagerDuty 的事件触发创建一条 OneUptime 事件——可以使用 OneUptime 的Webhook 触发器工作流:

  1. 新建一个使用Webhook 触发器的工作流,复制其 Webhook URL;
  2. 在 PagerDuty 侧配置一个 V3 webhook(或 Events Orchestration),把事件投递到该 URL;
  3. 在工作流中使用Opret hændelse(创建事件)组件,从 webhook 的request-body返回值中提取字段,构造 OneUptime 事件。

这种"外部工具把数据送入 OneUptime"的入站模式,在 集成总览文档 中有更完整的说明。Webhook 组件的返回值为request-body,引用方式形如{{local.components.webhook-1.returnValues.request-body}},可用 If/Else 与创建事件组件组合成完整的入站链路。

故障排查

现象原因与对策
400且响应为"invalid routing key"集成类型不是Events API v2(可能是已废弃的 v1 或其他类型)。回到 PagerDuty 的 Service → Integrations,重新添加 Events API v2 集成并重新复制 key。
resolve 调用没有关闭任何 PagerDuty 事件dedup_key与触发调用不一致(拼写、大小写或前后缀有差异)。PagerDuty 完全依赖该 key 匹配,务必逐字符核对。
工作流日志中没有任何记录确认工作流已激活(Enabled),且触发器模式确实为On Create(或 On Update)。未激活的工作流不会响应事件。
日志显示成功但 PagerDuty 无事件检查请求体中的{{...}}引用是否全部可解析——无法解析的引用会作为字面文本发送而不报错。打开运行日志的警告行,它会列出所有未被解析的引用。

延伸阅读

  • Workflow 集成总览 —— 各类集成的模式与认证方式汇总
  • Workflow 变量文档 —— 全局/本地变量、组件输出与常见陷阱
  • Workflow 组件文档 —— 每个组件可用的输出字段
  • Workflow 运行与日志文档 —— 如何查看每次运行中各变量的实际取值
  • On Call 文档 —— OneUptime 内置的值班与升级能力
  • Opsgenie 集成 —— 同样的思路用于 Opsgenie

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询