Bridge adapter enabling Apache Commons Logging applications to route calls through Log4j 2
npx @tessl/cli install tessl/maven-org-apache-logging-log4j--log4j-jcl@2.25.0A bridge adapter that enables applications using Apache Commons Logging (JCL) to seamlessly route their logging calls through Log4j 2 as the underlying logging implementation. It acts as a compatibility layer that implements the Commons Logging API while delegating actual logging operations to Log4j 2's high-performance logging framework.
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.25.1</version>
</dependency>import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MyClass {
private static final Log logger = LogFactory.getLog(MyClass.class);
public void doSomething() {
// Standard Commons Logging API - automatically routed through Log4j 2
logger.info("Starting operation");
try {
// Your application logic here
if (logger.isDebugEnabled()) {
logger.debug("Processing data with detailed info");
}
// All Commons Logging levels supported
logger.trace("Detailed execution trace");
logger.warn("Warning about potential issue");
} catch (Exception e) {
logger.error("Operation failed", e);
logger.fatal("Critical system error occurred", e);
}
logger.info("Operation completed");
}
// Factory can also create loggers by name
public void alternativeLoggerCreation() {
Log namedLogger = LogFactory.getLog("com.example.specific.Logger");
namedLogger.info("Using named logger instance");
}
}The bridge uses a three-layer architecture:
This design allows existing Commons Logging applications to benefit from Log4j 2's advanced features like asynchronous logging, structured logging, and extensive configuration options without requiring code changes.
The main entry point providing Commons Logging factory functionality with automatic Log4j 2 integration.
public class LogFactoryImpl extends LogFactory {
/**
* Gets a logger instance by name
* @param name Logger name
* @return Log instance backed by Log4j 2
* @throws LogConfigurationException If logger creation fails
*/
public Log getInstance(String name) throws LogConfigurationException;
/**
* Gets a logger instance by class
* @param clazz Class to use for logger name (raw type usage for Commons Logging compatibility)
* @return Log instance backed by Log4j 2
* @throws LogConfigurationException If logger creation fails
*/
public Log getInstance(Class clazz) throws LogConfigurationException;
/**
* Gets factory attribute value
* @param name Attribute name
* @return Attribute value or null if not found
*/
public Object getAttribute(String name);
/**
* Gets all factory attribute names
* @return Array of attribute names
*/
public String[] getAttributeNames();
/**
* Sets factory attribute
* @param name Attribute name
* @param value Attribute value (null removes attribute)
*/
public void setAttribute(String name, Object value);
/**
* Removes factory attribute
* @param name Attribute name to remove
*/
public void removeAttribute(String name);
/**
* Releases all logger resources
* Clears logger wrappers but underlying Log4j 2 loggers remain managed by their context
*/
public void release();
}Internal adapter managing logger instances and contexts with class loader awareness.
public class LogAdapter extends AbstractLoggerAdapter<Log> {
/**
* Creates a new Log instance for the given name and context
* @param name Logger name
* @param context Logger context from Log4j 2
* @return Log4jLog instance wrapping Log4j 2 logger
*/
protected Log newLogger(String name, LoggerContext context);
/**
* Gets the appropriate logger context
* Determines context based on class loader dependency configuration
* @return LoggerContext for current calling context
*/
protected LoggerContext getContext();
}Full implementation of Commons Logging's Log interface with Log4j 2 backing.
public class Log4jLog implements Log, Serializable {
/**
* Creates a Log4jLog wrapping the given ExtendedLogger
* Uses internal FQCN for proper caller location tracking
* @param logger The Log4j 2 ExtendedLogger to wrap
*/
public Log4jLog(ExtendedLogger logger);
/**
* Check if TRACE level logging is enabled
* @return true if TRACE level is enabled
*/
public boolean isTraceEnabled();
/**
* Check if DEBUG level logging is enabled
* @return true if DEBUG level is enabled
*/
public boolean isDebugEnabled();
/**
* Check if INFO level logging is enabled
* @return true if INFO level is enabled
*/
public boolean isInfoEnabled();
/**
* Check if WARN level logging is enabled
* @return true if WARN level is enabled
*/
public boolean isWarnEnabled();
/**
* Check if ERROR level logging is enabled
* @return true if ERROR level is enabled
*/
public boolean isErrorEnabled();
/**
* Check if FATAL level logging is enabled
* @return true if FATAL level is enabled
*/
public boolean isFatalEnabled();
/**
* Log message at TRACE level
* @param message Message object to log
*/
public void trace(Object message);
/**
* Log message at TRACE level with exception
* @param message Message object to log
* @param t Exception to log
*/
public void trace(Object message, Throwable t);
/**
* Log message at DEBUG level
* @param message Message object to log
*/
public void debug(Object message);
/**
* Log message at DEBUG level with exception
* @param message Message object to log
* @param t Exception to log
*/
public void debug(Object message, Throwable t);
/**
* Log message at INFO level
* @param message Message object to log
*/
public void info(Object message);
/**
* Log message at INFO level with exception
* @param message Message object to log
* @param t Exception to log
*/
public void info(Object message, Throwable t);
/**
* Log message at WARN level
* @param message Message object to log
*/
public void warn(Object message);
/**
* Log message at WARN level with exception
* @param message Message object to log
* @param t Exception to log
*/
public void warn(Object message, Throwable t);
/**
* Log message at ERROR level
* @param message Message object to log
*/
public void error(Object message);
/**
* Log message at ERROR level with exception
* @param message Message object to log
* @param t Exception to log
*/
public void error(Object message, Throwable t);
/**
* Log message at FATAL level
* @param message Message object to log
*/
public void fatal(Object message);
/**
* Log message at FATAL level with exception
* @param message Message object to log
* @param t Exception to log
*/
public void fatal(Object message, Throwable t);
}/**
* Exception thrown for logging configuration problems
* Defined in commons-logging library
*/
public class LogConfigurationException extends RuntimeException {
// From org.apache.commons.logging.LogConfigurationException
}
/**
* Abstract logger adapter base class from Log4j 2 SPI
* Defined in log4j-api library
*/
public abstract class AbstractLoggerAdapter<T> {
// From org.apache.logging.log4j.spi.AbstractLoggerAdapter
// Provides logger adapter functionality with generic type support
}
/**
* Logger context interface from Log4j 2 SPI
* Defined in log4j-api library
*/
public interface LoggerContext {
// From org.apache.logging.log4j.spi.LoggerContext
// Provides logger context management functionality
}
/**
* Extended logger interface from Log4j 2 API
* Defined in log4j-api library
*/
public interface ExtendedLogger {
// From org.apache.logging.log4j.spi.ExtendedLogger
// Provides advanced logging functionality beyond basic Logger interface
}The bridge is automatically discovered by Commons Logging through the Java service provider mechanism:
META-INF/services/org.apache.commons.logging.LogFactoryorg.apache.logging.log4j.jcl.LogFactoryImplCommons Logging levels map directly to Log4j 2 levels:
| Commons Logging | Log4j 2 |
|---|---|
| TRACE | TRACE |
| DEBUG | DEBUG |
| INFO | INFO |
| WARN | WARN |
| ERROR | ERROR |
| FATAL | FATAL |
Required Runtime Dependencies:
org.apache.logging.log4j:log4j-api - Log4j 2 APIcommons-logging:commons-logging - Apache Commons Logging APIOptional Dependencies:
org.apache.logging.log4j:log4j-core - For full Log4j 2 implementation featuresorg.apache.logging.log4j:log4j-slf4j-impl - If also bridging SLF4J loggingAll components are thread-safe:
ConcurrentHashMapLog4jLog implements Serializable with serialVersionUID = 1LThe bridge uses Log4j 2's configuration system. Configure Log4j 2 normally using:
log4j2.xml configuration filesCommons Logging applications will automatically use the configured Log4j 2 settings without code changes.