openstatus API 实战指南:用 ConnectRPC 将 uptime 监控与状态页写成代码
【免费下载链接】openstatus🫖 Status page with uptime monitoring & API monitoring as code 🫖项目地址: https://gitcode.com/GitHub_Trending/op/openstatus
openstatus 提供了一套类型化、基于 JSON-over-HTTP 的公共 API,底层由 ConnectRPC 驱动,基地址为https://api.openstatus.dev。Dashboard 上你能执行的每一个操作——创建监控器、管理状态页、发布事故报告、安排维护窗口——都能通过这套 API 以编程方式完成,并且共享同一个工作区、同一份审计日志和同一把 API Key。读完本文,你将掌握 API 的认证方式、核心服务与 RPC 结构、典型调用示例,以及它和 MCP 服务器之间的取舍,可以直接在 CI/CD、脚本与自建集成中把监控即代码落地。
从 Dashboard 到 API:openstatus 公共 API 全景
openstatus 公共 API 是ConnectRPC(Connect 协议)之上的类型化 JSON-over-HTTP 层。这意味着:
- 它遵循 schema-first 的
.proto文件定义,仓库中的全部契约位于 packages/proto/api/openstatus; - 请求与响应既可以是 JSON,也可以是 protobuf;
- 即使读操作也必须使用
POST方法; - 所有 RPC 挂在
/rpc/*路径前缀下,与既有的 REST API 共用同一个 Hono 服务端口。
仓库中的 ConnectRPC 规范说明 给出了明确的架构决策:仅支持 Connect 协议(兼容 HTTP/1.1)、仅使用 unary 调用(无流式)、schema 由 Buf 工具链管理(buf.yaml、buf.gen.yaml),包命名统一为openstatus.<domain>.v1(例如openstatus.monitor.v1),代码生成目标覆盖 TypeScript(@bufbuild/protobuf+@connectrpc/connect)与 Go。
服务端的实际挂载实现在 apps/server/src/routes/rpc/index.ts 中:所有/rpc/*请求先剥掉/rpc前缀,再匹配 Connect 路由表中的 handler,最后通过universalServerRequestFromFetch/universalServerResponseToFetch完成 Fetch API 与 Connect 通用消息的互转。
当前已注册到 Connect 路由表的服务(见 apps/server/src/routes/rpc/router.ts)包括:
| 服务 | 职责 |
|---|---|
MonitorService | 监控器 CRUD 与运维操作(HTTP/TCP/DNS/ICMP/gRPC 五种类型) |
StatusPageService | 状态页、组件、组件分组、订阅者与聚合状态查询 |
StatusReportService | 事故/状态报告的完整生命周期 |
MaintenanceService | 维护窗口的排期管理 |
NotificationService | 通知渠道管理 |
PrivateLocationService | 私有节点管理 |
HealthService | 健康检查 |
所有请求会依次经过五层拦截器:errorInterceptor(错误映射为 ConnectError)→loggingInterceptor(请求/响应日志)→authInterceptor(API Key 校验与工作区上下文注入)→validationInterceptor(基于 protovalidate 的消息校验)→trackingInterceptor(成功事件埋点)。
认证:x-openstatus-key头与 API Token
API 的认证方式非常简单:把 API Key 放在x-openstatus-key请求头中,Key 在Settings → API Tokens中生成,形如:
x-openstatus-key: os_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx服务端凭据提取的源码在 apps/server/src/libs/middlewares/credentials.ts:优先读取x-openstatus-key头,其次才尝试Authorization: Bearer <token>(x-openstatus-key优先级更高,两者并存时以 header 为准)。Key 的典型前缀为os_,另有sa_前缀表示超级管理员 Token,可借助x-workspace-id元数据头指定目标工作区(详见 ConnectRPC 规范说明)。
API Key 本身的管理(创建、吊销、列出)也通过 Dashboard 的 tRPC 路由暴露,实现在 packages/api/src/router/apiKey.ts:创建时返回一次性明文 Token,UI 展示一次后即丢弃;吊销与查询分别调用 services 层的revokeApiKey与listApiKeys。在服务端,每一次 API 调用的工作区身份都由authInterceptor从凭据推断,并在 apps/server/src/routes/rpc/adapter.ts 中携带apiKey.id进入服务上下文——这意味着 API 发起的变更会在审计日志中追溯到具体的 Key。
第一个请求:列出所有监控器
文档给出的最小可运行示例(注意 shell 变量$OPENSTATUS_API_KEY需提前导出):
curl https://api.openstatus.dev/rpc/openstatus.v1.MonitorService/ListMonitors \ -X POST \ -H "Content-Type: application/json" \ -H "x-openstatus-key: $OPENSTATUS_API_KEY" \ -d '{}'几点说明:
- 路径约定:Connect RPC 路径由「包名 + 服务名 + 方法名」组成。按仓库中
openstatus.<domain>.v1的包命名(见 monitor/v1/service.proto 的package openstatus.monitor.v1),MonitorService 的规范完整路径为/rpc/openstatus.monitor.v1.MonitorService/ListMonitors,生成的 TypeScript 服务定义在 packages/proto/gen/ts/openstatus/monitor/v1/service_pb.ts。 - 请求参数:
ListMonitorsRequest支持两个可选分页字段——limit(1~100,默认 50)与offset(≥0,默认 0)。 - 响应结构:
ListMonitorsResponse按协议类型分组返回http_monitors、tcp_monitors、dns_monitors、icmp_monitors、grpc_monitors,并附带total_size表示全部类型的监控器总数。 - 幂等标记:
ListMonitors在 proto 中声明了idempotency_level = NO_SIDE_EFFECTS,表明它是纯读操作,可安全重试。
监控器管理:五种协议类型的 CRUD 与运维操作
全部 RPC 一览
MonitorService是 API 中最核心的服务,定义于 monitor/v1/service.proto:
| RPC | 说明 |
|---|---|
CreateHTTPMonitor/CreateTCPMonitor/CreateDNSMonitor/CreateICMPMonitor/CreateGRPCMonitor | 创建对应类型的监控器 |
UpdateHTTPMonitor/UpdateTCPMonitor/UpdateDNSMonitor/UpdateICMPMonitor/UpdateGRPCMonitor | 部分更新(monitor字段全部可选) |
TriggerMonitor | 在所有已配置区域立即触发一次检查(受合成检查配额限流) |
DeleteMonitor | 删除监控器 |
ListMonitors | 分页列出工作区全部监控器 |
GetMonitor | 按 ID 读取单个监控器(通过MonitorConfigoneof 返回类型化配置) |
GetMonitorStatus | 返回各区域的实时状态 |
GetMonitorSummary | 返回聚合指标(延迟分位数、成功/降级/失败计数) |
ListMonitorHTTPResponseLogs/GetMonitorHTTPResponseLog | 查询 14 天窗口内的 HTTP 响应日志 |
MonitorConfig使用 oneof 将http、tcp、dns、icmp、grpc五种配置合为一体,GetMonitor的返回即这一结构。
HTTPMonitor 配置字段详解
HTTP 监控器的核心字段定义于 http_monitor.proto,字段约束可直接作为参数校验依据:
| 字段 | 类型/约束 | 说明 |
|---|---|---|
name | string,1~256 | 监控器名称(必填) |
url | string,1~2048,须为合法 URI | 目标地址(必填) |
periodicity | 枚举 | 检查周期,见下方枚举 |
method | 枚举 | HTTP 方法,默认GET |
body | string | 请求体(POST/PUT/PATCH 等场景) |
timeout | int64,0~120000 ms | 超时时间,默认 45000 |
degraded_at | int64,0~120000 ms | 判定为「降级」的延迟阈值 |
retry | int64,0~10 | 重试次数,默认 3 |
follow_redirects | bool | 是否跟随重定向,默认 true |
headers | 数组,最多 20 项 | 自定义请求头(key/value) |
status_code_assertions/body_assertions/header_assertions | 数组,各自最多 10 项 | 状态码/响应体/响应头断言,类型见 assertions.proto |
description | string,最大 1024 | 描述 |
active | bool | 是否立即开始检查,默认 false |
public | bool | 是否公开可见,默认 false |
regions | 数组,最多 28 项 | 执行检查的地理区域 |
open_telemetry | 对象 | OTEL 导出配置(endpoint + 最多 20 个自定义头) |
status | 枚举 | 当前运行状态(只读) |
private_location_ids | string 数组 | 关联的私有节点 ID(只读) |
相关枚举(定义于 monitor.proto):
- Periodicity:
PERIODICITY_30S、PERIODICITY_1M、PERIODICITY_5M、PERIODICITY_10M、PERIODICITY_30M、PERIODICITY_1H; - HTTPMethod:
GET、POST、HEAD、PUT、PATCH、DELETE、TRACE、CONNECT、OPTIONS; - MonitorStatus:
ACTIVE、DEGRADED、ERROR; - Region:覆盖 Fly.io(AMS/ARN/BOM/CDG/DFW/EWR/FRA/GRU/IAD/JNB/LAX/LHR/NRT/ORD/SJC/SIN/SYD/YYZ)、Koyeb(FRA/PAR/SFO/SIN/TYO/WAS)与 Railway(US_WEST2/US_EAST4/EUROPE_WEST4/ASIA_SOUTHEAST1)共 28 个区域。
创建 HTTP 监控器的示例
curl https://api.openstatus.dev/rpc/openstatus.monitor.v1.MonitorService/CreateHTTPMonitor \ -X POST \ -H "Content-Type: application/json" \ -H "x-openstatus-key: $OPENSTATUS_API_KEY" \ -d '{ "monitor": { "name": "Production API Health Check", "url": "https://api.example.com/health", "periodicity": "PERIODICITY_1M", "method": "HTTP_METHOD_GET", "timeout": 45000, "retry": 3, "headers": [{ "key": "Authorization", "value": "Bearer token123" }], "regions": ["REGION_FLY_IAD", "REGION_FLY_FRA"], "active": true } }'创建成功后返回带 ID 的HTTPMonitor;UpdateHTTPMonitor以id+ 可选的monitor字段实现部分更新;TriggerMonitor立即在所有配置区域跑一次真实检查(proto 中注明受 synthetic-checks 配额限流),适合验证配置或排障。
聚合指标与响应日志
- GetMonitorSummary:
time_range支持TIME_RANGE_1D/TIME_RANGE_7D/TIME_RANGE_14D,可按区域过滤(最多 28 项)。返回total_successful/total_degraded/total_failed计数、p50/p75/p90/p95/p99延迟分位数(毫秒)以及last_ping_at时间戳。 - ListMonitorHTTPResponseLogs:分页查询 14 天窗口内的响应日志,每条记录含
latency、status_code、request_status(SUCCESS/ERROR/DEGRADED)、region、trigger(CRON 或 API 触发)、cron_timestamp与timestamp。 - GetMonitorHTTPResponseLog:返回单次检查的完整详情,包括
HTTPResponseLogTiming五段耗时(dns/connect/tls/ttfb/transfer)、脱敏后的响应头(headers)、错误信息与序列化的断言配置(assertions),是定位慢请求与断言失败的最有力工具。
状态页管理:从建页到组件、分组与订阅
StatusPageService定义于 status_page/v1/service.proto,是 API 中 RPC 最丰富的服务,可分为四组:
页面 CRUD:CreateStatusPage、GetStatusPage、ListStatusPages(分页,limit 1~100 默认 50)、UpdateStatusPage、DeleteStatusPage。
创建状态页的核心字段与校验规则(CreateStatusPageRequest):
| 字段 | 约束 | 说明 |
|---|---|---|
title | 1~256 | 页面标题(必填) |
slug | 正则^[a-z0-9]+(?:-[a-z0-9]+)*$ | URL 友好别名,小写字母数字加连字符(必填) |
description | 最大 1024 | 描述 |
homepage_url/contact_url | URL | 主页与联系页 |
default_locale/locales | 枚举 | 默认语言与启用语言 |
custom_domain | 最大 256 | 自定义域名 |
theme | 枚举 | 视觉主题,默认SYSTEM |
access_type | 枚举 | 访问控制,默认PUBLIC |
password | 1~256 | 当access_type = PASSWORD_PROTECTED时必填 |
auth_email_domains | 数组 | 当access_type = AUTHENTICATED时使用的邮箱域名白名单 |
allowed_ip_ranges | 字符串 | 当access_type = IP_RESTRICTED时必填,逗号分隔的 IPv4 CIDR |
allow_index | bool | 是否允许搜索引擎收录,默认 true |
custom_theme | 对象 | 按模式覆盖 CSS 变量,仅接受受支持变量名(需要 custom-theme 套餐) |
组件与分组:AddMonitorComponent(把监控器挂到状态页,name缺省取监控器名)、AddStaticComponent(纯静态组件,需name)、RemoveComponent、UpdateComponent、GetPageComponent、CreateComponentGroup/DeleteComponentGroup/UpdateComponentGroup(分组支持default_open控制默认展开)。
订阅者:这里有两种互补的订阅 RPC,选哪个取决于谁发起的订阅:
SubscribeToPage:终端用户自助订阅,带双重 opt-in 验证——系统发送验证邮件,用户确认后订阅才生效;若该邮箱曾退订,则复用原有记录重新激活而非重复创建。CreatePageSubscription:运营方代建订阅,免验证立即生效,适用于已在线下确认同意的伙伴/厂商场景;支持 email 与 webhook 渠道(Slack/Discord 的 webhook URL 按前缀自动识别 payload 风格,也可附带自定义头),仍会生成管理 Token 供对方通过/manage/{token}与/unsubscribe/{token}自助管理。
另有UnsubscribeFromPage(按 email 或订阅者 ID)与ListSubscribers(支持include_unsubscribed)。
内容与聚合状态:
GetStatusPageContent:按id(需认证、限定工作区)或slug(公开访问,要求页面access_type = PUBLIC)返回页面完整内容——含组件、分组、进行中的状态报告与已排期维护。GetOverallStatus:返回聚合状态与各组件状态,聚合优先级为degraded(进行中的状态报告)> maintenance(进行中的维护窗口)> operational。GetStatusPageOverview:一次认证调用取回页面、富配置、组件、分组、报告、维护与计算出的状态。GetPageComponentDailySummary:按天返回ok/degraded/error/count桶并合并事件时间线(最多 45 天),是渲染状态条与 uptime 日历的单一事实来源;同样支持 id 与 slug 两种访问路径。
事故报告与维护窗口:把故障响应写成代码
状态报告(Status Report)
StatusReportService定义于 status_report/v1/service.proto,其生命周期状态枚举在 status_report.proto 中:INVESTIGATING→IDENTIFIED→MONITORING→RESOLVED。
主要 RPC:CreateStatusReport、GetStatusReport(含完整更新时间线)、ListStatusReports、UpdateStatusReport、DeleteStatusReport、AddStatusReportUpdate。
创建事故报告的示例(notify为 true 时将通过邮件通知页面订阅者):
curl https://api.openstatus.dev/rpc/openstatus.status_report.v1.StatusReportService/CreateStatusReport \ -X POST \ -H "Content-Type: application/json" \ -H "x-openstatus-key: $OPENSTATUS_API_KEY" \ -d '{ "title": "API Degradation Investigation", "status": "STATUS_REPORT_STATUS_INVESTIGATING", "message": "We are investigating reports of increased API latency.", "date": "2024-03-15T10:30:00Z", "page_id": "pg_xxxxxxxx", "notify": true }'date必须为 RFC 3339 格式(正则校验^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?(Z|[+-]\d{2}:\d{2})$)。AddStatusReportUpdate在追加时间线条目的同时把报告推进到指定状态;component_impacts字段(PAGE_COMPONENT_IMPACT_DEGRADED_PERFORMANCE/PARTIAL_OUTAGE/MAJOR_OUTAGE等)允许为每个组件声明受影响程度。
维护窗口(Maintenance)
MaintenanceService定义于 maintenance/v1/service.proto:CreateMaintenance、GetMaintenance、ListMaintenances、UpdateMaintenance、DeleteMaintenance。
curl https://api.openstatus.dev/rpc/openstatus.maintenance.v1.MaintenanceService/CreateMaintenance \ -X POST \ -H "Content-Type: application/json" \ -H "x-openstatus-key: $OPENSTATUS_API_KEY" \ -d '{ "title": "Database Migration", "message": "Scheduled maintenance for the primary database.", "from": "2024-03-01T02:00:00Z", "to": "2024-03-01T06:00:00Z", "page_id": "pg_xxxxxxxx" }'from/to均为必填的 RFC 3339 时间,维护窗口会以maintenance状态参与GetOverallStatus的聚合优先级计算。
其他服务:通知、私有节点与健康检查
- NotificationService(notification/v1/service.proto):通知渠道 CRUD,另有
SendTestNotification(发送测试通知)与CheckNotificationLimit(检查渠道配额)。 - PrivateLocationService(private_location/v1/service.proto):私有节点的创建、查询、列表、更新与删除,用于在自有基础设施中运行探针。
- HealthService(health/v1/health.proto):提供
Check健康检查 RPC。
Schema 与 SDK
- OpenAPI 描述文件:机器可读的 API 描述位于
https://api.openstatus.dev/openapi,同时提供/openapi.yaml、/openapi.json与/openapi-v1.json三种形式。服务端实现在 apps/server/src/routes/openapi.ts:文档公开、无需认证,并带有Access-Control-Allow-Origin: *与Cache-Control: public, max-age=3600,方便浏览器端与 Agent 直接抓取。 - Node SDK:
@openstatus/sdk-node,可从 jsr.io 获取,提供类型化客户端,省去手写 curl。 - Terraform Provider:官方工具链(见 openstatus.dev 的 tooling 页面)支持以声明式资源管理监控器等对象。
- 类型化客户端源码:本仓库已生成 TypeScript 客户端,见 packages/proto/gen/ts,可供自建集成直接参考调用签名。
错误处理
Connect 层统一使用标准错误码并携带 GoogleErrorInfo结构化详情(依据 ConnectRPC 规范说明):
| 错误码 | 典型场景 |
|---|---|
NOT_FOUND | 监控器/状态页 ID 不存在 |
INVALID_ARGUMENT | 参数未通过 protovalidate 校验(如 slug 非法、limit 越界) |
PERMISSION_DENIED | 凭据无权限访问目标资源 |
UNAUTHENTICATED | 缺少或错误的x-openstatus-key |
RESOURCE_EXHAUSTED | 触发限流或配额(如TriggerMonitor的合成检查配额) |
INTERNAL/UNAVAILABLE | 服务端内部错误或暂不可用 |
ErrorInfo的domain为openstatus.com,reason为机器可读的错误原因(如MONITOR_NOT_FOUND),metadata中携带requestId、resourceId等上下文,便于日志关联与排障。所有纯读 RPC 都声明了NO_SIDE_EFFECTS幂等级别,可安全重试;变更类 RPC 则被完整写入工作区审计日志,可通过apiKey.id追溯到具体凭据。
API 还是 MCP?何时选择
openstatus 同时提供两条自动化通路,选型取决于使用场景(MCP 的完整说明见 openstatus-mcp Skill 文档):
| 场景 | 推荐 | 原因 |
|---|---|---|
| 程序化集成、CI/CD、定时脚本、自建系统 | API | 以x-openstatus-key头认证,POST JSON 即可,无额外依赖;同一个 Key 同时可用于 CLI、REST API 与 Terraform provider |
| 聊天形态的 AI 客户端(Claude、Cursor、Codex 等) | MCP 服务器(https://api.openstatus.dev/mcp) | 支持 OAuth(PKCE)与 API Key 两种凭据,按工作区与读写范围授权;提供list_*/get_*与变更工具,适合对话式查询与发布操作 |
两者的数据面完全一致:同样的工作区、同样的审计日志、同样的底层服务。对多数工程化场景,直接调用 API 更加可控——一条 curl、一个 Node SDK 调用即可完成监控器创建、事故发布或维护排期,让整个监控与状态管理流程真正成为代码的一部分。
【免费下载链接】openstatus🫖 Status page with uptime monitoring & API monitoring as code 🫖项目地址: https://gitcode.com/GitHub_Trending/op/openstatus
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考