# Codex 可能正在狂写硬盘:检查 `logs_2.sqlite`,别让 TRACE 日志磨掉你的 SSD
最近如果你一直开着 Codex,或者经常让它跑流式任务、长时间任务,建议立刻检查一下本地这个文件:
~/.codex/logs_2.sqlite
~/.codex/logs_2.sqlite-wal
我自己的机器已经确认中招:Codex 在流式任务期间,会把大量 TRACE 级别日志持续写入 SQLite,本地 WAL 文件也跟着高频写盘。
这不是“日志多一点”的问题。公开反馈里,已经有人把这个问题估算到约 640 TB/year 的写入量级;也有人反馈 logs_2.sqlite-wal 增长到几十 GB,甚至出现磁盘空间被耗尽。
这篇文章给你一套可以直接照做的流程:
- 怎么判断自己有没有中招;
- 中招后怎么先备份;
- 怎么用 SQLite trigger 临时拦截写入;
- 怎么截断 WAL;
- 怎么确认
MAX(id)和 WAL 不再增长。
提醒:下面的 trigger 是紧急止血方案,会让 Codex 本地
logs表停止新增日志。它适合先保 SSD、保空间,不适合作为长期排障配置。
一、公开反馈已经不少
这个问题不是个例。
在 OpenAI Codex 的 GitHub issue 里,已经有多条类似反馈:
- issue #28224:
Codex SQLite feedback logs can write ~640 TB/year and rapidly consume SSD endurance - issue #29463:Windows Codex app 持续把高频
TRACEwebsocket 日志写入~/.codex/logs_2.sqlite - issue #17320:streaming 期间
TRACE日志导致 SQLite WAL 过量写入,并且没有被RUST_LOG正常压住 - issue #28997:
logs_2.sqlite-wal可以无界增长到几十 GB
OpenAI Community 也有人反馈:Codex 开着不管,磁盘空间被日志耗尽。
Notebookcheck 甚至已经用了这样的标题:OpenAI Codex has a critical bug that could kill your SSD in under a year。

这些反馈指向的是同一个风险链路:
流式事件很多
→ TRACE / websocket / tungstenite 日志被持久化
→ 写入 SQLite logs 表
→ WAL 高频增长
→ SSD 写入量异常
二、我这台机器的检测结果
我本机检测到的情况很典型。
最近 60 秒窗口里:
TRACE 1579 条
INFO 580 条
DEBUG 26 条
WARN 5 条
ERROR 3 条
短间隔采样中,MAX(id) 曾在 3 秒内增加 95 条。
日志内容主要集中在:
- websocket
- tokio-tungstenite
- response.completed
- 流式响应 payload

