概述
go-flashduty 是 Flashduty 官方开源的 Go 客户端,覆盖 Flashduty Open API 的每一个 REST 接口。它采用与 go-github 一致的设计风格——服务分组、类型化请求与响应、可组合传输层——并与 OpenAPI 规范保持严格 1:1:每个方法对应且仅对应一次 HTTP 调用,返回 (*T, *Response, error),不做任何跨接口的隐式聚合或增强。
SDK 的类型化接口由 Flashduty OpenAPI 规范生成,经单元测试覆盖,并针对线上 API 做过端到端验证。
SDK 故意保持”薄”。诸如短 ID 解析、跨接口编排等消费侧逻辑应放在调用方(CLI / MCP)中,而不是塞进 SDK 或滥用某个接口。这样 SDK 始终与 API 一一对应,可预测、可生成、可校验。
github.com/flashcatcloud/go-flashduty,包名为 flashduty,源码遵循 Apache-2.0 协议开源在 flashcatcloud/go-flashduty。
Open API 参考
全部接口的请求参数与响应字段说明。
命令行工具
在终端中直接操作 Flashduty 的 CLI。
安装
1
要求 Go 1.24+
请确认本地 Go 工具链版本不低于 1.24。
2
获取依赖
3
导入包
快速开始
以下是一个最小可运行示例:构造客户端、列出处于”已触发”状态的故障,并处理返回的三元组
(数据, *Response, error)。
创建客户端
NewClient 接收 app_key 与零到多个 Option。app_key 为空会直接返回错误。默认 Base URL 为 https://api.flashcat.cloud,默认 HTTP 超时为 30 秒,默认 User-Agent 为 go-flashduty。
私有化部署:用
WithBaseURL 将客户端指向您自有的 Flashduty 网关地址即可,其余调用方式完全不变。服务与方法
接口按服务分组挂在客户端上:调用约定统一为
client.<Service>.<Method>(ctx, req),返回 (*T, *Response, error)。例如 client.Incidents.List(ctx, req)、client.Sessions.Info(ctx, req)。
client.StatusPages.DraftCreate(POST /status-page/draft/create)把一次状态页事件草稿存下来,供人工在控制台审阅后发布,不会直接对外可见:draft 为任意 JSON,按原文存储、序列化后不超过 64 KB,其中 page_id、type(incident 或 maintenance)、name、message 会被校验;change_id(> 0 时表示追加到已有事件的一次更新)、status、affected_components 可选,新建 maintenance 时可用 start_time / end_time(Unix 秒)指定窗口。请求上的 source 是草稿来源标记(≤ 64 字符,如 ai_sre:sess_xxx);响应返回 draft_id(匹配 draft_[A-Za-z0-9]{22}),控制台的审阅链接即携带它。
client.Knowledge 对应 /safari/knowledge/* 的 9 个 API 操作:知识包侧为 PackReadGet(获取账户知识包)、PackReadList(列出知识包)、PackWriteEnsure(确保知识包存在)、PackWriteUpdate(变更知识包作用域)、PackWriteDelete(删除知识包);知识文件侧为 FileReadGet、FileReadList、FileWritePut(上传/覆盖)、FileWriteDelete。相关导出类型包括 KnowledgePackItem、KnowledgeFileItem、KnowledgeWarning 以及各 Knowledge*Request / Knowledge*Response。
client.Artifacts(AI SRE 产物)对应 /safari/artifact/* 的 11 个 API 操作:画廊读取侧 ReadGet(按 ID 获取单个已发布产物)、ReadList(分页列出调用方可见的产物,支持标题子串搜索、scope(all / personal / team)与 team_ids 过滤)、ReadGetFileState(批量探测会话展示文件(pf_ 前缀)是否已有上线产物,单次至多 50 个 ID);文件侧 ReadSign(为展示文件签发短期有效的下载/预览 URL,有效期 5 分钟,expires_in 固定 300 秒)与 ReadStream(凭签名 token 下载或预览文件,成功响应体是文件而非 JSON 信封,原始字节放在 Response.Raw);写入侧 WritePublish(把会话产生的文件发布为画廊产物)、WriteUpdate(重命名或转移个人/团队作用域)、WriteDelete(从画廊移除,源文件仍保留在会话中);公开分享 WriteShareEnable(开启匿名公开分享并返回公开链接,任何人凭链接即可查看、无需登录)、WriteShareRevoke(关闭分享,链接立即失效)、WriteShareSync(把公开快照刷新为最新内容——当 share_enabled 为 true 且 share_file_id 与 file_id 不一致时表示快照已过期,调用它刷新)。相关导出类型包括 PublishedArtifactItem、ArtifactShareState、SignedUrLs 以及各 Artifact*Request / Artifact*Response。
client.Diagnostics.QueryData 通过 POST /monit/query/data 执行同步查询,返回稳定的 query_result.v1 结构化结果(result.kind 为 frames / records / samples 之一),要求 monit-edge v0.65.0 及以上版本。日志模式和指标趋势分析统一使用 client.DataSources.ToolsInvoke,工具名称为 prometheus.metric_trends、loki.log_patterns 或 victorialogs.log_patterns。
client.DataSources.ToolsInvoke(POST /monit/datasource/tools/invoke,monit-datasource-tools-invoke)在某个已配置数据源上执行一个确定性工具:tool 名称由数据源类型前缀修饰(如 mysql.overview),params 为工具专属 JSON 参数(省略视为 {},显式 null 非法);除诊断工具外,入口支持 <type>.query 查询工具(prometheus、mysql、postgres、oracle、clickhouse、elasticsearch、loki、victorialogs、sls、tencent_cls),/monit/query/data 入口保持不变。该接口要求集群中所有在线可路由的 Edge 会话都支持 v0.71.0 基础调用协议(单个工具可能要求更新的实现),无工具目录、无自动重放、也不会回退到旧版 diagnose。请求体上限 128 KiB,完整成功响应上限 10 MiB,单工具超时至多 25 秒;响应为 DatasourceToolResult(data 为工具专属 JSON、永不为 null,summary 可选,出现 truncated 时其 reason 说明截断原因)。
client.DataSources 的 payload 按 type_ident 选择类型专属配置块。当前允许的 type_ident 共 15 种:prometheus、loki、mysql、oracle、postgres、clickhouse、elasticsearch、sls、tencent_cls、victorialogs,以及新增的诊断专用类型 redis_node、redis_sentinel、mongodb_mongod、mongodb_mongos、kafka——诊断专用类型的 alerting_enabled 恒为 false(不阻止非告警查询与工具调用),且拒绝传 true。连接地址规则:Redis/MongoDB 诊断类型为单个 host:port(IPv6 需加方括号),不接受 URI、userinfo 或 query;kafka 为 1–32 个以逗号分隔、互不重复的 host:port bootstrap 地址(规范化后至多 4096 字符,payload 中不再有 broker 列表);mongodb_mongod / mongodb_mongos 的配置块中 auth_source 默认为 admin,用户名与密码必须成对配置,不支持客户端证书;Redis 节点配置的 database 默认为 0。诊断类型的 password 与 Kafka 的 tls_key 等敏感字段支持 ${env:NAME} 引用:响应中字面值会被省略(仅当存储值本身就是 ${env:...} 引用时才回显),更新时省略这些字段即保留原值,显式传空字符串则清除。
enabled 与 alerting_enabled 相互独立:enabled(业务执行开关)创建时默认 true,alerting_enabled(是否允许参与告警评估;告警还要求 enabled 为 true 且类型支持告警)创建时对告警类型默认 true、对诊断专用类型默认 false;二者更新时省略均保留当前值,显式传 null 非法;当有启用的告警规则引用该数据源时,将其 enabled 置为 false 会以 conflict 拒绝。另外 /monit/datasource/list 响应中 payload 恒为 null(列表查询不读 payload 列),create/update/info 响应中才会填充。
所有标识符、服务字段名与方法名均与生成代码保持一致。具体每个服务有哪些方法、请求与响应类型,请以
services_gen.go 与各服务文件,以及 Open API 参考 为准。响应时间戳
响应中的时间字段不再是裸整数,而是自描述的
Timestamp(Unix 秒)或 TimestampMilli(毫秒)类型。它们序列化为本地时区的 RFC3339 字符串,因此 JSON、日志以及面向 LLM 的输出都直接可读;原始 epoch 仍只需一次方法调用即可取到。
- 序列化(出站):非零值序列化为带引号的 RFC3339 字符串(
TimestampMilli用 RFC3339Nano 以保留毫秒精度)。零值序列化为裸整数0——一个”未设置”哨兵,而非 1970 年的日期,并被json:",omitempty"丢弃。 - 反序列化(入站):既兼容数字 epoch(线上原始形态),也兼容 RFC3339 字符串(使序列化后的值可无损往返),还接受
null(→ 0)。
分页
所有列表接口共享
ListOptions,将其内嵌在请求结构体中即可。零值会被省略,不会覆盖服务端默认值(后端默认 p=1、limit=20)。
响应侧,
*Response 携带 Total、HasNextPage 与 SearchAfterCtx。推荐用 search-after 游标逐页遍历:
错误处理
Flashduty API 返回的未成功调用——无论是信封中携带了错误,还是 HTTP 状态非 2xx——都会返回
*ErrorResponse。它带有 Code、Message、可选的 Reason 与 RequestID 字段,排障时把 RequestID 提供给支持团队即可定位。Reason 携带服务端给出的可选原因(信封内的 DutyError 同样带有该字段,JSON 字段为 reason,omitempty);非空时它也会被追加到错误字符串末尾,形如 , reason X。
当 API 返回 429 时,错误被提升为 *RateLimitError:它内嵌 *ErrorResponse(所以 errors.As 取 *ErrorResponse 仍然成立),并额外带上 RetryAfter 提示。
如果你收到的是带非 JSON 响应体的非 2xx 响应,SDK 会返回普通
error,而不是 *ErrorResponse。这表示响应来自网关、负载均衡器或代理等中间层,通常是请求超过了中间层超时。你可以重试请求,或将耗时较长的批量请求拆分为更小的批次;不要假定 errors.As(err, &apiErr) 能匹配此类错误。errors.As):
重试
核心客户端不内置自动重试。请通过传输层组合可选的
retry 子包——一个安全默认的重试型 http.RoundTripper。
github.com/flashcatcloud/go-flashduty/retry 的特性:
- 重试条件:HTTP 429、任意 5xx(状态码 ≥ 500),以及传输错误。其他 4xx 与所有 2xx/3xx 立即返回。
- 退避策略:确定性指数退避(
MinWait * 2^attempt,每次上限为MaxWait);无随机抖动。存在合法的整数Retry-After头时,以其为准(同样不超过MaxWait)。 - 安全回放:仅当请求体可回放(
req.Body为 nil 或req.GetBody非空)时才重试,每次重试都在请求的克隆上重建请求体,绝不修改调用方的原始*http.Request。SDK 构造的所有请求都设置了GetBody,因此 POST 请求体都可安全回放。 - 尊重取消:等待退避期间若请求 context 被取消,立即返回 context 错误。
流式导出
client.Sessions.Export 用于导出一个 AI SRE 会话的完整事件转录,返回的是 io.ReadCloser(NDJSON 流,application/x-ndjson),而非 JSON 信封。首行始终是一条 session_meta 信封,其后每行是一个会话事件;当 req.IncludeSubagents 为 true 时,每条 subagent_dispatch 行后会跟随子会话自身的完整事件流。
由于响应体可能很大,应当逐行读取并直接写入文件,不要把整段转录缓冲进内存。返回的 io.ReadCloser 是活动 HTTP 响应体,由调用方持有并必须 Close(defer 关闭即正确)。配合 NewExportScanner 可按行扫描,DecodeExportLine 可将一行解码为 ExportLine:
NewExportScanner 配置的单行缓冲区足以容纳转录中较宽的事件行(如 tool 输出、LLM 调用),不受默认 64KB token 上限限制。任何非 2xx 状态下,响应体仍是常规 JSON 错误信封——Export 会读取并关闭它,返回类型化错误(*ErrorResponse,429 时为 *RateLimitError),此时 io.ReadCloser 为 nil,与其他生成接口行为一致。