Come si configura la registrazione in Hibernate 4 per utilizzare SLF4J


114

Hibernate 3.x utilizzato per la registrazione. Hibernate 4.x utilizza. Sto scrivendo un'applicazione standalone che utilizza Hibernate 4 e SLF4J per la registrazione.

Come posso configurare Hibernate per accedere a SLF4J?

Se non è possibile, come posso configurare la registrazione di Hibernate?

La sezione manuale di Hibernate 4.1 sulla registrazione inizia con l'avvertimento che è ...

Completamente antiquato. Hibernate utilizza JBoss Logging a partire dalla 4.0. Ciò verrà documentato durante la migrazione di questo contenuto alla Guida per gli sviluppatori.

... continua a parlare di SLF4J, e quindi è inutile. Né la guida introduttiva né la guida per sviluppatori parlano affatto di registrazione. Né la guida alla migrazione .

Ho cercato la documentazione su jboss-logging stesso, ma non sono riuscito a trovarne affatto. La pagina GitHub è silenziosa e la pagina dei progetti della comunità di JBoss non elenca nemmeno jboss-logging. Mi chiedevo se il bug tracker del progetto potesse avere problemi relativi alla fornitura della documentazione, ma non è così.

La buona notizia è che quando si utilizza Hibernate 4 all'interno di un server di applicazioni, come JBoss AS7, la registrazione è in gran parte gestita per te. Ma come posso configurarlo in un'applicazione standalone?


13
+1 per evidenziare che i documenti di Hibernate al momento della registrazione non sono aggiornati
mhnagaoka

Si può impostare la proprietà di sistema org.jboss.logging.provide = slf4j. Per ulteriori dettagli visita il link docs.jboss.org/hibernate/orm/4.3/topical/html/logging/… per la versione di ibernazione maggiore di 3.
Abhishek Ranjan

Risposte:


60

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

Così possibili valori org.jboss.logging.providersono: jboss, jdk, log4j, slf4j.

Se non lo imposti org.jboss.logging.provider, prova jboss, quindi log4j, poi slf4j (solo se viene utilizzato il logback) e fallback su jdk.

Uso slf4jcon logback-classic:

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

e tutto funziona bene!

AGGIORNAMENTO Alcuni utenti utilizzano in App.java molto principale:

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

ma per le soluzioni basate su container questo non funziona.

AGGIORNAMENTO 2 Coloro che pensano di gestire Log4j con SLF4J perché jboss-loggingnon è esattamente così. jboss-loggingutilizza direttamente Log4j senza SLF4J!


1
Dove impostare org.jboss.logging.provider?
Suzan Cioc

1
@SuzanCioc Secondo System.getProperty(LOGGING_PROVIDER_KEY);te è necessario impostare la proprietà di sistema. Attraverso java -D...=...o controlla i documenti per il tuo contenitore.
Gavenkoa

1
Il tuo secondo aggiornamento sull'impossibilità di utilizzare log4j tramite slf4j è stato utile. L'impostazione di org.jboss.logging.provider su slf4j mi ha fatto pensare che il mio supporto di log4j sarebbe entrato in gioco. Non è stato così. Ho dovuto impostarlo direttamente su log4j affinché funzionasse. Dispari. Qual è il punto di slf4j come opzione per questa configurazione, allora?
Travis Spencer

27

Per fare in modo che SLF4J funzioni con JBoss Logging senza Logback come backend richiede l'utilizzo di una proprietà di sistema org.jboss.logging.provider=slf4j. log4j-over-slf4jle tattiche non sembrano funzionare in questo caso perché la registrazione ricadrà su JDK se né Logback né log4j non sono effettivamente presenti in classpath.

Questo è un po 'una seccatura e per far funzionare il rilevamento automatico devi vedere che il classloader contiene almeno ch.qos.logback.classic.Loggerlogback-classic o org.apache.log4j.Hierarchylog4j per ingannare JBoss Logging dal non ricadere nel log JDK.

La magia è interpretata a org.jboss.logging.LoggerProviders

AGGIORNAMENTO: è stato aggiunto il supporto del caricatore di servizi in modo che sia possibile evitare problemi con il rilevamento automatico dichiarando META-INF/services/org.jboss.logging.LoggerProvider(con org.jboss.logging.Slf4jLoggerProvidercome valore). Sembra che ci sia anche il supporto log4j2 aggiunto.


1
Dove imposto questa proprietà di sistema?
jhegedus

