OneUptime × Jira 双向集成实战:用 Workflow 与 REST API 打通事故和 Issue 的双向同步
【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime
本篇基于 OneUptime 官方文档 Jira-Integration,讲解如何不安装任何 Jira 专用组件,仅靠 OneUptime 的 Workflow(On Create/Update Incident 触发器、API 组件、Webhook 触发器)调用 Jira REST API,实现“事故创建即开 Issue、事故状态移动即评论/转移 Issue、Jira 状态变化回写事故”的完整双向同步方案。读完你可以直接照抄全局变量、工作流组件配置与 JQL 查询落地这套集成,并掌握 Jira Cloud 与 Data Center 的差异、限流、认证过期等常见故障的排查方法。
双向同步总体架构
OneUptime 事故被宣布时打开一个 Jira Issue,事故状态变化时让 Jira Issue 跟随移动,Jira 中的状态变更再通过 Webhook 推回 OneUptime——整个链路只用两类通用组件完成:OneUptime 侧通过 API 组件调用 Jira REST API,Jira 侧通过 Webhook 触发器接收回调:
OneUptime Incident → On Create ──► API Post (POST /rest/api/3/issue) ──► Jira issue Jira issue transitioned ──► Automation rule (Send web request) ──► OneUptime Webhook trigger ──► Update One Incident下文除最后 Data Center 一节外,均按Jira Cloud编写;自托管读者请按文末的替换表调整。
背景提示:Atlassian 正在 Jira Cloud 中做大规模改名——project在界面上大多变成了space,issue变成了work item。租户处于新旧两种叫法并存期,因此本文在措辞重要的地方两种词汇都会出现。
前置条件
- 一个 Jira Cloud 站点(
https://your-domain.atlassian.net)和一个用于建 Issue 的项目,记下它的项目密钥——即OPS-1234中的OPS。 - 一个有权限在该项目创建 Issue 的 Jira 账号,以及对应的API-Token(在 Atlassian 账号中心 id.atlassian.com 的 security/api-tokens 页面生成)。强烈建议用服务账号而非个人账号——创建的 Issue 会归属到 Token 持有者名下。
- 有在该项目创建自动化规则(automation rule)的权限,用于入站方向。
- 一个可以创建 Workflow 和全局变量的 OneUptime 项目。
第一步:把 Jira 凭据存为全局变量秘密
Jira Cloud REST API 期望Basic-Auth:Atlassian 账号邮箱 + API-Token 拼成email:api_token后做 Base64 编码。
只编码一次,注意必须用
printf:printf '%s' 'you@example.com:your_api_token' | base64不要用
echo。echo会追加换行符,换行符被一起编码进字符串,Jira 会直接回401——而问题就藏在你看不出来的编码字符串里。在 OneUptime 中进入Arbeitsabläufe(工作流)→ Globale Variablen(全局变量)→ 创建,把变量命名为
JIRA_AUTH,粘贴 Base64 字符串作为内容(Inhalt),并勾选Geheimnis(秘密)。再创建一个非秘密变量
JIRA_URL,内容为https://your-domain.atlassian.net,结尾不带斜杠。
此后任何组件都可以用Basic {{global.variables.JIRA_AUTH}}作为Authorization头,Token 永远不会出现在工作流定义或执行日志里——这一点在源码层面有直接保证:OneUptime 的工作流日志写入前会经过一层秘密脱敏逻辑,把所有标记为 secret 的全局变量取值替换为[REDACTED],见 SecretRedaction.ts。变量机制的完整说明见 变量文档。
有两个关于 Atlassian API-Token 的事实,迟早会找上每一个没人盯着的集成:
- Token 会过期。Token 创建时长为 1 天到 1 年,默认 1 年,且没有续期机制——过期后必须回同一页面手动替换,并重新编码进
JIRA_AUTH。把到期日写进日历。如果某个工作流跑了几个月突然开始401,这就是原因。 - 带 Scopes 的 Token 走不同基址。Token 页面除经典Create API token外还提供Create API token with scopes。带 Scopes 的 Token 更安全,但它不指向你的站点:请求要发到
https://api.atlassian.com/ex/jira/<cloudId>,所以JIRA_URL要换成它,下文所有路径原样拼接在后面即可。cloudId可以在https://your-domain.atlassian.net/_edge/tenant_info的 JSON 响应里找到。带 Scopes 的 Token 打到your-domain.atlassian.net上会直接失败。
如果你的组织使用 Atlassian 集中用户管理,还有第三条路,可以从根本上绕开过期问题:为服务账号创建OAuth 2.0 Credential。这样你拿到的是 Client-ID 和 Secret 而非 Token,工作流在每次执行开头先换取一个短生命周期 Access Token——这正是 Microsoft Dynamics 365 集成所用的两组件结构:一个API Post (JSON)组件负责取 Token,其后所有组件发送Bearer <token>。一年后无需任何手动替换,API 基址为https://api.atlassian.com,具体 Token 请求格式见 Atlassian 官方文档。
第二步:为每个事故打开一个 Jira Issue
打开Arbeitsabläufe → Workflow 创建,命名为
Incidents → Jira,打开Builder。点击虚线占位组件,添加触发器On Create Incident。在Select Fields里勾选要发送的列:
{ "_id": true, "title": true, "description": true, "incidentNumber": true, "incidentSeverity": { "name": true } }Identifier保持为
incident-on-create-1——后续组件靠这个名字引用它的输出。点击Komponente hinzufügen(添加组件),加入API Post (JSON)组件,从触发器的Erfolg(成功)输出口连线到新组件的输入口。打开它,把Identifier设为
create-issue,填写:URL:
{{global.variables.JIRA_URL}}/rest/api/3/issueRequest Headers:
{ "Authorization": "Basic {{global.variables.JIRA_AUTH}}", "Accept": "application/json" }Request Body:
{ "fields": { "project": { "key": "OPS" }, "issuetype": { "name": "Bug" }, "summary": "OneUptime #{{local.components.incident-on-create-1.returnValues.model.incidentNumber}}: {{local.components.incident-on-create-1.returnValues.model.title}}", "labels": ["oneuptime"], "description": { "type": "doc", "version": 1, "content": [ { "type": "paragraph", "content": [ { "type": "text", "text": "{{local.components.incident-on-create-1.returnValues.model.description}}" } ] } ] } } }
把
OPS换成你的项目密钥,把Bug换成该项目实际存在的 Issue 类型。两者也可以按 ID 给出——{"id": "10000"}——这是 Atlassian 官方示例的做法;当你站点上有两个 Issue 类型同名时应当优先用 ID。这些 ID 可以通过下文createmeta调用来获得。
描述字段之所以显得笨重,是因为 Jira Cloud 的 v3 API 把富文本作为Atlassian Document Format(ADF)接收——一个文档树,而不是字符串。上面的形状就是最小合法文档:一个段落里包一个文本节点。同样的规则适用于environment和任何多行自定义文本字段;单行自定义文本字段仍然直接接收普通字符串。
然后在工作流Übersicht(概览)→ Workflow 编辑 → 启用中打开开关,宣布一个测试事故,查看Ausführungen & Protokolle(执行与日志)。create-issue组件应显示201和一个包含新 Issue 的id、key、self的响应体。画布上的修改会自动保存——没有保存按钮;而禁用的工作流根本不会运行,包括手动运行。
新 Issue 的 Key 在此之后对每个组件可见:
{{local.components.create-issue.returnValues.response-body.key}}这一点可以从组件元数据中印证:API 组件的返回值定义里确实包含response-status、response-headers、response-body三个字段(见 API.ts),并且带Success/Error两个输出口,与文档描述完全一致。
补全其他字段
fields内几个常见补充:
- 优先级—
"priority": { "id": "20000" },优先级 ID 取自你的站点。要把 OneUptime 严重度映射到 Jira 优先级,就在触发器和 API 组件之间加一个If / Else组件,按{{local.components.incident-on-create-1.returnValues.model.incidentSeverity.name}}分支。 - 负责人—
"assignee": { "id": "<accountId>" }。Jira Cloud 用 Atlassian Account ID 识别人;username和userKey多年前已从 Cloud API 移除。 - 标签—
"labels": ["oneuptime", "sev1"],一个扁平的字符串数组。标签不能含空格。 - 组件—
"components": [{ "id": "10000" }]。 - 自定义字段—
"customfield_10034": "...",用字段自己的 ID。值的形式取决于字段类型:单选是{"value": "red"},多选是 ID 数组,多行文本字段是 ADF 文档。
与其猜项目要什么,不如直接问 Jira。列出某项目的 Issue 类型,再列出其中一种类型的字段要求:
curl -u 'you@example.com:your_api_token' \ 'https://your-domain.atlassian.net/rest/api/3/issue/createmeta/OPS/issuetypes' curl -u 'you@example.com:your_api_token' \ 'https://your-domain.atlassian.net/rest/api/3/issue/createmeta/OPS/issuetypes/10001'第二个调用会列出该 Issue 类型接受的每个字段、哪些是必填、以及精确的customfield_NNNNNID。想从已有 Issue 上读出字段 ID,用?expand=names拉取它即可。
第三步:把事故 ID 带到 Jira 侧
双向同步的两半都需要一个存放对方标识的位置,而 Jira 是更好的选择:OneUptime 事故上的customFields列是单个 JSON 块,从工作流写一个值会覆盖该事故的全部自定义字段。
有 Jira 管理员时。给项目的创建屏幕加一个简短的自定义文本字段——叫它OneUptime Incident ID——用createmeta查出它的 ID,然后和其他字段一起写入:
"customfield_10050": "{{local.components.incident-on-create-1.returnValues.model._id}}"没有管理员时。把它塞进标签。标签不容忍空格,而 OneUptime ID 是纯 UUID,所以oneuptime-<id>是合法标签:
"labels": ["oneuptime", "oneuptime-{{local.components.incident-on-create-1.returnValues.model._id}}"]入站工作流之后需要从标签数组里把这个值挑出来,几行Run Custom JavaScript组件就能做到。能用自定义字段时它更干净。
顺手值得再建一个从 Jira 指回事故的链接:在create-issue之后加一个API Post (JSON)组件,指向{{global.variables.JIRA_URL}}/rest/api/3/issue/{{local.components.create-issue.returnValues.response-body.key}}/remotelink,Body 为:
{ "globalId": "system=https://oneuptime.com&id={{local.components.incident-on-create-1.returnValues.model._id}}", "object": { "url": "https://oneuptime.com/dashboard/{{local.components.incident-on-create-1.returnValues.model.projectId}}/incidents/{{local.components.incident-on-create-1.returnValues.model._id}}", "title": "OneUptime incident #{{local.components.incident-on-create-1.returnValues.model.incidentNumber}}" } }这样所有在 Jira 里的人都能一键跳回事故。为此需要把projectId加进触发器的Select Fields。globalId让这个调用可以安全重复:Jira 会更新已携带该 ID 的链接而不是再加一个。由于更新操作会清空你没发送的部分,请始终发送完整的object,不要发片段。
第四步:事故移动时,评论并转移 Issue
把这做成第二个工作流,这样这里的错误永远不可能阻塞第一步的开 Issue 动作。
- 创建 Workflow,命名
Incident updates → Jira,添加触发器On Update Incident。 - 在Listen on填
{"currentIncidentStateId": true}。这样触发器只在状态变化时触发,而不是每次编辑都触发。在Select Fields里要求{"_id": true, "currentIncidentState": {"name": true}}。 - 加一个If / Else组件:Input 1为
{{local.components.incident-on-update-1.returnValues.model.currentIncidentState.name}},Operator为==,Input 2为Resolved——或者你的项目里叫法不同的“已解决”状态名。状态与严重度的概念见 事故状态与严重度。
从Ja(是)分支出发,需要先找到第二步开的那个 Issue。用第三步存的 ID 向 Jira 查询,通过一个API Post (JSON)组件完成,Identifier设为find-issue:
URL:
{{global.variables.JIRA_URL}}/rest/api/3/search/jqlRequest Body:
{ "jql": "project = OPS AND labels = \"oneuptime-{{local.components.incident-on-update-1.returnValues.model._id}}\"", "maxResults": 1 }如果第三步用的是自定义字段而不是标签,这个子句变成
cf[10050] ~ \"...\"(用你自己的字段 ID)。
Issue ID 之后就是{{local.components.find-issue.returnValues.response-body.issues[0].id}},下文所有端点对 ID 和 Key 同样买账。
关于这个端点有三件事必须知道。JQL 要走 POST 发送,不要塞进 URL——值里带=的 Query String 从工作流发出时会被截断,而 JQL 几乎全是=。查询必须有范围限定:裸的order by key desc会被400拒绝,所以project =子句必须在那里。另外/rest/api/3/search/jql是当前端点——老的/rest/api/3/search已废弃并计划下线,别再去用它。
留评论是一个API Post (JSON)组件,打到{{global.variables.JIRA_URL}}/rest/api/3/issue/<id>/comment,Body 同样是 ADF 文档:
{ "body": { "type": "doc", "version": 1, "content": [ { "type": "paragraph", "content": [{ "type": "text", "text": "Resolved in OneUptime." }] } ] } }移动 Issue 需要两次调用,因为转移(transition)是按 ID 标识的,而这个 ID 在不同 Jira 工作流之间、甚至在某些看板的不同 Issue 之间都会变。
用API Get (JSON)组件请求
{{global.variables.JIRA_URL}}/rest/api/3/issue/<id>/transitions,返回从 Issue当前状态出发的所有可用转移,各带id、name,以及标明目标状态的to对象。用API Post (JSON)组件向同一 URL 执行其中一个:
{ "transition": { "id": "31" } }
成功的转移返回204且无 Body。如果不想在运行时读列表,可以手动对一个处于正确状态的 Issue 调一次,把 ID 写死——但记住它绑定的是那个 Jira 工作流,管理员一改 Jira 工作流就可能悄悄把它弄坏。
入站方向:从 Jira 推回 OneUptime
现在做另一半:有人把 Issue 拖到 Done,OneUptime 事故要跟随移动。
先建接收侧工作流
创建 Workflow,命名
Jira → OneUptime,添加触发器Webhook。打开该工作流的Einstellungen(设置),复制秘密 Webhook 密钥。你的 URL 是:
https://oneuptime.com/workflow/trigger/<webhook secret key>自托管部署用自己的主机名。把 URL 当密码保管——拿到它的人就能触发这个工作流——一旦外泄就在同一页面重置密钥。
加一个If / Else组件,在任何逻辑运行前校验共享秘密。Input 1为
{{local.components.webhook-1.returnValues.request-headers.x-oneuptime-secret}},Operator为==,Input 2为{{global.variables.JIRA_WEBHOOK_SECRET}}——一个你自己编出来、存为秘密全局变量的值。这个头部能被读到的前提是 Webhook 触发器确实会输出request-headers和request-body——这一点在组件元数据 Webhook.ts 中可见,触发器定义了三组request-headers、request-params、request-body返回值。从Ja分支加Update One Incident组件:
- Query:
{"_id": "{{local.components.webhook-1.returnValues.request-body.oneuptimeIncidentId}}"} - Data (JSON Object):Jira 的变更在这里意味着什么——通常是状态变化。
要移动事故需要目标状态 ID:用Find One Incident State组件以 Query
{"name": "Resolved"}查询,拿到{{local.components.incident-state-find-one-1.returnValues.model._id}},写进currentIncidentStateId。这些数据库组件是引擎按模型自动生成注册的(见 BaseModel.ts 的组件工厂与 ComponentMetadata.ts 的装配逻辑),Incident 模型开启了工作流开关后就会以incidents-find-one、incident-state-find-one这类 ID 出现在 Builder 里;其 Query 参数以列名为键,ID 列名是_id(id拼写也接受)。- Query:
把该工作流保持启用状态,现在给 Jira 一个可以调用的东西。
从 Jira 自动化规则发送事件
在 Jira 打开项目的自动化规则:新租户走Space settings → Automation,旧租户走Project settings → Automation。跨项目的规则走Settings → System → Global automation,需要全局权限Administer Jira。
Create rule,触发器选Work item transitioned——旧租户叫Issue transitioned。配置为状态变到(on)Done时运行。
务必选这个触发器,不要选Work item updated:Update 触发器刻意排除状态变更。
添加动作Send web request(发送 Web 请求)并配置:
Web request URL:上面的 OneUptime Webhook URL。
HTTP method:
POSTHeaders:
Content-Type/application/json,以及X-OneUptime-Secret/ 你的共享秘密。对秘密值使用Hide选项,防止其他规则编辑者读到——注意隐藏不可逆:规则被导出或复制时隐藏值会丢失。Web request body:选Custom format以自行控制结构:
{ "oneuptimeIncidentId": "{{issue.customfield_10050}}", "issueKey": "{{issue.key}}", "summary": "{{issue.summary}}", "status": "{{issue.status.name}}" }如果第三步用的是标签而非自定义字段,就发送
"labels": "{{issue.labels}}",然后在 OneUptime 侧用Run Custom JavaScript组件提取 ID。
启用规则,把一个测试 Issue 拖到 Done,然后两侧都检查:Jira 里规则的审计日志,以及 OneUptime 的执行与日志。
依赖它之前需要知道的限制:
- 目标端口受限。Send web request 只能到达 80、8080、443、6017、8443、8444、7990、8090、8085、8060、8900、9900。OneUptime Cloud 在 443 上;自托管部署跑在非标准端口上就无法被这样调用。
- 请求没有签名。该动作没有 HMAC 选项,HTTPS 加共享秘密头是 Atlassian 文档化的认证机制。接收侧工作流里那个 If / Else 检查才是让它值得做的部分。
- 规则执行会被计数。Jira Cloud 把成功的规则执行计入按月配额(取决于套餐:Free 100 次、Standard 1,700 次、Premium 每用户 1,000 次、Enterprise 不限)。一条在繁忙项目里每次转移都触发的规则,累计起来很快。
- 值不会替你 URL 编码。只有发送表单编码 Body 时才成为问题;上面的 JSON 无碍。
- Atlassian 会在 ip-ranges.atlassian.com 公布其出站 IP 段,如果你的 OneUptime 部署在正向允许名单之后可以用它。这些段会变,请定期拉取该 feed,不要写死地址。
或者改用 Jira 原生 Webhook
Jira 管理员也可以在Settings → System → Advanced → WebHooks直接注册 Webhook,选择要发送的事件,并可选一条限定触发 Issue 范围的 JQL。与自动化规则相比:
- Payload 是 Jira 自己的结构而非你自定义的:
webhookEvent、issue_event_type_name、完整issue对象,以及一个changelog,其items数组记录每个被改字段的前后值。状态变化要找field等于status的条目。在工作流里读它通常需要一个Run Custom JavaScript组件。 - Webhook可以签名——给 Webhook 设个密钥,Jira 就会发送包含请求体 HMAC 的
X-Hub-Signature头——但工作流无法校验它:签名覆盖的是 Jira 发出的原始字节,而 Webhook 触发器交给工作流的是已解析成 JSON 的 Body,没有东西可再哈希。想认证请求,请改用带共享秘密头的自动化规则。 - URL 必须是 HTTPS 且端口在 Jira 自己的列表内,而这份列表和自动化动作用的那份不是同一份——这里 80 端口不允许。
- 投递失败会重试最多 5 次,退避间隔 5 到 15 分钟,所以你的工作流必须能容忍同一事件到达两次(幂等设计)。
通过/rest/api/3/webhook由应用注册的 Webhook 又另当别论:不续期的话注册 30 天后失效;上面描述的由管理员注册的 Webhook 不会过期。
Jira Data Center 差异
自托管 Jira 同样可以跑通,只需做几处替换。Jira Server已于 2024 年 2 月停止支持、不再修复,因此把 Data Center 作为自托管目标。
| Cloud | Data Center |
|---|---|
/rest/api/3/... | /rest/api/2/...——Data Center 没有 v3 |
description用 ADF 文档 | description用 Wiki-Markup 纯字符串 |
Authorization: Basic base64(email:api_token) | Authorization: Bearer <personal access token> |
| API-Token 来自 id.atlassian.com | 在你自己的 Jira 账号里Profile → Personal access tokens → Create token |
| 自动化动作Send web request | 自动化动作Send outgoing web request |
建 Issue 的组件因此变成向/rest/api/2/issue发POST:
{ "fields": { "project": { "key": "OPS" }, "issuetype": { "name": "Bug" }, "summary": "OneUptime #123: Checkout is down", "description": "Plain text goes straight in here." } }没有文档树,模板写起来更简单。
还需要规划的更多差异:
- Personal access token自 Jira Core / Jira Software 8.14 及 Jira Service Management 4.15 起可用。Token 会过期——默认 365 天——界面会在到期前 5 天标记Expires soon。Data Center 上用户名+密码的 Basic-Auth 仍然可用,但连续几次登录失败会触发 CAPTCHA,把该账号彻底锁在 REST API 之外,直到有人在浏览器里解开——发现笔误的糟糕方式。用 Token。
- Automation 自 Jira Data Center 10.0 起内置,之前是需要单独安装的 Automation for Jira 应用。其出站请求默认超时 3000 ms,可用属性
outgoing.webhook.timeout.ms调整。 - Webhook在Administration → System → Advanced → WebHooks注册,支持 JQL 过滤。保持过滤器紧凑:Jira 在触发事件的那个线程上评估每个已注册 Webhook 的 JQL,十几个宽松过滤器会拖慢触发它们的那次用户操作。
- Data Center 10.0 起 Webhook 投递是异步的,且没有同步选项,事件可能乱序到达。接收侧工作流要做成幂等。
- Jira 10 移除了 Webhook URL 变量里的
$——${issue.id}变成{issue.id}——并把 Webhook REST 资源从/rest/webhooks/1.0/webhook挪到了/rest/jira-webhook/1.0/webhooks。
对告警(Alert)使用同一套模式
上面全部围绕事故展开,因为那是常见场景;但告警(Alert)完全一样——只换数据集类型,其余不变:
| 事故 | 告警 |
|---|---|
On Create Incident(incident-on-create-1) | On Create Alert(alert-on-create-1) |
On Update Incident(incident-on-update-1) | On Update Alert(alert-on-update-1) |
incidentNumber、currentIncidentState、incidentSeverity | alertNumber、currentAlertState、alertSeverity |
| Find One Incident State | Find One Alert State |
| Update One Incident | Update One Alert |
一个工作流只能有一个触发器,所以事故和告警各需要一个独立工作流。如果两者要做相同的工作,把 Jira 那一半只建一次,用Execute Workflow组件从两个触发工作流里调用它。
故障排查
先打开执行与日志里失败的那个组件。Jira 返回的 JSON Body 会准确说出拒绝原因,而 API 组件把它保留在response-body中。
401 Unauthorized。用printf重新编码email:api_token并更新JIRA_AUTH;echo的尾部换行是最常见原因。然后确认 Token 所属账号在该项目有创建 Issue 的权限。Data Center 上确认你发的是Bearer而非Basic。400 Bad Request且点名某个字段。Issue 类型在该项目不存在,或项目有必填字段而你没发。对项目和 Issue 类型跑一遍上面的createmeta调用并对照。400且抱怨description。Cloud v3 上描述必须是 ADF 文档而非字符串。发上面展示过的文档,或把该组件改打/rest/api/2/issue发纯文本。404 Not Found。检查基址和 API 版本——Cloud 用/rest/api/3/...,Data Center 用/rest/api/2/...。429 Too Many Requests。Jira 在限流。响应带Retry-After(秒)和RateLimit-Reason(说明撞了哪条限制)。对单个 Issue 的写操作限制很紧——量级约两秒 20 次——快速连续评论加转移的工作流完全可能在单个 Issue 上触发。在调用之间放一个Delay组件,或把批量工作挪进计划触发的工作流。- 转移调用返回
400。转移 ID 对 Issue当前状态无效。对该 Issue 拉一次/transitions,从响应里取 ID。 - 自动化规则显示成功,但 OneUptime 没收到。先查端口——见上面的受限列表。然后自己用
curl打一次 Webhook URL,看它是否出现在执行与日志里;你的请求到了而 Jira 的没到,问题就在 Jira 侧。 - 工作流跑了但事故没变。Update One Incident组件在 Query 未命中任何记录时报告
Items Updated: 0,并且算成功而非错误。检查 Payload 里的 ID 是不是真的 OneUptime 事故 ID,并且你确实按_id查询。 {{...}}引用原样出现在 Jira Issue 里。未解析的引用会作为文本透传而不是被清空。执行日志会列出每一个没能解析的引用——通常是组件 Identifier 拼错或变量被改名了。
延伸阅读
- 集成总览——入站与出站模式、认证速查表。
- Microsoft Dynamics 365——同一套结构对接 Dynamics 的双向集成。
- 工作流总览与创建工作流——画布、Identifier、启用工作流。
- 组件——API 组件、If / Else 与 OneUptime 数据组件。
- 变量——秘密变量、以及在一个组件里读另一个组件的输出。
- 配置与安全——Webhook 安全与出站网络访问。
- ServiceNow与PagerDuty——对接其他工具的同一套出站模式。
【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考