Codex 的日志、SQLite 状态库与 OTel 遥测:先分清三层,再决定开什么

2026-08-09

有人问 Codex(OpenAI Codex)的日志在哪,这个问题其实问错了粒度。Codex CLI 落在磁盘上的运行痕迹至少有三种,它们的格式、配置键、生命周期都不一样,用错了地方就会出现”我翻了半天日志什么都没找到”。先把这三层分清楚,后面开不开遥测、关不关历史,才有得可判断。

一、三层痕迹分别是什么

本机实测(codex-cli 0.147.0 / Windows 11),~/.codex/ 目录下与运行记录相关的条目大致是这几类:

本机观测到的条目相关配置键
进程日志log/ 目录,内含 codex-tui.loglog_dir(默认 $CODEX_HOME/log
会话记录sessions/(按年份分子目录)、archived_sessions/history.jsonlhistory.persistencehistory.max_bytes
状态库logs_2.sqlite(含 -shm-wal)、memories_1.sqlitegoals_1.sqlitesqlite_home

三层的用途完全不同。进程日志是 TUI 自己的运行输出,你想看”客户端这边发生了什么”就去这里。会话记录(官方叫 rollout)是每一轮对话的落盘文件,codex resumeforkarchive 这些子命令操作的就是它。SQLite 那几个库则是结构化状态,记忆和目标各占一个,剩下一个是日志库。

判断路径很直接:问题出在”这次会话内容”就翻 sessions,问题出在”客户端本身”就翻 log 目录,问题出在”记忆/目标怎么不对”就想到那两个 sqlite 文件。别指望在 codex-tui.log 里找会话正文。

二、磁盘占用是真实存在的运维问题

这不是理论担忧。本机 codex-cli 0.147.0 上,logs_2.sqlite 单个文件就到了 763 MB;codex doctor --summary 的 Notes 区里 rollouts 一项提示的是 405 active files · 3.07 GB on disk。一台日常用的开发机,光是 Codex 的历史痕迹就吃掉三四个 GB。

好在 doctor 会主动把这条报出来,所以体检的第一步就是它:

codex doctor --summary

本机实测这条命令的结尾会打一行统计,形如 17 ok · 1 idle · 1 notes · 0 warn · 0 fail,状态符号有 (ok)、(idle)、(notes/warn)、(fail)四种。rollouts 那条通常落在 notes 里——notes 不是报错,是”你该知道一下”,很多人扫一眼没有 fail 就关掉了,磁盘就是这么涨起来的。

三、该关哪一项:history.persistence 还是 --ephemeral

官方给了两个层级的开关,选哪个取决于你是”整体不想留”还是”这一次不想留”。

history.persistence 的取值是 save-allnone,另有 history.max_bytes 限制体积。这是全局口径,写进 config.toml 之后对所有会话生效。

codex exec --ephemeral 则是单次的,help 里的说明是”不把会话文件落盘”。跑一次性的脚本化任务时用它,比全局关掉历史克制得多——你还留着交互会话的可恢复性。

判断依据:你要的是”合规上不允许留存”,就用 history.persistence = "none";你要的是”这条流水线不要污染我的会话列表”,就用 --ephemeral 两者不是同一件事,前者会让 codex resume 失去可续的对象,后者不影响你平时的交互使用。

顺带一提,同一节还有两个容易被误当成”日志”的键:tool_output_token_limit 管的是工具输出进上下文的量,background_terminal_max_timeout 默认 300000(即 5 分钟)管的是后台终端的超时。它们影响的是运行行为,不是落盘内容,别拿它们去解决磁盘问题。

四、SQLite 状态库:doctor 里有两项专门盯它

配置里有一个 sqlite_home 键与这几个库的存放位置相关,不过官方《Configuration Reference》在这一处只列了键名、没给进一步说明,所以它具体接受什么样的值、改完之后旧库要不要手工搬过去,这篇不替官方补。真正有价值的是 doctor 里对应的两个检查项,本机实测在 Environment 分组下:

  • state:本机显示 databases healthy
  • threads:本机显示 rollout files and state DB thread inventory agree

第二项值得单独说。它比对的是磁盘上的 rollout 文件状态库里记的线程清单是否一致。也就是说,会话文件和状态库是两套东西,理论上会对不上——比如你手工删过 sessions/ 下的文件。如果哪天这一项不再是 agree,那说明问题出在”两边不同步”,而不是某一个会话本身坏了,排查方向完全不同。

这里还有一个容易误读的点。本机 codex features list 输出的特性阶段共五种:stableunder developmentexperimentaldeprecatedremoved。而 sqlite 这个特性在 0.147.0 上处于 removed 阶段,生效值却是 trueremoved 不等于功能被删掉了,它指的是这个开关本身不再需要你控制、行为已经固化。看到 removed 就以为 SQLite 存储没了,是纯粹的误会。

五、OTel 导出:键位、默认值与那个必须自己勾的开关

官方《Configuration Reference》里遥测相关的键是这一组:

取值 / 默认
otel.environment默认 dev
otel.exporternone / otlp-http / otlp-grpc
otel.metrics_exporter默认 statsig
otel.trace_exporter
otel.log_user_prompt需显式 opt in 才会导出原始用户提示

每个 exporter 下面还带 endpointprotocolbinaryjson)、headerstls.* 这几组子键。