Dipende dalla configurazione, ma normalmente -Dorg.jboss.logging.provider=slf4jè sufficiente un'opzione della riga di comando . LoggingProviders.java fornisce informazioni migliori su quali sono i valori correnti accettati e su cosa ci si aspetta che sia presente nel classpath.
Tuomas Kiviaho

2
Non penso che l'approccio del caricatore di servizi funzioni perché Slf4jLoggerProvidernon è una publicclasse?
holmis83

Ho bisogno di impostare org.jboss.logging.provider in un WAR weblogic nel codice sorgente, ma qualsiasi intiializer di classe statica viene richiamato dopo quello di LoggingProviders!
Antonio Petricca

12

Ispirato dal post di Leif su Hypoport , ecco come ho "piegato" Hibernate 4 su slf4j:

Supponiamo che tu stia usando Maven.

  • Aggiungi org.slf4j:log4j-over-slf4jcome dipendenza al tuo filepom.xml
  • Utilizzando il comando mvn dependency:tree, assicurati che nessuno degli artefatti che stai utilizzando dipenda da slf4j:slf4j(per essere precisi, nessun artefatto deve avere una dipendenza dall'ambito di compilazione o dall'ambito di runtimeslf4j:slf4j )

Sfondo: Hibernate 4.x ha una dipendenza dall'artefatto org.jboss.logging:jboss-logging. Transitivamente, questo artefatto ha una dipendenza dell'ambito fornito dall'artefatto slf4j:slf4j.

Dato che ora abbiamo aggiunto l' org.slf4j:log4j-over-slf4jartefatto, org.slf4j:log4j-over-slf4jimita l' slf4j:slf4jartefatto. Pertanto tutto ciò che JBoss Loggingregistra ora andrà effettivamente tramite slf4j.

Supponiamo che tu stia utilizzando Logback come backend di registrazione. Ecco un esempiopom.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>

Sul tuo percorso di classe, disponi di un logback.xml, come questo situato 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 -->

Alcuni componenti potrebbero voler avere accesso logback.xmlall'avvio di JVM per una registrazione corretta, ad esempio il plug-in Jetty Maven. In tal caso, aggiungi un sistema Java logback.configurationFile=./path/to/logback.xmlal tuo comando (ad esempio mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run).

Nel caso in cui stai ancora ottenendo l'output di ibernazione stdout della console "grezzo" (come Hibernate: select ...), potrebbe essere applicata la domanda di overflow dello stack " Disattiva la registrazione dell'ibernazione sulla console ".


1
Assicurati che nessun'altra libreria includa log4j, altrimenti non funzionerà. Esempio: activemq-all.jar contiene log4j. Suggerimento: apri il tuo IDE e trova facilmente log4j nel tuo codice.
Dimitri Dewaele

Ho avuto questo problema con JBoss Hibernate4 e un (troppo) vecchio server. Questo post, inclusa 1 riga in application.properties, ha funzionato per me. Quindi TNX !!! E l'ultima riga nelle mie proprietà è stata scritta in un'altra risposta qui:org.jboss.logging.provider=slf4j
Jeroen van Dijk-Jun

8

Per prima cosa ti rendi conto che SLF4J non è una libreria di registrazione corretta, è un wrapper di registrazione. Da solo non registra nulla, si limita a delegare ai "backend".

Per "configurare" jboss-logging devi semplicemente aggiungere qualsiasi framework di log che vuoi usare sul tuo classpath (insieme a jboss-logging) e jboss-logging calcola il resto.

Ho creato una guida incentrata su Hibernate alla configurazione di JBoss Logging: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html


2
Mi rendo conto che SLF4J è una facciata, sì. L'invio della registrazione di Hibernate a SLF4J significa che finisce in qualsiasi backend che ho scelto per il resto della mia applicazione, che è quello che voglio.
Tom Anderson

10
Quindi quello che stai dicendo sulla configurazione è che non esiste una configurazione (il che è bello!), Ma che jboss-logging in qualche modo rileva e seleziona un backend? Ah, ora mi prendo il tempo per guardare effettivamente il codice, vedo che è esattamente quello che succede . In particolare, jboss-logging tenta, in ordine, JBoss LogManager, log4j, Logback tramite SLF4J e registrazione JDK. Ma questo può essere sovrascritto con la org.jboss.logging.providerproprietà di sistema.
Tom Anderson

2
Molti di noi sono stati scottati dal logaritmo dei commons per capire le cose per te, quindi sapere esattamente come funziona jboss-logging è fondamentale per poterlo supportare nel mondo reale quando accade l'imprevisto.
AMS

