Làm cách nào để bạn định cấu hình đăng nhập Hibernate 4 để sử dụng SLF4J


114

Hibernate 3.x đã được sử dụng để ghi nhật ký. Sử dụng Hibernate 4.x. Tôi đang viết một ứng dụng độc lập sử dụng Hibernate 4 và SLF4J để ghi nhật ký.

Làm cách nào để cấu hình Hibernate để đăng nhập SLF4J?

Nếu không thể, làm cách nào để tôi có thể định cấu hình ghi nhật ký của Hibernate?

Phần hướng dẫn sử dụng Hibernate 4.1 về ghi nhật ký bắt đầu với cảnh báo rằng ...

Hoàn toàn lỗi thời. Hibernate sử dụng JBoss Logging bắt đầu từ phiên bản 4.0. Điều này sẽ được ghi lại khi chúng tôi di chuyển nội dung này sang Hướng dẫn dành cho nhà phát triển.

... tiếp tục nói về SLF4J, và như vậy là vô ích. Cả hướng dẫn bắt đầu và hướng dẫn nhà phát triển đều không nói về việc ghi nhật ký. Hướng dẫn di chuyển cũng không .

Tôi đã tìm kiếm tài liệu về jboss-logging, nhưng tôi không thể tìm thấy bất kỳ tài liệu nào. Các trang GitHub là im lặng , và JBoss của trang dự án cộng đồng không danh sách thậm chí JBoss-logging. Tôi tự hỏi liệu trình theo dõi lỗi của dự án có thể có bất kỳ vấn đề nào liên quan đến việc cung cấp tài liệu hay không, nhưng không.

Tin tốt là khi sử dụng Hibernate 4 bên trong một máy chủ ứng dụng, chẳng hạn như JBoss AS7, việc ghi nhật ký phần lớn được thực hiện cho bạn. Nhưng làm thế nào tôi có thể cấu hình nó trong một ứng dụng độc lập?


13
1 cho nhấn mạnh rằng tài liệu Hibernate về khai thác gỗ hết hạn
mhnagaoka

Người ta có thể đặt thuộc tính hệ thống org.jboss.logging.provide = slf4j. Để biết thêm chi tiết, vui lòng truy cập liên kết docs.jboss.org/hibernate/orm/4.3/topical/html/logging/… cho phiên bản ngủ đông lớn hơn 3.
Abhishek Ranjan

Câu trả lời:


60

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

Vì vậy, giá trị có thể cho org.jboss.logging.providerlà: jboss, jdk, log4j, slf4j.

Nếu bạn không đặt, org.jboss.logging.providernó sẽ thử jboss, sau đó log4j, sau đó slf4j (chỉ khi đăng nhập được sử dụng) và dự phòng thành jdk.

Tôi sử dụng slf4jvới logback-classic:

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

và tất cả đều hoạt động tốt!

CẬP NHẬT Một số người dùng sử dụng trong App.java rất chính:

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

nhưng đối với các giải pháp dựa trên vùng chứa, điều này không hoạt động.

CẬP NHẬT 2 Những người nghĩ rằng họ quản lý Log4j bằng SLF4J cho jboss-loggingnó thì không hẳn như vậy. jboss-loggingtrực tiếp sử dụng Log4j mà không cần SLF4J!


1
Đặt ở đâu org.jboss.logging.provider?
Suzan Cioc

1
@SuzanCioc Theo System.getProperty(LOGGING_PROVIDER_KEY);bạn cần đặt thuộc tính hệ thống. Thông qua java -D...=...hoặc kiểm tra tài liệu cho vùng chứa của bạn.
gavenkoa

1
Cập nhật thứ hai của bạn về việc không thể sử dụng log4j thông qua slf4j rất hữu ích. Việc đặt org.jboss.logging.provider thành slf4j khiến tôi nghĩ rằng việc hỗ trợ log4j của tôi sẽ có hiệu quả. Tuy nhiên, điều đó đã không xảy ra. Tôi phải đặt trực tiếp thành log4j để nó hoạt động. Kỳ quặc. Điểm của slf4j như một tùy chọn cho cấu hình này sau đó là gì?
Travis Spencer

27