有三处判断依据必须讲清楚:

第一,otel.environment 默认是 dev 你把数据打到公司的可观测性平台之后,如果没改这个值,所有机器上报的环境标签都是 dev。这不会报错,只会让你在看板上分不出谁是谁。接生产链路时它是第一个要改的。

第二,metrics 和 traces 是分开配的。 otel.exporterotel.metrics_exporterotel.trace_exporter 是不同的键,而 otel.metrics_exporter 有自己的默认值 statsig。所以”我把 exporter 设成 none 了应该就全关了”这个假设并不成立——指标那一路有独立的默认,要关这一路得单独去配 otel.metrics_exporter。至于这个键能填哪些值,官方在这一处只给了默认值、没有列出取值枚举,具体以官方《Configuration Reference》为准,别照着 otel.exporter 的枚举去猜。这是这套配置里最反直觉的一处。

第三,otel.log_user_prompt 需要显式 opt in。 默认情况下原始用户提示不会被导出。这个默认值是保守的,但反过来说:一旦有人为了排查方便把它打开,你团队成员输进 Codex 的每一句话就都进了遥测管道。这个开关不该由某个人顺手改掉,应该走配置评审。至于打开之后具体链路上谁能看到,官方文档没有给出这一层的说明,我也没有实测过,不做推断。

至于 otlp-httpotlp-grpc 选哪个,官方文档在这一处只给了取值枚举,没有给性能或兼容性口径——按你的采集端(collector)实际支持的协议来定,别按感觉选。protocolbinary / json 同理,取决于对端。

还有两个和遥测容易混的键在配置的其它节:analytics.enabledfeedback.enabled(默认 true)。它们和 otel.* 是各管各的,把 OTel 关了不等于这两项也关了。

六、一段可以直接改的配置骨架

log_dir = "~/.codex/log"

[history]
persistence = "save-all"
max_bytes = 104857600

[otel]
environment = "prod"
exporter = "otlp-http"
log_user_prompt = false

这段里刻意没写 otel.metrics_exporter——上一节说过,它的可选值官方没给枚举,我不会替它编一个填进示例里;你真要动指标这一路,请对着官方《Configuration Reference》里这个键的说明写。以上为按官方文档键位组合的示例,未逐项实测,以官方文档为准。想临时试一下不改文件的话,顶层 -c 支持点号路径表示嵌套,官方给的写法就是 -c shell_environment_policy.inherit=all 这种形式;-c 的值按 TOML 解析,解析失败会按字面字符串处理,不会拦你。

七、改完没生效?先确认配置到底加载了

这是本机实测得到的一条很实用的结论。故意传一段语法不合法的 TOML:

codex -c 'features=[unclosed' doctor --summary

在 codex-cli 0.147.0(Windows 11)上,命令没有崩溃退出,doctor 照常跑完,但结果里多了一行:

✗ config       config could not be loaded - Fix the reported config error, then rerun codex doctor.

意思很明白:配置坏了它不吵你,只是安静地不加载。所以”我明明配了 otel 怎么一条数据都没出去”,第一步不是去查网络,是跑一次 doctor 看 config 这一行是不是 ✓。

也别指望 --strict-config 兜底。它的作用是”config.toml 里出现本版本不认识的字段时直接报错退出”,但本机实测 codex -c model_reasoning_effortt=high --strict-config exec --help 正常打印了 help,没有报未知字段错误——说明校验发生在真正加载配置去跑会话的路径上,--help 这类不进入会话的路径不触发。别把它当成”任何情况下都会拦住拼写错误”的护栏。

八、什么时候根本不需要 OTel

如果你的目标只是”把某次非交互运行的过程记下来”,接一整套采集链路是杀鸡用牛刀。codex exec 自带两个更轻的出口:--json 把事件以 JSONL 打到 stdout,-o, --output-last-message <FILE> 把 agent 的最后一条消息写到文件。前者适合喂给下游脚本,后者适合 CI 里取结论。

需要提醒的是,我们没有发起过真实的模型对话请求,所以 JSONL 里具体有哪些事件类型、字段叫什么,这篇不给出——那些得你自己跑一次拿到真实输出再对着写解析。

另外,要把诊断结果发给别人时用 codex doctor --json,官方对它的说明是”Emit a redacted machine-readable report”,即输出是脱敏的。这比手工截 config.toml 靠谱,但贴出去之前自己再扫一眼路径和主机名,总归不亏。

相关阅读


本文依据 Codex 官方文档(learn.chatgpt.com/docs/ 的《Configuration Reference》页面)整理,核对日 2026-08-09;文中标注「本机实测」的部分基于 codex-cli 0.147.0 / Windows 11 环境下的只读命令输出。产品功能、模型与价格以官方最新说明为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。