Source Code for Apache Log4j Web Servlet Containers

Apache Log4j Web Servlet Containers provides support for automatically enabling Log4j in Servlet containers.

Bytecode (Java 8) for Apache Log4j Web Servlet Containers is provided in a separate JAR file like log4j-web-2.14.1.jar.

Source Code files for Apache Log4j IOStreams are provided in both binary packge like apache-log4j-2.14.1-bin.zip and source package like apache-log4j-2.14.1-src.zip. You can download them at Apache Log4j Website.

You can also browse Source Code files for Apache Log4j Web Servlet Containers 2.14.1 below.

✍: FYIcenter.com

org/apache/logging/log4j/web/Log4jWebInitializerImpl.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache license, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the license for the specific language governing permissions and
 * limitations under the license.
 */
package org.apache.logging.log4j.web;

import java.net.URI;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletContext;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.AbstractLifeCycle;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.async.AsyncLoggerContext;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.impl.ContextAnchor;
import org.apache.logging.log4j.core.impl.Log4jContextFactory;
import org.apache.logging.log4j.core.lookup.Interpolator;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.selector.ContextSelector;
import org.apache.logging.log4j.core.selector.NamedContextSelector;
import org.apache.logging.log4j.core.util.Loader;
import org.apache.logging.log4j.core.util.NetUtils;
import org.apache.logging.log4j.core.util.SetUtils;
import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.apache.logging.log4j.util.LoaderUtil;

/**
 * This class initializes and deinitializes Log4j no matter how the initialization occurs.
 */
final class Log4jWebInitializerImpl extends AbstractLifeCycle implements Log4jWebLifeCycle {

    private static final String WEB_INF = "/WEB-INF/";

    static {
        if (Loader.isClassAvailable("org.apache.logging.log4j.core.web.JNDIContextFilter")) {
            throw new IllegalStateException("You are using Log4j 2 in a web application with the old, extinct "
                    + "log4j-web artifact. This is not supported and could cause serious runtime problems. Please"
                    + "remove the log4j-web JAR file from your application.");
        }
    }

    private final Map<String, String> map = new ConcurrentHashMap<>();
    private final StrSubstitutor substitutor = new StrSubstitutor(new Interpolator(map));
    private final ServletContext servletContext;

    private String name;
    private NamedContextSelector namedContextSelector;
    private LoggerContext loggerContext;

    private Log4jWebInitializerImpl(final ServletContext servletContext) {
        this.servletContext = servletContext;
        this.map.put("hostName", NetUtils.getLocalHostname());
    }

    /**
     * Initializes the Log4jWebLifeCycle attribute of a ServletContext. Those who wish to obtain this object should use
     * the {@link org.apache.logging.log4j.web.WebLoggerContextUtils#getWebLifeCycle(javax.servlet.ServletContext)}
     * method instead.
     *
     * @param servletContext
     *        the ServletContext to initialize
     * @return a new Log4jWebLifeCycle
     * @since 2.0.1
     */
    protected static Log4jWebInitializerImpl initialize(final ServletContext servletContext) {
        final Log4jWebInitializerImpl initializer = new Log4jWebInitializerImpl(servletContext);
        servletContext.setAttribute(SUPPORT_ATTRIBUTE, initializer);
        return initializer;
    }

    @Override
    public synchronized void start() {
        if (this.isStopped() || this.isStopping()) {
            throw new IllegalStateException("Cannot start this Log4jWebInitializerImpl after it was stopped.");
        }

        // only do this once
        if (this.isInitialized()) {
            super.setStarting();

            this.name = this.substitutor.replace(this.servletContext.getInitParameter(LOG4J_CONTEXT_NAME));
            final String location = this.substitutor.replace(this.servletContext
                    .getInitParameter(LOG4J_CONFIG_LOCATION));
            final boolean isJndi = "true".equalsIgnoreCase(this.servletContext
                    .getInitParameter(IS_LOG4J_CONTEXT_SELECTOR_NAMED));

            if (isJndi) {
                this.initializeJndi(location);
            } else {
                this.initializeNonJndi(location);
            }
            if (this.loggerContext instanceof AsyncLoggerContext) {
                ((AsyncLoggerContext) this.loggerContext).setUseThreadLocals(false);
            }

            this.servletContext.setAttribute(CONTEXT_ATTRIBUTE, this.loggerContext);
            super.setStarted();
        }
    }

    private void initializeJndi(final String location) {
        final URI configLocation = getConfigURI(location);

        if (this.name == null) {
            throw new IllegalStateException("A log4jContextName context parameter is required");
        }

        LoggerContext context;
        final LoggerContextFactory factory = LogManager.getFactory();
        if (factory instanceof Log4jContextFactory) {
            final ContextSelector selector = ((Log4jContextFactory) factory).getSelector();
            if (selector instanceof NamedContextSelector) {
                this.namedContextSelector = (NamedContextSelector) selector;
                context = this.namedContextSelector.locateContext(this.name,
                        WebLoggerContextUtils.createExternalEntry(this.servletContext), configLocation);
                ContextAnchor.THREAD_CONTEXT.set(context);
                if (context.isInitialized()) {
                    context.start();
                }
                ContextAnchor.THREAD_CONTEXT.remove();
            } else {
                LOGGER.warn("Potential problem: Selector is not an instance of NamedContextSelector.");
                return;
            }
        } else {
            LOGGER.warn("Potential problem: LoggerContextFactory is not an instance of Log4jContextFactory.");
            return;
        }
        this.loggerContext = context;
        LOGGER.debug("Created logger context for [{}] using [{}].", this.name, context.getClass().getClassLoader());
    }

