Codex 被曝日志写盘 Bug 后,我做了一次本地自查和止血

看到一条 Codex 严重 Bug 的报道(oschina.net 新闻 465890)。这类问题最烦的地方不是功能不好用,而是发生在本地后台:你看不到报错,磁盘却被持续写入。自查对象是 Codex Desktop 的 SQLite 日志库 ~/.codex/logs_2.sqlite。我本机确实残留过一轮 TRACE 级别日志爆量写入,集中在 websocket、tungstenite、hyper 这些底层网络日志,处理后 logs 表清空、WAL 截断为 0B、后续插入被拦截。下面是完整过程。

问题现象

Codex Desktop 在 ~/.codex 下维护多个 SQLite 库,日志相关的是这三个文件:

~/.codex/logs_2.sqlite
~/.codex/logs_2.sqlite-wal
~/.codex/logs_2.sqlite-shm

如果 RUST_LOG 被设成 trace,或某些版本、某些路径把底层 TRACE 日志写进 SQLite,就会出现高频写盘。我检查到的级别分布长这样:

TRACE|2022|4715|49475
DEBUG|226|4806|49474
INFO |110|4756|49468

最近 500 条里 TRACE 占绝大多数:

TRACE|492
INFO |4
DEBUG|4

基本可以定性:不是业务日志,是 TRACE 在刷屏。

确认自己是否中招

四步。先看文件大小:

ls -lh ~/.codex/logs_2.sqlite ~/.codex/logs_2.sqlite-wal ~/.codex/logs_2.sqlite-shm

再看整体级别分布:

sqlite3 ~/.codex/logs_2.sqlite 
"SELECT level, COUNT(*), MIN(id), MAX(id)
 FROM logs
 GROUP BY level
 ORDER BY COUNT(*) DESC;"

重点看最近 500 条:

sqlite3 ~/.codex/logs_2.sqlite 
"SELECT level, COUNT(*)
 FROM logs
 WHERE id > (SELECT MAX(id)-500 FROM logs)
 GROUP BY level
 ORDER BY COUNT(*) DESC;"

最后连续采样,盯 MAX(id) 和 WAL 是否增长:

for i in 1 2 3 4 5 6; do
  sqlite3 ~/.codex/logs_2.sqlite 
  "SELECT strftime('%Y-%m-%d %H:%M:%S','now'), MAX(id), COUNT(*) FROM logs;"
  stat -f "%z %Sm" ~/.codex/logs_2.sqlite-wal
  sleep 2
done

如果 MAX(id) 持续上涨、logs_2.sqlite-wal 持续变大、最近日志几乎都是 TRACE,基本就中招了。

根治:关掉 SQLite 日志

Codex 支持配置关闭 SQLite 日志。编辑:

~/.codex/config.toml

顶层加入一行:

sqlite_logs_enabled = false

一定放顶层,不要放进 [desktop]、[mcp_servers...] 或其它 section 下面:

示例:
sqlite_logs_enabled = false
​
notify = [...]
model_provider = "custom"
Image_2026-06-28_21-01-06

保存后完全退出再重新打开 Codex Desktop。这个方案比设置 RUST_LOG 好:launchctl setenv RUST_LOG off 不是 Codex 专属,它影响当前 macOS 登录会话后续启动的所有 GUI 应用,其它读 RUST_LOG 的 Rust 程序会被一起带进沟里。

兜底:用 trigger 拦截写入

要立刻止血、或担心配置没生效,可以给 logs 表加 trigger 直接拦 insert。动手前备份:

sqlite3 ~/.codex/logs_2.sqlite 
".backup '$HOME/.codex/logs_2.sqlite.backup-before-trigger'"

建 trigger(含一次 WAL checkpoint):

sqlite3 ~/.codex/logs_2.sqlite 
"CREATE TRIGGER IF NOT EXISTS codex_block_logs_insert
 BEFORE INSERT ON logs
 BEGIN
   SELECT RAISE(IGNORE);
 END;
 PRAGMA wal_checkpoint(TRUNCATE);"

检查是否存在:

sqlite3 ~/.codex/logs_2.sqlite 
"SELECT name, sql
 FROM sqlite_master
 WHERE type='trigger' AND tbl_name='logs';"

我本机最终留了两个:

codex_block_logs_insert
block_log_inserts

都在 insert 前执行 RAISE(IGNORE),静默丢弃新日志。

清理历史日志并验证

止住写入后历史日志还在库里,确认不要了就清掉。清空前再备份一次:

sqlite3 ~/.codex/logs_2.sqlite 
".backup '$HOME/.codex/logs_2.sqlite.backup-before-clear'"

删表数据、重置自增、压缩、截断 WAL:

sqlite3 ~/.codex/logs_2.sqlite 
"DELETE FROM logs;
 DELETE FROM sqlite_sequence WHERE name='logs';
 VACUUM;
 PRAGMA wal_checkpoint(TRUNCATE);"

清完后库从约 4.2MB 降到 40KB,WAL 为 0B。

最终验证,连续采样看有没有反弹:

for i in 1 2 3 4; do
sqlite3 ~/.codex/logs_2.sqlite
 "SELECT strftime('%Y-%m-%d %H:%M:%S','now'), COUNT(*), MAX(id) FROM logs;"
stat -f "%z %Sm" ~/.codex/logs_2.sqlite-wal
 sleep 2
done

看到下面的输出、采样稳定,就说明写入停住了:

COUNT(*) = 0
MAX(id) = NULL
WAL     = 0B
Image_2026-06-28_21-12-19

以后要恢复日志

先删掉这行配置:

sqlite_logs_enabled = false

再删 trigger:

sqlite3 ~/.codex/logs_2.sqlite 
"DROP TRIGGER IF EXISTS codex_block_logs_insert;
DROP TRIGGER IF EXISTS block_log_inserts;"

然后重启 Codex Desktop 即可。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容