web-dev-qa-db-fra.com

Comment configurer la journalisation dans Hibernate 4 pour utiliser SLF4J

Hibernate 3.x utilisait slf4j pour la journalisation. Hibernate 4.x utilise jboss-logging . J'écris une application autonome qui utilise Hibernate 4 et SLF4J pour la journalisation.

Comment puis-je configurer Hibernate pour se connecter à SLF4J?

Si ce n'est pas possible, comment puis-je configurer la journalisation d'Hibernate?

Le manuel de Hibernate 4.1 sur la journalisation commence par l'avertissement qu'il est en cours ...

Complètement obsolète. Hibernate utilise JBoss Logging à partir de la version 4.0. Cela sera documenté lors de la migration de ce contenu vers le Guide du développeur.

... continue à parler de SLF4J, et est donc inutile. Ni le Getting Started Guide ni le Developer Guide ne parlent de la journalisation. Le migration guide non plus.

J'ai cherché de la documentation sur jboss-logging, mais je n'ai pas réussi à en trouver. La page GitHub est muette et la page des projets community de JBoss ne répertorie même pas jboss-logging. Je me demandais si le bug tracker du projet posait problème, mais ce n’est pas le cas.

La bonne nouvelle est que, lorsque vous utilisez Hibernate 4 dans un serveur d'applications, tel que JBoss AS7, la journalisation est en grande partie assurée pour vous. Mais comment puis-je le configurer dans une application autonome?

106
Tom Anderson

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

Les valeurs possibles pour org.jboss.logging.provider sont donc: jboss, jdk, log4j, slf4j.

Si vous ne définissez pas org.jboss.logging.provider, il essaie jboss, puis log4j, puis slf4j (uniquement si la connexion est utilisée) et se replie sur jdk.

J'utilise slf4j avec logback-classic:

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

et tout fonctionne bien!

UPDATE Certains utilisateurs utilisent la version principale d'App.Java:

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

mais pour les solutions basées sur des conteneurs, cela ne fonctionne pas.

UPDATE 2 Ceux qui pensent gérer Log4j avec SLF4J pour jboss-logging ne le sont pas exactement. jboss-logging utilise directement Log4j sans SLF4J!

54
gavenkoa

Pour que SLF4J fonctionne avec JBoss Logging sans Logback en tant que backend, vous devez utiliser une propriété système org.jboss.logging.provider=slf4j. La tactique log4j-over-slf4j ne semble pas fonctionner dans ce cas, car la journalisation retombera sur JDK si ni Logback ni log4j ne sont réellement présents dans Classpath.

Ceci est un peu gênant et pour que la détection automatique fonctionne, vous devez voir que le chargeur de classes contient au moins ch.qos.logback.classic.Logger de logback-classic ou org.Apache.log4j.Hierarchy de log4j pour tromper la journalisation JBoss de ne pas revenir à la journalisation JDK.

La magie est interprétée à org.jboss.logging.LoggerProviders

UPDATE: La prise en charge du service loader a été ajoutée. Il est donc possible d'éviter les problèmes de détection automatique en déclarant META-INF/services/org.jboss.logging.LoggerProvider (avec org.jboss.logging.Slf4jLoggerProvider en tant que valeur). Il semble que le support log4j2 ait également été ajouté.

26
Tuomas Kiviaho

Inspiré par Le post Hypoport de Leif , voici comment j'ai "plié" Hibernate 4 vers slf4j: 

Supposons que vous utilisez Maven.

  • Ajoutez org.slf4j:log4j-over-slf4j comme dépendance à votre pom.xml
  • A l'aide de la commande mvn dependency:tree, assurez-vous que aucun des artefacts que vous utilisez dépendent de slf4j:slf4j (pour être précis, aucun artefact ne doit avoir une dépendance compiler scope ou exécution dépendance sur slf4j:slf4j)

Fond: Hibernate 4.x a une dépendance sur l'artefact org.jboss.logging:jboss-logging. De manière transitoire, cet artefact a une dépendance fournie sur l'artefact slf4j:slf4j

Comme nous avons maintenant ajouté l'artefact org.slf4j:log4j-over-slf4j, org.slf4j:log4j-over-slf4j imite l'artefact slf4j:slf4j. Par conséquent, tout ce que les journaux JBoss Logging vont maintenant passer par slf4j. 

Supposons que vous utilisiez Logback _ comme backend de journalisation. Voici un exemple 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>

Sur votre chemin de classe, ayez un logback.xml, tel que celui-ci situé dans 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 -->

