2012-07-27 94 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