Bagaimana Anda mengkonfigurasi log in Hibernate 4 untuk menggunakan SLF4J

114

Hibernate 3.x digunakan untuk penebangan. Hibernate 4.x menggunakan. Saya menulis aplikasi mandiri yang menggunakan Hibernate 4, dan SLF4J untuk logging.

Bagaimana cara mengkonfigurasi Hibernate untuk masuk ke SLF4J?

Jika itu tidak memungkinkan, bagaimana saya bisa mengkonfigurasi logging Hibernate sama sekali?

Bagian manual Hibernate 4.1 tentang logging dimulai dengan peringatan bahwa ...

Benar-benar ketinggalan zaman. Hibernate menggunakan JBoss Logging mulai 4.0. Ini akan didokumentasikan saat kami memigrasi konten ini ke Panduan Pengembang.

... terus berbicara tentang SLF4J, dan begitu juga tidak berguna. Baik panduan memulai maupun panduan pengembang berbicara tentang logging sama sekali. Begitu pula dengan panduan migrasi .

Saya telah mencari dokumentasi tentang jboss-logging itu sendiri, tetapi saya belum dapat menemukannya sama sekali. The halaman GitHub diam , dan JBoss ini masyarakat memproyeksikan halaman bahkan tidak daftar JBoss-logging. Saya bertanya-tanya apakah pelacak bug proyek ini mungkin memiliki masalah yang berkaitan dengan penyediaan dokumentasi, tetapi ternyata tidak.

Kabar baiknya adalah saat menggunakan Hibernate 4 di dalam server aplikasi, seperti JBoss AS7, logging sebagian besar dilakukan untuk Anda. Tetapi bagaimana saya bisa mengkonfigurasinya dalam aplikasi mandiri?

Tom Anderson
sumber
13
+1 untuk menyoroti bahwa dokumen Hibernate tentang penebangan sudah kedaluwarsa
mhnagaoka
Seseorang dapat mengatur properti sistem org.jboss.logging.provide = slf4j. Untuk detail lebih lanjut silakan kunjungi tautan docs.jboss.org/hibernate/orm/4.3/topical/html/logging/… untuk versi hibernasi lebih dari 3.
Abhishek Ranjan

Jawaban:

60

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

Jadi nilai yang mungkin untuk org.jboss.logging.provideradalah: jboss, jdk, log4j, slf4j.

Jika Anda tidak mengatur org.jboss.logging.provider , coba jboss, lalu log4j, lalu slf4j (hanya jika logback digunakan) dan fallback ke jdk.

Saya gunakan slf4jdengan logback-classic:

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

dan semuanya bekerja dengan baik!

UPDATE Beberapa pengguna kegunaan dalam App.java sangat utama:

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

tetapi untuk solusi berbasis kontainer, ini tidak berhasil.

UPDATE 2 Mereka yang berpikir bahwa mereka mengelola Log4j dengan SLF4J untuk jboss-loggingitu sebenarnya tidak demikian. jboss-logginglangsung menggunakan Log4j tanpa SLF4J!

gavenkoa.dll
sumber
1
Dimana mengatur org.jboss.logging.provider?
Suzan Cioc
1
@SuzanCioc Menurut System.getProperty(LOGGING_PROVIDER_KEY);Anda perlu mengatur properti sistem. Melalui java -D...=...atau periksa dokumen untuk wadah Anda.
gavenkoa
1
Pembaruan kedua Anda tentang tidak dapat menggunakan log4j melalui slf4j sangat membantu. Menyetel org.jboss.logging.provider ke slf4j membuat saya berpikir bahwa dukungan log4j saya akan berpengaruh. Namun ternyata tidak. Saya harus mengaturnya langsung ke log4j agar itu berfungsi. Aneh. Apa gunanya slf4j sebagai opsi untuk konfigurasi ini?
Travis Spencer
27

Untuk membuat SLF4J bekerja dengan JBoss Logging tanpa Logback karena backend membutuhkan penggunaan properti sistem org.jboss.logging.provider=slf4j. log4j-over-slf4jtaktik tampaknya tidak berfungsi dalam kasus ini karena logging akan kembali ke JDK jika baik Logback maupun log4j tidak benar-benar ada di classpath.

Ini adalah sedikit gangguan dan untuk mendapatkan deteksi otomatis untuk bekerja Anda harus melihat bahwa classloader berisi setidaknya ch.qos.logback.classic.Loggerdari logback-classic atau org.apache.log4j.Hierarchydari log4j untuk mengelabui JBoss Logging agar tidak kembali ke logging JDK.

Sihir ditafsirkan di org.jboss.logging.LoggerProviders

UPDATE: Dukungan pemuat layanan telah ditambahkan sehingga memungkinkan untuk menghindari masalah dengan deteksi otomatis dengan mendeklarasikan META-INF/services/org.jboss.logging.LoggerProvider(dengan org.jboss.logging.Slf4jLoggerProvidersebagai nilai). Tampaknya ada dukungan tambahan log4j2 juga.

