Master MyBatis Logging: Configure SLF4J, Log4j, and Custom Loggers
This guide explains how MyBatis initializes its logging factory, shows how to add SLF4J and Log4j dependencies, configure SimpleLogger properties, resolve multiple SLF4J bindings, and switch the logging implementation via mybatis-config.xml and log4j.properties, with full code examples and sample output.
1. LogFactory Initialization
MyBatis provides the built‑in logging factory org.apache.ibatis.logging.LogFactory which selects a concrete logger implementation at runtime. The static block tries implementations in order: SLF4J, Commons Logging, Log4j2, Log4j, JDK logging, and finally a no‑logging fallback.
public final class LogFactory {
public static final String MARKER = "MYBATIS";
private static Constructor<? extends Log> logConstructor;
static {
tryImplementation(LogFactory::useSlf4jLogging);
tryImplementation(LogFactory::useCommonsLogging);
tryImplementation(LogFactory::useLog4J2Logging);
tryImplementation(LogFactory::useLog4JLogging);
tryImplementation(LogFactory::useJdkLogging);
tryImplementation(LogFactory::useNoLogging);
}
private LogFactory() { /* disable construction */ }
public static Log getLog(Class<?> clazz) { return getLog(clazz.getName()); }
public static Log getLog(String logger) {
try { return logConstructor.newInstance(logger); }
catch (Throwable t) { throw new LogException("Error creating logger for logger " + logger, t); }
}
public static synchronized void useCustomLogging(Class<? extends Log> clazz) { setImplementation(clazz); }
public static synchronized void useSlf4jLogging() { setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class); }
public static synchronized void useCommonsLogging() { setImplementation(org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class); }
public static synchronized void useLog4JLogging() { setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class); }
public static synchronized void useLog4J2Logging() { setImplementation(org.apache.ibatis.logging.log4j2.Log4j2Impl.class); }
public static synchronized void useJdkLogging() { setImplementation(org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class); }
public static synchronized void useStdOutLogging() { setImplementation(org.apache.ibatis.logging.stdout.StdOutImpl.class); }
public static synchronized void useNoLogging() { setImplementation(org.apache.ibatis.logging.nologging.NoLoggingImpl.class); }
private static void tryImplementation(Runnable runnable) {
if (logConstructor == null) {
try { runnable.run(); } catch (Throwable t) { /* ignore */ }
}
}
private static void setImplementation(Class<? extends Log> implClass) {
try {
Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
Log log = candidate.newInstance(LogFactory.class.getName());
if (log.isDebugEnabled()) { log.debug("Logging initialized using '" + implClass + "' adapter."); }
logConstructor = candidate;
} catch (Throwable t) {
throw new LogException("Error setting Log implementation. Cause: " + t, t);
}
}
}2. Test Logging Dependencies
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.32</version>
<scope>compile</scope>
</dependency>These dependencies enable the simple SLF4J implementation.
3. SimpleLogger Configuration
Create a simplelogger.properties file on the classpath with optional settings such as:
#org.slf4j.simpleLogger.logFile=System.out
#org.slf4j.simpleLogger.cacheOutputStream=true
org.slf4j.simpleLogger.defaultLogLevel=debug
#org.slf4j.simpleLogger.showDateTime=true
#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS
#org.slf4j.simpleLogger.showThreadName=true
#org.slf4j.simpleLogger.showLogName=true
#org.slf4j.simpleLogger.showShortLogName=false
#org.slf4j.simpleLogger.levelInBrackets=false
#org.slf4j.simpleLogger.warnLevelString=WARN4. Multiple Logging Implementations
When both slf4j-simple and slf4j-log4j12 are on the classpath, SLF4J reports multiple bindings:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/.../slf4j-simple-1.7.32.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/.../slf4j-log4j12-1.7.32.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
[main] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.5. Switching to Log4j
Specify the desired logger in mybatis-config.xml:
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
</configuration>Add a log4j.properties file:
log4j.rootLogger = debug, stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%‑5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n6. Sample Output
Running the test now produces Log4j‑styled logs, for example:
PooledDataSource forcefully closed/removed all connections.
[DEBUG] 2021-11-04 13:04:33,475 method:org.apache.ibatis.datasource.pooled.PooledDataSource.forceCloseAll(PooledDataSource.java:363)
[main] DEBUG test.UsersMapperTest - 查询列表
Created connection 386163331.
==> Preparing: select * from t_users
==> Parameters:
<== Total: 2
[Users [id=1, username=admin, password=123123], Users [id=2, username=guest, password=111111]]These logs confirm that Log4j is now the active logging implementation.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
