web-dev-qa-db-de.com

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

Hibernate 3.x verwendete slf4j zur Protokollierung. Hibernate 4.x verwendet jboss-logging . 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?

Das Hibernate 4.1-Handbuch Abschnitt zum Logging beginnt mit der Warnung, dass es ...

Völlig veraltet Der Ruhezustand verwendet die JBoss-Protokollierung ab 4.0. Dies wird dokumentiert, wenn wir diesen Inhalt zum Entwicklerhandbuch migrieren.

... spricht weiter über SLF4J und ist auch nutzlos. Weder der Getting Started Guide noch der Developer Guide sprechen überhaupt über Logging. Der Migrationsleitfaden .

Ich habe nach Dokumentation zum jboss-logging selbst gesucht, aber ich konnte überhaupt keine finden. Die GitHub-Seite ist stumm , und JBoss's Community-Projekte listet nicht einmal Jboss-Logging auf. Ich fragte mich, ob der Bug-Tracker des Projekts Probleme mit der Bereitstellung von Dokumentation haben könnte, aber das ist nicht der Fall.

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

106
Tom Anderson

Siehe 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();
}

Mögliche Werte für org.jboss.logging.provider sind also: jboss, jdk, log4j, slf4j.

Wenn Sie nicht org.jboss.logging.provider setzen, wird jboss, dann log4j, dann slf4j (nur bei Verwendung von Logback) und Fallback auf jdk versucht.

Ich benutze slf4j mit 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 hauptsächlich App.Java:

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

bei behälterbasierten Lösungen funktioniert dies jedoch nicht.

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

54
gavenkoa

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

Dies ist etwas ärgerlich und um die automatische Erkennung zu aktivieren, müssen Sie feststellen, dass der Classloader mindestens ch.qos.logback.classic.Logger aus logback-classic oder org.Apache.log4j.Hierarchy aus log4j enthält, um die JBoss-Protokollierung dazu zu bringen, nicht auf die JDK-Protokollierung zurückzugreifen.

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

UPDATE: Die Unterstützung des Service Loader wurde hinzugefügt, um Probleme mit der automatischen Erkennung zu vermeiden, indem META-INF/services/org.jboss.logging.LoggerProvider (mit org.jboss.logging.Slf4jLoggerProvider als Wert) deklariert wird. Es scheint auch Support log4j2 hinzugefügt worden zu sein.

26
Tuomas Kiviaho

Inspiriert von Leifs Hypoport-Post , habe ich Hibernate 4 folgendermaßen auf slf4j "zurückgebogen":

Nehmen wir an, Sie verwenden Maven.

  • Füge org.slf4j:log4j-over-slf4j als Abhängigkeit zu deinem pom.xml hinzu
  • Stellen Sie mit dem Befehl mvn dependency:tree sicher, dass keine der verwendeten Artefakte von slf4j:slf4j abhängen (um genau zu sein, nein Artefakt muss eine Kompilierungs- Bereichsabhängigkeit oder Laufzeit- Bereichsabhängigkeit von slf4j:slf4j haben.)

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

Da wir nun das Artefakt org.slf4j:log4j-over-slf4j hinzugefügt haben, ahmt org.slf4j:log4j-over-slf4j das Artefakt slf4j:slf4j nach. Daher läuft alles, was JBoss Logging protokolliert, jetzt tatsächlich über slf4j.

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

Habe auf deinem Klassenpfad einen logback.xml, wie diesen 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, z. B. das Jetty Maven-Plugin, möchten möglicherweise beim Start von JVM Zugriff auf logback.xml haben, um eine ordnungsgemäße Protokollierung zu gewährleisten. In diesem Fall fügen Sie Ihrem Befehl ein Java System logback.configurationFile=./path/to/logback.xml hinzu (z. B. mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run).

Wenn Sie immer noch eine "unformatierte" Konsolen-Standardausgabe im Ruhezustand erhalten (wie Hibernate: select ...), kann die Frage " Deaktivieren Sie die Protokollierung im Ruhezustand in der Konsole " zutreffen.

