OneUptime 集成 Discord:用内置工作流组件将事故通知推送到频道
【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime
导读
本指南讲解如何在 OneUptime 中通过内置的Discord 工作流组件,把事故(Incident)的新建与更新消息自动推送到 Discord 频道。这是一条典型的出站(Outbound)集成:OneUptime 借助 Discord 的 Incoming Webhook URL 向频道发送消息,无需安装任何插件,只需在可视化工作流画布上拖拽连接即可完成。读完本文,你将掌握从创建 Discord Webhook、用全局变量保管密钥,到构建事件驱动工作流、使用 API 组件做替代方案的完整实战方法,并能结合仓库源码理解该组件的底层安全与实现原理。
集成模式:出站推送
Discord 集成属于 OneUptime 集成体系中的出站模式——即"OneUptime 里的某个事件,应该在另一个工具中呈现"。官方集成概览文档将出站模式的通用配方归纳为三步(见 App/FeatureSet/Docs/Content/en/integrations/index.md):
- 构建一个以OneUptime 事件触发器开头的流程,例如Incident → On Create;
- 添加一个调用对方 REST API 的API 组件(或专用组件),携带事故详情;
- 把 API 密钥保存为秘密全局变量,确保密钥不会出现在流程或日志中。
本集成的完整数据流如下:
OneUptime Incident → On Create ──► Discord component ──► message in your channel在整个集成目录中,Discord 与 Telegram 一样,都是典型的出站集成(Outbound);而 Slack、Microsoft Teams 则属于更深的原生工作区连接,支持双向操作与自动事故频道,需要时建议优先走工作区连接而非工作流。
为什么它是"最快的集成之一"
Discord 集成之所以开箱即用、搭建最快,是因为 OneUptime 在自动化引擎中内置了名为Send Message to Discord的专用组件,其组件元数据定义在 Common/Types/Workflow/Components/Discord.ts:
- 组件 ID:
DiscordSendMessageToChannel,分类(category)为Discord; - 输入参数:
webhook-url(Discord Incoming Webhook URL,必填、标记为敏感isSensitive: true)和text(消息正文,必填长文本); - 输出:
success与error两个出端口,分别对应"消息发送成功"与"发生错误"。
而真正执行发送的运行时实现位于 Common/Server/Types/Workflow/Components/Discord/SendMessageToChannel.ts,它调用 Discord 官方Execute Webhook接口(POST到 webhook URL,请求体为{ content: args["text"] })。注意:在run()开始处,若没有提供text参数会直接抛出BadDataException("Discord message not found"),因此消息正文是强制项。
前置准备:OneUptime 工作流基本概念
在动手之前,先补充工作流中的三个基础概念(详见 工作流组件文档 与 变量文档):
- 触发器(Trigger):流程的起点,例如
Incident → On Create,表示"当事故被创建时"启动流程; - 组件(Component):触发器之后添加的构建块,每个块只做一件事——发消息、调 API、做判断——并与下一个块相连。Discord、API、Conditions(条件判断)都是组件;
- 变量(Variable):分全局变量与局部变量两类,用于在块之间传递数据,也是保管密钥的官方方式。
第一步:在 Discord 创建 Webhook
- 打开目标频道的Edit Channel(编辑频道)→ Integrations(集成)→ Webhooks;
- 点击New Webhook(新建 Webhook),给它一个便于识别的名称(例如
OneUptime),确认目标频道无误; - 点击Copy Webhook URL(复制 Webhook URL)复制形如下面的地址:
https://discord.com/api/webhooks/<WEBHOOK_ID>/<WEBHOOK_TOKEN>关于这个地址,有一个值得注意的仓库细节:OneUptime 的 Discord 组件在发送前会对 Webhook URL 做域名白名单校验。在 Common/Server/Types/Workflow/Components/IncomingWebhookUtils.ts 中定义:
export const DISCORD_WEBHOOK_DOMAINS: Array<string> = [ "discord.com", "discordapp.com", ];getPinnedWebhookUrl()会校验 URL 原始字符串必须落在discord.com/discordapp.com这两个域名上,否则流程会通过onError停止并给出可操作的错误信息。这意味着你无法把该组件指向任意第三方 URL——这是出于 SSRF(服务端请求伪造)防护的设计,比单纯维护黑名单更安全(白名单无法被 DNS 重绑定、备用 IP 写法或重定向绕过)。同时源码中发送请求还设置了doNotFollowRedirects: true,避免重定向把数据交给其他主机控制者。
第二步:把 Webhook URL 存入全局变量(推荐)
直接把 URL 粘贴进组件固然可行,但官方强烈建议先存入全局变量,理由是可以跨多个工作流复用,并在单点轮换密钥。
- 进入Workflows → Global Variables → Create;
- 将变量命名为
DISCORD_WEBHOOK_URL,把 URL 粘贴进 Content 字段; - 打开Is Secret开关,保存。
全局变量的关键属性(见 变量文档):
| 属性 | 说明 |
|---|---|
| Name | 引用时使用的名字。至少 2 个字符,不能有空格,只允许字母、数字、连字符和下划线;官方建议使用UPPER_SNAKE_CASE命名习惯 |
| Description | 可选的自由文本,用于说明用途 |
| Secret | 开启后,变量值会从运行日志(run logs)与步骤追踪(step traces)中抹除 |
| Content | 实际值,属于长文本字段,支持多行内容 |
在任何工作流中引用全局变量使用{{global.variables.NAME}}语法;工作流局部变量则使用{{local.variables.NAME}}。两点提醒:
- 变量名区分大小写:
{{global.variables.MyKey}}与{{global.variables.mykey}}是两个不同的变量; - 未解析的引用会原样透传:拼写错误或变量被重命名后,引用不会报错、也不会变成空字符串,而是把花括号原样发出去(例如出现在 Discord 消息正文里),同时运行日志会给出警告行——所以重命名被引用的变量之前要三思。
第三步:构建事故 → Discord 工作流
- 打开Workflows → Create Workflow,命名(例如
Incidents → Discord),进入Builder(画布); - 添加Incident触发器,触发条件设为On Create,并将它重命名为
Incident(后续引用触发器输出时要用到该 ID); - 添加Discord组件,把它连接到触发器,并填写参数:
- Webhook URL:
{{variable.DISCORD_WEBHOOK_URL}}(或直接粘贴 URL); - Message:
🔴 New incident: {{Incident.title}}\n{{Incident.description}}
- Webhook URL:
- 点击Save,启用工作流,然后创建一条测试事故——消息应出现在你的 Discord 频道中。
关于消息模板中的变量引用,这里补充一下官方文档的准确用法:触发器属于"记录类型触发器",运行时会返回一个名为model的值,需要逐级下钻引用,例如某触发器 ID 为incident-on-create-1时,事故标题的引用写法是{{local.components.incident-on-create-1.returnValues.model.title}}。在画布编辑器中,请优先使用组件值选择器(picker)插入这类引用,它会生成运行器所期望的精确 ID,避免手写出错。Discord 组件的消息字段同样支持变量(参见"变量在何处生效"一节:Slack、Teams、Discord、Telegram、Email 的消息文本都接受变量)。
发送失败时的分支处理
Discord 组件有两个出端口:Success(成功发到频道)与Error(发送出错)。从 SendMessageToChannel.ts 的实现可见:网络失败或非 2xx 响应时,返回值returnValues.error会携带错误消息并走 error 端口。建议把Error端口接到Log组件或Email通知上,让发送失败本身也能被看到。
替代方案:使用 API 组件
如果不想使用专用组件,API组件完全可以实现相同效果。API 组件支持GET、POST、PUT、PATCH、DELETE方法,配置如下:
- Method(方法):
POST - URL:
{{variable.DISCORD_WEBHOOK_URL}} - Headers(请求头):
Content-Type: application/json - Body(请求体):
{ "content": "New incident: {{Incident.title}}" }
当需要 Discord 更丰富的embed(嵌入卡片)时,API 方案是更好的选择——只需在请求体中追加embeds数组即可(对应 Discord Execute Webhook 接口的embeds参数)。API 组件的输出包含Success与Error两个端口:Success 在调用成功(2xx)时触发并透传状态、请求头与响应体;Error 在网络失败或非 2xx 时触发并透传错误消息。
一个使用上的差别值得说明:专用 Discord 组件内部已经替你完成了"把content字段封装进 JSON 请求体"这一步;而 API 组件需要你自己构造完整的 JSON 请求体。此外,若你用 API 组件发送到 Discord,请同样把 URL 保存在秘密全局变量中,避免密钥进入日志。
进阶技巧
按严重程度过滤:只在特定级别发消息
用Conditions(If / Else)组件在 Discord 块之前做分支。Conditions 组件支持==、!=、>、>=、<、<=、contains、starts with、ends with等运算符,对事故严重程度字段做比较:
- Left value(左值):
{{Incident.incidentSeverity.name}} - Operator(运算符):
== - Right value(右值):例如
Critical
Conditions 输出Yes与No两个分支,把 Discord 组件接在 Yes 分支上即可实现"仅严重级别为 Critical 时推送"。
覆盖完整生命周期:On Update 工作流
触发器Incident → On Create只覆盖创建事件。要同步发布**确认(acknowledgement)和解决(resolution)**消息,可以再构建一个以Incident → On Update为触发器的工作流,同样接 Discord 组件发到同一频道,消息模板可以引用更新后的事故状态字段。
在流程之间复用通知逻辑
组件文档中还提到一种模式:用Execute Workflow组件构建一个"发到事故频道"的共享工作流,然后从任何需要通知频道的流程中调用它。调用方继续运行、不等待被调用流程结束。配合全局变量中的DISCORD_WEBHOOK_URL,通知逻辑只需维护一处。
安全与限制小结
- 域名白名单:Discord 组件只接受
discord.com与discordapp.com域名的 Webhook URL(IncomingWebhookUtils.ts); - 禁止重定向:发送时设置
doNotFollowRedirects: true,防止数据被转发给其他主机(SendMessageToChannel.ts); - 密钥脱敏:把 URL 标记为 Secret 后,值会在运行日志与步骤追踪中被抹除;官方还提示"变量可写但不可读回"——
content字段对 API 而言是只写的,这正适合存放轮换的令牌; - 消息必填:
text参数缺失时组件会直接报错,请确保模板引用能正确解析(未解析引用会原样透传,务必检查运行日志)。
延伸阅读
- 集成概览 —— 出站 / 入站两种模式与全部集成目录
- Telegram 集成 —— 相同的思路用于 Telegram
- 工作流组件参考 —— Discord 及全部组件目录
- 工作流变量 —— 全局变量、秘密变量与引用语法
- Discord 组件运行时实现:SendMessageToChannel.ts
- Discord 组件元数据定义:Common/Types/Workflow/Components/Discord.ts
【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考