The Apache Log4j support for web servlet containers
—
Utilities for managing LoggerContext instances in web applications, including context retrieval, lifecycle management, and execution wrapping for async operations. These components ensure thread-safe logging context handling in multi-threaded servlet environments.
Utility class providing static methods for LoggerContext management in servlet environments. Handles context retrieval, lifecycle operations, and execution wrapping for proper thread-local context binding.
/**
* Utility methods for retrieving and managing LoggerContext in servlet environments.
* Provides thread-safe access to LoggerContext instances and execution wrapping.
*/
public final class WebLoggerContextUtils {
/**
* Retrieves the LoggerContext associated with a ServletContext.
* Returns null if no LoggerContext is found.
*
* @param servletContext ServletContext to locate LoggerContext for
* @return LoggerContext instance or null if not found
*/
public static LoggerContext getWebLoggerContext(ServletContext servletContext);
/**
* Retrieves the LoggerContext with validation that it exists.
* Never returns null - throws exception if LoggerContext is not found.
*
* @param servletContext ServletContext to locate LoggerContext for
* @return LoggerContext instance (never null)
* @throws IllegalStateException if no LoggerContext found in ServletContext
*/
public static LoggerContext getRequiredWebLoggerContext(ServletContext servletContext);
/**
* Finds or initializes the Log4jWebLifeCycle singleton for the ServletContext.
* Thread-safe singleton pattern with lazy initialization.
*
* @param servletContext ServletContext to get the Log4jWebLifeCycle for
* @return Log4jWebLifeCycle instance for the ServletContext
*/
public static Log4jWebLifeCycle getWebLifeCycle(ServletContext servletContext);
/**
* Wraps a Runnable with proper LoggerContext management.
* Sets context before execution, clears after execution.
* Essential for async servlet operations.
*
* @param servletContext ServletContext to locate LoggerContext for
* @param runnable Runnable to wrap with logging context
* @return Wrapped Runnable with automatic context management
*/
public static Runnable wrapExecutionContext(ServletContext servletContext, Runnable runnable);
/**
* Gets the current ServletContext from thread-bound LoggerContext.
* Returns null if no ServletContext is available.
*
* @return Current ServletContext or null if not available
*/
public static ServletContext getServletContext();
}Usage Examples:
// Get LoggerContext with validation
ServletContext servletContext = request.getServletContext();
LoggerContext loggerContext = WebLoggerContextUtils.getRequiredWebLoggerContext(servletContext);
// Wrap async task with proper context
Runnable asyncTask = WebLoggerContextUtils.wrapExecutionContext(servletContext, () -> {
Logger logger = LogManager.getLogger();
logger.info("Executing with proper logging context");
});
// Execute in separate thread
executor.submit(asyncTask);Primary interface defining the contract for web application Log4j integration. Provides methods for context management and execution wrapping.
/**
* Interface for setting and clearing thread-bound LoggerContext in web applications.
* Defines contract for Log4j web integration components.
*/
public interface Log4jWebSupport {
/**
* Sets the logger context for the current thread.
* Enables easy access to loggers via LogManager.getLogger().
*/
void setLoggerContext();
/**
* Clears the logger context set up in setLoggerContext().
* Should be called in finally blocks to ensure cleanup.
*/
void clearLoggerContext();
/**
* Convenience method that wraps Runnable execution with context management.
* Calls setLoggerContext(), executes runnable, then calls clearLoggerContext().
*
* @param runnable Runnable to execute with configured logger context
*/
void wrapExecution(Runnable runnable);
}Context Management Constants:
public interface Log4jWebSupport {
/** ServletContext parameter name for LoggerContext name */
String LOG4J_CONTEXT_NAME = "log4jContextName";
/** ServletContext parameter name for configuration location */
String LOG4J_CONFIG_LOCATION = "log4jConfiguration";
/** ServletContext parameter name for JNDI flag */
String IS_LOG4J_CONTEXT_SELECTOR_NAMED = "isLog4jContextSelectorNamed";
/** ServletContext parameter name for auto-initialization disable flag */
String IS_LOG4J_AUTO_INITIALIZATION_DISABLED = "isLog4jAutoInitializationDisabled";
/** ServletContext parameter name for auto-shutdown disable flag */
String IS_LOG4J_AUTO_SHUTDOWN_DISABLED = "isLog4jAutoShutdownDisabled";
/** ServletContext attribute key for Log4jWebSupport instance */
String SUPPORT_ATTRIBUTE = "org.apache.logging.log4j.web.Log4jWebSupport.INSTANCE";
/** ServletContext attribute key for LoggerContext instance */
String CONTEXT_ATTRIBUTE = "org.apache.logging.log4j.spi.LoggerContext.INSTANCE";
}Extended interface combining Log4jWebSupport with LifeCycle management. Provides complete lifecycle control for Log4j in web applications.
/**
* Internal interface for initializing and deinitializing Log4j in web applications.
* Combines context management with lifecycle operations.
* This is a package-private interface used internally by Log4j web components.
* Users should access lifecycle functionality through WebLoggerContextUtils.getWebLifeCycle().
*/
// Note: This interface is package-private and not directly accessible to application code
interface Log4jWebLifeCycle extends Log4jWebSupport, LifeCycle {
/**
* Starts up Log4j in the web application.
* Calls setLoggerContext() after initialization is complete.
*
* @throws IllegalStateException if JNDI config location specified but no name provided
*/
@Override
void start();
/**
* Shuts down Log4j in the web application.
* Calls clearLoggerContext() immediately before deinitialization begins.
*/
@Override
void stop();
}Log4jWebSupport webSupport = (Log4jWebSupport) servletContext.getAttribute(
Log4jWebSupport.SUPPORT_ATTRIBUTE);
// Manual context binding
webSupport.setLoggerContext();
try {
Logger logger = LogManager.getLogger();
logger.info("Logging with proper context");
} finally {
webSupport.clearLoggerContext();
}Log4jWebSupport webSupport = WebLoggerContextUtils.getWebLifeCycle(servletContext);
// Automatic wrapping
webSupport.wrapExecution(() -> {
Logger logger = LogManager.getLogger();
logger.info("Context automatically managed");
});@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
AsyncContext asyncContext = request.startAsync();
ServletContext servletContext = request.getServletContext();
// Wrap async task with proper logging context
Runnable asyncTask = WebLoggerContextUtils.wrapExecutionContext(servletContext, () -> {
try {
// Async processing with proper logging context
Logger logger = LogManager.getLogger();
logger.info("Processing async request");
// Simulate async work
Thread.sleep(1000);
asyncContext.getResponse().getWriter().write("Async complete");
asyncContext.complete();
} catch (Exception e) {
logger.error("Async processing failed", e);
asyncContext.complete();
}
});
// Execute in thread pool
executor.submit(asyncTask);
}
}All utility methods in WebLoggerContextUtils are thread-safe:
ReentrantLock for thread-safe lazy initializationThe thread-local context binding ensures proper isolation between concurrent requests while maintaining performance.
Install with Tessl CLI
npx tessl i tessl/maven-org-apache-logging-log4j--log4j-web