12
Abdull

Zunächst stellen Sie fest, dass SLF4J keine Protokollbibliothek ist, sondern ein Wrapper für die Protokollierung. Es selbst protokolliert nichts, es delegiert einfach an "Backends". 

Um "jboss-logging" zu konfigurieren, fügen Sie einfach das Protokollframework hinzu, das Sie für Ihren Klassenpfad verwenden möchten (zusammen mit jboss-logging), und jboss-logging ermittelt den Rest.

Ich habe ein Hibernate-Handbuch zur Konfiguration von JBoss Logging erstellt: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html

8
Steve Ebersole

Ich verwende Hibernate Core 4.1.7.Final plus Spring 3.1.2.RELEASE in einer Standalone-App. Ich habe Log4j 1.2.17 zu meinen Abhängigkeiten hinzugefügt. Da JBoss Logging sich direkt in log4j einloggt und Spring Commons Logging verwendet, kann Log4j verwendet werden, sofern dies verfügbar ist. Alle Logging-Vorgänge könnten ü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>
3
Stefan Scheidt

Hibernate 4.3 enthält einige Dokumentationen zur Steuerung von org.jboss.logging:

  • Es durchsucht den Klassenpfad nach einem Protokollierungsanbieter. Es sucht nach slf4j, nachdem es nach log4j gesucht hat. Theoretisch sollte also sichergestellt werden, dass Ihr Klassenpfad (WAR) nicht log4j und nicht die slf4j-API enthält, und ein Back-End sollte funktionieren.

  • Als letzten Ausweg können Sie die Systemeigenschaft org.jboss.logging.provider auf slf4j setzen.


Trotz der Behauptungen der Dokumentation bestand org.jboss.logging darauf, log4j zu verwenden, obwohl log4j nicht vorhanden war und SLF4J vorhanden war. In meiner Tomcat-Protokolldatei (/var/log/Tomcat/catalina.out) wurde folgende Meldung angezeigt:

 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-slf4j-Brücke einbeziehen.

3
Raedwald

also, 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 nicht slf4j aus Abhängigkeiten entfernen müssen.

  1. include zum Kompilieren:

    org.slf4j: slf4j-api

    org.slf4j: log4j-over-slf4j

    z.B. für logback (ch.qos.logback: logback-classic, ch.qos.logback: logback-core: 1.0.12)

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

result: hibernate logs via slf4j auf logback . natürlich sollten sie eine andere log-implementierung als logback verwenden können

um sicherzugehen, dass kein log4j vorhanden ist, überprüfen Sie Ihre libs in classpath oder web-inf/lib auf Kriegsdateien.

natürlich haben Sie die Logger in logback.xml gesetzt, z. :

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

2

Ich benutze Maven und fügte die folgende Abhängigkeit hinzu:

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

Dann habe ich eine log4j.properties-Datei in /src/main/resources erstellt:

# 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

Dadurch wird es an der Wurzel Ihres .jar abgelegt. Es wirkt wie ein Zauber...

2

Ich hatte ein Problem bei der Protokollierung des Ruhezustands 4 mit weblogic 12c und log4j. 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>
1
gozer

Jedem, der das gleiche Problem hatte, das ich hatte. Falls Sie alle anderen hier beschriebenen Lösungen ausprobiert haben und immer noch keine Hibernate-Protokollierung mit Ihrem slf4j-System sehen, kann dies daran liegen, dass Sie einen Container verwenden, in dessen Ordner-Bibliotheken sich die Datei jboss-logging.jar befindet. Das bedeutet, dass das Programm vorab geladen wird, bevor Sie sogar eine Konfiguration festlegen können, die es beeinflusst. Um dieses Problem in der Weblogik zu vermeiden, können Sie in der Datei weblogic-application.xml in Ihrem Ohr/META-INF angeben, dass die aus der Bibliothek geladene Bibliothek bevorzugt wird Anwendung. Es sollte einen ähnlichen Mechanismus für andere Servercontainer geben. In meinem Fall musste ich Folgendes 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>
0
Massimo