    private void initializeNonJndi(final String location) {
        if (this.name == null) {
            this.name = this.servletContext.getServletContextName();
            LOGGER.debug("Using the servlet context name \"{}\".", this.name);
        }
        if (this.name == null) {
            this.name = this.servletContext.getContextPath();
            LOGGER.debug("Using the servlet context context-path \"{}\".", this.name);
        }
        if (this.name == null && location == null) {
            LOGGER.error("No Log4j context configuration provided. This is very unusual.");
            this.name = new SimpleDateFormat("yyyyMMdd_HHmmss.SSS").format(new Date());
        }
        if (location != null && location.contains(",")) {
            final List<URI> uris = getConfigURIs(location);
            this.loggerContext = Configurator.initialize(this.name, this.getClassLoader(), uris,
                    WebLoggerContextUtils.createExternalEntry(this.servletContext));
            return;
        }

        final URI uri = getConfigURI(location);
        this.loggerContext = Configurator.initialize(this.name, this.getClassLoader(), uri,
                WebLoggerContextUtils.createExternalEntry(this.servletContext));
    }

    private List<URI> getConfigURIs(final String location) {
        final String[] parts = location.split(",");
        final List<URI> uris = new ArrayList<>(parts.length);
        for (final String part : parts) {
            final URI uri = getConfigURI(part);
            if (uri != null) {
                uris.add(uri);
            }
        }
        return uris;
    }

    private URI getConfigURI(final String location) {
        try {
            String configLocation = location;
            if (configLocation == null) {
                final String[] paths = SetUtils.prefixSet(servletContext.getResourcePaths(WEB_INF), WEB_INF + "log4j2");
                LOGGER.debug("getConfigURI found resource paths {} in servletContext at [{}]", Arrays.toString(paths), WEB_INF);
                if (paths.length == 1) {
                    configLocation = paths[0];
                } else if (paths.length > 1) {
                    final String prefix = WEB_INF + "log4j2-" + this.name + ".";
                    boolean found = false;
                    for (final String str : paths) {
                        if (str.startsWith(prefix)) {
                            configLocation = str;
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        configLocation = paths[0];
                    }
                }
            }
            if (configLocation != null) {
                final URL url = servletContext.getResource(configLocation);
                if (url != null) {
                    final URI uri = url.toURI();
                    LOGGER.debug("getConfigURI found resource [{}] in servletContext at [{}]", uri, configLocation);
                    return uri;
                }
            }
        } catch (final Exception ex) {
            // Just try passing the location.
        }
        if (location != null) {
            try {
                final URI correctedFilePathUri = NetUtils.toURI(location);
                LOGGER.debug("getConfigURI found [{}] in servletContext at [{}]", correctedFilePathUri, location);
                return correctedFilePathUri;
            } catch (final Exception e) {
                LOGGER.error("Unable to convert configuration location [{}] to a URI", location, e);
            }
        }
        return null;
    }

    @Override
    public synchronized boolean stop(final long timeout, final TimeUnit timeUnit) {
        if (!this.isStarted() && !this.isStopped()) {
            throw new IllegalStateException("Cannot stop this Log4jWebInitializer because it has not started.");
        }

        // only do this once
        if (this.isStarted()) {
            this.setStopping();
            if (this.loggerContext != null) {
                LOGGER.debug("Removing LoggerContext for [{}].", this.name);
                this.servletContext.removeAttribute(CONTEXT_ATTRIBUTE);
                if (this.namedContextSelector != null) {
                    this.namedContextSelector.removeContext(this.name);
                }
                this.loggerContext.stop(timeout, timeUnit);
                this.loggerContext.setExternalContext(null);
                this.loggerContext = null;
            }
            this.setStopped();
        }
        return super.stop(timeout, timeUnit);
    }

    @Override
    public void setLoggerContext() {
        if (this.loggerContext != null) {
            ContextAnchor.THREAD_CONTEXT.set(this.loggerContext);
        }
    }

    @Override
    public void clearLoggerContext() {
        ContextAnchor.THREAD_CONTEXT.remove();
    }

    @Override
    public void wrapExecution(final Runnable runnable) {
        this.setLoggerContext();

        try {
            runnable.run();
        } finally {
            this.clearLoggerContext();
        }
    }

    private ClassLoader getClassLoader() {
        try {
            // if container is Servlet 3.0, use its getClassLoader method
            // this may look odd, but the call below will throw NoSuchMethodError if user is on Servlet 2.5
            // we compile against 3.0 to support Log4jServletContainerInitializer, but we don't require 3.0
            return this.servletContext.getClassLoader();
        } catch (final Throwable ignore) {
            // LOG4J2-248: use TCCL if possible
            return LoaderUtil.getThreadContextClassLoader();
        }
    }

}

org/apache/logging/log4j/web/Log4jWebInitializerImpl.java

 

⇒ Source Code for Apache Log4j Tag Library

⇐ Source Code for Apache Log4j IOStreams

⇑ Downloading and Reviewing Apache Log4j Packages

⇑⇑ FAQ for Apache Log4j

2015-11-04, 6878👍, 0💬