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?
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!
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.
Inspiriert von Leifs Hypoport-Post , habe ich Hibernate 4 folgendermaßen auf slf4j "zurückgebogen":
Nehmen wir an, Sie verwenden Maven.
org.slf4j:log4j-over-slf4j
als Abhängigkeit zu deinem pom.xml
hinzumvn 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.
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
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>
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.
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.
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)
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"/>
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...
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>
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>