Log4j API to SLF4J adapter that bridges Log4j API calls to SLF4J implementations
npx @tessl/cli install tessl/maven-org-apache-logging-log4j--log4j-to-slf4j@2.25.0A bridge/adapter library that forwards Log4j API calls to SLF4J implementations, enabling applications using the Log4j API to redirect their logging output through SLF4J while maintaining all Log4j API functionality and features.
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.25.1</version>
</dependency>Standard Log4j API imports work transparently:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;The adapter works transparently - use standard Log4j API calls:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
public class Example {
private static final Logger logger = LogManager.getLogger(Example.class);
public void demonstrateLogging() {
// Standard Log4j logging - automatically forwards to SLF4J
logger.info("This is an info message");
logger.error("Error occurred", new RuntimeException("test"));
// Thread context (MDC) support
ThreadContext.put("userId", "12345");
logger.info("User action performed");
ThreadContext.clear();
// Fluent logging API
logger.atInfo()
.withMarker(MarkerManager.getMarker("AUDIT"))
.log("Audit event: {}", "user_login");
}
}This library implements the Log4j Provider SPI to transparently bridge Log4j API calls to SLF4J:
Core provider that registers with Log4j's logging system to intercept and forward API calls.
public class SLF4JProvider extends org.apache.logging.log4j.spi.Provider {
public SLF4JProvider();
public LoggerContextFactory getLoggerContextFactory();
public ThreadContextMap getThreadContextMapInstance();
}The provider is automatically discovered and has priority 15, allowing higher-priority providers to override it.
Factory responsible for creating and managing the SLF4J logger context.
public class SLF4JLoggerContextFactory implements LoggerContextFactory {
public SLF4JLoggerContextFactory();
public LoggerContext getContext(String fqcn, ClassLoader loader, Object externalContext, boolean currentContext);
public LoggerContext getContext(String fqcn, ClassLoader loader, Object externalContext, boolean currentContext, URI configLocation, String name);
public void removeContext(LoggerContext context);
public boolean isClassLoaderDependent();
}The factory validates configuration to prevent conflicts with slf4j-impl jars and returns a singleton context.
Context that creates and manages SLF4J-backed logger instances.
public class SLF4JLoggerContext implements LoggerContext {
public Object getExternalContext();
public ExtendedLogger getLogger(String name);
public ExtendedLogger getLogger(String name, MessageFactory messageFactory);
public boolean hasLogger(String name);
public boolean hasLogger(String name, MessageFactory messageFactory);
public boolean hasLogger(String name, Class<? extends MessageFactory> messageFactoryClass);
}Main logger implementation that forwards Log4j API calls to underlying SLF4J loggers.
public class SLF4JLogger extends AbstractLogger {
public static final long serialVersionUID = 1L;
public SLF4JLogger(String name, MessageFactory messageFactory, org.slf4j.Logger logger);
public SLF4JLogger(String name, org.slf4j.Logger logger);
// Level management
public Level getLevel();
public org.slf4j.Logger getLogger();
// Level checking methods
public boolean isEnabled(Level level, Marker marker, Message data, Throwable t);
public boolean isEnabled(Level level, Marker marker, CharSequence data, Throwable t);
public boolean isEnabled(Level level, Marker marker, Object data, Throwable t);
public boolean isEnabled(Level level, Marker marker, String data);
public boolean isEnabled(Level level, Marker marker, String data, Object... p1);
public boolean isEnabled(Level level, Marker marker, String message, Object p0);
public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1);
public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1, Object p2);
public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3);
public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4);
public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5);
public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6);
public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7);
public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8);
public boolean isEnabled(Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8, Object p9);
public boolean isEnabled(Level level, Marker marker, String data, Throwable t);
// Core logging method
public void logMessage(String fqcn, Level level, Marker marker, Message message, Throwable t);
// Fluent API builders
public LogBuilder always();
public LogBuilder atTrace();
public LogBuilder atDebug();
public LogBuilder atInfo();
public LogBuilder atWarn();
public LogBuilder atError();
public LogBuilder atFatal();
public LogBuilder atLevel(Level level);
}Builder pattern implementation for constructing log statements fluently.
public class SLF4JLogBuilder implements LogBuilder {
public SLF4JLogBuilder(SLF4JLogger logger, Level level);
public SLF4JLogBuilder();
// Builder configuration
public LogBuilder reset(SLF4JLogger logger, Level level);
public LogBuilder withMarker(Marker marker);
public LogBuilder withThrowable(Throwable throwable);
// State management
public boolean isInUse();
// Location methods (ignored as SLF4J doesn't support explicit location)
public LogBuilder withLocation();
public LogBuilder withLocation(StackTraceElement location);
// Logging methods (various overloads for different message types)
public void log();
public void log(Message message);
public void log(CharSequence message);
public void log(Object message);
public void log(String message);
public void log(String message, Object... params);
public void log(String message, Supplier<?>... params);
public void log(String message, Object p0);
public void log(String message, Object p0, Object p1);
public void log(String message, Object p0, Object p1, Object p2);
public void log(String message, Object p0, Object p1, Object p2, Object p3);
public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4);
public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5);
public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6);
public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7);
public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8);
public void log(String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8, Object p9);
public void log(Supplier<Message> messageSupplier);
public Message logAndGet(Supplier<Message> messageSupplier);
}Implementation that bridges Log4j ThreadContext operations to SLF4J MDC.
public class MDCContextMap implements CleanableThreadContextMap {
// Basic operations
public void put(String key, String value);
public void putAll(Map<String, String> map);
public String get(String key);
public void remove(String key);
public void removeAll(Iterable<String> keys);
public void clear();
// Query operations
public boolean containsKey(String key);
public boolean isEmpty();
// Map access
public Map<String, String> getCopy();
public Map<String, String> getImmutableMapOrNull();
// Log4j compatibility
public StringMap getReadOnlyContextData();
}Activator for OSGi environments to properly initialize the SLF4J provider.
public class Activator extends ProviderActivator {
public Activator();
}Log4j levels are mapped to SLF4J levels as follows:
TRACE → SLF4J TRACEDEBUG → SLF4J DEBUGINFO → SLF4J INFOWARN → SLF4J WARNERROR → SLF4J ERRORFATAL → SLF4J TRACE (atFatal() returns Level.TRACE, though this appears inconsistent with other level handling)Log4j Markers are converted to SLF4J Markers while preserving:
The library automatically detects and prevents conflicts with slf4j-impl jars by checking for org.slf4j.helpers.Log4jLoggerFactory on the classpath and throwing an IllegalStateException if found.
Supports both SLF4J 1.x and 2.x versions with version range [1.7,3) in OSGi environments.
The provider is automatically discovered via the Java ServiceLoader mechanism using the service file:
META-INF/services/org.apache.logging.log4j.spi.Provider