Skip to content

控制面结构化日志和 /metrics,部署文档写清怎么接 Loki 和 Prometheus (#29) - #120

Merged
joesmart merged 2 commits into
mainfrom
joesmart/ops-structured-logs
Oct 24, 2026
Merged

joesmart merged 2 commits into
mainfrom
joesmart/ops-structured-logs

Conversation

@joesmart

Copy link
Copy Markdown
Contributor

改了什么

结构化日志

  • 新增 packages/control-plane/src/log.ts,不引新依赖。每行一条 JSON:time、level、msg,再带上下文字段 runId、computerId、groupId、botId(有哪个带哪个)和各处自己的字段。LOG_FORMAT=pretty 输出 HH:MM:SS.mmm LEVEL msg k=v,错误另起几行写 message 和 stack。
  • pnpm dev 给控制面默认设 LOG_FORMAT=pretty,生产不设就是 JSON;写了别的值启动报 LOG_FORMAT 只能是 json 或 pretty 并以 1 退出。
  • 控制面 src/ 里除了 src/scripts/*(给人复制的 CLI 输出)以外,console.* 全部换成 log.*。原来打完整 error 的地方,err 带 name、code、message、stack;原来只记 errorKind 的地方(报文、牌桌、例行这类异常原文可能夹着用户正文的),改用 concealed(error),只记 name、code 和 stack 里的 at 行,隐私边界不变。
  • 脱敏:每行输出前,Bearer xxx 换成 Bearer [已隐去],UPSTREAM_API_KEY、METRICS_TOKEN 的原值换成 [已隐去]。电脑 token、网关 key、登录 cookie 本来就不进日志。

指标

  • GET /metrics,Prometheus 文本格式。只有设了 METRICS_TOKEN 才开,要带 Authorization: Bearer <token>,错了回 401,没设回 404。
  • 指标:baize_computers_online、baize_runs{state=running|unsettled|settled}、baize_gateway_responses_total{code}(网关 /chat/completions 回给电脑的每个状态码,含 模型网关加上游超时和按电脑限速,Pi 拿到 504/429 报错收尾不再挂住 (#46) #116 的 504 和 429)、baize_continuation_backlog(补扫积压)、baize_websocket_connections{kind=agent|push|live}。

错误上报

  • 不接第三方。error 日志加上指标,已经够运维接 Loki/Prometheus:docs/部署.md 新开「日志和指标」一节,写了字段含义、Promtail 的 docker_sd 示例、指标表、Prometheus 抓取配置和告警示例;还写明 Caddy 不转发 /metrics,要从内网直接抓 3001。

其他

  • .env.example、docs/开发.md、deploy/README.md、deploy/remote/docker-compose.yml 加了 LOG_FORMAT、METRICS_TOKEN。
  • 电脑代理和运行器这次不动。

为什么

#29:控制面的日志原来是 console.error(文案, error) 拼出来的散文,收集器按 run 或电脑查不了;也没有任何指标可抓。另外,旧代码在上游报错时会把上游回包的前 200 字原样写进日志,上游要是在回包里回显了 Authorization,UPSTREAM_API_KEY 就进了日志(下面「main 上的证据」)。

怎么验证

pnpm format:check && pnpm typecheck && pnpm lint      # 通过,0 error(警告都在别的包的老代码里)
.lane/pg-serial.sh pnpm --filter @baize/control-plane test
  Test Files  127 passed | 1 skipped (128)
       Tests  1602 passed | 1 skipped (1603)
E2E_API_PORT=3931 E2E_WEB_PORT=5931 .lane/pg-serial.sh pnpm --filter @baize/e2e test
  Test Files  27 passed (27)
       Tests  55 passed (55)

新加的用例:

  • test/metrics-endpoint.test.ts:没设 token 回 404;token 不带或错回 401,对了回 200,在线电脑数和 WebSocket 数对得上;派出一个 run 记成 running,run_done 结账后挪到 settled。
  • test/gateway.test.ts 的「运维」:504 和 429 按状态码记进 /metrics;上游把收到的 Authorization 原样回显,日志里既没有网关 key 也没有上游 key。
  • test/process.test.ts:不设 LOG_FORMAT 时真进程每行都是合法 JSON,单聊里交上来的复盘被丢掉,那一行带 runId、computerId、groupId、botId,也不带复盘正文;LOG_FORMAT=pretty 输出人读的一行;写了别的值以 1 退出。
  • 7 个已有测试文件(env、gateway、oauth、p3-cp-guards-uplink、p3-table-cp、publish、reconnect)原来断言的是 console 参数的形状,改成解析 JSON 行,再断言 msg 和字段,语义不变。

main 上的证据:把 packages/control-plane/src 换回 main,跑新用例,8 条里红 7 条(404 那条本来就绿,因为没有这个路由)。去掉密钥那条的 JSON 解析断言再跑一次,报 上游 key: expected '模型上游返回 401,正文前 200 字:bad credentials:…' not to contain 'sk-fake-upstream',说明旧代码确实会把上游 key 写进日志。

Closes #29

🤖 Generated with Claude Code

https://claude.ai/code/session_01LiP6qRYYXznuykpeTFtrZC

joesmart and others added 2 commits October 25, 2026 04:02
onError 原来记 c.req.path,/api/hooks/<token> 出错时凭据会原样写进 error 日志。改记 hono/route 的 routePath(c, -1),中间件里抛的也落到具体路由上。补一条用例:webhook 开运行记录失败回 500,断言日志里没有 token。

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Be3SZps2JjqvyrJ1vbLmni
@joesmart
joesmart force-pushed the joesmart/ops-structured-logs branch from f8819a8 to 040516c Compare October 24, 2026 20:07
@joesmart
joesmart merged commit 25f1bd9 into main Oct 24, 2026
1 check failed
@joesmart
joesmart deleted the joesmart/ops-structured-logs branch October 24, 2026 20:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

可观测性只有 console:缺结构化日志、指标和错误上报

1 participant