Windows Codex app continuously writes high-volume TRACE websocket logs to ~/.codex/logs_2.sqlite despite RUST_LOG=warn

Open 💬 7 comments Opened Jun 22, 2026 by LeoZhu1999
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

On Windows, Codex Desktop continuously writes high-frequency TRACE logs into ~/.codex/logs_2.sqlite, mainly from websocket/tungstenite internals, even though RUST_LOG=warn and analytics/OTel export are disabled in ~/.codex/config.toml.

This causes persistent SQLite/WAL writes and database growth.

Environment

  • OS: Windows
  • Codex app package: OpenAI.Codex_26.616.6631.0_x64__2p2nqsd0c76g0
  • Codex app-server process:
  • codex.exe app-server --analytics-default-enabled
  • Database:
  • C:\Users\<user>\.codex\logs_2.sqlite
  • WAL mode with logs_2.sqlite-wal

Relevant config

~/.codex/config.toml includes:

[analytics]
enabled = false

[otel]
exporter = "none"

Environment variable checks:

RUST_LOG Process = warn
RUST_LOG User    = unset
RUST_LOG Machine = unset

Observed behavior

After fully restarting Codex Desktop, logs_2.sqlite continues to receive high-frequency writes.

A 28-second sample after restart showed:

max(id) increased by 573
logs_2.sqlite-wal continued updating
row count stayed constant, indicating new rows are inserted while older rows are deleted

Recent 1000 inserted ids were dominated by:

TRACE log                                      839 rows
INFO  codex_otel.log_only                      41 rows
INFO  codex_otel.trace_safe                    40 rows
TRACE codex_api::endpoint::responses_websocket 40 rows
TRACE codex_api::sse::responses                40 rows

Latest TRACE log bodies include low-level websocket/tungstenite messages such as:

tokio-tungstenite ... compat.rs ... Read.with_context read -> poll_read
tokio-tungstenite ... lib.rs ... WebSocketStream.with_context
Parsed headers [...]
WouldBlock

Impact

  • Continuous disk writes to SQLite/WAL
  • logs_2.sqlite growth and churn
  • Extra local storage usage
  • Potential performance and SSD wear concern
  • TRACE-level logs may capture more detailed internal request/response metadata than expected

Before manual maintenance, the database was approximately:

logs_2.sqlite before VACUUM: 199,499,776 bytes
logs_2.sqlite after VACUUM:   75,206,656 bytes

After reopening Codex, WAL growth resumed:

logs_2.sqlite-wal around 5 MB and still updating

Expected behavior

With RUST_LOG=warn, [analytics].enabled = false, and [otel].exporter = "none", Codex should not continuously persist high-volume TRACE websocket/tungstenite logs to the local SQLite log store during normal use.

If local SQLite diagnostics intentionally retain TRACE records, there should be a documented configuration option to disable or reduce this verbosity.

Reproduction steps

  1. Start Codex Desktop on Windows.
  2. Ensure:
  • RUST_LOG=warn
  • [analytics].enabled = false
  • [otel].exporter = "none"
  1. Open or continue a Codex thread.
  2. Inspect ~/.codex/logs_2.sqlite and ~/.codex/logs_2.sqlite-wal.
  3. Sample max(id), level, target, and WAL modification time over 20-30 seconds.
  4. Observe continuous inserts of TRACE log, codex_api::endpoint::responses_websocket, and codex_api::sse::responses.

Notes

I avoided attaching the SQLite database directly because it may contain sensitive local diagnostic/session details.

View original on GitHub ↗

7 Comments

github-actions[bot] contributor · 28 days ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #28224
  • #29177
  • #28997

Powered by Codex Action

YancyWei · 27 days ago

Additional Windows reproduction / mitigation data from another Codex Desktop install.

Environment:

  • OS: Windows
  • Log DB: C:\Users\Admin\.codex\logs_2.sqlite
  • Timezone: Asia/Shanghai
  • Observed on: 2026-06-23

Observed state before mitigation:

  • logs_2.sqlite size: 753,307,648 bytes (~718 MiB)
  • logs_2.sqlite-wal existed and was updating
  • logs table retained row count: 67,214
  • MAX(id): advanced from 58,159,254 to 58,204,400 during investigation
  • Level counts in retained rows:
  • TRACE: 33,672, estimated bytes 69,385,610
  • INFO: 27,662, estimated bytes 37,341,429
  • DEBUG: 5,626, estimated bytes 7,687,324
  • WARN: 226
  • ERROR: 28

Recent high-frequency sample:

  • Around 2026-06-23 12:10, one minute contained ~2,000 log rows, including ~1,499 TRACE rows.
  • Recent rows were dominated by websocket/tungstenite internals and frame parsing, including WouldBlock, Read.with_context, AllowStd.with_context, WebSocketStream.with_context, received websocket frames, parsed headers, opcodes, etc.

Top retained targets by count included:

  • TRACE codex_api::endpoint::responses_websocket: 12,771 rows, estimated bytes 49,797,435
  • TRACE log: 10,515 rows
  • TRACE codex_mcp::connection_manager: 2,711 rows
  • TRACE hyper_util::client::legacy::pool: 2,652 rows
  • TRACE codex_api::sse::responses: 2,418 rows
  • INFO codex_otel.log_only: 13,225 rows
  • INFO codex_otel.trace_safe: 13,207 rows

