Jak skonfigurować logowanie w Hibernate 4, aby używać SLF4J


114

Użyto Hibernate 3.x. do logowania. Hibernate 4.x używa. Piszę samodzielną aplikację, która używa Hibernate 4 i SLF4J do logowania.

Jak mogę skonfigurować Hibernację, aby logowała się do SLF4J?

Jeśli nie jest to możliwe, jak w ogóle mogę skonfigurować logowanie Hibernate?

Sekcja podręcznika Hibernate 4.1 dotycząca logowania zaczyna się od ostrzeżenia, że ​​jest to ...

Całkowicie nieaktualny. Hibernate korzysta z JBoss Logging począwszy od wersji 4.0. Zostanie to udokumentowane, gdy przeniesiemy tę zawartość do Podręcznika programisty.

... dalej mówi o SLF4J, więc jest bezużyteczny. Ani przewodnik dla początkujących, ani przewodnik dla programistów w ogóle nie mówią o logowaniu. Nie ma też tego przewodnik po migracji .

Szukałem dokumentacji na temat samego jboss-logging, ale w ogóle nie mogłem znaleźć. Strona GitHub jest cicha , a na stronie projektów społeczności JBoss nie ma nawet listy logowania jboss. Zastanawiałem się, czy program do śledzenia błędów projektu może mieć jakieś problemy związane z dostarczaniem dokumentacji, ale tak nie jest.

Dobra wiadomość jest taka, że ​​podczas korzystania z Hibernate 4 na serwerze aplikacji, takim jak JBoss AS7, logowanie jest w dużej mierze obsługiwane za Ciebie. Ale jak mogę to skonfigurować w samodzielnej aplikacji?


13
+1 za podkreślenie, że dokumenty Hibernate podczas logowania są nieaktualne
mhnagaoka

Można ustawić właściwość systemową org.jboss.logging.provide = slf4j. Aby uzyskać więcej informacji, odwiedź link docs.jboss.org/hibernate/orm/4.3/topical/html/logging/… dla wersji hibernacji większej niż 3.
Abhishek Ranjan

Odpowiedzi:


60

Spójrz na 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();
}

Więc możliwe wartości org.jboss.logging.providerto: jboss, jdk, log4j, slf4j.

Jeśli nie ustawisz org.jboss.logging.provider, spróbuje jboss, następnie log4j, następnie slf4j (tylko jeśli używane jest logowanie) i powrót do jdk.

Używam slf4jz logback-classic:

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

i wszystko działa dobrze!

AKTUALIZACJA Niektórzy użytkownicy używają w bardzo głównym App.java:

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

ale w przypadku rozwiązań opartych na kontenerach to nie działa.

UPDATE 2 Ci, którzy myślą, że zarządzają Log4j z SLF4J, bo jboss-loggingtak nie jest. jboss-loggingbezpośrednio używa Log4j bez SLF4J!


1
Gdzie ustawić org.jboss.logging.provider?
Suzan Cioc

1
@SuzanCioc Zgodnie z System.getProperty(LOGGING_PROVIDER_KEY);potrzebami należy ustawić właściwość systemową. Przejrzyj java -D...=...lub sprawdź dokumenty swojego kontenera.
gavenkoa

1
Twoja druga informacja o niemożności korzystania z log4j przez slf4j była pomocna. Ustawienie org.jboss.logging.provider na slf4j sprawiło, że pomyślałem, że moje wsparcie dla log4j zadziała. Jednak tak się nie stało. Musiałem ustawić to bezpośrednio na log4j, aby to zadziałało. Dziwny. Jaki jest więc sens slf4j jako opcji dla tej konfiguracji?
Travis Spencer

27

Aby SLF4J współpracował z JBoss Logging bez Logback jako backend, wymaga użycia właściwości systemowej org.jboss.logging.provider=slf4j. log4j-over-slf4jWydaje się, że taktyka nie działa w tym przypadku, ponieważ logowanie powróci do JDK, jeśli ani Logback, ani log4j nie są obecne w ścieżce klas.

Jest to trochę uciążliwe i aby autodetekcja działała, musisz zobaczyć, że program ładujący klasy zawiera przynajmniej ch.qos.logback.classic.Loggerz logback-classic lub org.apache.log4j.Hierarchyz log4j, aby oszukać JBoss Logging, aby nie cofnął się do logowania JDK.

Magia jest interpretowana na org.jboss.logging.LoggerProviders

AKTUALIZACJA: Dodano obsługę modułu ładującego usługi, dzięki czemu można uniknąć problemów z automatycznym wykrywaniem poprzez zadeklarowanie META-INF/services/org.jboss.logging.LoggerProvider( org.jboss.logging.Slf4jLoggerProviderjako wartość). Wydaje się, że dodano również obsługę log4j2.


1
Gdzie ustawić tę właściwość systemową?
jhegedus

