2016년 2월 12일 금요일

Spring의 SimpleMappingExceptionResolver에서 로그 남기기

회사에서 개발중인 시스템에서 Spring의 SimpleMappingExceptionResolver와 관련된 부분을 수정했기에 블로그로 남긴다.

1.
Web프레임웍으로 Anyframe을 사용중인데, *.do 요청을 AJAX로 보내면 Exception 발생시에도 stacktrace를 로그에 남기지 않아서 불편한 점이 있었다. 그동안은 *.do 요청이 많지 않아서 불편함이 드러나지 않았는데, 최근에 *.do 요청으로 중요 로직을 연결하여 사용하다보니 불편함이 느껴져서 고치게 되었다.

2.
Exception유형에 따른 View를 결정할때 Anyframe의 AjaxServiceExceptionHandler를 사용하고 있다. AjaxServiceExceptionHandler는 Spring의 SimpleMappingExceptionResolver를 상속받은 클래스이고, HttpRequestHeader에 X-Requested-With 헤더값이 XMLHttpRequest일때는 super.resolveException를 호출하지 않도록 구현되어 있다.

3.
좀 더 찾아보니 SimpleMappingExceptionResolver는 AbstractHandlerExceptionResolver를 상속받았기 때문에 warnLogCategory를 사용하는 방법이 있었다. WarnLogCategory에 logger의 이름을 넣어주면 해당 logger로 warn 레벨의 로그를 남겨주게 되어 있다.

spring-webmvc-4.0.3.RELEASE.jar:AbstractHandlerExceptionResolver.class의 일부

            public void setWarnLogCategory(String loggerName)
            {
/* 108*/        warnLogger = LogFactory.getLog(loggerName);
            }

            protected void logException(Exception ex, HttpServletRequest request)
            {
/* 186*/        if(warnLogger != null && warnLogger.isWarnEnabled())
/* 187*/            warnLogger.warn(buildLogMessage(ex, request), ex);
            }

그런데 2번에서 언급한 것 처럼 super를 호출하지 않기 때문에 빈생성시 warnLogCategory 프러퍼티를 넣어주어도 로그가 남지 않고 있었다.

4.
AjaxServiceExceptionHandler가 super.resolveException를 항상 호출하도록 수정할 수 없으니, AbstractHandlerExceptionResolver의 warnLogCategory를 활용하는 방법으로 해결하는 것은 포기하고, 검색하다 발견한 블로그처럼 AjaxServiceExceptionHandler를 상속받은 LogAjaxServiceExceptionHandler를 새로 만들어서 사용하기로 했다.

public class LogAjaxServiceExceptionHandler extends AjaxServiceExceptionHandler {

private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
logger.error(ex.getMessage(), ex);
return super.resolveException(request, response, handler, ex);
}

}

5.
logger를 새로 생성하지 않고 AbstractHandlerExceptionResolver가 가지고 있는 logger를 사용해도 무방하다. 다만, 나중에 logger의 이름을 변경하게 될 것 같아서 별도로 생성해 놨다.

6.
검색하다 보니 stacktrace를 로그로 남기는 방법을 직접 구현한 블로그도 있었는데, logger에 2번째 파라미터로 Exception을 넘겨주면 알아서 stacktrace도 찍어주기 때문에 불필요했다.


댓글 없음:

댓글 쓰기