SQLite metadata:

  • journal_mode: wal
  • page_size: 4096
  • page_count: 183,913
  • freelist_count: 138,975

The large freelist means the DB file stayed large after pruning/retention cleanup, so the retained row count substantially under-represents the write volume that already occurred.

Temporary mitigation applied locally:

  1. Backed up logs_2.sqlite, logs_2.sqlite-wal, and logs_2.sqlite-shm.
  2. Added a local trigger to block further inserts into logs:
CREATE TRIGGER IF NOT EXISTS codex_block_logs_insert
BEFORE INSERT ON logs
BEGIN
  SELECT RAISE(IGNORE);
END;
  1. Ran PRAGMA wal_checkpoint(TRUNCATE).
  2. Sampled for ~21 seconds afterward.

Post-mitigation sampling result:

  • MAX(id) stayed fixed at 58,204,400
  • retained row count stayed fixed at 67,214
  • logs_2.sqlite stayed fixed at 753,307,648 bytes
  • logs_2.sqlite-wal stayed fixed at 0 bytes

This confirms the write churn was coming through logs inserts, and blocking that table stopped WAL growth on this machine. This workaround is obviously not ideal because it disables persisted logs, but it was needed to stop the local write churn.

Qin202 · 27 days ago

Confirmed independently on Windows with Codex Desktop 26.616.9593.0 (x64).

Before cleanup:

  • logs_2.sqlite: 197,857,280 bytes
  • logs_2.sqlite-wal: 6,027,592 bytes
  • Retained rows: 7,310
  • Levels: TRACE 4,639 (63.5%), INFO 2,190, DEBUG 465, WARN 16
  • MAX(id): 22,467,668
  • SQLite freelist: 43,622 / 48,305 pages (~90.3%)

During a 5-second sample, the retained row count stayed constant while MAX(id) increased by 44, confirming continuous insert/delete churn.

RUST_LOG was already warn, with no trace/debug/sqlite override in config.toml. After deleting TRACE/DEBUG, running VACUUM, truncating the WAL, and persisting RUST_LOG=warn, TRACE/DEBUG immediately returned. During a subsequent 10-second sample, MAX(id) increased by 151.

As a diagnostic workaround, a SQLite BEFORE INSERT trigger that ignored TRACE/DEBUG stopped those records completely; only one INFO record was added during the next 10-second sample. This suggests the high-volume records are being persisted upstream of, or independently from, the documented RUST_LOG filter.

No database or raw log bodies are attached because they may contain sensitive session data.

april-yc · 27 days ago

I can reproduce this on Windows with a newer Codex Desktop package.

Environment

  • OS: Windows
  • Codex package:

OpenAI.Codex_26.616.9593.0_x64__2p2nqsd0c76g0

  • Codex executable:

C:\Program Files\WindowsApps\OpenAI.Codex_26.616.9593.0_x64__2p2nqsd0c76g0\app\resources\codex.exe

  • Database:

C:\Users\<redacted>\.codex\logs_2.sqlite
C:\Users\<redacted>\.codex\logs_2.sqlite-wal

Observed behavior

The database is in WAL mode. The main database file size stays mostly unchanged, but logs_2.sqlite-wal continues to update while Codex is running.

A read-only snapshot showed:

  • MAX(id) increased by 188 within 10 seconds.
  • Later, MAX(id) increased by another 155 within 25 seconds.
  • The total row count did not meaningfully increase, which suggests Codex may be inserting new log rows while pruning old rows.
  • In a recent 30-second window:
  • Around 09:30:02, there were about 2010 TRACE rows, with an estimated log-body size of about 1.33 MB.
  • Around 09:31:05, the recent 30-second window still contained about 1258 TRACE rows.
  • Recent one-hour write sources were dominated by:
  • TRACE log: 1041 rows
  • TRACE codex_api::sse::responses: 1003 rows
  • The latest log rows were almost all TRACE.
  • The associated process_uuid pointed to the currently running Codex process.

Configuration

I did not find any explicit TRACE, RUST_LOG, or log-level configuration in:

C:\Users\<redacted>\.codex\config.toml

Windows denied reading the full process command line, so I cannot confirm whether the log level is being set by the startup environment.

Expected behavior

Codex Desktop should not continuously persist high-frequency TRACE logs into the local SQLite log database during normal usage, especially when no TRACE-level logging is configured by the user.

If persistent local diagnostic logging is intentional, there should be a documented option to reduce the SQLite log level or disable high-volume TRACE persistence.

Yassycodes · 26 days ago

Thanks for writing this up. I am seeing a related Windows Codex Desktop performance regression in #28855. My case started with a large logs_2.sqlite / WAL problem too, but even after rotating logs and reproducing with small fresh logs, Codex Desktop still caused intermittent mouse/typing/system input lag on Windows.

I linked your report in a broader Discussion collecting recent Windows Desktop performance reports here: https://github.com/openai/codex/discussions/29949#discussioncomment-17428007

No action needed from you unless you want to add more detail there, but I wanted to connect the reports because the recent Windows performance issues look related enough that they may need a canonical tracker.

denispol · 25 days ago

Expected: the SQLite sink builds its own Targets filter (hardcoded TRACE) and only the stderr layer honors RUST_LOG. Fix adds CODEX_LOG_DB_LEVEL (and [log] level) and lowers the default to INFO: https://github.com/denispol/codex/pull/1