Comment configurer la journalisation dans Hibernate 4 pour utiliser SLF4J

114

Hibernate 3.x utilisé pour la journalisation. Utilisations d'Hibernate 4.x. J'écris une application autonome qui utilise Hibernate 4 et SLF4J pour la journalisation.

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

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

La section du manuel Hibernate 4.1 sur la journalisation commence par l'avertissement qu'il s'agit ...

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 en parlant de SLF4J, et est donc inutile. Ni le guide de démarrage ni le guide du développeur ne parlent du tout de journalisation. Le guide de migration non plus .

J'ai cherché de la documentation sur jboss-logging lui-même, mais je n'ai pas pu en trouver du tout. La page GitHub est silencieuse et la page des projets communautaires de JBoss ne répertorie même pas la journalisation jboss. Je me suis demandé si le suivi des bogues du projet pouvait avoir des problèmes liés à la fourniture de documentation, 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 prise en charge pour vous. Mais comment puis-je le configurer dans une application autonome?

Tom Anderson
la source
13
+1 pour souligner que les documents Hibernate sur la journalisation sont obsolètes
mhnagaoka
On peut définir la propriété système org.jboss.logging.provide = slf4j. Pour plus de détails, veuillez visiter le lien docs.jboss.org/hibernate/orm/4.3/topical/html/logging/… pour la version hibernate supérieure à 3.
Abhishek Ranjan

Réponses:

60

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

Ainsi , les valeurs possibles pour org.jboss.logging.providersont: jboss, jdk, log4j, slf4j.

Si vous ne le définissez pas, org.jboss.logging.provideril essaie jboss, puis log4j, puis slf4j (uniquement si logback est utilisé) et revient à jdk.

J'utilise slf4javec 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!

MISE À JOUR Certains utilisateurs utilisent dans la très principale 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 car jboss-loggingce n'est pas exactement ainsi. jboss-loggingutilise directement Log4j sans SLF4J!

gavenkoa
la source
1
Où installer org.jboss.logging.provider?
Suzan Cioc
1
@SuzanCioc Selon System.getProperty(LOGGING_PROVIDER_KEY);vous, vous devez définir la propriété système. Via java -D...=...ou consultez les documents de votre conteneur.
gavenkoa
1
Votre deuxième mise à jour sur l'impossibilité d'utiliser log4j via slf4j a été utile. Définir org.jboss.logging.provider sur slf4j m'a fait penser que mon soutien à log4j allait entrer en jeu. Ce n'est pas le cas. J'ai dû définir cela directement sur log4j pour que cela fonctionne. Impair. Quel est l'intérêt de slf4j en tant qu'option pour cette configuration alors?
Travis Spencer
27

Pour que SLF4J fonctionne avec JBoss Logging sans Logback en tant que backend, il faut utiliser une propriété système org.jboss.logging.provider=slf4j. log4j-over-slf4jtactics ne semble pas fonctionner dans ce cas parce que la journalisation retournera à JDK si ni Logback ni log4j ne sont réellement présents dans classpath.

C'est un peu gênant et pour que la détection automatique fonctionne, vous avez vu que le chargeur ch.qos.logback.classic.Loggerde classe contient au moins de logback-classic ou org.apache.log4j.Hierarchyde log4j pour empêcher JBoss Logging de ne pas revenir à la journalisation JDK.

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

MISE À JOUR: la prise en charge du chargeur de service 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(avecorg.jboss.logging.Slf4jLoggerProvider comme valeur). Il semble y avoir également un support supplémentaire log4j2.

Tuomas Kiviaho
la source
1
Où définir cette propriété système?
jhegedus
Dépend de votre configuration, mais normalement un commutateur de ligne de commande -Dorg.jboss.logging.provider=slf4jsuffit. LoggingProviders.java vous donne de meilleures informations sur les valeurs actuellement acceptées et sur ce qui doit être présent dans le chemin de classe.
Tuomas Kiviaho
2
Je ne pense pas que l'approche du chargeur de service fonctionne parce que ce Slf4jLoggerProvidern'est pas une publicclasse?
holmis83
Je dois définir org.jboss.logging.provider dans un WAR weblogic dans le code source, mais tout intiializer de classe statique est appelé après celui de LoggingProviders!
Antonio Petricca
12

Inspiré par l'article de Leif sur Hypoport, voici comment j'ai «replié» Hibernate 4 vers slf4j:

Supposons que vous utilisez Maven.

  • Ajouter en org.slf4j:log4j-over-slf4jtant que dépendance à votrepom.xml
  • À l'aide de la commande mvn dependency:tree, assurez-vous qu'aucun des artefacts que vous utilisez ne dépend slf4j:slf4j(pour être précis, aucun artefact ne doit avoir une dépendance de portée de compilation ou une dépendance de portée d' exécutionslf4j:slf4j )

Contexte: 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 de portée fournie sur l'artefact slf4j:slf4j.

Comme nous avons maintenant ajouté l' org.slf4j:log4j-over-slf4jartefact, org.slf4j:log4j-over-slf4jimite l' slf4j:slf4jartefact. Par conséquent, tout ce qui JBoss Loggingenregistre sera désormais transféré via slf4j.

Disons que vous utilisez Logback comme backend de journalisation. Voici un échantillonpom.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 au moment logback.xmldu démarrage de la JVM pour une journalisation appropriée, par exemple le plug-in Jetty Maven. Dans ce cas, ajoutez un système Java logback.configurationFile=./path/to/logback.xmlà votre commande (par exemple mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run).

Si vous obtenez toujours une sortie de mise en veille prolongée stdout de la console "brute" (comme Hibernate: select ...), la question de Stack Overflow " Désactiver la journalisation de mise en veille prolongée sur la console " peut s'appliquer.

Abdull
la source
1
Assurez-vous qu'aucune autre bibliothèque n'inclut log4j, sinon cela ne fonctionnera pas. Exemple: activemq-all.jar contient log4j. Astuce: ouvrez votre IDE et trouvez facilement log4j dans votre code.
Dimitri Dewaele
J'ai eu ce problème avec JBoss Hibernate4 et un (trop) vieux serveur. Cet article, comprenant 1 ligne dans application.properties, a fait l'affaire pour moi. Alors TNX !!! Et cette dernière ligne dans mes propriétés a été écrite dans une autre réponse ici:org.jboss.logging.provider=slf4j
Jeroen van Dijk-Jun
8

Tout d'abord, vous réalisez que SLF4J n'est pas un droit de bibliothèque de journalisation, c'est un wrapper de journalisation. Il n'enregistre rien lui-même, il délègue simplement aux "backends".

Pour "configurer" jboss-logging, il vous suffit d'ajouter le framework de journal que vous souhaitez utiliser sur votre chemin de classe (avec jboss-logging) et jboss-logging comprend le reste.

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

Steve Ebersole
la source
2
Je me rends compte que SLF4J est une façade, oui. L'envoi de la journalisation Hibernate à SLF4J signifie qu'il se termine sur le backend que j'ai choisi pour le reste de mon application, ce que je veux.
Tom Anderson
10
Donc, ce que vous dites à propos de la configuration, c'est qu'il n'y a pas de configuration (ce qui est bien!), Mais que jboss-logging détecte et sélectionne en quelque sorte un backend? Ah, maintenant je prends le temps de regarder le code, je vois que c'est exactement ce qui se passe . Plus précisément, jboss-logging essaie, dans l'ordre, JBoss LogManager, log4j, Logback via SLF4J et la journalisation JDK. Mais cela peut être remplacé par la org.jboss.logging.providerpropriété système.
Tom Anderson
2
Beaucoup d'entre nous ont été brûlés par le fait que la journalisation des communs détermine les choses pour vous, donc savoir exactement comment fonctionne jboss-logging est essentiel pour pouvoir le supporter dans le monde réel lorsque l'inattendu se produit.
Ams
1
Le lien ci-dessus montre en fait exactement ce qui se passe si c'est ce que vous voulez vraiment voir, donc ne pas suivre ...
Steve Ebersole
3

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, comme JBoss Logging se connecte directement à log4j si 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>
Stefan Scheidt
la source
3

alors, je l'ai juste fait fonctionner dans mon projet. hibernate 4, slf4j, connexion. mon projet est gradle, mais devrait être le même pour maven.

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

  1. include pour compiler la portée:

    org.slf4j: slf4j-api

    org.slf4j: log4j-over-slf4j

    par exemple pour logback (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: mise en veille prolongée des journaux via slf4j pour se connecter. bien sûr, vous devriez pouvoir utiliser une implémentation de journal différente de celle de la connexion

pour être sûr qu'aucun log4j n'est présent, vérifiez vos bibliothèques sur classpath ou 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"/>

dasAnderl ausMinga
la source
eu ce problème exact. log4j était importé en tant que dépendance transitive d'une autre bibliothèque. Je l'ai exclu et la journalisation de la mise en veille prolongée a commencé à fonctionner comme prévu en utilisant logback et le pont slf4j log4j
Paul Zepernick
3

Hibernate 4.3 a une documentation sur la façon de contrôler org.jboss.logging:

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

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


Malgré les affirmations de la documentation, org.jboss.loggingj'ai 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.

J'ai dû suivre la suggestion de la réponse de dasAnderl ausMinga et inclure le log4j-over-slf4jpont.

Raedwald
la source
2

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.propertiesfichier 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 mettra à la racine de votre .jar. Il fonctionne comme un charme...

Jérôme Verstrynge
la source
3
Cela configure l'utilisation de log4j. L'OP ne souhaite pas utiliser log4j; ils veulent utiliser slf4j.
Raedwald
1

J'ai eu un problème pour que la journalisation de Hibernate 4 fonctionne avec weblogic 12c et log4j. La solution est de 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>
gozer
la source
0

À tous ceux qui pourraient faire face au même problème que moi. Si vous avez essayé toutes les autres solutions expliquées ici et que vous ne voyez toujours pas la journalisation de la mise en veille prolongée fonctionner avec votre slf4j, cela peut être dû au fait que vous utilisez un conteneur qui a dans ses bibliothèques de dossiers le jboss-logging.jar. Cela signifie que cela est préchargé avant même de pouvoir définir une configuration pour l'influencer. Pour éviter ce problème dans weblogic vous pouvez spécifier dans le fichier weblogic-application.xml dans votre oreille / META-INF de préférer la bibliothèque chargée à partir de l'application. il devrait y avoir un mécanisme similaire pour les autres conteneurs de serveur. Dans mon cas, j'ai dû 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>
Massimo
la source
-2

avez-vous essayé ceci:

- slf4j-log4j12.jar dans le cas de Log4J. Consultez la documentation SLF4J pour plus de détails. Pour utiliser Log4j, vous devrez également placer un fichier log4j.properties dans votre chemin de classe. Un exemple de fichier de propriétés est distribué avec Hibernate dans le répertoire src /

ajoutez simplement ces jars et propriétés ou log4j xml dans le classpath

Avihai Marchiano
la source
4
C'est une citation de la documentation Hibernate 3.x. Pensez-vous que cela fonctionnera toujours avec Hibernate 4.x, qui n'utilise pas SLF4J?
Tom Anderson
autant que je me souvienne, log4j suffit
Avihai Marchiano