Tuomas Kiviaho
sumber
1
Di mana saya menyetel properti sistem ini?
jhegedus
Tergantung pada penyiapan Anda, tetapi biasanya sakelar baris perintah -Dorg.jboss.logging.provider=slf4jsudah cukup. LoggingProviders.java memberi Anda wawasan yang lebih baik tentang apa saja nilai yang diterima saat ini dan apa yang diharapkan ada di classpath.
Tuomas Kiviaho
2
Saya tidak berpikir pendekatan pemuat layanan berfungsi karena Slf4jLoggerProviderbukan publickelas?
holmis83
Saya perlu menyetel org.jboss.logging.provider dalam WAR weblogic ke dalam kode sumber, tetapi semua intiializer kelas statis dipanggil setelah LoggingProviders!
Antonio Petricca
12

Terinspirasi oleh pos Hypoport Leif , inilah cara saya "membengkokkan" Hibernate 4 kembali ke slf4j:

Anggap saja Anda menggunakan Maven.

  • Tambahkan org.slf4j:log4j-over-slf4jsebagai ketergantungan pada filepom.xml
  • Dengan menggunakan perintah mvn dependency:tree, pastikan tidak ada artefak yang Anda gunakan bergantung slf4j:slf4j(tepatnya, tidak ada artefak yang akan memiliki dependensi cakupan kompilasi atau dependensi runtime scope slf4j:slf4j)

Latar belakang: Hibernate 4.x memiliki ketergantungan pada artefak org.jboss.logging:jboss-logging. Transitif, artefak ini memiliki disediakan lingkup ketergantungan pada artefak slf4j:slf4j.

Karena sekarang kita telah menambahkan org.slf4j:log4j-over-slf4jartefak, org.slf4j:log4j-over-slf4jmeniru slf4j:slf4jartefak tersebut. Oleh karena itu, semua yang JBoss Loggingdicatat sekarang akan benar-benar melalui slf4j.

Katakanlah Anda menggunakan Logback sebagai backend logging Anda. Ini contohnyapom.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>

Di jalur kelas Anda, miliki logback.xml, seperti ini yang terletak di 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 -->

Beberapa komponen mungkin ingin memiliki akses ke logback.xmlJVM waktu start-up untuk logging yang benar, misalnya Plugin Jetty Maven. Dalam hal ini, tambahkan sistem Java logback.configurationFile=./path/to/logback.xmlke perintah Anda (misalnya mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run).

Jika Anda masih mendapatkan output Hibernate stdout konsol "mentah" (seperti Hibernate: select ...), maka pertanyaan Stack Overflow " Matikan logging hibernasi ke konsol " mungkin berlaku.

Abdull
sumber
1
Pastikan tidak ada pustaka lain yang menyertakan log4j, atau ini tidak akan berhasil. Contoh: activemq-all.jar berisi log4j. Petunjuk: Buka IDE Anda dan temukan log4j dengan mudah di kode Anda.
Dimitri Dewaele
Saya mengalami masalah ini dengan JBoss Hibernate4 dan server (terlalu) lama. Posting ini, termasuk 1 baris di application.properties melakukan trik untuk saya. Jadi TNX !!! Dan baris terakhir di properti saya ditulis dalam jawaban lain di sini:org.jboss.logging.provider=slf4j
Jeroen van Dijk-
8

Pertama, Anda menyadari bahwa SLF4J bukanlah perpustakaan logging, itu pembungkus logging. Itu sendiri tidak mencatat apa pun, itu hanya mendelegasikan ke "backend".

Untuk "mengkonfigurasi" jboss-logging Anda cukup menambahkan kerangka kerja log apa pun yang ingin Anda gunakan pada classpath Anda (bersama dengan jboss-logging) dan jboss-logging mencari tahu sisanya.

Saya membuat panduan yang berfokus pada Hibernate untuk konfigurasi JBoss Logging: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html

Steve Ebersole
sumber
2
Saya benar-benar menyadari bahwa SLF4J adalah fasad, ya. Mengirim logging Hibernate ke SLF4J berarti bahwa itu berakhir di backend apa pun yang telah saya pilih untuk sisa aplikasi saya, yang saya inginkan.
Tom Anderson
10
Jadi apa yang Anda katakan tentang konfigurasi adalah bahwa tidak ada konfigurasi (yang bagus!), Tetapi jboss-logging entah bagaimana mendeteksi dan memilih backend? Ah, sekarang saya meluangkan waktu untuk benar-benar melihat kodenya, saya melihat itulah yang sebenarnya terjadi . Secara khusus, jboss-logging mencoba, secara berurutan, JBoss LogManager, log4j, Logback via SLF4J, dan JDK logging. Tapi ini bisa diganti dengan org.jboss.logging.providerproperti sistem.
Tom Anderson
2
Banyak dari kita telah terbakar oleh milik umum-logging mencari tahu hal-hal untuk Anda, jadi mengetahui dengan tepat cara kerja jboss-logging sangat penting untuk dapat mendukungnya di dunia nyata ketika hal yang tidak terduga terjadi.
pagi
1
Tautan di atas sebenarnya menunjukkan dengan tepat apa yang terjadi jika itu yang benar-benar ingin Anda lihat, jadi jangan mengikuti ...
Steve Ebersole
3

