之前看到有人说 Codex Desktop 会高频写入本地 SQLite 日志,导致 SSD 写入量异常增加。

我在自己电脑上验证了一下,这个问题确实存在。最后用一个 SQLite trigger 做了临时筛选,把最重的流式日志过滤掉了。不是官方修复,但目前效果还可以。

最近官方的修复也说修复了该问题,但实际测试,官方已经做了部分降噪修复,但我的当前安装版本没有彻底解决 logs_2.sqlite 高频写入问题。

直接丢给 Codex 的 Prompt


这个问题可以让 Codex 自己验证、自己定位、自己加临时规则、自己复测。

直接跟 Codex 说一句就行:

帮我验证并临时缓解 Codex Desktop 的 logs_2.sqlite 高频写入问题。


如果担心它读日志正文,可以再补一句:

不要读取或展示日志正文,只看元数据;不要用只读、ACL 拒写、运行中删除文件这种硬拦截方式,方案必须可回滚。


然后看它自己干活,再做下决定就行了。以后官方修复了问题,也可以让 codex 自己回滚。

Codex 其实还给了另一个方法,**把日志转移到 RAM Disk**,如果是重度使用,挺合适的。

- 思路是让 logs_2.sqlite* 写到内存盘,而不是 SSD。
- 效果:能明显减少 SSD 写入。
- 缺点:需要 RAM Disk 工具;重启后日志消失;符号链接处理不当可能导致 Codex 启动失败。

这个比“硬拦截”靠谱,因为 SQLite 仍然能正常写,只是写到内存里。

发现问题


Codex 的本地日志文件在 Windows 上一般是这个:

C:\Users\Kerry\.codex\logs_2.sqlite


它不是普通文本日志,而是 SQLite 数据库。旁边还有:

logs_2.sqlite-wal
logs_2.sqlite-shm


我第一次看的时候,logs_2.sqlite 已经到 1.31 GiB 左右。后来退出 Codex 删除过一次,空间是释放了,但重启之后它又会重新创建并继续增长。

所以单纯删除只能清空历史日志,不能解决运行时高频写入。

我让 Codex 自己检查了一下这个 SQLite 数据库,只看表结构和统计信息,不读取具体聊天内容。

logs 表里主要有这些字段:

level
target
feedback_log_body
estimated_bytes
module_path
file
line


未处理前,最近 60 秒大概有:

2954 条日志
约 2.85 MB 日志体积


再看 leveltarget,大头基本是这些:

TRACE / codex_api::sse::responses
TRACE / codex_api::endpoint::responses_websocket
DEBUG / codex_core::stream_events_utils


也就是说,主要不是错误日志,而是 SSE、websocket、stream event 这类流式过程日志。

文件层采样也能对上:未处理前,logs_2.sqlite-wal 基本每秒都在刷新,主库也会频繁更新。

这就不是普通桌面软件“偶尔写日志”的水平了。

解决问题


不建议把 logs_2.sqlite 设置成只读,也不建议用 ACL 直接拒绝写入。

SQLite 需要正常写主库、写 WAL、做 checkpoint。硬拦截很可能导致 Codex 报错、重试,甚至更卡。

更稳的办法是:让 SQLite 仍然可写,但过滤低价值的高频日志。

我最后加了这个 trigger:

CREATE TRIGGER codex_temp_drop_trace_logs
BEFORE INSERT ON logs
WHEN NEW.level = 'TRACE'
OR (NEW.level = 'DEBUG' AND NEW.target = 'codex_core::stream_events_utils')
BEGIN
SELECT RAISE(IGNORE);
END


这条规则做的事情很简单:

- 丢弃全部 TRACE 日志。
- 丢弃 DEBUG / codex_core::stream_events_utils。
- 保留 INFO / WARN / ERROR。
- 保留其他 DEBUG。

它不是关闭 Codex 日志系统,只是把最吵的流式过程日志挡掉。

如果要执行,可以用下面这条 PowerShell:

python -c "import sqlite3, pathlib; db=pathlib.Path.home()/'.codex'/'logs_2.sqlite'; con=sqlite3.connect(db); con.execute(\"DROP TRIGGER IF EXISTS codex_temp_drop_trace_logs\"); con.execute(\"\"\"CREATE TRIGGER codex_temp_drop_trace_logs BEFORE INSERT ON logs WHEN NEW.level = 'TRACE' OR (NEW.level = 'DEBUG' AND NEW.target = 'codex_core::stream_events_utils') BEGIN SELECT RAISE(IGNORE); END;\"\"\"); con.commit(); con.close()"


执行前最好先退出 Codex,或者至少确认当前没有大量任务正在跑。

效果


加规则前:

约 2954 条日志 / 分钟
约 2.85 MB / 分钟
WAL 基本每秒刷新


加规则后,活跃验证窗口:

约 95 条日志 / 分钟
约 50 KB / 分钟


等待一段时间后的安静窗口:

5 条日志 / 分钟
218 bytes / 分钟


按活跃窗口算,日志体积下降约 98.2%。按安静窗口算,下降更多。

文件层也有变化。之前 WAL 基本每秒跳,处理后采样时主库基本不刷新,WAL 也不会持续每秒更新。

这不是 SSD NAND 层的精确磨损数据,但 SQLite/WAL 是这次问题的主要写入源。源头写入少了两个数量级,由 Codex 日志带来的实时 SSD 写入压力也就明显下来了。

回滚


如果 Codex 后续官方修复了,或者你发现 Codex 行为异常,可以删除这个 trigger:

python -c "import sqlite3, pathlib; db=pathlib.Path.home()/'.codex'/'logs_2.sqlite'; con=sqlite3.connect(db); con.execute('DROP TRIGGER IF EXISTS codex_temp_drop_trace_logs'); con.commit(); con.close()"


客户端更新后也要重新检查一次。更新可能会重建数据库,trigger 可能会被清掉。

总结


这次问题的核心不是 Codex 不能写日志,而是把大量流式过程日志写进 SQLite,导致 WAL 高频刷新。

直接删文件只能释放空间,不能解决运行时写入。直接拒绝写入风险又太高。

目前比较稳的临时方案是用 SQLite trigger 做筛选:保留必要日志,过滤 TRACE 和一个高频 stream event DEBUG 源。

现在看下来,写入量已经从异常高频降到正常桌面应用可以接受的范围。后面如果官方把日志分级、轮转、批量写入和大小限制做好,这个 trigger 就可以删掉。

Rate this post