2012-07-27 50 views
5

我有Spring MVC安装程序使用公共日志记录来记录异常,但发现一些运行时异常未被记录。Spring MVC没有记录所有异常

下面是由弹簧提供的默认异常解析器我的bean的配置:

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

回答

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是described in detail here

+1

那么使用这种方法将会错过哪些例外,并且有什么方法可以获得这些方法? – 2015-08-25 07:54:45

+0

好点。我很久没有使用过春天了,不记得了。我应该在上面包含更多信息。我最好的猜测就是从'RuntimeException'派生的异常,正如我上面所暗示的。 – 2015-08-25 11:16:38

3

为了扩大@Brad Parks的说法,我建议您也创建一个HttpServlet过滤器,它将首先运行(并最后完成)以捕获Spring将会错过的异常。另外,因为存在Spring代码可能会失败,如Spring Security和自定义Http拦截器,它们不属于SimpleMappingException解析器(即,如果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的巨力公司)记录。

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

+0

完全同意这个答案 - ** Spring **有一个**严重的限制** - 它只能处理** **异常类**的实例,所有**错误**实例**都被忽略**并发送到标准处理堆栈。所以,为了克服这个** Spring缺陷**应该在整个堆栈顶部添加Filter并确保处理** ALL **异常** ** – Yura 2014-07-08 18:45:38

1

在我的测试中,使用SimpleMappingExceptionResolver无法登录MissingServletRequestParameterException,我结合@ControllerAdviceFilter做记录。

使用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; 
     } 
    } 

    ...... 
} 

的logback配置

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

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

您可以完整的代码查看my gist