Saya menggunakan Hibernate Core 4.1.7.Final plus Spring 3.1.2.RELEASE dalam aplikasi mandiri. Saya menambahkan Log4j 1.2.17 ke dependensi saya dan tampaknya, karena JBoss Logging langsung log ke log4j jika tersedia dan Spring menggunakan Commons Logging, penyihir juga menggunakan Log4j jika tersedia, semua Logging dapat dikonfigurasi melalui Log4J.

Inilah daftar dependensi saya yang relevan:

<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
sumber
3

jadi, baru saja berfungsi di proyek saya. hibernate 4, slf4j, logback. proyek saya adalah gradle, tetapi harus sama untuk maven.

Pada dasarnya Abdull benar. Dimana dia TIDAK benar, adalah bahwa Anda TIDAK perlu menghapus slf4j dari dependensi.

  1. termasuk untuk mengkompilasi ruang lingkup:

    org.slf4j: slf4j-api

    org.slf4j: log4j-over-slf4j

    misalnya untuk logback (ch.qos.logback: logback-classic, ch.qos.logback: logback-core: 1.0.12)

  2. mengecualikan sepenuhnya log4j libs dari dependensi

hasil: log hibernasi melalui slf4j untuk logback. tentu saja Anda harus dapat menggunakan implementasi log yang berbeda dari logback

untuk memastikan bahwa tidak ada log4j, periksa libs Anda di classpath atau web-inf / lib untuk file perang.

tentu saja Anda telah mengatur logger di logback.xml misalnya:

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

dasAnderl ausMinga
sumber
memiliki masalah yang sama persis. log4j dibawa sebagai dependensi transitif dari library lain. Mengecualikannya, dan logging hibernasi mulai berfungsi seperti yang diharapkan menggunakan logback dan jembatan slf4j log4j
Paul Zepernick
3

Hibernate 4.3 memiliki beberapa dokumentasi tentang cara mengontrol org.jboss.logging:

  • Ini mencari jalur kelas untuk penyedia logging . Ia mencari slf4j setelah mencari log4j. Jadi, secara teori, memastikan bahwa classpath (WAR) Anda tidak menyertakan log4j dan tidak menyertakan API slf4j dan back-end seharusnya berfungsi.

  • Sebagai upaya terakhir, Anda dapat menyetel org.jboss.logging.providerproperti sistem ke slf4j.


Terlepas dari klaim dokumentasi, org.jboss.loggingbersikeras untuk mencoba menggunakan log4j, meskipun log4j tidak ada dan SLF4J ada, menghasilkan pesan berikut di file log Tomcat saya ( /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.

Saya harus mengikuti saran jawaban oleh dasAnderl ausMinga dan memasukkan log4j-over-slf4jjembatan.

Raedwald
sumber
2

Saya menggunakan maven dan menambahkan ketergantungan berikut:

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

Kemudian, saya membuat log4j.propertiesfile di /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

Ini akan meletakkannya di root file .jar. Ini bekerja seperti pesona ...

Jérôme Verstrynge
sumber
3
Ini mengonfigurasi penggunaan log4j. OP tidak ingin menggunakan log4j; mereka ingin menggunakan slf4j.
Raedwald
1

Saya mengalami masalah saat membuat logging hibernasi 4 bekerja dengan weblogic 12c dan log4j. Solusinya adalah dengan meletakkan yang berikut ini di weblogic-application.xml Anda:

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

Kepada siapa pun yang bisa menghadapi masalah yang sama dengan saya. Jika Anda telah mencoba semua solusi lain yang dijelaskan di sini dan masih tidak melihat logging hibernasi berfungsi dengan slf4j Anda, itu bisa jadi karena Anda menggunakan wadah yang memiliki pustaka jboss-logging.jar di foldernya. Ini berarti itu dimuat sebelum Anda bahkan dapat mengatur konfigurasi apa pun untuk mempengaruhinya. Untuk menghindari masalah ini dalam weblogic Anda dapat menentukan di file weblogic-application.xml di telinga Anda / META-INF agar lebih memilih perpustakaan yang dimuat dari aplikasi. harus ada mekanisme serupa untuk penampung server lainnya. Dalam kasus saya, saya harus menambahkan:

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

apakah kamu mencoba ini:

- slf4j-log4j12.jar dalam kasus Log4J. Lihat dokumentasi SLF4J untuk detail lebih lanjut. Untuk menggunakan Log4j, Anda juga perlu menempatkan file log4j.properties di classpath Anda. Contoh file properti didistribusikan dengan Hibernate di direktori src /

cukup tambahkan jars dan properti ini atau log4j xml di classpath

Avihai Marchiano
sumber
4
Itu adalah kutipan dari dokumentasi Hibernate 3.x. Apakah menurut Anda itu masih akan berfungsi dengan Hibernate 4.x, yang tidak menggunakan SLF4J?
Tom Anderson
Sejauh yang saya ingat log4j sudah cukup
Avihai Marchiano