最近看到一条关于 Codex 严重 Bug 的报道:OSChina 新闻。这类问题最麻烦的地方不在于「某个功能不好用」,而在于它可能发生在本地后台:你不一定立刻看到报错,但磁盘可能正在被持续写入。
- 重点排查的是 Codex Desktop 的
SQLite日志库:
~/.codex/logs_2.sqlite
最终确认,我本机确实残留过一轮 T 级别日志爆量写入,主要集中在 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,或者 Codex 某些版本/路径把底层 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"

保存后,完全退出并重新打开 Codex Desktop。这个方案比设置 RUST_LOG 更合适。因为:launchctl setenv RUST_LOG off 不是 Codex 专属,它会影响当前 macOS 登录会话下后续启动的其它 GUI 应用。其它 Rust 程序如果读取 RUST_LOG,也可能被一起影响。
兜底方案:用 SQLite trigger 拦截写入
如果你想立刻止血,或者担心配置项还没生效,可以给 logs 表加 trigger,直接拦截 insert。
修改前先备份:
sqlite3 ~/.codex/logs_2.sqlite \
".backup '$HOME/.codex/logs_2.sqlite.backup-before-trigger'"
创建 trigger:
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';"
我本机最终保留了两个拦截 trigger:
codex_block_logs_insert
block_log_inserts
它们都会在 logs 表 insert 前执行 RAISE(IGNORE),也就是静默丢弃新日志。
清空历史 TRACE 日志
止住写入后,历史日志还在库里。如果确认不再需要,可以清掉。
清空前再备份一次:
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);"
我清空后,logs_2.sqlite 从约 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
连续采样没有反弹,说明写入已经停住。
如果以后要恢复日志
先移除配置:
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。

必须 注册 为本站用户, 登录 后才可以发表评论!