-
Apache Tomcat ErrorReportValve에 logOnError 옵션 추가하기Spring Framework 2026. 1. 21. 22:13반응형
개요
Apache Tomcat의 ErrorReportValve는 HTTP 에러 발생 시 사용자에게 에러 페이지를 보여주는 역할을 합니다.
하지만 에러가 발생했을 때 이를 로그로 남겨 빠르게 인지할 수 있는 기능은 제공하지 않았습니다.
이로 인해 Tomcat 처리 단계에서 발생한 에러는 운영 환경에서 쉽게 놓치기 쉬웠고,
이를 개선하기 위해 에러 로그를 남길 수 있는 옵션을 추가하는 PR을 작성하게 되었습니다.Spring Boot + Tomcat 처리 흐름
Spring Boot + Tomcat 환경에서 하나의 HTTP 요청은 보통 다음 순서로 처리됩니다.
Client → Tomcat → Filter → DispatcherServlet → Controller여기서 DispatcherServlet이 요청을 받게 된다면 BasicErrorController가 오류를 처리하며, 기본 설정일 경우 우리가 잘 아는 Whitelabel Error Page를 렌더링합니다.
하지만 만약 Tomcat이 처리하는 과정에서 오류가 발생하게 되면 요청은 DispatcherServlet 까지 도달하지 못하게 되며 이때는 ErrorReportValve 클래스에 의해 Tomcat 기본 HTML 에러 페이지가 생성됩니다.
예를 들면 규격에 맞지 않는 URI, 애플리케이션 버그로 인한 Tomcat 버그 유발 등이 있습니다.
즉, 에러 페이지의 종류만 보아도 요청이 어느 단계에서 실패했는지를 유추할 수 있습니다.
에러는 발생하지만, 로그는 남지 않는다
ErrorReportValve가 처리한 에러는 애플리케이션 로그나 에러 로그에 별도로 남지 않아,
문제 인지와 원인 분석이 외부 제보에 의존할 수밖에 없는 한계가 있었습니다.Observability 개선 구현
ErrorReportValve에 logOnError 옵션을 추가하여, 에러 응답을 생성하는 시점에 요청 정보와 예외를 로그로 기록하도록 구현했습니다.
옵션이 활성화된 경우에만 로그를 남기도록 하여, 기존 동작과의 호환성을 유지하였으며, 이를 통해 Spring 이전 단계에서 발생한 에러도 운영 환경에서 즉시 인지할 수 있기를 기대합니다.PR 설명
1. logOnError 옵션 추가
기존에는 showReport, showServerInfo 옵션만 존재했으며,
여기에 에러 로깅 여부를 제어하는 logOnError 플래그를 추가하였습니다.기본값을 false로 설정한 이유는 하위 호환성을 유지하기 위함이며,
봇이나 비정상적인 요청으로 인해 불필요한 에러 로그가 대량으로 발생하는 경우를
운영 환경에서 제어할 수 있도록 하기 위함입니다.2. 로깅 메시지 국제화 지원
톰캣은 LocalStrings.properties 파일에서 로깅 메시지의 국제화를 지원합니다.
StringManager를 통하여 errorReportValve.errorLogged 특정 키로 조회하여 메시지를 제공합니다.
3. 문서화 추가
webapps/docs/config/valve.xml 문서에 logOnError 필드가 의미하는 바를 추가하였습니다.
4. 테스트 추가
TestErrorReportValve 클래스에 testLogOnErrorEnabled, testLogOnErrorDisabled 두 가지 테스트를 추가하여 옵션에 따라 에러로그가 남는지, 남지 않는지 검증하였습니다.
pr 링크
- https://github.com/apache/tomcat/pull/943
마무리
이번 logOnError 옵션 추가는 기능적으로는 작은 변화지만,
운영 중 발생하는 Tomcat 레벨 에러를 인지하는 데에는 꽤 큰 차이를 만들어줍니다.
비슷한 문제를 겪고 있다면 이 경험이 하나의 참고 사례가 되었으면 합니다.'Spring Framework' 카테고리의 다른 글
Kotlin coroutine graceful shutdown in spring boot (0) 2025.04.06 MSA 환경에서 enum에 대한 위험성 줄여나가기 (0) 2024.11.16 Spring Bean 이름은 왜 소문자로 시작할까? (0) 2024.11.03 분산시스템에서 로깅 트레이싱 전파는 어떻게 이루어질까? (0) 2024.10.26 Spring Boot Distributed Scheduling (0) 2024.06.30