123

Hibernate 3.x used for logging. Hibernate 4.x uses . 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?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Tom Anderson
  • 46,189
  • 17
  • 92
  • 133
  • 14
    +1 for highlighting that Hibernate docs on logging are out of date – mhnagaoka Oct 29 '13 at 17:48
  • One can set system property org.jboss.logging.provide=slf4j. For further details please visit the link http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html for hibernate version greater than 3. – Abhishek Ranjan May 19 '19 at 09:19

11 Answers11

66

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 (make sure you exclude corresponding jar from classpath!), 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 doesn't work.

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!

gavenkoa
  • 45,285
  • 19
  • 251
  • 303
  • 1
    Where to set `org.jboss.logging.provider`? – Suzan Cioc Nov 23 '14 at 20:27
  • 1
    @SuzanCioc According to `System.getProperty(LOGGING_PROVIDER_KEY);` you need set system property. Through `java -D...=...` or check docs for your container. – gavenkoa Nov 24 '14 at 09:21
  • 1
    Your second update about not being able to use log4j through slf4j was helpful. Setting org.jboss.logging.provider to slf4j made me think that my backing of log4j would kick in. It didn't though. I had to set that directly to log4j in order for that to work. Odd. What's the point of slf4j as an option for this config then? – Travis Spencer Apr 16 '16 at 08:36
29

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.

Tuomas Kiviaho
  • 355
  • 3
  • 9
  • 1
    Where do I set this system property? – jhegedus Mar 11 '14 at 13:43
  • Depends on your setup, but normally a command line switch `-Dorg.jboss.logging.provider=slf4j` is enough. [LoggingProviders.java](https://github.com/jboss-logging/jboss-logging/blob/master/src/main/java/org/jboss/logging/LoggerProviders.java) gives you better insights on what the current accepted values are and what is to be expected to be present in the classpath. – Tuomas Kiviaho Sep 10 '14 at 05:24
  • 3
    I don't think the service loader approach works because `Slf4jLoggerProvider` is not a `public` class? – holmis83 Mar 14 '16 at 13:14
  • I need to set org.jboss.logging.provider in a weblogic WAR into the source code, but any static class intiializer is invoked after the LoggingProviders one! – Antonio Petricca Apr 09 '19 at 21:27
12

Inspired by Leif's Hypoport post, this is how I "bent" Hibernate 4 back to slf4j:

Let's assume you are using Maven.

  • Add org.slf4j:log4j-over-slf4j as a dependency to your pom.xml
  • Using the command mvn dependency:tree, make sure none of the artifacts you're using depende on slf4j:slf4j (to be precise, no artifact shall have a compile scope dependency or runtime scope dependency on slf4j:slf4j)

Background: Hibernate 4.x has a dependency on the artifact org.jboss.logging:jboss-logging. Transitively, this artifact has a provided scope dependency on the artifact slf4j:slf4j.

As we now have added the org.slf4j:log4j-over-slf4j artifact, org.slf4j:log4j-over-slf4j mimicks the slf4j:slf4j artifact. Therefore everything that JBoss Logging logs will now actually go via slf4j.

Let's say you're using Logback as your logging backend. Here is a sample pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

    ....
    <properties>
        ....
        <slf4j-api-version>1.7.2</slf4j-api-version>
        <log4j-over-slf4j-version>1.7.2</log4j-over-slf4j-version>
        <jcl-over-slf4j-version>1.7.2</jcl-over-slf4j-version> <!-- no problem to have yet another slf4j bridge -->
        <logback-core-version>1.0.7</logback-core-version>
        <logback-classic-version>1.0.7</logback-classic-version>
        <hibernate-entitymanager-version>4.1.7.Final</hibernate-entitymanager-version> <!-- our logging problem child -->
    </properties>

    <dependencies>
            <!-- begin: logging-related artifacts .... -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${slf4j-api-version}</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>jcl-over-slf4j</artifactId>
                <version>${jcl-over-slf4j-version}</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>log4j-over-slf4j</artifactId>
                <version>${log4j-over-slf4j-version}</version>
            </dependency>   
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>${logback-core-version}</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>${logback-classic-version}</version>
            </dependency>
            <!-- end: logging-related artifacts .... -->

            <!-- begin: some artifact with direct dependency on log4j:log4j ....  -->
            <dependency>
            <groupId>org.foo</groupId>
                <artifactId>some-artifact-with-compile-or-runtime-scope-dependency-on-log4j:log4j</artifactId>
                <version>${bla}</version>
                <exclusions>
                    <exclusion>
                        <groupId>log4j</groupId>
                        <artifactId>log4j</artifactId>
                    </exclusion>
                </exclusions>   
            </dependency>
            <!-- begin: some artifact with direct dependency on log4j:log4j ....  -->

            <!-- begin: a hibernate 4.x problem child........... -->
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-entitymanager</artifactId>
                <version>${hibernate-entitymanager-version}</version>
            </dependencies>
            <!-- end: a hibernate 4.x problem child........... -->
    ....
</project>

On your classpath, have a logback.xml, such as this one located in src/main/java:

<!-- begin: logback.xml -->
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender> 

<logger name="org.hibernate" level="debug"/>

<root level="info">
    <appender-ref ref="console"/>
</root>

</configuration>
<!-- end: logback.xml -->

Some components may want to have access to logback.xml at JVM start-up time for proper logging, for instance the Jetty Maven Plugin. In that case, add a Java system logback.configurationFile=./path/to/logback.xml to your command (e.g. mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run).

In case you are still getting "raw" console stdout Hibernate output (like Hibernate: select ...), then Stack Overflow question " Turn off hibernate logging to console " may apply.

Community
  • 1
  • 1
Abdull
  • 26,371
  • 26
  • 130
  • 172
  • 1
    Make sure no other library icludes log4j, or this will not work. Example: activemq-all.jar contains log4j. Hint: Open your IDE and find log4j easily in your code. – Dimitri Dewaele Oct 22 '13 at 08:34
  • I had this problem with JBoss Hibernate4 and a (too) old server. This post, including 1 line in application.properties did the trick for me. So TNX!!! And that last line in my properties was written in another answer here: `org.jboss.logging.provider=slf4j` – Jeroen van Dijk-Jun Apr 18 '17 at 11:27
8

First you do realize that SLF4J is not a logging library right, its a logging wrapper. It itself does not log anything, it simply delegates to "backends".

To "configure" jboss-logging you just add whatever log framework you want to use on your classpath (along with jboss-logging) and jboss-logging figures out the rest.

I created a Hibernate-focused guide to JBoss Logging config: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html

Steve Ebersole
  • 9,339
  • 2
  • 48
  • 46
  • 3
    I do realise that SLF4J is a facade, yes. Sending Hibernate logging to SLF4J means that it ends up at whatever backend i've chosen for the rest of my application, which is what i want. – Tom Anderson Jul 25 '12 at 07:29
  • 11
    So what you're saying about configuration is that there is no configuration (which is nice!), but that jboss-logging somehow detects and selects a backend? Ah, now i take the time to actually look at the code, i see that is [exactly what happens](https://github.com/jboss-logging/jboss-logging/blob/master/src/main/java/org/jboss/logging/LoggerProviders.java#L37). Specifically, jboss-logging tries, in order, JBoss LogManager, log4j, Logback via SLF4J, and JDK logging. But this *can* be overridden with the `org.jboss.logging.provider` system property. – Tom Anderson Jul 25 '12 at 07:33
  • 4
    Many of us have been burned by commons-logging figures out things for you, so knowing exactly how jboss-logging works is critical for being able to support it in the real world when the unexpected happens. – ams Aug 12 '12 at 20:31
  • 1
    The link above in fact shows exactly what happens if thats what you really want to see, so not following... – Steve Ebersole Aug 13 '12 at 12:36
3

I'm using Hibernate Core 4.1.7.Final plus Spring 3.1.2.RELEASE in a standalone app. I added Log4j 1.2.17 to my dependencies and it seems, as JBoss Logging logs directly to log4j if available and Spring uses Commons Logging, witch also uses Log4j if available, all Logging could be configured via Log4J.

Here's my list of relevant dependencies:

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>4.1.7.Final</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>3.1.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>3.1.2.RELEASE</version>
</dependency>
3

so, just got it working in my project. hibernate 4, slf4j, logback. my project is gradle, but should be same for maven.

Basically Abdull is right. Where he is NOT right, is that you DONT have to remove slf4j from dependencies.

  1. include to compile scope:

    org.slf4j:slf4j-api

    org.slf4j:log4j-over-slf4j

    e.g. for logback (ch.qos.logback:logback-classic, ch.qos.logback:logback-core:1.0.12)

  2. completely exclude log4j libs from dependencies

result: hibernate logs via slf4j to logback. of course you should be able to use different log implementation than logback

to be sure that no log4j is present, check your libs on classpath or web-inf/lib for war files.

of course you have set the loggers in logback.xml e.g. :

<logger name="org.hibernate.SQL" level="TRACE"/>

  • had this exact issue. log4j was getting brought in as a transitive dependency from another library. Excluded it, and the hibernate logging started to work as expected using logback and the slf4j log4j bridge – Paul Zepernick Jan 24 '20 at 18:15
3

Hibernate 4.3 has some documentation about how to control org.jboss.logging:

  • It searches the class-path for a logging provider. It searches for slf4j after searching for log4j. So, in theory, ensuring that your classpath (WAR) does not include log4j and does include the slf4j API and a back-end should work.

  • As a last resort you can set the org.jboss.logging.provider system property to slf4j.


Despite the claims of the documentation, org.jboss.logging insisted on trying to use log4j, despite log4j being absent and SLF4J being present, resulting in the following message in my Tomcat log file (/var/log/tomcat/catalina.out):

 log4j:WARN No appenders could be found for logger (org.jboss.logging).
 log4j:WARN Please initialize the log4j system properly.
 log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

I had to follow the suggestion of the answer by dasAnderl ausMinga and include the log4j-over-slf4j bridge.

Community
  • 1
  • 1
Raedwald
  • 46,613
  • 43
  • 151
  • 237
1

I use maven and added the following dependency:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.6</version>
</dependency>

Then, I created a log4j.properties files in /src/main/resources:

# direct log messages to 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=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
# set log levels
log4j.rootLogger=warn

This will put it at the root of your .jar. It works like a charm...

Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
1

I had an issue making hibernate 4 logging work with weblogic 12c and log4j. The solution is to put the following in your weblogic-application.xml:

<prefer-application-packages>
    <package-name>org.apache.log4j.*</package-name>
    <package-name>org.jboss.logging.*</package-name>
</prefer-application-packages>
gozer
  • 11
  • 1
1

To anyone that could face the same problem I had. In case you have tried all the other solutions explained here and still don't see hibernate logging working with your slf4j, it could be because you are using a container that has in his folder libraries the jboss-logging.jar. This means that gets preloaded before you can even set any configuration to influence it. To avoid this problem in weblogic you can specify in the file weblogic-application.xml in you ear/META-INF to prefer the library loaded from the application. there should be a similar mechanism for other server containers. In my case I had to add:

<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-application xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-application" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/javaee_5.xsd http://xmlns.oracle.com/weblogic/weblogic-application http://xmlns.oracle.com/weblogic/weblogic-application/1.5/weblogic-application.xsd">
   <wls:prefer-application-packages>    
       <!-- logging -->
       <wls:package-name>org.slf4j.*</wls:package-name>
       <wls:package-name>org.jboss.logging.*</wls:package-name>             
   </wls:prefer-application-packages>
   <wls:prefer-application-resources>
        <wls:resource-name>org/slf4j/impl/StaticLoggerBinder.class</wls:resource-name>
    </wls:prefer-application-resources>     
</wls:weblogic-application>
Massimo
  • 1,012
  • 14
  • 23
-3

did you try this:

- slf4j-log4j12.jar in the case of Log4J. See the SLF4J documentation for more detail. To use Log4j you will also need to place a log4j.properties file in your classpath. An example properties file is distributed with Hibernate in the src/ directory

just add these jars and properties or log4j xml in the classpath

Avihai Marchiano
  • 3,837
  • 3
  • 38
  • 55