    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements. See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache license, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License. You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the license for the specific language governing permissions and
    015     * limitations under the license.
    016     */
    017    package org.apache.logging.log4j.web;
    018
    019    import java.io.IOException;
    020    import javax.servlet.Filter;
    021    import javax.servlet.FilterChain;
    022    import javax.servlet.FilterConfig;
    023    import javax.servlet.ServletContext;
    024    import javax.servlet.ServletException;
    025    import javax.servlet.ServletRequest;
    026    import javax.servlet.ServletResponse;
    027
    028    import org.apache.logging.log4j.Logger;
    029    import org.apache.logging.log4j.status.StatusLogger;
    030
    031    /**
    032     * This is responsible for the following:
    033     * <ul>
    034     *     <li>Clearing the logger context when the application has finished starting up.</li>
    035     *     <li>Setting the logger context before processing a request and clearing it after processing a request.</li>
    036     *     <li>Setting the logger context when the application is starting to shut down.</li>
    037     * </ul>
    038     * This filter is a once-per-request filter. It is capable of filtering all the different types of requests
    039     * (standard, asynchronous, error, etc.) but will not apply processing if the filter matches multiple times on the same
    040     * logical request.
    041     */
    042    public class Log4jServletFilter implements Filter {
    043
    044        private static final Logger LOGGER = StatusLogger.getLogger();
    045
    046        static final String ALREADY_FILTERED_ATTRIBUTE = Log4jServletFilter.class.getName() + ".FILTERED";
    047
    048        private ServletContext servletContext;
    049        private Log4jWebLifeCycle initializer;
    050
    051        @Override
    052        public void init(final FilterConfig filterConfig) throws ServletException {
    053            this.servletContext = filterConfig.getServletContext();
    054            LOGGER.debug("Log4jServletFilter initialized.");
    055
    056            this.initializer = WebLoggerContextUtils.getWebLifeCycle(this.servletContext);
    057            this.initializer.clearLoggerContext(); // the application is mostly finished starting up now
    058        }
    059
    060        @Override
    061        public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
    062                throws IOException, ServletException {
    063            if (request.getAttribute(ALREADY_FILTERED_ATTRIBUTE) != null) {
    064                chain.doFilter(request, response);
    065            } else {
    066                request.setAttribute(ALREADY_FILTERED_ATTRIBUTE, Boolean.TRUE);
    067
    068                try {
    069                    this.initializer.setLoggerContext();
    070
    071                    chain.doFilter(request, response);
    072                } finally {
    073                    this.initializer.clearLoggerContext();
    074                }
    075            }
    076        }
    077
    078        @Override
    079        public void destroy() {
    080            if (this.servletContext == null || this.initializer == null) {
    081                throw new IllegalStateException("Filter destroyed before it was initialized.");
    082            }
    083            LOGGER.debug("Log4jServletFilter destroyed.");
    084
    085            this.initializer.setLoggerContext(); // the application is just now starting to shut down
    086        }
    087    }