001
002 /*
003 * Copyright (C) 2011 Archie L. Cobbs. All rights reserved.
004 *
005 * $Id: ExceptionLoggingFilter.java 203 2011-12-30 20:21:11Z archie.cobbs $
006 */
007
008 package org.dellroad.stuff.servlet;
009
010 import java.io.IOException;
011 import java.net.SocketException;
012
013 import javax.servlet.FilterChain;
014 import javax.servlet.ServletException;
015 import javax.servlet.http.HttpServletRequest;
016 import javax.servlet.http.HttpServletResponse;
017
018 import org.slf4j.Logger;
019 import org.slf4j.LoggerFactory;
020 import org.springframework.web.filter.OncePerRequestFilter;
021
022 /**
023 * Servlet filter that ensures any exceptions which are not handled by the servlet get logged somewhere.
024 */
025 public class ExceptionLoggingFilter extends OncePerRequestFilter {
026
027 private final Logger defaultLogger = LoggerFactory.getLogger(this.getClass());
028
029 /**
030 * Process the request. If an exception is thrown, it will be (possibly) logged and re-thrown.
031 *
032 * @see #shouldLogException
033 */
034 @Override
035 public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
036 throws IOException, ServletException {
037 try {
038 filterChain.doFilter(request, response);
039 } catch (IOException e) {
040 if (this.shouldLogException(e))
041 this.logException(e);
042 throw e;
043 } catch (ServletException e) {
044 if (this.shouldLogException(e))
045 this.logException(e);
046 throw e;
047 } catch (RuntimeException e) {
048 if (this.shouldLogException(e))
049 this.logException(e);
050 throw e;
051 } catch (Error e) {
052 if (this.shouldLogException(e))
053 this.logException(e);
054 throw e;
055 } catch (Throwable e) {
056 if (this.shouldLogException(e))
057 this.logException(e);
058 throw new ServletException(e);
059 }
060 }
061
062 /**
063 * Determine if an exception caught by this instance should be logged.
064 *
065 * <p>
066 * The implementation in {@link ExceptionLoggingFilter} returns {@code true} except for
067 * {@link SocketException} (typically caused by the client disconnecting) and {@link ThreadDeath}
068 * (typically caused by virtual machine shutdown).
069 * Subclasses should override if necessary.
070 *
071 * @param t exception caught by this instance
072 */
073 protected boolean shouldLogException(Throwable t) {
074 if (t instanceof SocketException)
075 return false;
076 if (t instanceof ThreadDeath)
077 return false;
078 return true;
079 }
080
081 /**
082 * Log an exception caught by this instance.
083 *
084 * <p>
085 * The implementation in {@link ExceptionLoggingFilter} logs the exception as an error via the logger
086 * returned by {@link #getLogger getLogger()}.
087 * Subclasses should override if necessary.
088 *
089 * @param t exception caught by this instance
090 */
091 protected void logException(Throwable t) {
092 this.getLogger(t).error("exception within servlet", t);
093 }
094
095 /**
096 * Get the logging destination.
097 *
098 * <p>
099 * The implementation in {@link ExceptionLoggingFilter} uses the {@link Logger} returned by
100 * {@link LoggerFactory#getLogger} when passed this instance's class as the parameter.
101 * Subclasses should override if necessary.
102 *
103 * @param t the exception about to be logged
104 */
105 protected Logger getLogger(Throwable t) {
106 return this.defaultLogger;
107 }
108 }
109