app-server: OTLP logs remain empty while traces and metrics export, then emit BatchLogProcessor.Emit.AfterShutdown on shutdown
What version of the Codex App are you using (From “About Codex” dialog)?
Codex Desktop internal Codex binary 0.136.0
What subscription do you have?
ChatGPT Business
What platform is your computer?
macOS arm64
What issue are you seeing?
codex app-server exports OTLP traces and OTLP metrics, but native OTLP logs remain empty even when OTLP log export is explicitly configured and the same collector is successfully receiving the other signals.
In repeated local repros, the collector output shows:
logs.json: emptytraces.json: non-emptymetrics.json: non-empty
On shutdown, codex app-server emits this warning:
BatchLogProcessor.Emit.AfterShutdown
with the message:
Logs are being emitted even after Shutdown. This indicates incorrect lifecycle management of OTelLoggerProvider in application. Logs will not be exported.
This appears to be an app-server / codex-otel lifecycle bug rather than a collector or config issue.
What steps can reproduce the bug?
- Start an OTLP collector that writes logs, traces, and metrics to local files.
- Run a long-lived
codex app-serverinstance with OTLP enabled in config:
[analytics]
enabled = true
[otel]
environment = "local-sre-agent-ws"
log_user_prompt = true
exporter = { otlp-http = { endpoint = "http://127.0.0.1:4319/v1/logs", protocol = "json" } }
trace_exporter = { otlp-http = { endpoint = "http://127.0.0.1:4319/v1/traces", protocol = "json" } }
metrics_exporter = { otlp-http = { endpoint = "http://127.0.0.1:4319/v1/metrics", protocol = "json" } }
- Connect to the running app-server over WebSocket and perform a real request flow:
initializeinitializedthread/startturn/start
- Complete the turn successfully.
- Stop the server cleanly.
- Inspect collector outputs and app-server stderr.
Observed result:
- OTLP traces export successfully.
- OTLP metrics export successfully.
- OTLP logs remain empty.
- app-server prints:
BatchLogProcessor.Emit.AfterShutdownLogs are being emitted even after Shutdown. This indicates incorrect lifecycle management of OTelLoggerProvider in application. Logs will not be exported.
I also reproduced the same symptom through codex debug app-server send-message-v2, but the long-lived WebSocket repro is stronger because it removes the built-in helper client as the primary variable.
What is the expected behavior?
If [otel].exporter is configured for codex app-server, native OTLP log events should be exported successfully, just like traces and metrics.
Representative events that appear to be intended for log export include:
codex.conversation_startscodex.api_requestcodex.websocket_connectcodex.websocket_requestcodex.sse_eventcodex.user_prompt
These should reach the OTLP log exporter without the AfterShutdown failure.
Additional information
Why this looks like an upstream code bug
The open-source code appears to support log export on the app-server path:
app-serverbuilds an OTEL provider and installs both logger and tracing layers:codex-rs/app-server/src/lib.rs- OTEL event macros emit log-only events to
codex_otel.log_only: codex-rs/otel/src/events/shared.rs- session telemetry emits many log-capable events:
codex-rs/otel/src/events/session_telemetry.rs
However, app-server later explicitly shuts OTEL down:
codex-rs/app-server/src/lib.rs
and OtelProvider also shuts down again in Drop:
codex-rs/otel/src/provider.rs
The provider shutdown logic also force-flushes traces before shutdown, but does not explicitly force-flush logs.
Root-cause hypothesis
Most likely explanation:
app-serverstill has active drop/cleanup paths that emittracinglog events after the OTEL logger provider has already been shut down.- The global tracing subscriber remains installed, so those later log events hit
OpenTelemetryTracingBridge. - OTEL rejects them with
BatchLogProcessor.Emit.AfterShutdown, so logs are never exported.
Relevant code references
codex-rs/app-server/src/lib.rs- OTEL provider construction and layer installation
- explicit
otel.shutdown()near process shutdown codex-rs/otel/src/provider.rsOtelProvider::shutdown()impl Drop for OtelProviderlogger_layer()build_logger()codex-rs/core/src/otel_init.rs- analytics gating appears to affect metrics, not log export
codex-rs/otel/src/events/shared.rslog_event!target iscodex_otel.log_onlycodex-rs/otel/src/events/session_telemetry.rs- events such as
codex.user_prompt,codex.api_request,codex.websocket_*,codex.sse_event
High-level fix outline
I believe the fix is likely one or more of:
- keep the OTel provider alive until after all remaining app-server cleanup/drop paths finish emitting logs
- remove or redesign the explicit
otel.shutdown()vsDropdouble-shutdown behavior - make shutdown one-shot / idempotent
- ensure the log exporter is flushed before shutdown if the logger provider supports it
I have a local repro and can provide more exact command/output detail if useful.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