Spring MVC not logging all exceptions

旧巷老猫 提交于 2021-02-07 06:49:11

问题


I have Spring MVC setup to log exceptions using commons logging, but find that some runtime exceptions aren't being logged.

Here's my bean configuration for the default exception resolver provided by spring:

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.Exception">error</prop>
        </props>
    </property>
</bean>

回答1:


To get this to log most exceptions, I had to add the following line to my config:

    <property name="warnLogCategory" value="someCategoryStringYouMakeUp" />

So ultimately it became the following:

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="warnLogCategory" value="apperror" />
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.Exception">error</prop>
        </props>
    </property>
</bean>

warnLogCategory is described in detail here.




回答2:


To augment what @Brad Parks said I recommend that you also make a HttpServlet Filter that will run first (and finish last) to catch exceptions that Spring will miss. Also because there is Spring code that can fail like Spring Security and custom Http Interceptors that fall outside of the SimpleMappingException Resolver (ie if the DispatchServlet or Interceptors fail you will not get the exception).

Here's an example filter I use on top of the SimpleMappingExceptionResolver.

public class ExceptionLoggerServletFilter implements Filter {

    private CommonAccessLogFormatter requestFormat = new CommonAccessLogFormatter();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException {
        try {
            chain.doFilter(request, response);
        } catch (Exception e) {
            StringBuilder sb = new StringBuilder("Very Bad shit has happened:");
            if (request instanceof HttpServletRequest)
                requestFormat.appendLogEntry((HttpServletRequest) request, sb);
            log.fatal(sb.toString(), e);
            throw new ServletException(e);
        }
    }

    @Override
    public void destroy() {
    }


    private static final Logger log = Logger.getLogger(ExceptionLoggerServletFilter.class);

}

The reason I recommend this is that for most servlet containers uncaught exception may or may not be logged with probably not your logging framework (for Tomcat its JULI).

The commons log access formatter just logs the request similar to Apache log files.




回答3:


In my test, use SimpleMappingExceptionResolver can't log MissingServletRequestParameterException, I combined @ControllerAdvice and Filter to do log.

Use ControllerAdvice to catch Throwable raised in Spring MVC Controller.

@ControllerAdvice
public class GlobalDefaultExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger("global_controller_exception_logger");

    @ExceptionHandler(value = Throwable.class)
    public void defaultErrorHandler(Throwable e) throws Throwable {
        // If the exception is annotated with @ResponseStatus rethrow it and let
        // the framework handle it.
        // AnnotationUtils is a Spring Framework utility class.
        if (AnnotationUtils.findAnnotation
                (e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }

        // Otherwise log exception
        logger.error("global controller default exception handler", e);
        throw e;
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public void httpBadRequest(Exception e, HttpServletRequest request) throws Exception {
        StringBuffer requestURL = request.getRequestURL();
        logger.warn("{}   HTTP Status 400 - {}", requestURL, e.getMessage());
        throw e;
    }
}

Use Filter to catch additional Exception.

@WebFilter(
        filterName = "ExceptionLogFilter",
        urlPatterns = "/*",
        dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR}
)
public class ExceptionLogFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger("global_filter_exception_logger");


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (IOException | ServletException e) {
            logger.error("bad thing happened during doFilter", e);
            throw e;
        }
    }

    ......
}

logback configuration

<logger name="global_controller_exception_logger" level="info"/>

<logger name="global_filter_exception_logger" level="info"/>

You can view my gist for full code.



来源:https://stackoverflow.com/questions/11692635/spring-mvc-not-logging-all-exceptions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!