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