
부제: 성공만 로깅되던 서버에서 실패를 조사할 수 있게 만들기
성공 경로는 촘촘히 로깅되는데, 실패·거부 경로에서는 서버가 조용했다.
HEIF 이미지가 왜 안 올라갔는지, 채팅이 어디서 타임아웃 났는지, 403이 왜 났는지 —
조사할 때마다 로그가 없어서 원인 특정에 막혔다.
문제를 두 축으로 나눴다. 무엇을 로깅할지, 그리고 그걸 어디로 모아 얼마나 보존할지.
성공만 남던 서버
실패를 성공만큼 남기기로 했다.
다만 원칙을 세웠다.
판정에 쓴 입력값과 함께 남기되, 본문 내용은 넣지 않고(개인정보 0),
4xx는 경고, 5xx는 에러 수준으로 남긴다.
여기서 갈림길이 있었다.
실패가 나는 자리마다 로그를 한 줄씩 심을 수도 있었다.
그런데 그러면 자리마다 남기는 방식이 제각각이 되고, 새 에러 코드가 생기면 로그를 또 빠뜨린다.
실패는 한 곳에서 삼킨다
그래서 개별 지점이 아니라 중앙 예외 핸들러가 실패를 삼키게 했다.
에러 코드가 붙은 모든 예외는 결국 한 핸들러로 수렴한다.
거기서 error_code·status·path를 한 번에 남기면,
나중에 새 에러 코드를 추가해도 로깅은 자동으로 따라온다.
- 검증 실패(422)는 어느 필드가 틀렸는지 경로만 남기고 값은 넣지 않는다
- 스트리밍 도중 터진 예외는 이미 응답이 나간 뒤라 중앙 핸들러 밖이어서, 그 자리에서 타입과 메시지를 남긴다
- 에이전트 쪽은 요청 ID를 추적 메타데이터에 실어, LLM 추적과 앱 로그를 이어 볼 수 있게 했다
로그에 남기는 건 코드·상태·타입·크기·ID뿐이다.
메시지 본문이나 파일 내용, 건강 데이터는 구조적으로 들어가지 않게 했다.
어디로 모으고 얼마나 남길까
두 번째 축은 수집이었다.
앱이 직접 파일에 쓰게 할 수도 있었지만, 그러면 앱 코드가 늘고
여러 워커가 같은 파일을 두고 다투는 문제가 생긴다.
그래서 앱은 콘솔(stdout)로만 뱉고,
수집은 Fluent Bit 사이드카에게 맡겼다.
전 컨테이너의 stdout을 도커가 녹화하면, Fluent Bit가 그걸 훑어
서비스별로 갈라 logs/<service>/app.log로 떨어뜨린다.
앱 입장에선 추가 코드가 없고, docker logs도 그대로 살아 있고, 모든 서비스에 똑같이 적용된다.
클라우드 로깅이나 Elasticsearch·Kibana 같은 건 얹지 않았다.
단일 VM에 트래픽도 낮은 환경엔 과하다.
호스트에서 파일을 직접 tail·grep하고 docker logs로 보는 걸로 충분했다.
볼륨은 인프라로 막는다
로그를 파일로 떨구니 용량이 문제였다.
그렇다고 "필요한 로그를 용량 걱정 때문에 안 남기는" 건 방향이 틀렸다고 봤다.
샘플링하거나 버리는 대신, logrotate 사이드카로 상한을 걸었다.
Fluent Bit의 파일 출력은 스스로 로테이션을 안 해서,
별도 사이드카가 서비스별 디렉터리를 만들고 5MB에서 잘라 몇 개만 남긴다.
서비스당 대략 25MB가 상한이다.
실제로 유휴 상태에서 초당 62바이트, 하루 5MB쯤 쌓였다.
대부분 헬스체크 같은 주기 로그였고, 트래픽이 늘면 비례해서 늘되 로테이션이 상한을 잡아 준다.
정리
- 실패도 성공만큼 남기되, 판정 입력값과 함께·본문 없이·상태 코드에 따라 수준을 나눴다
- 자리마다 심는 대신 중앙 예외 핸들러 한 곳에서 삼켜, 새 에러 코드도 자동으로 커버된다
- 앱은 콘솔로만 뱉고 수집·저장·로테이션은 Fluent Bit + 사이드카에 맡겨 앱 코드를 늘리지 않았다
- 단일 VM·저볼륨엔 클라우드 로깅이 과해서, 호스트 파일과
docker logs로 충분했다 - 용량 때문에 로그를 버리는 대신 logrotate로 상한을 걸었다
실패는 성공만큼, 판정에 쓴 값과 함께, 개인정보 없이, 보존되는 곳으로.
이 네 가지만 지키면 조사할 때 서버가 더는 침묵하지 않는다.
'Infra' 카테고리의 다른 글
| [비동기] SSE heartbeat 컨텍스트 누수 OTel 트레이스 깨짐 (0) | 2026.07.10 |
|---|---|
| [디버깅] user thread 완전복제 재현 원본 오염 방지 (1) | 2026.07.09 |
| [백업] restic DB 백업 용량 최소화 복원 자동검증 (0) | 2026.07.08 |
| [ClickHouse] Langfuse 쿼리 스톨 오진단 24.10 타임아웃 슬롯 버그 (0) | 2026.07.01 |
| [nginx] docker-compose command override envsubst 미실행 ${VAR} (0) | 2026.06.25 |