개발 slecs

리스너 로깅의 유니코드 인코딩 에러 수정기

목차

listener 모듈에서 부모 fetch 작업 예외를 로깅할 때 발생하는 ASCII 인코딩 에러를 수정했다. 단순한 로깅 버그처럼 보이지만, 이 문제를 통해 Python의 인코딩 처리와 예외 안전성에 대해 다시 생각해 본 부분이 있다.

문제가 드러난 순간

listener 모듈은 async 패턴으로 부모 서비스에서 데이터를 fetch하고 예외 상황을 로깅하는 역할을 한다. 대부분의 경우 정상적으로 작동했지만, 특정 상황에서 예외 메시지를 기록할 때 인코딩 에러가 발생했다.

문제는 예외 객체의 메시지 부분에 ASCII 범위를 벗어난 문자(예: 한글, 특수 기호, URL 인코딩된 값 등)가 포함될 때였다. Python에서 기본적으로 ASCII 인코딩을 사용하는 환경에서 이런 문자들을 그대로 기록하려 하면 UnicodeEncodeError가 발생한다. 더 짜증나는 건 이 에러가 로깅 자체를 실패시켜서 예외 정보가 아예 남지 않는다는 것이다.

ASCII vs UTF-8, 그리고 예외 처리의 진정한 의미

로깅 코드를 보면 보통 이렇게 작성하곤 한다:

try:
    await parent_fetch()
except Exception as e:
    logger.error(f"Parent fetch failed: {e}")

이 코드는 e를 문자열로 변환할 때 기본 인코딩을 사용한다. 만약 시스템의 기본 인코딩이 ASCII거나, 로거 설정에서 인코딩을 명시하지 않았다면, 멀티바이트 문자는 처리되지 못한다. 더 나쁜 건, 이렇게 되면 원래 발생한 예외의 정보를 완전히 잃는다는 뜻이다.

리스너 패턴에서 예외 처리는 단순 "에러를 기록"하는 게 아니라 시스템의 신뢰성을 지키는 최후의 방어선이다. 만약 이 로깅이 실패하면:
- 문제를 추적할 단서가 없어짐
- 사용자 관점에서는 "왜 데이터가 안 왔지?"만 느낌
- 팀이 인시던트 대응할 때 로그를 찾으려고 해도 아무것도 없음

수정 방향: UTF-8 명시 + 안전한 문자 처리

Python 3에서는 UTF-8이 권장되는 표준이다. 수정은 간단했다:

항목 before after
인코딩 처리 시스템 기본값 (ASCII) UTF-8 명시
에러 안전성 특수 문자 → 인코딩 에러 특수 문자 → 안전하게 기록
로그 가독성 에러로 인해 기록 안 됨 모든 메시지 정상 기록

listener.py에서 로깅을 초기화할 때, 또는 예외를 처리하는 부분에서 명시적으로 UTF-8 인코딩을 지정했다:

# logger 설정 예시
logging.basicConfig(
    encoding='utf-8',  # 명시적으로 UTF-8 지정
    ...
)

# 또는 예외 처리 시 직접 인코딩
try:
    await parent_fetch()
except Exception as e:
    error_msg = str(e).encode('utf-8', errors='replace').decode('utf-8')
    logger.error(f"Parent fetch failed: {error_msg}")

errors='replace' 옵션은 변환할 수 없는 문자를 '?'로 바꾸는데, 이렇게 하면 로깅 자체는 실패하지 않는다. 상황에 따라 'ignore' (무시), 'backslashreplace' (백슬래시 이스케이프) 등을 선택할 수도 있다.

회고: 작은 버그 하나에서 배운 점

이번 수정을 하면서 팀과 공유한 포인트들:

  1. 인코딩은 "나중에 생각할 것"이 아니다 — 처음부터 명시적으로 다루지 않으면, 특정 환경에서만 터지는 버그가 된다.

  2. 예외 로깅은 회피 불가능 — "어차피 예외는 드물지 않나" 같은 생각은 위험하다. listener 같은 백그라운드 작업에서는 예외 로그가 유일한 단서다.

  3. 테스트에 엣지 케이스를 포함하자 — 한글 문자열, 특수 기호, emoji 등을 포함한 예외 메시지로 테스트했다면 초반에 잡았을 것이다.

  4. 시스템 기본값을 믿지 말자 — 환경마다 다를 수 있으니 코드에서 명시적으로 지정하는 게 낫다.

다음 코드 리뷰 때는 예외 처리 부분에서 인코딩을 체크하는 항목을 추가했다. listener 같은 critical path에서는 특히.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.