Codex 源码解析 · 第 44 讲
Codex 源码解析系列 第 44 讲:遥测与分析——OTEL + Analytics 基于 OpenAI Codex 源码 · 2026-11-07 💡 本讲一句话: Codex 的遥测不是一根管子,而是两条并行管线——otel crate 把日志/追踪/指标发到 OTLP 端点,analytics crate 把产品事件聚合后 POST 到 ChatGPT 后端。核心设计是"PII 隔离":用户 prompt、账号邮箱、工具输出只进 log_only 通道;trace_safe 通道只带计数和时长。本讲逐行拆解双目标事件宏、[REDACTED] 脱敏开关、字符边界截断、直方图桶边界、mTLS 导出,以及"队列满了宁可丢也不阻塞"的有界设计。 一、全景:一个仓库里的两条遥测管线 前几讲我们拆过 Codex 的执行核心——工具调用、沙箱、多智能体。但每次 codex 跑起来,背后都有两条数据流在悄悄工作:一条是标准的 OpenTelemetry(日志 + 追踪 + 指标),另一条是产品分析事件。它们分属两个 crate: codex-rs/otel (约 5.9K 行)和 codex-rs/analytics (约 7.4K 行)。为什么不用一套系统干两件事?先看对照: otel vs analytics:两条管线对照 数据类型 OTEL 日志 / 追踪 span / 指标(OTLP 标准信号) Analytics 产品行为事件:turn、工具调用、插件、Guardian… 目的地 OTEL 可配置 OTLP gRPC/HTTP 端点;内置 Statsig(ab.chatgpt.com) Analytics ChatGPT 后端 POST /codex/analytics-events/events PII 策略 OTEL 双通道:log_only 可带账号 ID/邮箱/prompt;trace_safe 只带计数与时长 Analytics 事实(fact)是协议级元数据,不含 prompt 正文 状态性 OTEL 无状态,事件发生即上报 Analytics reducer 把零散事实聚合成完整 turn 级事件再上报 默认开关 OTEL metrics_exporter=statsig 默认开;log/trace exporter 默认关 Analytics 跟随 analytics.enabled(用户可整体关闭) 两条管线的分工逻辑很清晰: otel 面向"系统" ——延迟、错误率、token 用量这类工程指标,走开放标准,企业可以指向自己的 OTLP collector; analytics 面向"产品" ——用户用了什么功能、turn 成功还是失败,聚合后回传 OpenAI。正因为目的地和受众不同,PII 策略也必须分开设计——这就是本讲的核心。 二、双目标事件:log_only 与 trace_safe otel crate 里所有遥测事件都通过 tracing::event! 发出,但每个事件必须声明自己属于哪个"目标(target)"。整个隔离机制的地基只有 11 行代码—— otel/src/targets.rs : 📄 codex-rs/otel/src/targets.rs (第 1-11 行) pub(crate) const OTEL_TARGET_PREFIX: &str = "codex_otel"; // 所有遥测目标共享这个前缀,导出器靠它判断事件归属 pub(crate) const OTEL_LOG_ONLY_TARGET: &str = "codex_otel.log_only"; // log-only 通道:可含 PII(账号 ID、邮箱),只进日志导出器 pub(crate) const OTEL_TRACE_SAFE_TARGET: &str = "codex_otel.trace_safe"; // trace-safe 通道:禁止 PII,可随追踪一起导出 pub(crate) fn is_log_export_target(target: &str) -> bool { // 判断某事件目标是否属于日志导出器 target.starts_with(OTEL_TARGET_PREFI…
阅读全文:Codex 源码解析 第 44 讲