这基本就是“流式任务期间高频 TRACE 写盘”的典型形态。
三、先检查文件大小
Windows PowerShell:
Get-ChildItem -Force $HOME\.codex |
Where-Object { $_.Name -like 'logs_2.sqlite*' } |
Select-Object FullName,Length,LastWriteTime |
Format-Table -AutoSize
macOS / Linux:
ls -lh ~/.codex/logs_2.sqlite*
重点看这几个文件:
logs_2.sqlite
logs_2.sqlite-wal
logs_2.sqlite-shm
如果 logs_2.sqlite-wal 一直变大,尤其是在你和 Codex 对话、跑任务、流式输出时快速增长,就要继续往下查。
四、统计日志等级
如果你本机有 sqlite3,直接查:
sqlite3 ~/.codex/logs_2.sqlite "
select level, count(*) as n, min(id), max(id), min(ts), max(ts)
from logs
group by level
order by n desc;
"
如果没有 sqlite3,用 Python 自带的 SQLite 模块:
import sqlite3
from pathlib import Path
p = Path.home() / ".codex" / "logs_2.sqlite"
con = sqlite3.connect(f"file:{p}?mode=ro", uri=True, timeout=2)
cur = con.cursor()
for row in cur.execute("""
select level, count(*) as n, min(id), max(id), min(ts), max(ts)
from logs
group by level
order by n desc
"""):
print(row)
print("max id:", cur.execute("select max(id) from logs").fetchone()[0])
con.close()
如果 TRACE 占比很高,而且最新日志集中在 websocket、tungstenite、SSE、response payload,就很可疑。
五、短间隔采样:看它是不是还在涨
只看总量还不够,关键是看它现在是不是仍在增长。
运行下面脚本:
import sqlite3, time
from pathlib import Path
p = Path.home() / ".codex" / "logs_2.sqlite"
wal = Path(str(p) + "-wal")
def sample():
con = sqlite3.connect(f"file:{p}?mode=ro", uri=True, timeout=2)
cur = con.cursor()
max_id = cur.execute("select max(id) from logs").fetchone()[0]
con.close()
wal_size = wal.stat().st_size if wal.exists() else 0
return max_id, wal_size
for i in range(5):
print(i, sample())
time.sleep(3)
如果几次采样里:
MAX(id)一直变大;logs_2.sqlite-wal一直变大;- 同时 Codex 正在跑流式任务;
那就不要犹豫,先止损。
六、中招后的止损流程
核心思路很简单:
先备份
→ 再拦截 logs 表写入
→ checkpoint/truncate WAL
→ 再采样确认不增长
第一步:备份数据库
不要直接粗暴复制主库文件。SQLite 可能还有 WAL 中的已提交内容没有 checkpoint。
用 Python online backup:
import sqlite3, shutil, time
from pathlib import Path
src = Path.home() / ".codex" / "logs_2.sqlite"
stamp = time.strftime("%Y%m%d-%H%M%S")
backup = src.with_name(f"logs_2.sqlite.backup-before-trigger-{stamp}")
ro = sqlite3.connect(f"file:{src}?mode=ro", uri=True, timeout=10)
bk = sqlite3.connect(str(backup), timeout=10)
with bk:
ro.backup(bk)
bk.close()
ro.close()
for suffix in ["-wal", "-shm"]:
side = Path(str(src) + suffix)
if side.exists():
dst = src.with_name(f"logs_2.sqlite{suffix}.backup-before-trigger-{stamp}")
shutil.copy2(side, dst)
print("backup:", backup)
这一步会生成数据库备份,也会把 WAL/SHM sidecar 一起留存。
第二步:用 trigger 拦截写入
import sqlite3
from pathlib import Path
p = Path.home() / ".codex" / "logs_2.sqlite"
con = sqlite3.connect(str(p), timeout=10)
cur = con.cursor()
cur.execute("""
CREATE TRIGGER IF NOT EXISTS codex_stop_logs_insert
BEFORE INSERT ON logs
BEGIN
SELECT RAISE(IGNORE);
END;
""")
con.commit()
print("trigger installed")
print(cur.execute("PRAGMA wal_checkpoint(TRUNCATE)").fetchall())
con.close()
这条 trigger 会让后续写入 logs 表的 INSERT 被忽略。
换句话说:Codex 还可以运行,但本地日志表不会继续增长。
代价是:后续本地日志会丢失。
第三步:确认 WAL 被截断
再看一次文件大小:
ls -lh ~/.codex/logs_2.sqlite*
Windows PowerShell:
Get-ChildItem -Force $HOME\.codex |
Where-Object { $_.Name -like 'logs_2.sqlite*' } |
Select-Object FullName,Length,LastWriteTime |
Format-Table -AutoSize
理想情况下,logs_2.sqlite-wal 会被截断到 0 或非常小。
第四步:连续采样确认不再增长
import sqlite3, time
from pathlib import Path
p = Path.home() / ".codex" / "logs_2.sqlite"
wal = Path(str(p) + "-wal")
def sample(i):
con = sqlite3.connect(f"file:{p}?mode=ro", uri=True, timeout=2)
cur = con.cursor()
row = cur.execute("select max(id), count(*) from logs").fetchone()
trig = cur.execute("""
select count(*)
from sqlite_master
where type='trigger'
and name='codex_stop_logs_insert'
""").fetchone()[0]
con.close()
print({
"i": i,
"max_id": row[0],
"rows": row[1],
"wal_size": wal.stat().st_size if wal.exists() else 0,
"trigger": trig,
})
for i in range(6):
sample(i)
time.sleep(3)
如果你看到:
MAX(id) 不再增长
rows 不再增长
wal_size 不再增长
trigger = 1
说明止血成功。
七、升级后怎么恢复日志?
如果你后续升级到了包含修复的 Codex 版本,或者你需要恢复本地日志,可以删除 trigger:
import sqlite3
from pathlib import Path
p = Path.home() / ".codex" / "logs_2.sqlite"
con = sqlite3.connect(str(p), timeout=10)
cur = con.cursor()
cur.execute("DROP TRIGGER IF EXISTS codex_stop_logs_insert")
con.commit()
print(cur.execute("PRAGMA wal_checkpoint(TRUNCATE)").fetchall())
con.close()
恢复后不要马上放心。
建议继续跑几分钟流式任务,再采样:
MAX(id) 是否快速增长?
logs_2.sqlite-wal 是否快速增长?
TRACE 是否又占了大头?
如果问题复现,就继续保留 trigger,或者等待更明确的上游修复版本。
八、上游修复正在推进
公开信息里可以看到,相关 PR 已经出现:
- PR #29432:避免持久化完整 response payload。
- PR #29457:减少带有 tool/stdout 等内容的 OTEL event 持久化。
- PR #29599:继续处理 raw event level 本地遥测持久化问题。
issue #28224 的描述也提到,部分 PR 已进入 0.142.0,反馈中称可以减少大量日志。
但我建议不要只看版本号。
真正可靠的判断是:
升级以后,再跑一次采样。
MAX(id) 不快速增长,WAL 不快速增长,才是真的安心。
最后说两句
这篇文章不是说“Codex 一定会写坏所有 SSD”。
更准确地说,它提醒的是一个已经被多方反馈、也能本机复现的风险形态:
在 streaming 和长时间运行场景下,Codex 本地 SQLite 日志可能出现高频 TRACE 写入;如果持续存在,会造成异常磁盘写入和 WAL 膨胀。
AI 工具越强,我们越容易把它开着不管。
但本地机器不是无限资源。CPU、内存、网络、磁盘、SSD 寿命,都是需要被尊重的边界。
如果你正在用 Codex,今天就花一分钟查一下:
~/.codex/logs_2.sqlite-wal
它安静,你就安心。
它狂涨,就先止损。
文末互动
你可以把这篇文章转给正在使用 Codex、Claude Code、Cursor、VS Code Agent 插件或其他本地 AI 编程工具的朋友
codex使用方法大全橙皮书下载点击查看
链接:https://pan.quark.cn/s/c4b28b23db05
更多推荐


所有评论(0)