Conversation
c3e83e8 to
85a72d5
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 85a72d5361
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. What shall we delve into next? ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Motivation
Today config.toml has three different OTEL knobs under
[otel]:exportercontrols where OTEL logs gotrace_exportercontrols where OTEL traces gometrics_exportercontrols where metrics goThose often (pretty much always?) serve different purposes.
For example, for OpenAI internal usage, the log exporter is already being used for IT/security telemetry, and that use case is intentionally content-rich: tool calls, arguments, outputs, MCP payloads, and in some cases user content are all useful there.
log_user_promptis a good example of that distinction. When it’s enabled, we include raw prompt text in OTEL logs, which is acceptable for the security use case.The trace exporter is a different story. The goal there is to give OpenAI engineers visibility into latency and request behavior when they run Codex locally, without sending sensitive prompt or tool data as trace event data. In other words, traces should help answer “what was slow?” or “where did time go?”, not “what did the user say?” or “what did the tool return?”
The complication is that Rust’s
tracingcrate does not make a hard distinction between “logs” and “trace events.” It gives us one instrumentation API for logs and trace events (viatracing::event!), and subscribers decide what gets treated as logs, trace events, or both.Before this change, our OTEL trace layer was effectively attached to the general tracing stream, which meant turning on
trace_exportercould pick up content-rich events that were originally written with logging (and thelog_exporter) in mind. That made it too easy for sensitive data to end up in exported traces by accident.Concrete example
In
otel_manager.rs, thistracing::event!call would be exported in both logs AND traces (as a trace event).Instead of
tracing::event!, we should now be usinglog_event!andtrace_event!instead to more clearly indicate which sink (logs vs. traces) that event should be exported to.What changed
This PR makes the log and trace export distinct instead of treating them as two sinks for the same data.
On the provider side, OTEL logs and traces now have separate routing/filtering policy. The log exporter keeps receiving the existing
codex_otelevents, while trace export is limited to spans and trace events.On the event side,
OtelManagernow emits two flavors of telemetry where needed:It also has a convenience
log_and_trace_event!macro for emitting to both logs and traces when it's safe to do so, as well as log- and trace-specific fields.That means prompts, tool args, tool output, account email, MCP metadata, and similar content stay in the log lane, while traces get the pieces that are actually useful for performance work: durations, counts, sizes, status, token counts, tool origin, and normalized error classes.
This preserves current IT/security logging behavior while making it safe to turn on trace export for employees.
Full list of things removed from trace export
codex.user_promptcodex.tool_resultcodex.tool_result(mcp_server, mcp_server_origin)user.emailanduser.account_idfrom trace-safe OTEL eventshost.namefrom trace resourcescodex.tool_decisionevents from tracescodex.sse_eventevents from traceshandle_tool_callspanWhat traces now keep instead is mostly: