Wie konfigurieren Sie die Protokollierung in Hibernate 4 für die Verwendung von SLF4J?

114

Ruhezustand 3.x verwendet zur Protokollierung. Hibernate 4.x verwendet. Ich schreibe eine eigenständige Anwendung, die Hibernate 4 und SLF4J für die Protokollierung verwendet.

Wie kann ich den Ruhezustand so konfigurieren, dass er sich bei SLF4J anmeldet?

Wenn dies nicht möglich ist, wie kann ich die Protokollierung von Hibernate überhaupt konfigurieren?

Der manuelle Abschnitt zu Hibernate 4.1 zur Protokollierung beginnt mit der Warnung, dass ...

Völlig veraltet. Hibernate verwendet JBoss Logging ab 4.0. Dies wird dokumentiert, wenn wir diesen Inhalt in das Entwicklerhandbuch migrieren.

... spricht weiter über SLF4J und ist daher nutzlos. Weder in der Anleitung für die ersten Schritte noch in der Anleitung für Entwickler wird überhaupt über die Protokollierung gesprochen. Der Migrationsleitfaden auch nicht .

Ich habe nach Dokumentation zur JBoss-Protokollierung selbst gesucht, aber ich konnte überhaupt keine finden. Die GitHub-Seite ist still und auf der Community- Projektseite von JBoss wird nicht einmal die JBoss-Protokollierung aufgeführt. Ich habe mich gefragt, ob der Bug-Tracker des Projekts möglicherweise Probleme mit der Bereitstellung von Dokumentation hat, aber das tut er nicht.

Die gute Nachricht ist, dass bei Verwendung von Hibernate 4 in einem Anwendungsserver wie JBoss AS7 die Protokollierung weitgehend für Sie erledigt wird. Aber wie kann ich es in einer eigenständigen Anwendung konfigurieren?

Tom Anderson
quelle
13
+1 für das Hervorheben, dass Hibernate-Dokumente bei der Protokollierung veraltet sind
mhnagaoka
Man kann die Systemeigenschaft org.jboss.logging.provide = slf4j setzen. Weitere Informationen finden Sie unter dem Link docs.jboss.org/hibernate/orm/4.3/topical/html/logging/… für eine Ruhezustandversion größer als 3.
Abhishek Ranjan

Antworten:

60

Schauen Sie unter https://github.com/jboss-logging/jboss-logging/blob/master/src/main/java/org/jboss/logging/LoggerProviders.java nach :

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 mögliche Werte org.jboss.logging.providersind: jboss, jdk, log4j, slf4j.

Wenn Sie es nicht festlegen org.jboss.logging.provider, versuchen Sie es mit jboss, dann mit log4j, dann mit slf4j (nur wenn logback verwendet wird) und mit jdk.

Ich benutze slf4jmit logback-classic:

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.0.13</version>
        <scope>${logging.scope}</scope>
    </dependency>

und alle funktionieren gut!

UPDATE Einige Benutzer verwenden in sehr Haupt-App.java:

static { //runs when the main class is loaded.
    System.setProperty("org.jboss.logging.provider", "slf4j");
}

Bei containergestützten Lösungen funktioniert dies jedoch nicht.

UPDATE 2 Wer glaubt, Log4j mit SLF4J dafür zu verwalten jboss-logging, ist nicht genau so. jboss-loggingverwendet direkt Log4j ohne SLF4J!

Gavenkoa
quelle
1
Wo einstellen org.jboss.logging.provider?
Suzan Cioc
1
@SuzanCioc Entsprechend müssen System.getProperty(LOGGING_PROVIDER_KEY);Sie die Systemeigenschaft festlegen. Durchsuchen java -D...=...oder überprüfen Sie die Dokumente für Ihren Container.
Gavenkoa
1
Ihr zweites Update über die Nichtverwendung von log4j über slf4j war hilfreich. Das Setzen von org.jboss.logging.provider auf slf4j ließ mich denken, dass meine Unterstützung von log4j einspringen würde. Ich musste das direkt auf log4j setzen, damit das funktioniert. Seltsam. Was bringt slf4j als Option für diese Konfiguration?
Travis Spencer
27

