6

我有 Spring MVC 设置以使用公共日志记录来记录异常,但发现一些运行时异常没有被记录。

这是spring提供的默认异常解析器的bean配置:

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

3 回答 3

4

为了让它记录大多数异常,我必须将以下行添加到我的配置中:

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

所以最终变成了下面这样:

<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在这里有详细描述

于 2012-07-27T17:25:41.153 回答
3

为了增强@Brad Parks 所说的内容,我建议您还制作一个 HttpServlet 过滤器,它将首先运行(最后完成)以捕获 Spring 将错过的异常。还因为有可能失败的 Spring 代码,如 Spring Security 和自定义 Http 拦截器,它们不在 SimpleMappingException Resolver 范围内(即,如果 DispatchServlet 或拦截器失败,您将不会收到异常)。

这是我在 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);

}

我推荐这样做的原因是,对于大多数 servlet 容器,未捕获的异常可能会或可能不会记录在您的日志框架中(对于 Tomcat,它的 JULI)。

公共日志访问格式化程序只记录类似于 Apache 日志文件的请求。

于 2012-07-27T17:32:29.090 回答
2

在我的测试中,使用SimpleMappingExceptionResolvercan't log MissingServletRequestParameterException,我结合@ControllerAdviceFilter做 log。

用于ControllerAdvice捕获 Spring MVC 控制器中引发的 Throwable。

@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;
    }
}

用于Filter捕获额外的异常。

@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;
        }
    }

    ......
}

回退配置

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

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

您可以查看我的要点以获取完整代码。

于 2017-02-10T14:39:15.277 回答