Codex 疯狂写盘怎么办?一招教你用 SQL 触发器拯救 SSD
最近有不少朋友吐槽,自家的 Codex Desktop 即使在配置文件里把 RUST_LOG 设为了 warn,甚至关闭了分析统计功能,那个 ~/.codex/logs_2.sqlite 文件依然像个贪吃蛇一样疯狂增长,磁盘占用率高居不下。
这种情况不仅会占用宝贵的磁盘空间,高频的写操作对 SSD 寿命也是一种潜在的消耗。虽然官方文档说环境变量能控制日志等级,但从实测反馈来看(直到最近版本的 Windows 客户端),这个 TRACE 级别的日志写入bug 依然存在。
既然源头(软件更新)暂时无法解决,我们只能自己动手在“水管”上做个手术。这里分享一个非常“硬核”但实用的方案:直接在数据库层面拦截日志写入。
Codex Desktop 的日志文件不断膨胀,占用大量磁盘空间
为什么不建议简单粗暴地加密文件?
很多网上的教程会建议你把 logs_2.sqlite 设为“只读”。这确实能阻止写入,但副作用很明显:Codex 程序在尝试写入日志失败时,可能会抛出错误,轻则运行不稳定,重则直接崩溃。
更稳的思路是:让程序以为它写成功了,但数据库其实根本没存。 这就需要用到 SQLite 的触发器(Trigger)机制。
操作前的准备
我们需要用到 Windows 的 PowerShell 和 Python。如果你电脑上装了 Python 3,基本都能直接跑下面的脚本。为了保险起见,操作前记得先把 Codex 彻底关掉。
第一步:强制结束进程并备份数据库
打开 PowerShell,依次执行以下命令。首先是关掉所有 Codex 相关进程,防止文件被占用:
Get-Process | Where-Object {
$_.ProcessName -like "codex" -or $_.Path -like "OpenAI.Codex"
} | Stop-Process -Force -ErrorAction SilentlyContinue
接着,找到数据库文件并做一个带时间戳的备份。万一玩坏了还能回滚:
$dir = Join-Path $env:USERPROFILE ".codex"
$db = Join-Path $dir "logs_2.sqlite"
$bak = Join-Path $dir ("logs_2.sqlite.bak-" + (Get-Date -Format "yyyyMMdd-HHmmss"))
Copy-Item $db $bak -ErrorAction SilentlyContinue
VACUUM 操作示意:清理旧日志并回收数据库空间
第二步:清理旧账与安装拦截器
这是最关键的一步。我们将通过一段 Python 脚本连接到 SQLite 数据库,做三件事:
- 清理旧账:把表里以前堆积如山的日志删了,收缩数据库体积(VACUUM)。
- 重置日志:截断 WAL(Write-Ahead Logging)文件,释放磁盘空间。
- 安装拦截器:创建一个
BEFORE INSERT触发器,当有新日志试图插入时,直接返回IGNORE,让写入操作“石沉大海”。
直接在 PowerShell 里粘贴并运行这一大段代码:
@'
import sqlite3, pathlib
# 定位数据库文件
p = pathlib.Path.home() / ".codex" / "logs_2.sqlite"
con = sqlite3.connect(str(p))
# 1. 清理旧日志,删除可能存在的旧触发器
con.execute("DROP TRIGGER IF EXISTS block_log_inserts")
con.execute("DELETE FROM logs")
con.commit()
# 2. 压缩主库,回收空间
con.execute("VACUUM")
con.commit()
# 3. 截断 WAL 文件
con.execute("PRAGMA wal_checkpoint(TRUNCATE)")
con.commit()
# 4. 创建阻断插入的触发器
con.execute("""
CREATE TRIGGER IF NOT EXISTS block_log_inserts
BEFORE INSERT ON logs
BEGIN
SELECT RAISE(IGNORE);
END;
""")
con.commit()
# 再次截断确保生效
con.execute("PRAGMA wal_checkpoint(TRUNCATE)")
con.close()
print("done: logs cleared, trigger installed")
'@ | python -
看到输出 done 就大功告成了。这时候重新打开 Codex,你会发现它运行一切正常,但磁盘不再狂闪了。
第三步:验证效果
为了保险起见,我们可以检查一下数据库相关的文件大小,特别是那个 -wal 后缀的文件,它不应该再疯狂长大了。
Get-Item "$env:USERPROFILE\.codex\logs_2.sqlite*" | Select-Object Name, Length, LastWriteTime
如果你还想更严谨地验证,可以查询一下数据库里最近 60 秒有没有新日志写入(特别是 TRACE 级别):
@'
import sqlite3, pathlib
p = pathlib.Path.home() / ".codex" / "logs_2.sqlite"
con = sqlite3.connect(f"file:{p}?mode=ro", uri=True)
for row in con.execute("""
SELECT level, COUNT(*) AS rows
FROM logs
WHERE ts >= CAST(strftime('%s','now') AS INTEGER) - 60
GROUP BY level
ORDER BY rows DESC;
"""):
print(row)
con.close()
'@ | python -
如果输出为空,或者 Trace 类别的日志数量极低,说明拦截器已经生效了!
后续:如何“解禁”?
这个方案属于“止损”操作,虽然好用但毕竟绕过了软件本身的机制。等到哪天 Codex 官方发布更新修复了日志狂写的问题,你可以运行以下脚本删除触发器,恢复正常记录:
@'
import sqlite3, pathlib
p = pathlib.Path.home() / ".codex" / "logs_2.sqlite"
con = sqlite3.connect(str(p))
con.execute("DROP TRIGGER IF EXISTS block_log_inserts")
con.commit()
con.close()
print("trigger removed")
'@ | python -
两个重要的避坑提示
- 别太迷信配置修改:不要以为改了配置文件里的
[analytics] enabled = false或者设置系统环境变量RUST_LOG=warn就能搞定。实测表明,在这特定的 Bug 版本中,这些设置对该 SQLite 日志表无效,唯有 Trigger 才能物理级拦截。 - 保护隐私:如果你在网络上反馈这个问题,千万不要把整个
logs_2.sqlite文件上传截图或附件。这个数据库里不仅有你疯狂滚动的日志,很可能还残留了你的会话内容、本地文件路径等敏感信息。
用技术手段解决技术问题,在等官方修车的日子里,先给我们的硬盘做个“微创手术”吧。

评论已关闭