Damit SLF4J mit JBoss Logging ohne Logback als Backend funktioniert, muss eine Systemeigenschaft verwendet werden org.jboss.logging.provider=slf4j. log4j-over-slf4jDie Taktik scheint in diesem Fall nicht zu funktionieren, da die Protokollierung auf JDK zurückgreift, wenn weder Logback noch log4j tatsächlich im Klassenpfad vorhanden sind.

Dies ist ein bisschen lästig und um die automatische Erkennung zum Laufen zu bringen, haben Sie gesehen, dass der Klassenlader mindestens ch.qos.logback.classic.Loggervon logback-classic oder enthältorg.apache.log4j.Hierarchy log4j enthält, um die JBoss-Protokollierung davon abzuhalten, nicht auf die JDK-Protokollierung zurückzugreifen.

Die Magie wird bei interpretiert org.jboss.logging.LoggerProviders

UPDATE: Die Unterstützung für Service Loader wurde hinzugefügt, damit Probleme mit der automatischen Erkennung durch Deklarieren META-INF/services/org.jboss.logging.LoggerProvider(mit org.jboss.logging.Slf4jLoggerProviderals Wert) vermieden werden können . Es scheint auch Unterstützung für log4j2 hinzugefügt zu haben.

Tuomas Kiviaho
quelle
1
Wo lege ich diese Systemeigenschaft fest?
Jhegedus
Hängt von Ihrem Setup ab, aber normalerweise reicht ein Befehlszeilenschalter -Dorg.jboss.logging.provider=slf4jaus. Mit LoggingProviders.java erhalten Sie bessere Einblicke in die aktuell akzeptierten Werte und in das, was im Klassenpfad zu erwarten ist.
Tuomas Kiviaho
2
Ich glaube nicht, dass der Service Loader-Ansatz funktioniert, weil er Slf4jLoggerProviderkeine publicKlasse ist.
holmis83
Ich muss org.jboss.logging.provider in einem Weblogic WAR in den Quellcode setzen, aber jeder statische Klassen-Intiializer wird nach dem LoggingProviders aufgerufen!
Antonio Petricca
12

Inspiriert von Leifs Hypoport-Post , habe ich Hibernate 4 auf diese Weise zurück zu slf4j "gebogen":

Nehmen wir an, Sie verwenden Maven.

  • Fügen Sie org.slf4j:log4j-over-slf4jals Abhängigkeit zu Ihrem hinzupom.xml
  • Stellen Sie mit dem Befehl mvn dependency:treesicher, dass keines der Artefakte, von denen Sie abhängig sind, abhängig ist slf4j:slf4j(um genau zu sein, darf kein Artefakt eine Abhängigkeit vom Kompilierungsbereich oder vom Laufzeitbereich habenslf4j:slf4j ).

Hintergrund: Hibernate 4.x ist vom Artefakt abhängig org.jboss.logging:jboss-logging. Transitiv hat dieses Artefakt eine bereitgestellte Bereichsabhängigkeit von dem Artefakt slf4j:slf4j.

Da wir jetzt das org.slf4j:log4j-over-slf4jArtefakt hinzugefügt haben , org.slf4j:log4j-over-slf4jahmt es das slf4j:slf4jArtefakt nach. Deshalb alles dasJBoss Logging wird jetzt protokolliert wird, tatsächlich über slf4j übertragen.

Angenommen , Sie verwenden Logback als Protokollierungs-Backend. Hier ist ein Beispielpom.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>

Haben Sie auf Ihrem Klassenpfad eine logback.xml, wie diese 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 -->

Einige Komponenten logback.xml, z. B. das Jetty Maven Plugin, möchten möglicherweise beim Start von JVM Zugriff auf die ordnungsgemäße Protokollierung haben. Fügen Sie in diesem Fall logback.configurationFile=./path/to/logback.xmlIhrem Befehl ein Java-System hinzu (z mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run. B. ).

Wenn Sie immer noch eine "rohe" Konsolen-Standardausgabe im Ruhezustand (wie Hibernate: select ...) erhalten, kann die Stapelüberlauf-Frage " Deaktivieren der Ruhezustandsprotokollierung an der Konsole " zutreffen.

