Codex Desktop 待机不动,磁盘灯一直在闪,一看 ~/.codex/logs_2.sqlite 被高频 TRACE 日志狂写。官方没有开关,RUST_LOG 也压不住——这篇记录我们怎么用一行 SQLite 触发器把它止住。
如果此篇内容看完也不明白怎么操作,可以直接复制链接丢给Codex让他自己操作。
📝 问题是什么
Codex Desktop 默认把大量诊断日志以 TRACE 级别(最详细的级别)持续写入本地 SQLite 数据库:
日志内容包括 WebSocket 数据包、系统文件读写、底层行为等极细粒度信息。问题在于,即使 Codex 空闲或只做轻量任务,这个写入也不会停。
本机实测,主库 62.3 MB,WAL 6.16 MB。看起来不大,但实际写入频率远超文件大小能反映的程度。
📝 排查过程
1) 数据库结构
SQLite 里有一张
logs 表,字段包括 id、ts、level、target、feedback_log_body、estimated_bytes 等十几个字段。日志级别分布一眼就能看出问题:
级别 | 行数 |
TRACE | 13,000+ |
INFO | 7,000+ |
DEBUG | 1,000+ |
WARN / ERROR | 少量 |
TRACE 占了绝对大头。高频写入目标主要是
codex_api::sse::responses、codex_otel.log_only、codex_otel.trace_safe、codex_api::endpoint::responses_websocket 这几个模块 —— 都是 SSE 流和 WebSocket 相关的底层通信日志。2) 60 秒静默采样
光看 SQLite 的行数不够,关键是看它空闲时还在不在写。
做了 60 秒静默采样——中间不展开日志正文,只查
MAX(id) 的变化:- 起始
MAX(id):5,848,707
- 60 秒后
MAX(id):5,849,631
- 增量:924 行
约等于 15.4 行/秒。而
logs 表总行数基本不变,说明它在边写边删——单看文件大小完全会低估实际写入频率。这就是磁盘灯一直闪的原因。
📝 为什么不能直接关掉
优先方案当然是更新 Codex。 但排查时
codex-cli 0.142.0 即使设了 RUST_LOG=warn,TRACE 写入仍然不停——说明日志级别在这个版本上不完全受环境变量控制。官方公开文档里也没有
sqlite_logs_enabled = false 之类的稳定开关。社区 issue 里有人验证可用的临时方案是:给 SQLite 的 logs 表加一个 BEFORE INSERT 触发器,直接拦截 TRACE 级别的写入。这不是根治,但能立刻止住高频写盘。
📝 修复方案:一行触发器
核心就一条 SQL:
RAISE(IGNORE) 的效果是:当插入的行 level = 'TRACE' 时,直接丢弃这条记录,不写入。DEBUG / INFO / WARN / ERROR 全部正常通过。完整 PowerShell 脚本
保存为
fix-codex-trace-logs.ps1:脚本做了五件事:
- 备份原始数据库三个文件(主库 + WAL + SHM)
- 写入触发器,拦截后续所有 TRACE 级别写入
- 删除已有的 13,690 条 TRACE 旧记录
- VACUUM 压缩数据库
- WAL checkpoint 截断 WAL 文件
运行方式:
建议先退出 Codex Desktop 再运行。 运行完再打开。
📝 修复效果
写入频率对比
修复前,60 秒静默采样新增 924 行,全是 TRACE。修复后再次 60 秒采样:
级别 | 60s 新增 |
DEBUG | 103 |
INFO | 56 |
WARN | 5 |
TRACE | 0 |
TRACE 彻底归零。总写入量从 924 行/分钟降到 164 行/分钟,降了 82%。
文件大小对比
文件 | 修复前 | 修复后 |
主库 | 62.3 MB | 18.8 MB |
WAL | 6.16 MB | 0 |
清理掉 13,690 条 TRACE 记录后,主库体积降了 70%,WAL 直接清零。
📝 恢复默认行为
如果以后 Codex 官方彻底修好了,删掉触发器就能恢复默认日志行为:
🤗 注意事项
这是临时缓解,不是官方根治。 触发器会阻止 TRACE 级别诊断日志写入,但保留 DEBUG 及以上。如果需要给官方提 issue 附诊断信息,运行前先停掉触发器,或者直接用修复前的备份。
logs_2.sqlite 是诊断日志库,不是 Codex 会话正文存储。删掉 TRACE 不影响对话历史。feedback_log_body 字段里可能包含你的私密上下文——往 issue 里贴内容前务必检查脱敏。核心思路其实很通用: 任何用 SQLite 做日志后端的本地应用,如果日志级别不可控、写入太激进,都可以用
BEFORE INSERT 触发器做行级过滤。不碰源码、不碰配置文件,代价就是以后升级要记得删触发器。