排障
先看 monitor 自己的 endpoint,再改 CPA 或 auth files。
如果还没启动 dashboard,可以先跑不改状态的检查:
codex-quota-monitor print-config
codex-quota-monitor doctor
doctor 会报告加载了哪个配置文件、监听端口是否可绑定、SQLite state 路径是否可写。如果本机 service 接线已经混乱,用 codex-quota-monitor init --mode user 重新生成一份干净 starter 配置。
Python 安装后,这些交互命令里的 codex-quota-monitor 可以替换成 cqm。
1. Monitor 是否已经运行?
curl -fsS http://127.0.0.1:4515/healthz
预期输出:
{"ok":true}
如果失败,先看进程或 service manager:
- 前台 Python 或 Nix:看运行
codex-quota-monitor的终端。 - systemd:
systemctl status codex-quota-monitor --no-pager和journalctl -u codex-quota-monitor -n 100 --no-pager。 - Docker:
docker ps和docker logs <container>。
/healthz 只表示 monitor 进程还活着;它不代表 CPA、management key、auth 文件、SQLite history 或 benchmark import 都正常。
2. 日志在哪里?
Monitor 遵循 Unix service 模型:
- stdout 用于命令输出,例如
print-config、doctor --json和init生成的 artifact。 - 运行日志写到 stderr;前台运行时显示在终端,systemd 会收进 journal,Docker 通过
docker logs查看。 - 默认是
--log-format text;日志采集器需要每行一个 JSON object 时用--log-format json。 - HTTP access log 使用
codex-quota-monitor.httplogger,默认开启。请求级日志太吵时,用--access-log off或CODEX_QUOTA_MONITOR_ACCESS_LOG=off关闭。 - SQLite
Audithistory 记录运维快照变化,不是用户访问审计日志。
不要把 stderr 当稳定 API 抓取。机器可读状态应使用 /api/v1/status、/api/v1/diagnostics、/api/v1/alerts、/api/v1/recommendations、/metrics 或配置的 SQLite history database。codex-quota-benchmark 是例外:它会把实验 artifact 写到输出目录,请求保留临时 gateway 工作目录时也会包含 gateway stdout/stderr。
3. CPA 是否可达?
curl -fsS http://127.0.0.1:4515/api/v1/diagnostics | jq '.'
Diagnostics 标签页和 /api/v1/diagnostics 会拆开显示:
- gateway
/healthz - CPA management APIs
- direct quota sampling
- SQLite history
- benchmark summary import
如果 Docker 容器访问不到宿主上的 CPA,把 CPA host 写成 host.docker.internal;Linux Docker 上还需要加:
--add-host=host.docker.internal:host-gateway
4. Management key 是否生效?
CPA management endpoints 通常要求 management key,包括 localhost 请求。前台运行时用 --management-key-file /path/to/management-key;service 和 Docker 部署时用 CODEX_QUOTA_MONITOR_MANAGEMENT_KEY_FILE。裸 CPA endpoint 的 key file 内容必须和 CPA remote-management.secret-key 明文值一致。
401通常表示 key 缺失,或和 CPAremote-management.secret-key不一致。403 remote management disabled通常表示 CPA 认为请求不是 localhost;改用 loopback URL,或有意识地启用 remote management。/v0/management/*返回404通常表示较新的 CPA 因为没有配置remote-management.secret-key而禁用了 management API。
5. 为什么 quota 是 Unknown?
Unknown quota 通常表示 direct Codex quota sampling 不可用:
- 没有传
--auth-dir,路径不对,或容器里没有挂载。 - service user 没有 auth files 读权限。
- auth file 已 disabled、unavailable、expired,或处于 CPA cooldown。
- direct quota API 返回了
deactivated_workspace;dashboard 会把该账号或 workspace 当作不可用,并从 pool capacity 中排除。 - direct Codex quota response shape 发生变化。
检查:
curl -fsS http://127.0.0.1:4515/api/v1/status | jq '.tabs.diagnostics'
curl -fsS http://127.0.0.1:4515/api/v1/alerts | jq '.'
如果 Diagnostics 明确说 direct quota response shape changed,只分享脱敏后的 diagnostics/alerts payload 和 package version。不要分享原始 auth files,也不要分享可能包含 credential material 的 provider 原始响应。
6. 为什么 Pool capacity 比 raw 5h 低?
默认会用 weekly remaining * 6.0 限制总 5h 容量,避免 weekly quota 接近耗尽时高估短窗口容量。
覆盖倍率:
codex-quota-monitor --weekly-to-five-hour-multiplier 8.0
关闭:
codex-quota-monitor --weekly-to-five-hour-multiplier off
7. 为什么 Trends 或 Audit 是空的?
Trends 和 Audit 需要可写 SQLite state database。
- 直接
nix run或临时前台运行要传--state-db /path/to/history.sqlite3。 - Docker image 默认写
/data/history.sqlite3;需要持久化就挂载/data。 - NixOS module 默认写
/var/lib/codex-quota-monitor/history.sqlite3。
SQLite 写入错误会出现在 Diagnostics 标签页。
state 生命周期基础操作:
# 备份
cp /var/lib/codex-quota-monitor/history.sqlite3 /var/lib/codex-quota-monitor/history.sqlite3.bak
# 清空历史:先停服务,再删 DB
systemctl stop codex-quota-monitor
rm /var/lib/codex-quota-monitor/history.sqlite3
systemctl start codex-quota-monitor
rootless service 路径通常是 ~/.local/state/codex-quota-monitor/history.sqlite3;Docker 容器内路径通常是 /data/history.sqlite3,实际文件在绑定的 volume 里。下一次成功写入时 monitor 会重新创建 DB。
8. 为什么 dashboard 会周期性占用 CPU?
浏览器会轮询 /api/v1/status。缓存命中时响应很轻;但 refreshSeconds
到期后,monitor 会刷新 CPA management 数据、可选 direct quota samples、
dashboard snapshot,以及 SQLite-backed Trends/Stats 摘要。应按机器能力设置足够长的
refreshSeconds;15s 很及时,但在 CPA pool 较大、散热受限的笔记本上可能偏吵。
SQLite history 由 historyRetentionDays 控制保留周期。删除后的页可能继续留在
database 文件里,表现为 SQLite freelist;这是文件体积压力,不等于活跃历史行数。
服务不会在 request path 自动跑 VACUUM,因为它可能阻塞 monitor。如果文件已经过大,
先备份、停服务,再由 operator 手动维护:
systemctl stop codex-quota-monitor
cp /var/lib/codex-quota-monitor/history.sqlite3 /var/lib/codex-quota-monitor/history.sqlite3.bak
sqlite3 /var/lib/codex-quota-monitor/history.sqlite3 'PRAGMA freelist_count; VACUUM;'
systemctl start codex-quota-monitor
如果不需要 Trends、ETA、Audit、Stats history 或原生历史备份,可以不传
--state-db 来关闭 SQLite history。这样本机工作量更低,但 dashboard 也会失去历史功能。
9. 什么信息可以分享?
不要分享 auth files、CPA admin keys、API keys、私有 gateway URL,或包含这些内容的完整日志。通常可以分享:
- package version
- install method
- 脱敏后的命令行
/healthz结果- 脱敏后的
/api/v1/diagnostics - 脱敏后的
/api/v1/alerts - service manager 错误原文
用 codex-quota-monitor redact 生成可分享副本:
codex-quota-monitor redact /tmp/cqm-diagnostics.json --output /tmp/cqm-diagnostics-redacted.json
codex-quota-monitor redact /path/to/history.sqlite3 --output /tmp/history-redacted.sqlite3
10. 可以绑定 0.0.0.0 吗?
只有在你同时控制 firewall,或把 dashboard 放在带鉴权的 reverse proxy 后面时才建议这么做。UI 和 /api/v1/status 设计上不会暴露 auth secret 内容,但会暴露账号 label、quota 状态、model activity 和 gateway health 这类运维元数据。
直接通过非 loopback 地址访问时,还要用 --allowed-host <域名或 IP> 放行浏览器访问用的
authority;非预期 Host 和 Origin 会被拒绝。
其它设备需要访问时,优先让应用继续监听 127.0.0.1,再通过 reverse proxy 暴露到外面。例如先用 basic auth 或外部 access layer 保护 proxy,再把 https://quota.example/ 转发到 http://127.0.0.1:4515/。
当前支持的 reverse-proxy 拓扑是专用 hostname 的根路径。https://example/tools/quota/
这类 path-prefix 部署不是 v1 支持范围,因为 UI 资源和浏览器 API 请求使用根相对路径。
11. 不用 Prometheus 怎么发现故障?
Prometheus 是可选项。最简单的本机检查:
curl -fsS http://127.0.0.1:4515/api/v1/alerts | jq '.ok'
systemd 示例已经包含 Restart=on-failure。system service 用 systemctl status codex-quota-monitor --no-pager,rootless user service 用 systemctl --user status codex-quota-monitor --no-pager。