Để SLF4J hoạt động với JBoss Logging mà không cần Logback vì phụ trợ yêu cầu sử dụng thuộc tính hệ thống org.jboss.logging.provider=slf4j. log4j-over-slf4jcác chiến thuật dường như không hoạt động trong trường hợp này vì việc ghi nhật ký sẽ trở lại JDK nếu cả Logback và log4j đều không thực sự xuất hiện trong classpath.

Điều này hơi phiền phức và để tự động phát hiện hoạt động, bạn phải thấy rằng trình nạp lớp chứa ít nhất ch.qos.logback.classic.Loggertừ logback-classic hoặc org.apache.log4j.Hierarchytừ log4j để lừa Ghi nhật ký JBoss không trở lại ghi nhật ký JDK.

Điều kỳ diệu được diễn giải tại org.jboss.logging.LoggerProviders

CẬP NHẬT: Hỗ trợ trình nạp dịch vụ đã được thêm vào để có thể tránh các vấn đề với tự động phát hiện bằng cách khai báo META-INF/services/org.jboss.logging.LoggerProvider(với org.jboss.logging.Slf4jLoggerProviderdưới dạng giá trị). Dường như cũng có hỗ trợ log4j2.


1
Tôi đặt thuộc tính hệ thống này ở đâu?
jhegedus

Tùy thuộc vào thiết lập của bạn, nhưng thông thường chỉ cần chuyển đổi dòng lệnh -Dorg.jboss.logging.provider=slf4jlà đủ. LoggingProviders.java cung cấp cho bạn thông tin chi tiết tốt hơn về các giá trị được chấp nhận hiện tại là gì và những gì sẽ có trong classpath.
Tuomas Kiviaho

2
Tôi không nghĩ rằng cách tiếp cận trình tải dịch vụ hoạt động vì Slf4jLoggerProviderkhông phải là một publiclớp?
holmis83

Tôi cần đặt org.jboss.logging.provider trong một weblogic WAR thành mã nguồn, nhưng bất kỳ bộ xâm nhập lớp tĩnh nào cũng được gọi sau LoggingProviders!
Antonio Petricca

12

Lấy cảm hứng từ bài đăng Hypoport của Leif , đây là cách tôi "bẻ cong" Hibernate 4 trở lại slf4j:

Giả sử bạn đang sử dụng Maven.

  • Thêm org.slf4j:log4j-over-slf4jnhư một phụ thuộc vào của bạnpom.xml
  • Sử dụng lệnh mvn dependency:tree, đảm bảo rằng không có tạo tác nào bạn đang sử dụng phụ thuộc vào slf4j:slf4j(chính xác là không có tạo tác nào có phụ thuộc phạm vi biên dịch hoặc phụ thuộc phạm vi thời gian chạyslf4j:slf4j )

Bối cảnh: Hibernate 4.x có phụ thuộc vào tạo tác org.jboss.logging:jboss-logging. Transitively, hiện tượng này có cung cấp phụ thuộc phạm vi trên vật slf4j:slf4j.

Vì bây giờ chúng ta đã thêm org.slf4j:log4j-over-slf4jhiện vật, org.slf4j:log4j-over-slf4jbắt chước slf4j:slf4jtạo tác. Do đó, mọi thứ mà JBoss Loggingcác bản ghi bây giờ sẽ thực sự đi qua slf4j.

Giả sử bạn đang sử dụng Logback làm chương trình phụ trợ ghi nhật ký của mình. Đây là một mẫupom.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>

Trên classpath của bạn, có một logback.xml, chẳng hạn như cái này nằm trong 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 -->

Một số thành phần có thể muốn có quyền truy cập logback.xmlvào thời điểm khởi động JVM để ghi nhật ký thích hợp, chẳng hạn như Plugin Jetty Maven. Trong trường hợp đó, hãy thêm một hệ thống Java logback.configurationFile=./path/to/logback.xmlvào lệnh của bạn (ví dụ mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run).

Trong trường hợp bạn vẫn nhận được đầu ra "thô" của bảng điều khiển Stdout Hibernate (như Hibernate: select ...), thì câu hỏi Stack Overflow " Tắt ghi nhật ký ngủ đông vào bảng điều khiển " có thể áp dụng.