Certains composants peuvent souhaiter avoir accès à logback.xml au moment du démarrage de la machine virtuelle Java pour une journalisation correcte, par exemple le plugin Jetty Maven. Dans ce cas, ajoutez un logback.configurationFile=./path/to/logback.xml système Java à votre commande (par exemple mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run). 

Si vous obtenez toujours une sortie "brute" de la console stdout Hibernate (telle que Hibernate: select ...), la question de débordement de pile " Désactive la journalisation de l'hibernation sur la console " peut s'appliquer.

12
Abdull

Tout d’abord, vous vous rendez compte que SLF4J n’est pas un droit de bibliothèque de journalisation, c’est un wrapper de journalisation. Il ne se connecte rien en soi, il délègue simplement à "backends". 

Pour "configurer" jboss-logging, vous devez simplement ajouter le framework de journal que vous souhaitez utiliser sur votre chemin de classe (avec jboss-logging) et jboss-logging calcule le reste.

J'ai créé un guide axé sur Hibernate sur la configuration de JBoss Logging: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html

8
Steve Ebersole

J'utilise Hibernate Core 4.1.7.Final plus Spring 3.1.2.RELEASE dans une application autonome. J'ai ajouté Log4j 1.2.17 à mes dépendances et il semble que, JBoss Logging enregistre directement dans log4j s'il est disponible et que Spring utilise Commons Logging, qui utilise également Log4j si disponible, toute la journalisation peut être configurée via Log4J.

Voici ma liste de dépendances pertinentes:

<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 a de la documentation sur la façon de contrôler org.jboss.logging:

  • Il recherche dans le chemin de classe un fournisseur logging. Il recherche slf4j après la recherche de log4j. Donc, en théorie, vous assurer que votre classpath (WAR) n'inclut pas log4j et n'inclut pas l'API slf4j et qu'un back-end devrait fonctionner.

  • En dernier recours, vous pouvez définir la propriété système org.jboss.logging.provider sur slf4j.


Malgré les affirmations de la documentation, org.jboss.logging a insisté pour essayer d'utiliser log4j, malgré l'absence de log4j et la présence de SLF4J, ce qui a entraîné le message suivant dans mon fichier journal Tomcat (/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.

Je devais suivre la suggestion de la réponse de dasAnderl ausMinga et inclure le pont log4j-over-slf4j.

3
Raedwald

alors, je viens de le faire fonctionner dans mon projet. hibernate 4, slf4j, logback. mon projet est en cours, mais devrait être identique pour maven.

En gros, Abdull a raison. Là où il n’a PAS raison, c’est que vous ne devez PAS supprimer slf4j des dépendances.

  1. inclure pour compiler la portée:

    org.slf4j: slf4j-api

    org.slf4j: log4j-over-slf4j

    par exemple. pour la consignation (ch.qos.logback: logback-classic, ch.qos.logback: logback-core: 1.0.12)

  2. exclure complètement les bibliothèques log4j des dépendances

résultat: hibernate les journaux via slf4j pour vous connecter . vous devriez bien sûr pouvoir utiliser une implémentation de journal différente de celle de logback

pour être sûr qu’aucun log4j n’est présent, vérifiez votre bibliothèque sur classpath ou sur web-inf/lib pour les fichiers war.

bien sûr, vous avez défini les enregistreurs dans logback.xml, par exemple. :

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

2
dasAnderl ausMinga

J'utilise maven et j'ai ajouté la dépendance suivante:

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

Ensuite, j'ai créé un log4j.properties fichiers dans /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

Cela le placera à la racine de votre .jar. Il fonctionne comme un charme...

2
Jérôme Verstrynge

J'ai eu un problème en faisant en sorte que la journalisation d'hibernation 4 fonctionne avec weblogic 12c et log4j. La solution consiste à mettre ce qui suit dans votre weblogic-application.xml:

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

À quiconque pourrait faire face au même problème que moi. Si vous avez essayé toutes les autres solutions expliquées ici et que la journalisation de veille prolongée ne fonctionne toujours pas avec votre slf4j, c'est peut-être parce que vous utilisez un conteneur qui contient dans ses bibliothèques de dossiers le fichier jboss-logging.jar. Cela signifie que le fichier est préchargé avant que vous puissiez configurer une configuration pour l’influencer . Pour éviter ce problème dans weblogic, vous pouvez le spécifier dans le fichier weblogic-application.xml de votre répertoire/META-INF afin de préférer la bibliothèque chargée à partir du fichier. application. il devrait exister un mécanisme similaire pour les autres conteneurs de serveurs . Dans mon cas, je devais ajouter:

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