Abdull
quelle
1
Stellen Sie sicher, dass keine andere Bibliothek log4j enthält, da dies sonst nicht funktioniert. Beispiel: activemq-all.jar enthält log4j. Tipp: Öffnen Sie Ihre IDE und finden Sie log4j einfach in Ihrem Code.
Dimitri Dewaele
Ich hatte dieses Problem mit JBoss Hibernate4 und einem (zu) alten Server. Dieser Beitrag, einschließlich 1 Zeile in application.properties, hat den Trick für mich getan. Also TNX !!! Und diese letzte Zeile in meinen Eigenschaften wurde in einer anderen Antwort hier geschrieben:org.jboss.logging.provider=slf4j
Jeroen van Dijk-Jun
8

Zuerst stellen Sie fest, dass SLF4J keine Protokollierungsbibliothek ist, sondern ein Protokollierungs-Wrapper. Es selbst protokolliert nichts, es delegiert einfach an "Backends".

Um die jboss-Protokollierung zu "konfigurieren", fügen Sie einfach das Protokollframework hinzu, das Sie in Ihrem Klassenpfad verwenden möchten (zusammen mit der jboss-Protokollierung), und die jboss-Protokollierung ermittelt den Rest.

Ich habe eine auf den Ruhezustand ausgerichtete Anleitung zur JBoss-Protokollierungskonfiguration erstellt: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html

Steve Ebersole
quelle
2
Mir ist klar, dass SLF4J eine Fassade ist, ja. Das Senden der Hibernate-Protokollierung an SLF4J bedeutet, dass sie an dem Backend landet, das ich für den Rest meiner Anwendung ausgewählt habe.
Tom Anderson
10
Was Sie also über die Konfiguration sagen, ist, dass es keine Konfiguration gibt (was nett ist!), Aber dass jboss-logging irgendwie ein Backend erkennt und auswählt? Ah, jetzt nehme ich mir die Zeit, um mir den Code anzuschauen. Ich sehe, dass genau das passiert . Insbesondere versucht die jboss-Protokollierung nacheinander die JBoss LogManager-, log4j-, Logback via SLF4J- und JDK-Protokollierung. Dies kann jedoch mit der org.jboss.logging.providerSystemeigenschaft überschrieben werden.
Tom Anderson
2
Viele von uns wurden von Commons-Logging verbrannt, um herauszufinden, was genau für Sie funktioniert. Daher ist es wichtig, genau zu wissen, wie JBoss-Logging funktioniert, um es in der realen Welt unterstützen zu können, wenn das Unerwartete eintritt.
Ams
1
Der Link oben zeigt in der Tat genau, was passiert, wenn es das ist, was Sie wirklich sehen wollen, also nicht folgen ...
Steve Ebersole
3

Ich verwende Hibernate Core 4.1.7.Final plus Spring 3.1.2.RELEASE in einer eigenständigen App. Ich habe Log4j 1.2.17 zu meinen Abhängigkeiten hinzugefügt, und es scheint, dass JBoss Logging direkt in log4j protokolliert, sofern verfügbar, und Spring Commons Logging verwendet. Wenn verfügbar, wird auch Log4j verwendet. Die gesamte Protokollierung kann über Log4J konfiguriert werden.

Hier ist meine Liste der relevanten Abhängigkeiten:

<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>
Stefan Scheidt
quelle
3

Also, ich habe es gerade in meinem Projekt zum Laufen gebracht. Ruhezustand 4, slf4j, Logback. mein projekt ist gradle, sollte aber für maven gleich sein.

Grundsätzlich hat Abdull recht. Wo er NICHT Recht hat, ist, dass Sie slf4j NICHT aus Abhängigkeiten entfernen müssen.

  1. include zum Kompilieren des Gültigkeitsbereichs:

    org.slf4j: slf4j-api

    org.slf4j: log4j-over-slf4j

    zB für Logback (ch.qos.logback: logback-classic, ch.qos.logback: logback-core: 1.0.12)

  2. log4j libs vollständig von Abhängigkeiten ausschließen

Ergebnis: Protokolle im Ruhezustand über slf4j zum Zurückmelden. Natürlich sollten Sie in der Lage sein, eine andere Protokollimplementierung als Logback zu verwenden