1
Đảm bảo không có thư viện nào khác bao gồm log4j, nếu không điều này sẽ không hoạt động. Ví dụ: activemq-all.jar chứa log4j. Gợi ý: Mở IDE của bạn và dễ dàng tìm thấy log4j trong mã của bạn.
Dimitri Dewaele

Tôi đã gặp sự cố này với JBoss Hibernate4 và một máy chủ (quá) cũ. Bài đăng này, bao gồm 1 dòng trong application.properties đã giúp tôi. TNX vậy !!! Và dòng cuối cùng đó trong tài sản của tôi đã được viết trong một câu trả lời khác ở đây:org.jboss.logging.provider=slf4j
Jeroen van Dijk-Tháng sáu

8

Đầu tiên, bạn nhận ra rằng SLF4J không phải là một thư viện ghi nhật ký, nó là một trình bao bọc ghi nhật ký. Bản thân nó không ghi nhật ký bất cứ thứ gì, nó chỉ đơn giản là ủy quyền cho "phụ trợ".

Để "cấu hình" jboss-logging, bạn chỉ cần thêm bất kỳ khung nhật ký nào bạn muốn sử dụng trên classpath của mình (cùng với jboss-logging) và jboss-logging tìm ra phần còn lại.

Tôi đã tạo một hướng dẫn tập trung vào Hibernate cho cấu hình Ghi nhật ký JBoss: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html


2
Tôi nhận ra rằng SLF4J là một mặt tiền, vâng. Gửi đăng nhập Hibernate tới SLF4J có nghĩa là nó sẽ kết thúc ở bất kỳ phần phụ trợ nào mà tôi đã chọn cho phần còn lại của ứng dụng của mình, đó là những gì tôi muốn.
Tom Anderson,

10
Vì vậy, những gì bạn đang nói về cấu hình là không có cấu hình (thật tuyệt!), Nhưng việc ghi nhật ký jboss bằng cách nào đó phát hiện và chọn một chương trình phụ trợ? Ah, bây giờ tôi dành thời gian để thực sự xem mã, tôi thấy đó chính xácnhững gì sẽ xảy ra . Cụ thể, jboss-logging sẽ thử theo thứ tự JBoss LogManager, log4j, Logback qua SLF4J và ghi nhật ký JDK. Nhưng điều này có thể được ghi đè với thuộc tính org.jboss.logging.providerhệ thống.
Tom Anderson,

2
Nhiều người trong chúng ta đã bị đốt cháy bởi tính năng ghi nhật ký chung tìm ra những thứ cho bạn, vì vậy biết chính xác cách ghi nhật ký jboss hoạt động là rất quan trọng để có thể hỗ trợ nó trong thế giới thực khi điều bất ngờ xảy ra.
ams

1
Liên kết ở trên trong thực tế các chương trình chính xác những gì sẽ xảy ra nếu thats những gì bạn thực sự muốn xem, vì vậy không sau ...
Steve Ebersole

3

Tôi đang sử dụng Hibernate Core 4.1.7.Final cộng với Spring 3.1.2.RELEASE trong một ứng dụng độc lập. Tôi đã thêm Log4j 1.2.17 vào các phần phụ thuộc của mình và có vẻ như, vì JBoss Logging ghi trực tiếp vào log4j nếu có và Spring sử dụng Commons Logging, phù thủy cũng sử dụng Log4j nếu có, tất cả Logging có thể được định cấu hình thông qua Log4J.

Đây là danh sách các phụ thuộc có liên quan của tôi:

<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

vì vậy, nó chỉ hoạt động trong dự án của tôi. ngủ đông 4, slf4j, đăng nhập. dự án của tôi là gradle, nhưng sẽ giống như maven.

Về cơ bản, Abdull đã đúng. Trường hợp anh ta KHÔNG đúng, là bạn KHÔNG phải xóa slf4j khỏi các phần phụ thuộc.

  1. bao gồm để biên dịch phạm vi:

    org.slf4j: slf4j-api

    org.slf4j: log4j-over-slf4j

    ví dụ: đối với logback (ch.qos.logback: logback-classic, ch.qos.logback: logback-core: 1.0.12)

  2. loại trừ hoàn toàn libs log4j khỏi các phần phụ thuộc

