blob: 3ff0f05d6e63da95d91052994a7211141e14d5da [file] [log] [blame]
/*
* 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.util.AbstractMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.ServletContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.impl.ContextAnchor;
/**
* Convenience methods for retrieving the {@link org.apache.logging.log4j.core.LoggerContext} associated with a
* particular ServletContext. These methods are most particularly useful for asynchronous servlets where the
* Thread Context ClassLoader (TCCL) is potentially different from the TCCL used by the
* Servlet container that bootstrapped Log4j.
*
* @since 2.0.1
*/
public final class WebLoggerContextUtils {
private WebLoggerContextUtils() {
}
private static final Lock WEB_SUPPORT_LOOKUP = new ReentrantLock();
private static final String SERVLET_CONTEXT = "__SERVLET_CONTEXT__";
/**
* Finds the main {@link org.apache.logging.log4j.core.LoggerContext} configured for the given ServletContext.
*
* @param servletContext the ServletContext to locate a LoggerContext for
* @return the LoggerContext for the given ServletContext
* @since 2.0.1
*/
public static LoggerContext getWebLoggerContext(final ServletContext servletContext) {
return (LoggerContext) servletContext.getAttribute(Log4jWebSupport.CONTEXT_ATTRIBUTE);
}
/**
* Finds the main {@link org.apache.logging.log4j.core.LoggerContext} configured for the given ServletContext.
*
* @param servletContext the ServletContext to locate a LoggerContext for
* @return the LoggerContext for the given ServletContext or {@code null} if none was set
* @throws java.lang.IllegalStateException if no LoggerContext could be found on the given ServletContext
* @since 2.0.1
*/
public static LoggerContext getRequiredWebLoggerContext(final ServletContext servletContext) {
final LoggerContext loggerContext = getWebLoggerContext(servletContext);
if (loggerContext == null) {
throw new IllegalStateException(
"No LoggerContext found in ServletContext attribute " + Log4jWebSupport.CONTEXT_ATTRIBUTE);
}
return loggerContext;
}
/**
* Finds or initializes the {@link org.apache.logging.log4j.web.Log4jWebLifeCycle} singleton for the given
* ServletContext.
*
* @param servletContext the ServletContext to get the Log4jWebLifeCycle for
* @return the Log4jWebLifeCycle for the given ServletContext
* @since 2.0.1
*/
public static Log4jWebLifeCycle getWebLifeCycle(final ServletContext servletContext) {
WEB_SUPPORT_LOOKUP.lock();
try {
Log4jWebLifeCycle webLifeCycle = (Log4jWebLifeCycle) servletContext.getAttribute(
Log4jWebSupport.SUPPORT_ATTRIBUTE);
if (webLifeCycle == null) {
webLifeCycle = Log4jWebInitializerImpl.initialize(servletContext);
}
return webLifeCycle;
} finally {
WEB_SUPPORT_LOOKUP.unlock();
}
}
/**
* Wraps a Runnable instance by setting its thread context {@link org.apache.logging.log4j.core.LoggerContext}
* before execution and clearing it after execution.
*
* @param servletContext the ServletContext to locate a LoggerContext for
* @param runnable the Runnable to wrap execution for
* @return a wrapped Runnable
* @since 2.0.1
*/
public static Runnable wrapExecutionContext(final ServletContext servletContext, final Runnable runnable) {
return () -> {
final Log4jWebSupport webSupport = getWebLifeCycle(servletContext);
webSupport.setLoggerContext();
try {
runnable.run();
} finally {
webSupport.clearLoggerContext();
}
};
}
public static Map.Entry<String, Object> createExternalEntry(ServletContext servletContext) {
return new AbstractMap.SimpleEntry<>(SERVLET_CONTEXT, servletContext);
}
public static void setServletContext(LoggerContext lc, ServletContext servletContext) {
if (lc != null) {
lc.putObject(SERVLET_CONTEXT, servletContext);
}
}
/**
* Gets the current {@link ServletContext} if it has already been assigned to a LoggerContext's external context.
*
* @return the current ServletContext attached to a LoggerContext or {@code null} if none could be found
* @since 2.1
*/
public static ServletContext getServletContext() {
org.apache.logging.log4j.spi.LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get();
if (lc == null) {
lc = LogManager.getContext(false);
}
Object obj = lc != null ? lc.getObject(SERVLET_CONTEXT) : null;
if (obj instanceof ServletContext) {
return (ServletContext) obj;
}
return null;
}
}