Um sicherzustellen, dass kein log4j vorhanden ist, überprüfen Sie Ihre Bibliotheken auf classpath oder web-inf / lib auf Kriegsdateien.

Natürlich haben Sie die Logger in logback.xml gesetzt, zB:

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

dasAnderl ausMinga
quelle
hatte genau dieses Problem. log4j wurde als transitive Abhängigkeit von einer anderen Bibliothek eingeführt. Ausgeschlossen, und die Protokollierung im Ruhezustand begann wie erwartet mit Logback und der slf4j log4j-Brücke zu funktionieren
Paul Zepernick
3

In Hibernate 4.3 finden Sie einige Dokumentationen zur Steuerung org.jboss.logging:

  • Es durchsucht den Klassenpfad nach einem Protokollierungsanbieter . Nach der Suche nach log4j wird nach slf4j gesucht. Theoretisch sollte also funktionieren, um sicherzustellen, dass Ihr Klassenpfad (WAR) nicht log4j und die slf4j-API enthält und ein Back-End funktionieren sollte.

  • Als letzten Ausweg können Sie die org.jboss.logging.providerSystemeigenschaft auf festlegen slf4j.


Trotz der Behauptungen der Dokumentation org.jboss.loggingbestand ich darauf, log4j zu verwenden, obwohl log4j nicht vorhanden war und SLF4J vorhanden war, was zu der folgenden Meldung in meiner Tomcat-Protokolldatei ( /var/log/tomcat/catalina.out) führte:

 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.

Ich musste dem Vorschlag der Antwort von dasAnderl ausMinga folgen und die log4j-over-slf4jBrücke einschließen .

Raedwald
quelle
2

Ich benutze Maven und habe die folgende Abhängigkeit hinzugefügt:

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

Dann habe ich eine log4j.propertiesDatei erstellt 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

Dies wird es an die Wurzel Ihres .jar. Es wirkt wie ein Zauber...

Jérôme Verstrynge
quelle
3
Dies konfiguriert die Verwendung von log4j. Das OP möchte log4j nicht verwenden. Sie wollen slf4j verwenden.
Raedwald
1

Ich hatte ein Problem damit, dass die Protokollierung im Ruhezustand 4 mit Weblogic 12c und log4j funktioniert. Die Lösung besteht darin, Folgendes in Ihre weblogic-application.xml aufzunehmen:

<prefer-application-packages>
    <package-name>org.apache.log4j.*</package-name>
    <package-name>org.jboss.logging.*</package-name>
</prefer-application-packages>
gozer
quelle
0

Für jeden, der das gleiche Problem haben könnte, das ich hatte. Falls Sie alle anderen hier erläuterten Lösungen ausprobiert haben und immer noch keine Protokollierung im Ruhezustand mit Ihrem slf4j sehen, kann dies daran liegen, dass Sie einen Container verwenden, der in seinen Ordnerbibliotheken die Datei jboss-logging.jar enthält. Dies bedeutet, dass es vorinstalliert wird, bevor Sie überhaupt eine Konfiguration festlegen können, um sie zu beeinflussen. Um dieses Problem in Weblogic zu vermeiden, können Sie in der Datei weblogic-application.xml in Ihrem Ohr / META-INF angeben, dass die aus der Anwendung geladene Bibliothek bevorzugt wird. Es sollte einen ähnlichen Mechanismus für andere Servercontainer geben. In meinem Fall musste ich hinzufügen:

<?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
quelle
-2

Hast du das versucht:

- slf4j-log4j12.jar im Fall von Log4J. Weitere Informationen finden Sie in der SLF4J-Dokumentation. Um Log4j verwenden zu können, müssen Sie außerdem eine Datei log4j.properties in Ihren Klassenpfad einfügen. Eine Beispiel-Eigenschaftendatei wird mit Hibernate im Verzeichnis src / verteilt

Fügen Sie einfach diese Jars und Eigenschaften oder log4j xml in den Klassenpfad ein

Avihai Marchiano
quelle
4
Dies ist ein Zitat aus der Hibernate 3.x-Dokumentation. Denken Sie, dass dies weiterhin mit Hibernate 4.x funktioniert, das SLF4J nicht verwendet?
Tom Anderson
Soweit ich mich erinnere, ist log4j genug
Avihai Marchiano