kết quả: nhật ký ngủ đông qua slf4j để đăng nhập lại. tất nhiên bạn sẽ có thể sử dụng triển khai nhật ký khác với logback

để chắc chắn rằng không có log4j, hãy kiểm tra libs của bạn trên classpath hoặc web-inf / lib để tìm các tệp chiến tranh.

tất nhiên bạn đã thiết lập các trình ghi nhật ký trong logback.xml, ví dụ:

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


có vấn đề chính xác này. log4j được đưa vào như một phụ thuộc bắc cầu từ một thư viện khác. Đã loại trừ nó và ghi nhật ký ngủ đông bắt đầu hoạt động như mong đợi bằng cách sử dụng logback và cầu slf4j log4j
Paul Zepernick

3

Hibernate 4.3 có một số tài liệu về cách kiểm soát org.jboss.logging:

  • Nó tìm kiếm đường dẫn lớp cho một nhà cung cấp nhật ký . Nó tìm kiếm slf4j sau khi tìm kiếm log4j. Vì vậy, về lý thuyết, đảm bảo rằng classpath (WAR) của bạn không bao gồm log4j và không bao gồm API slf4j và back-end sẽ hoạt động.

  • Phương sách cuối cùng bạn có thể đặt thuộc tính org.jboss.logging.providerhệ thống slf4j.


Bất chấp các tuyên bố của tài liệu, org.jboss.loggingvẫn cố gắng sử dụng log4j, mặc dù log4j vắng mặt và SLF4J hiện diện, dẫn đến thông báo sau trong tệp nhật ký Tomcat của tôi ( /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.

Tôi đã phải làm theo gợi ý câu trả lời của dasAnderl ausMinga và bao gồm cả log4j-over-slf4jcây cầu.


2

Tôi sử dụng maven và thêm phần phụ thuộc sau:

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

Sau đó, tôi đã tạo một log4j.propertiestệp trong /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

Điều này sẽ đặt nó ở gốc của bạn .jar. Nó hoạt động như một say mê...


3
Điều này cấu hình việc sử dụng log4j. OP không muốn sử dụng log4j; họ muốn sử dụng slf4j.
Raedwald

1

Tôi đã gặp sự cố khi ghi nhật ký ngủ đông 4 hoạt động với weblogic 12c và log4j. Giải pháp là đặt nội dung sau vào weblogic-application.xml của bạn:

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

0

Đối với bất kỳ ai có thể gặp phải vấn đề tương tự như tôi. Trong trường hợp bạn đã thử tất cả các giải pháp khác được giải thích ở đây mà vẫn không thấy ghi nhật ký ngủ đông hoạt động với slf4j của mình, thì có thể là do bạn đang sử dụng một vùng chứa có trong thư viện thư mục của anh ấy là jboss-logging.jar. Điều này có nghĩa là nó được tải trước trước khi bạn thậm chí có thể đặt bất kỳ cấu hình nào để ảnh hưởng đến nó. Để tránh sự cố này trong weblogic, bạn có thể chỉ định trong tệp weblogic-application.xml trong tai bạn / META-INF để thích thư viện được tải từ ứng dụng. cần có một cơ chế tương tự cho các vùng chứa máy chủ khác. Trong trường hợp của tôi, tôi phải thêm:

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

bạn đã thử cái này chưa:

- slf4j-log4j12.jar trong trường hợp Log4J. Xem tài liệu SLF4J để biết thêm chi tiết. Để sử dụng Log4j, bạn cũng sẽ cần đặt tệp log4j.properties trong classpath của mình. Một tệp thuộc tính mẫu được phân phối với Hibernate trong thư mục src /

chỉ cần thêm các lọ và thuộc tính này hoặc log4j xml trong classpath


4
Đó là trích dẫn từ tài liệu Hibernate 3.x. Bạn có nghĩ rằng điều đó vẫn sẽ hoạt động với Hibernate 4.x, không sử dụng SLF4J?
Tom Anderson,

as far as i nhớ log4j là đủ
Avihai Marchiano
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.