Conversation
This was referenced Jun 27, 2026
This was referenced Jun 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
App-server deployments can emit JSON logs that downstream applications use for diagnostics and operational measurements. Tool latency is especially useful when it can answer more than "how long did the handler run?": consumers may need to distinguish dispatch/queue time from handler time, correlate nested code-mode calls, and avoid double-counting tools that execute concurrently.
Structured
INFOevents provide those measurements through the existing logging pipeline without requiring an OTEL exporter. For example, an app-server consumer can:What changed
codex.tool_callcompletion event covering the full outer tool lifecycle. It records dispatch, handler, and total durations together with conversation, turn, call, source, code-mode, and trace correlation fields.codex.inferencecompletion event for each model sampling section. It reuses the existing turn timing guard and records a per-turn inference index, result, model/provider identity, correlation fields, and total duration.codex.tool_resultwith trace/turn/source correlation fields and a numericduration_secondsfield while preserving all existing fields. In particular,argumentsandoutputpredate this change and remain unchanged for compatibility.codex.exec_server_requestandcodex.exec_server_processevents for request handling and actual process lifetime.INFOtarget is enabled; expressions that can remain insidetracingmacros are evaluated there.LOG_FORMAT=json, drives anexec_commandthrough the public v2 JSON-RPC API, and verifies the tool events plus both inference boundaries.Suggested logging filters
Timing-only app-server consumers can enable the two compact targets without enabling general
INFOlogging:LOG_FORMAT=json \ RUST_LOG='warn,codex_core::tools::parallel=info,codex_core::turn_timing=info' \ codex app-serverExec-server timing can be enabled independently:
RUST_LOG='warn,codex_exec_server::telemetry=info' codex-exec-servercodex.tool_resultis emitted oncodex_otel.log_only. That pre-existing target includes tool arguments and output, so timing-only consumers should leave it disabled unless they specifically need those verbose fields.Event examples
These are representative records produced with
LOG_FORMAT=json. Identifier and timing values are illustrative, and session metadata oncodex.tool_resultvaries with the caller.codex.tool_callThis event describes the complete outer tool-call lifetime, including time spent waiting to dispatch and time spent in the handler.
{ "timestamp": "2026-06-27T03:45:20.443Z", "level": "INFO", "fields": { "message": "tool call completed", "event.name": "codex.tool_call", "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", "conversation.id": "67e55044-10b1-426f-9247-bb680e5fe0c8", "turn_id": "019f04f8-6ac2-78f1-8625-f04a6d35af18", "tool_name": "exec_command", "call_id": "call_7b8483", "tool_source": "direct", "code_mode_cell_id": "", "code_mode_runtime_tool_call_id": "", "execution_started": true, "dispatch_duration_seconds": 0.012, "handler_duration_seconds": 0.431, "total_duration_seconds": 0.443 }, "target": "codex_core::tools::parallel" }codex.inferenceThis event describes one complete model sampling section. The completion timestamp and duration make both inference boundaries reconstructable, while
inference_indexorders repeated requests within one turn.{ "timestamp": "2026-06-27T03:45:20.882Z", "level": "INFO", "fields": { "message": "inference completed", "event.name": "codex.inference", "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", "conversation.id": "67e55044-10b1-426f-9247-bb680e5fe0c8", "turn_id": "019f04f8-6ac2-78f1-8625-f04a6d35af18", "model": "gpt-5.1-codex", "provider_name": "OpenAI", "inference_index": 2, "result": "success", "duration_seconds": 1.284 }, "target": "codex_core::turn_timing" }codex.tool_resultThis existing event now carries the correlation fields needed to join it to
codex.tool_call, plus a numeric duration in seconds. Existing fields such as arguments, output, and session metadata remain available.{ "timestamp": "2026-06-27T03:45:20.443Z", "level": "INFO", "fields": { "event.name": "codex.tool_result", "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", "turn_id": "019f04f8-6ac2-78f1-8625-f04a6d35af18", "tool_name": "exec_command", "call_id": "call_7b8483", "tool_source": "direct", "code_mode_cell_id": "", "code_mode_runtime_tool_call_id": "", "arguments": "{\"cmd\":\"git status\"}", "duration_ms": "431", "duration_seconds": 0.431, "success": "true", "output": "Chunk ID: 14f9ac\nProcess exited with code 0", "mcp_server": "", "mcp_server_origin": "", "event.timestamp": "2026-06-27T03:45:20.443Z", "conversation.id": "67e55044-10b1-426f-9247-bb680e5fe0c8", "app.version": "0.1.0", "auth_mode": "chatgpt", "originator": "codex_app_server_rs", "terminal.type": "unknown", "model": "gpt-5.1-codex", "slug": "" }, "target": "codex_otel.log_only" }codex.exec_server_requestThis event measures exec-server handling for one JSON-RPC request and retains the incoming trace context when present.
{ "timestamp": "2026-06-27T03:45:20.447Z", "level": "INFO", "fields": { "message": "exec-server request completed", "event.name": "codex.exec_server_request", "request_id": "request-42", "method": "process/start", "result": "success", "duration_seconds": 0.018, "traceparent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" }, "target": "codex_exec_server::telemetry" }codex.exec_server_processThis event measures the lifetime of the actual process, which can outlive the request that started it.
{ "timestamp": "2026-06-27T03:45:20.861Z", "level": "INFO", "fields": { "message": "exec-server process completed", "event.name": "codex.exec_server_process", "process_id": "process-018f27", "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", "result": "success", "duration_seconds": 0.414 }, "target": "codex_exec_server::telemetry" }Test plan
just test -p codex-app-serverjust test -p codex-exec-serverjust test -p codex-oteljust test -p codex-core tools::parallel::testsjust test -p codex-core tools::registry::testsjust test -p codex-cli app_server_emits_json_info_events