1
Il link sopra, infatti, mostra esattamente cosa succede se è quello che vuoi veramente vedere, quindi non seguire ...
Steve Ebersole

3

Sto usando Hibernate Core 4.1.7.Final plus Spring 3.1.2.RELEASE in un'app standalone. Ho aggiunto Log4j 1.2.17 alle mie dipendenze e sembra che, poiché JBoss Logging registra direttamente su log4j se disponibile e Spring utilizza Commons Logging, che usa anche Log4j se disponibile, tutto il logging potrebbe essere configurato tramite Log4J.

Ecco il mio elenco di dipendenze rilevanti:

<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

quindi, l'ho appena fatto funzionare nel mio progetto. ibernazione 4, slf4j, logback. il mio progetto è gradle, ma dovrebbe essere lo stesso per Maven.

Fondamentalmente Abdull ha ragione. Dove NON ha ragione, è che NON devi rimuovere slf4j dalle dipendenze.

  1. include per compilare l'ambito:

    org.slf4j: slf4j-api

    org.slf4j: log4j-over-slf4j

    ad esempio per il logback (ch.qos.logback: logback-classic, ch.qos.logback: logback-core: 1.0.12)

  2. escludere completamente le librerie log4j dalle dipendenze

risultato: ibernare i log tramite slf4j per eseguire il logback. ovviamente dovresti essere in grado di utilizzare un'implementazione del log diversa dal logback

per essere sicuro che non sia presente alcun log4j, controlla le tue librerie su classpath o web-inf / lib per i file war.

ovviamente hai impostato i logger in logback.xml ad esempio:

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


ha avuto questo problema esatto. log4j veniva introdotto come dipendenza transitiva da un'altra libreria. L'ho escluso e la registrazione di ibernazione ha iniziato a funzionare come previsto utilizzando logback e il bridge slf4j log4j
Paul Zepernick il

3

Hibernate 4.3 ha della documentazione su come controllare org.jboss.logging:

  • Cerca un provider di registrazione nel percorso di classe . Cerca slf4j dopo aver cercato log4j. Quindi, in teoria, assicurandoti che il tuo classpath (WAR) non includa log4j e includa l'API slf4j e un back-end dovrebbe funzionare.

  • Come ultima risorsa è possibile impostare la org.jboss.logging.providerproprietà di sistema su slf4j.


Nonostante le affermazioni della documentazione, org.jboss.loggingho insistito nel provare a utilizzare log4j, nonostante log4j fosse assente e SLF4J fosse presente, risultando nel seguente messaggio nel mio file di registro 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.

Ho dovuto seguire il suggerimento della risposta di dasAnderl ausMinga e includere il log4j-over-slf4jbridge.


2

Uso Maven e ho aggiunto la seguente dipendenza:

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

Quindi, ho creato un log4j.propertiesfile 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

Questo lo metterà alla radice del tuo .jar. Esso funziona magicamente...


3
Questo configura l'uso di log4j. L'OP non vuole usare log4j; vogliono usare slf4j.
Raedwald

1

Ho riscontrato un problema durante il funzionamento della registrazione di ibernazione 4 con weblogic 12c e log4j. La soluzione è inserire quanto segue nel tuo weblogic-application.xml:

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

0

A chiunque potesse affrontare lo stesso problema che ho avuto io. Nel caso in cui tu abbia provato tutte le altre soluzioni spiegate qui e continui a non vedere la registrazione di ibernazione funzionante con slf4j, potrebbe essere perché stai utilizzando un contenitore che ha nelle sue librerie di cartelle jboss-logging.jar. Ciò significa che viene precaricato prima ancora che tu possa impostare qualsiasi configurazione per influenzarlo. Per evitare questo problema in weblogic puoi specificare nel file weblogic-application.xml in te / META-INF di preferire la libreria caricata dall'applicazione. dovrebbe esserci un meccanismo simile per altri contenitori di server. Nel mio caso ho dovuto aggiungere:

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

-2

hai provato questo:

- slf4j-log4j12.jar nel caso di Log4J. Vedere la documentazione di SLF4J per maggiori dettagli. Per usare Log4j dovrai anche inserire un file log4j.properties nel tuo classpath. Un file delle proprietà di esempio è distribuito con Hibernate nella directory src /

basta aggiungere questi vasi e proprietà o log4j xml nel classpath


4
Questa è una citazione dalla documentazione di Hibernate 3.x. Pensi che funzionerà ancora con Hibernate 4.x, che non usa SLF4J?
Tom Anderson

per quanto ricordo log4j è sufficiente
Avihai Marchiano
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.