How do you configure logging in Hibernate 4 to use SLF4J
Hibernate 3.x used slf4j for logging. Hibernate 4.x uses jboss-logging. I am writing a standalone application which uses Hibernate 4, and SLF4J for logging.
How can i configure Hibernate to log to SLF4J?
If that's not possible, how can i configure Hibernate's logging at all?
The Hibernate 4.1 manual section on logging starts with the warning that it is ...
Completely out of date. Hibernate uses JBoss Logging starting in 4.0. This will get documented as we migrate this content to the Developer Guide.
... goes on to talk about SLF4J, and so is useless. Neither the getting started guide nor the developer guide talk about logging at all. Nor does the migration guide.
I have looked for documentation on jboss-logging itself, but i haven't been able to find any at all. The GitHub page is silent, and JBoss's community projects page doesn't even list jboss-logging. I wondered if th project's bug tracker might have any issues relating to providing documentation, but it doesn't.
The good news is that when using Hibernate 4 inside an application server, such as JBoss AS7, logging is largely taken care of for you. But how can i configure it in a standalone application?
Look to https://github.com/jboss-logging/jboss-logging/blob/master/src/main/java/org/jboss/logging/LoggerProviders.java:
static final String LOGGING_PROVIDER_KEY = "org.jboss.logging.provider";
private static LoggerProvider findProvider() {
// Since the impl classes refer to the back-end frameworks directly, if this classloader can't find the target
// log classes, then it doesn't really matter if they're possibly available from the TCCL because we won't be
// able to find it anyway
final ClassLoader cl = LoggerProviders.class.getClassLoader();
try {
// Check the system property
final String loggerProvider = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty(LOGGING_PROVIDER_KEY);
}
});
if (loggerProvider != null) {
if ("jboss".equalsIgnoreCase(loggerProvider)) {
return tryJBossLogManager(cl);
} else if ("jdk".equalsIgnoreCase(loggerProvider)) {
return tryJDK();
} else if ("log4j".equalsIgnoreCase(loggerProvider)) {
return tryLog4j(cl);
} else if ("slf4j".equalsIgnoreCase(loggerProvider)) {
return trySlf4j();
}
}
} catch (Throwable t) {
}
try {
return tryJBossLogManager(cl);
} catch (Throwable t) {
// nope...
}
try {
return tryLog4j(cl);
} catch (Throwable t) {
// nope...
}
try {
// only use slf4j if Logback is in use
Class.forName("ch.qos.logback.classic.Logger", false, cl);
return trySlf4j();
} catch (Throwable t) {
// nope...
}
return tryJDK();
}
So possible values for org.jboss.logging.provider
are: jboss
, jdk
, log4j
, slf4j
.
If you don't set org.jboss.logging.provider
it tries jboss, then log4j, then slf4j (only if logback used) and fallback to jdk.
I use slf4j
with logback-classic
:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
<scope>${logging.scope}</scope>
</dependency>
and all work fine!
UPDATE Some users uses in very main App.java:
static { //runs when the main class is loaded.
System.setProperty("org.jboss.logging.provider", "slf4j");
}
but for container based solutions this is not worked.
UPDATE 2 Those who think that they manage Log4j with SLF4J for jboss-logging
it is not exactly thus. jboss-logging
directly uses Log4j without SLF4J!
To get SLF4J to work with JBoss Logging without Logback as backend requires usage of a system property org.jboss.logging.provider=slf4j
. log4j-over-slf4j
tactics doesn't seem to be working in this case because the logging will fall back to JDK if neither Logback nor log4j isn't actually present in classpath.
This is a bit of a nuisance and in order to get autodetection to work you have see that the classloader contains at least ch.qos.logback.classic.Logger
from logback-classic or org.apache.log4j.Hierarchy
from log4j to trick the JBoss Logging from not falling back to JDK logging.
The magic is interpreted at org.jboss.logging.LoggerProviders
UPDATE: Service loader support has been added so it is possible to avoid problems with autodetection by declaring META-INF/services/org.jboss.logging.LoggerProvider
(with org.jboss.logging.Slf4jLoggerProvider
as a value). There seems to be added support log4j2 as well.