Zależy od konfiguracji, ale zwykle -Dorg.jboss.logging.provider=slf4jwystarczy przełącznik wiersza poleceń . LoggingProviders.java zapewnia lepszy wgląd w to, jakie są obecnie akceptowane wartości i czego można się spodziewać w ścieżce klas.
Tuomas Kiviaho,

2
Nie sądzę, że podejście do programu ładującego usługi działa, ponieważ Slf4jLoggerProvidernie jest publicklasą?
holmis83

Muszę ustawić org.jboss.logging.provider w weblogic WAR do kodu źródłowego, ale każdy inicjator klasy statycznej jest wywoływany po inicjatorze LoggingProviders!
Antonio Petricca

12

Zainspirowany postem Leif's Hypoport , w ten sposób „ wygiąłem ” Hibernate 4 z powrotem do slf4j:

Załóżmy, że używasz Mavena.

  • Dodaj org.slf4j:log4j-over-slf4jjako zależność do swojegopom.xml
  • Używając polecenia mvn dependency:tree, upewnij się, że żaden z artefaktów, których używasz slf4j:slf4j, nie jest zależny od (a dokładniej, żaden artefakt nie może mieć zależności zakresu kompilacji ani zależności zakresu czasu wykonywaniaslf4j:slf4j )

Tło: Hibernate 4.x jest zależne od artefaktu org.jboss.logging:jboss-logging. Przejściowo ten artefakt ma podaną zależność zakresu od artefaktu slf4j:slf4j.

Ponieważ dodaliśmy teraz org.slf4j:log4j-over-slf4jartefakt, org.slf4j:log4j-over-slf4jnaśladuje slf4j:slf4jartefakt. Dlatego wszystko, co JBoss Loggingloguje, będzie teraz przechodziło przez slf4j.

Załóżmy, że używasz Logback jako zaplecza logowania. Oto próbkapom.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>

Na swojej ścieżce klas umieść logback.xmltaki, jak ten, który znajduje się w 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 -->

Niektóre komponenty mogą chcieć mieć dostęp logback.xmlpodczas uruchamiania maszyny JVM w celu prawidłowego logowania, na przykład wtyczka Jetty Maven. W takim przypadku dodaj system Java logback.configurationFile=./path/to/logback.xmldo polecenia (np mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run.).

W przypadku, gdy nadal otrzymujesz "surowe" wyjście z trybu hibernacji konsoli (np. Hibernate: select ...), Może pojawić się pytanie o przepełnienie stosu " Wyłącz logowanie hibernacji do konsoli ".


1
Upewnij się, że żadna inna biblioteka nie zawiera log4j, bo inaczej to nie zadziała. Przykład: activemq-all.jar zawiera log4j. Wskazówka: otwórz IDE i łatwo znajdź log4j w swoim kodzie.
Dimitri Dewaele

Miałem ten problem z JBoss Hibernate4 i (zbyt) starym serwerem. Ten post, w tym 1 linia w application.properties, załatwił sprawę. Więc TNX !!! A ta ostatnia linijka w moich nieruchomościach została napisana w innej odpowiedzi tutaj:org.jboss.logging.provider=slf4j
Jeroen van Dijk-Jun

8

Po pierwsze, zdajesz sobie sprawę, że SLF4J nie jest biblioteką rejestrowania, a opakowaniem dziennika. Sama niczego nie rejestruje, po prostu deleguje do „zaplecza”.

Aby "skonfigurować" jboss-logging, wystarczy dodać dowolny framework dziennika, którego chcesz używać do swojej ścieżki klas (wraz z jboss-logging), a jboss-logging wykrywa resztę.

Stworzyłem przewodnik po konfiguracji JBoss Logging skoncentrowany na Hibernacji: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html


2
Zdaję sobie sprawę, że SLF4J to fasada, tak. Wysłanie logowania Hibernate do SLF4J oznacza, że ​​kończy się ono na dowolnym zapleczu, który wybrałem dla reszty mojej aplikacji, a tego właśnie chcę.
Tom Anderson,

10
Więc to, co mówisz o konfiguracji, to fakt, że nie ma konfiguracji (co jest miłe!), Ale że jboss-logging w jakiś sposób wykrywa i wybiera backend? Ach, teraz poświęcam trochę czasu, aby faktycznie spojrzeć na kod, widzę, że tak właśnie się dzieje . Konkretnie, jboss-logging próbuje w kolejności JBoss LogManager, log4j, Logback przez SLF4J i JDK. Ale można to przesłonić za pomocą org.jboss.logging.providerwłaściwości systemowej.
Tom Anderson,

2
Wielu z nas zostało spalonych przez zwykłe rejestrowanie danych, więc wiedza dokładnie, jak działa jboss-log, ma kluczowe znaczenie, aby móc wesprzeć go w prawdziwym świecie, gdy wydarzy się coś nieoczekiwanego.
AMS

1
Powyższy link w rzeczywistości pokazuje dokładnie, co się stanie, jeśli to jest to, co naprawdę chcesz zobaczyć, więc nie
podążaj

3

Używam Hibernate Core 4.1.7.Final plus Spring 3.1.2.RELEASE w samodzielnej aplikacji. Dodałem Log4j 1.2.17 do moich zależności i wygląda na to, że JBoss Logging loguje się bezpośrednio do log4j, jeśli jest dostępny, a Spring używa Commons Logging, który używa również Log4j, jeśli jest dostępny, wszystkie Logging można skonfigurować za pomocą Log4J.

Oto moja lista odpowiednich zależności:

<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

więc właśnie uruchomiłem go w moim projekcie. hibernacja 4, slf4j, logowanie. mój projekt to gradle, ale powinien być taki sam dla maven.

Zasadniczo Abdull ma rację. Tam, gdzie on NIE ma racji, jest to, że NIE musisz usuwać slf4j z zależności.

  1. uwzględnij w zakresie kompilacji:

    org.slf4j: slf4j-api

    org.slf4j: log4j-over-slf4j

    np. do logback (ch.qos.logback: logback-classic, ch.qos.logback: logback-core: 1.0.12)

  2. całkowicie wyklucz biblioteki log4j z zależności

wynik: logi hibernacji przez slf4j do logback. oczywiście powinieneś być w stanie użyć innej implementacji dziennika niż logback

aby upewnić się, że nie ma log4j, sprawdź swoje biblioteki w classpath lub web-inf / lib w poszukiwaniu plików wojennych.

oczywiście loggery ustawiłeś w logback.xml np:

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


miał dokładnie ten problem. log4j był wprowadzany jako zależność przechodnia z innej biblioteki. Wykluczono go, a rejestrowanie hibernacji zaczęło działać zgodnie z oczekiwaniami przy użyciu logback i mostu slf4j log4j
Paul Zepernick

3

Hibernate 4.3 zawiera dokumentację dotyczącą kontrolowania org.jboss.logging:

  • Przeszukuje ścieżkę klasy dla dostawcy rejestrowania . Wyszukuje slf4j po wyszukaniu log4j. Zatem teoretycznie upewnienie się, że ścieżka klas (WAR) nie obejmuje log4j i zawiera API slf4j, a zaplecze powinno działać.

  • W ostateczności możesz ustawić org.jboss.logging.providerwłaściwość systemową na slf4j.


Pomimo roszczeń z dokumentacji, org.jboss.loggingnalegałem na próbę użycia log4j, pomimo braku log4j i obecności SLF4J, co spowodowało następujący komunikat w moim pliku dziennika Tomcata ( /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.

Musiałem postępować zgodnie z sugestią odpowiedzi udzieloną przez dasAnderl ausMinga i dołączyć log4j-over-slf4jmost.


2

Używam maven i dodałem następującą zależność:

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

Następnie utworzyłem log4j.propertiespliki w /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

Spowoduje to umieszczenie go u źródła twojego .jar. To działa jak urok...


3
To konfiguruje użycie log4j. OP nie chce używać log4j; chcą używać slf4j.
Raedwald,

1

Miałem problem z logowaniem hibernacji 4 z weblogic 12c i log4j. Rozwiązaniem jest umieszczenie w pliku weblogic-application.xml następujących elementów:

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

0

Dla każdego, kto mógłby zmierzyć się z tym samym problemem, co ja. Jeśli wypróbowałeś wszystkie inne wyjaśnione tutaj rozwiązania i nadal nie widzisz rejestrowania hibernacji działającego z twoim slf4j, może to być spowodowane tym, że używasz kontenera, który ma w swoich bibliotekach folderów jboss-logging.jar. Oznacza to, że jest wstępnie ładowany, zanim będzie można ustawić jakąkolwiek konfigurację, aby na nią wpłynąć. Aby uniknąć tego problemu w weblogic, możesz określić w pliku weblogic-application.xml w swoim uchu / META-INF, aby preferować bibliotekę ładowaną z aplikacji. powinien istnieć podobny mechanizm dla innych kontenerów serwerów. W moim przypadku musiałem dodać:

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

czy próbowałeś tego:

- slf4j-log4j12.jar w przypadku Log4J. Więcej szczegółów można znaleźć w dokumentacji SLF4J. Aby użyć Log4j, musisz również umieścić plik log4j.properties w ścieżce klas. Przykładowy plik właściwości jest dystrybuowany z Hibernate w katalogu src /

po prostu dodaj te pliki jar i właściwości lub log4j xml w ścieżce klas


4
To cytat z dokumentacji Hibernate 3.x. Czy myślisz, że to nadal będzie działać z Hibernate 4.x, który nie używa SLF4J?
Tom Anderson

o ile pamiętam log4j wystarczy
Avihai Marchiano
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.