---
title: "Codex 로그 버그, 로컬 SSD에 연 640TB 쓰기 만들 수 있음"
published: 2026-06-22T07:30:17.000Z
canonical: https://jeff.news/article/4218
---
# Codex 로그 버그, 로컬 SSD에 연 640TB 쓰기 만들 수 있음

Codex의 SQLite 피드백 로그가 TRACE 레벨 로그를 과도하게 저장하면서 로컬 SSD에 비정상적으로 많은 쓰기를 발생시킬 수 있다는 GitHub 이슈야. 제보자는 21일 가동 후 37TB 쓰기를 관측했고, 이를 연간으로 환산하면 약 640TB에 달한다고 주장함.

- Codex가 로컬 SQLite 피드백 로그에 너무 많이 쓰고 있다는 GitHub 이슈가 올라옴
  - 문제 파일은 `~/.codex/logs_2.sqlite`, `logs_2.sqlite-wal`, `logs_2.sqlite-shm`
  - 제보자 머신에서 약 21일 가동 후 메인 SSD 쓰기량이 37TB까지 올라갔고, 프로세스·파일 단위 확인 결과 Codex SQLite 로그가 주요 지속 writer로 지목됨

- 이 속도를 1년으로 늘리면 숫자가 꽤 살벌함
  - 대략 640TB/year, 즉 1TB SSD 기준 연간 640회 전체 드라이브 쓰기 수준
  - 일부 소비자용 SSD 보증 내구성이 600TBW 근처라서, 최악의 경우 1년 안에 보증 쓰기 수명을 거의 다 먹을 수 있다는 계산임

> [!WARNING]
> 장시간 Codex를 켜두는 환경이라면 `~/.codex/logs_2.sqlite-wal` 같은 파일 크기와 SSD write total을 한 번 확인해볼 만함.

- retained DB 크기만 보면 문제가 작아 보일 수 있는데, 실제론 쓰기 증폭이 핵심임
  - 15초 샘플에서 약 36,211행이 삽입됐지만 retained row count는 거의 그대로였다고 함
  - 즉 로그를 넣고, 인덱싱하고, WAL에 쓰고, 다시 pruning하는 루프가 계속 돌면서 디스크 쓰기량만 커질 수 있음

- 가장 큰 원인 후보는 SQLite 피드백 로그 sink의 global TRACE 기본값임
  - 코드상 `Targets::new().with_default(Level::TRACE)`가 사용된 것으로 지목됨
  - 이러면 Codex 자체 로그뿐 아니라 dependency/internal 로그, raw websocket/SSE payload까지 기본적으로 TRACE 수준에서 저장될 수 있음

- 샘플 기준으로 줄일 수 있는 로그가 대부분을 차지함
  - TRACE 로그만 retained bytes의 70.7%였음
  - `codex_otel.log_only`와 `codex_otel.trace_safe`가 추가로 25.3%를 차지해서, 이 세 범주만 필터링해도 샘플 기준 약 96%의 retained log bytes를 줄일 수 있다고 주장함

- 실제 예시도 꽤 잡음에 가까움
  - inotify 이벤트로 `ld.so.cache` OPEN이 128,764회, `locale.alias` OPEN이 37,982회, `passwd` OPEN이 23,843회 기록됨
  - tokio-tungstenite 내부 `poll_next`, `read`, `WouldBlock`, WebSocket opcode 같은 저수준 이벤트도 수천 회 단위로 남음

- 제안된 수정 방향은 ‘로그 끄기’보다 ‘기본 필터링을 sane하게’임
  - SQLite 피드백 로그 sink에 global TRACE를 기본으로 쓰지 말 것
  - `target=log`, `hyper_util`, `tokio-tungstenite`, inotify spam, 저수준 OpenTelemetry SDK 로그의 threshold를 올리거나 버릴 것
  - raw websocket/SSE payload 전문 대신 이벤트 종류, duration, 성공·실패, token usage, payload byte length 같은 요약만 저장할 것
  - per-thread cap만으로는 부족하니 전역 DB 크기·쓰기 cap을 둘 것

- 관련 이슈도 이미 여러 개라서 단발 제보로 보기 어려움
  - SQLite WAL write, logs_N.sqlite 무한 성장, idle Codex process의 heavy I/O, WSL2 100% disk active time, goals_1.sqlite write amplification 등이 함께 언급됨
  - 개발자 도구가 ‘관측성’을 넣다가 로컬 머신 자원을 조용히 태우는 전형적인 사고 패턴임

---
## 기술 맥락

- 여기서 기술적 선택은 피드백 로그를 SQLite에 얼마나 자세히 남길지예요. 왜냐하면 피드백 디버깅에는 상세 로그가 필요하지만, global TRACE를 기본값으로 두면 사용자 머신의 디스크가 로그 저장소처럼 쓰이기 때문이에요.

- SQLite WAL은 작은 로컬 DB에 편한 선택이지만, 계속 삽입하고 지우는 workload에서는 쓰기량이 생각보다 커질 수 있어요. 특히 retained row count가 유지돼도 WAL 기록, 인덱스 갱신, pruning이 반복되면 SSD 입장에선 계속 쓰는 거거든요.

- 제보자가 제안한 방향은 기능을 없애자는 게 아니라 저장 대상을 좁히자는 쪽이에요. raw websocket/SSE payload나 dependency TRACE 로그 대신 이벤트 종류, 시간, 성공 여부, 토큰 사용량 같은 요약만 남기면 디버깅 가치는 남기고 I/O 비용은 크게 줄일 수 있어요.

- 이 문제는 Codex만의 특수한 버그라기보다 에이전트형 개발 도구 전반의 운영 이슈에 가까워요. 장시간 떠 있는 CLI나 데스크톱 앱은 로컬 로그 정책도 제품 품질의 일부로 봐야 해요.

## 핵심 포인트

- Codex가 ~/.codex/logs_2.sqlite와 WAL 파일에 지속적으로 대량 쓰기를 수행함
- 21일간 37TB 쓰기 관측, 연간 약 640TB로 환산됨
- TRACE 로그가 보존 바이트의 70.7%, OpenTelemetry 미러 로그가 추가 25.3%를 차지함
- 15초 동안 약 36,211행이 삽입됐지만 보존 행 수는 거의 유지돼 insert-and-prune 증폭이 의심됨

## 인사이트

개발 도구의 로깅 기본값 하나가 SSD 수명 문제로 이어지는 꽤 현실적인 사례임. 특히 장시간 켜두는 CLI·데스크톱 에이전트는 ‘로그는 싸다’는 가정이 깨질 수 있음.
