developer tip

SLF4J를 사용하도록 Hibernate 4에서 로깅을 구성하는 방법

optionbox 2020. 7. 29. 08:08
반응형

SLF4J를 사용하도록 Hibernate 4에서 로깅을 구성하는 방법


Hibernate 3.x 는 로깅을 위해 사용 . Hibernate 4.x는 사용합니다 . 로깅을 위해 Hibernate 4 및 SLF4J를 사용하는 독립형 응용 프로그램을 작성 중입니다.

SLF4J에 로그인하도록 Hibernate를 어떻게 구성 할 수 있습니까?

이것이 가능하지 않다면 어떻게 Hibernate의 로깅을 구성 할 수 있습니까?

로깅에 관한 Hibernate 4.1 매뉴얼 섹션 은 다음과 같은 경고로 시작됩니다.

완전히 구식입니다. Hibernate는 4.0부터 JBoss Logging을 사용합니다. 이 내용은 개발자 안내서로 마이그레이션 할 때 문서화됩니다.

... SLF4J에 대해 계속 이야기하며 쓸모가 없습니다. 어느 시작 안내서개발자 가이드 모두에서 로깅에 대한 이야기. 마이그레이션 가이드 도 아닙니다 .

jboss-logging 자체에 대한 문서를 찾았지만 전혀 찾을 수 없었습니다. GitHub의 페이지는 침묵 하고, 보스의 사회 프로젝트 페이지 도 목록 JBoss의 로깅을하지 않습니다. 프로젝트의 버그 추적기에 문서 제공과 관련된 문제가 있을지 궁금 했지만 그렇지 않았습니다.

좋은 소식은 JBoss AS7과 같은 응용 프로그램 서버에서 Hibernate 4를 사용할 때 로깅이 대부분 당신을 위해 처리된다는 것입니다. 그러나 독립형 응용 프로그램에서 어떻게 구성 할 수 있습니까?


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

그래서 사용할 수있는 값은 org.jboss.logging.provider다음과 같습니다 jboss, jdk, log4j, slf4j.

설정하지 않으면 org.jboss.logging.providerjboss, log4j, slf4j (로그 백이 사용 된 경우에만)를 시도하고 jdk로 대체합니다.

나는 slf4j함께 사용 logback-classic:

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

그리고 모두 잘 작동합니다!

업데이트 일부 사용자는 매우 주요 App.java에서 사용합니다.

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

그러나 컨테이너 기반 솔루션의 경우 작동하지 않습니다.

업데이트 2 SLF4J로 Log4j를 관리한다고 생각하는 사람들 jboss-logging은 정확하게 그렇지 않습니다. jboss-loggingSLF4J없이 Log4j를 직접 사용합니다!


백엔드로 SLF4J가 JBoss Logging과 Logback없이 작동하게하려면 시스템 속성을 사용해야합니다 org.jboss.logging.provider=slf4j. log4j-over-slf4jLogback이나 log4j가 클래스 경로에 실제로 존재하지 않으면 로깅이 JDK로 폴백하기 때문에이 경우에는 전술이 작동하지 않는 것 같습니다.

이것은 약간 성가신 일이며 자동 감지 기능을 사용하려면 클래스 로더에 적어도 ch.qos.logback.classic.Loggerlogback-classic 또는 org.apache.log4j.Hierarchylog4j가 포함되어 JBoss Logging이 JDK 로깅으로 넘어 가지 않도록 속이는 것을 알 수 있습니다.

마법은 org.jboss.logging.LoggerProviders

업데이트 : 서비스 로더 지원이 추가되었으므로 META-INF/services/org.jboss.logging.LoggerProvider( org.jboss.logging.Slf4jLoggerProvider값으로) 선언하여 자동 감지 문제를 피할 수 있습니다 . 지원 log4j2도 추가 된 것 같습니다.


Leif의 Hypoport post 에서 영감을 받아 , 이것이 Hibernate 4를 slf4j로 다시 "구부린"방법입니다.

Maven을 사용한다고 가정 해 봅시다.

  • org.slf4j:log4j-over-slf4j에 의존으로 추가pom.xml
  • 명령을 사용하여 mvn dependency:tree, 확인되지 아무도 당신에 DEPENDE을 사용하고있는 유물을 slf4j:slf4j(정확히 말하자면, 어떤 유물은지지 않습니다 컴파일 범위 의존성 또는 런타임 에 범위 종속 slf4j:slf4j)

배경 : Hibernate 4.x는 artifact에 의존합니다 org.jboss.logging:jboss-logging. 전 이적으로이 아티팩트는 아티팩트에 제공된 범위 종속성을 갖습니다 slf4j:slf4j.

이제 org.slf4j:log4j-over-slf4j아티팩트를 추가 org.slf4j:log4j-over-slf4j했으므로 아티팩트를 모방합니다 slf4j:slf4j. 따라서 JBoss Logging로그에 기록 된 모든 것이 실제로는 slf4j를 통해 전달됩니다.

Logback 을 로깅 백엔드로 사용한다고 가정 해 봅시다 . 여기 샘플이 있습니다pom.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>

클래스 패스에,이 logback.xml같은에 위치한이 하나 같이 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 -->

일부 구성 요소 ( logback.xml예 : Jetty Maven Plugin)와 같은 적절한 로깅을 위해 JVM 시작시 액세스 할 수 있습니다 . 이 경우 logback.configurationFile=./path/to/logback.xml명령에 Java 시스템 추가 하십시오 (예 :) mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run.

여전히 "raw"콘솔 stdout 최대 절전 모드 출력 (예 Hibernate: select ...:)이 표시되는 경우 스택 오버플로 질문 " 최대 절전 모드 로깅을 콘솔로 끄기 "가 적용될 수 있습니다.


First you do realize that SLF4J is not a logging library right, its a logging wrapper. It itself does not log anything, it simply delegates to "backends".

To "configure" jboss-logging you just add whatever log framework you want to use on your classpath (along with jboss-logging) and jboss-logging figures out the rest.

I created a Hibernate-focused guide to JBoss Logging config: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html


I'm using Hibernate Core 4.1.7.Final plus Spring 3.1.2.RELEASE in a standalone app. I added Log4j 1.2.17 to my dependencies and it seems, as JBoss Logging logs directly to log4j if available and Spring uses Commons Logging, witch also uses Log4j if available, all Logging could be configured via Log4J.

Here's my list of relevant dependencies:

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

Hibernate 4.3 has some documentation about how to control org.jboss.logging:

  • It searches the class-path for a logging provider. It searches for slf4j after searching for log4j. So, in theory, ensuring that your classpath (WAR) does not include log4j and does include the slf4j API and a back-end should work.

  • As a last resort you can set the org.jboss.logging.provider system property to slf4j.


Despite the claims of the documentation, org.jboss.logging insisted on trying to use log4j, despite log4j being absent and SLF4J being present, resulting in the following message in my Tomcat log file (/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.

I had to follow the suggestion of the answer by dasAnderl ausMinga and include the log4j-over-slf4j bridge.


I use maven and added the following dependency:

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

Then, I created a log4j.properties files 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

This will put it at the root of your .jar. It works like a charm...


so, just got it working in my project. hibernate 4, slf4j, logback. my project is gradle, but should be same for maven.

Basically Abdull is right. Where he is NOT right, is that you DONT have to remove slf4j from dependencies.

  1. include to compile scope:

    org.slf4j:slf4j-api

    org.slf4j:log4j-over-slf4j

    e.g. for logback (ch.qos.logback:logback-classic, ch.qos.logback:logback-core:1.0.12)

  2. completely exclude log4j libs from dependencies

result: hibernate logs via slf4j to logback. of course you should be able to use different log implementation than logback

to be sure that no log4j is present, check your libs on classpath or web-inf/lib for war files.

of course you have set the loggers in logback.xml e.g. :

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


I had an issue making hibernate 4 logging work with weblogic 12c and log4j. The solution is to put the following in your weblogic-application.xml:

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

To anyone that could face the same problem I had. In case you have tried all the other solutions explained here and still don't see hibernate logging working with your slf4j, it could be because you are using a container that has in his folder libraries the jboss-logging.jar. This means that gets preloaded before you can even set any configuration to influence it. To avoid this problem in weblogic you can specify in the file weblogic-application.xml in you ear/META-INF to prefer the library loaded from the application. there should be a similar mechanism for other server containers. In my case I had to add:

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

did you try this:

-Log4J의 경우 slf4j-log4j12.jar 자세한 내용은 SLF4J 설명서를 참조하십시오. Log4j를 사용하려면 클래스 경로에 log4j.properties 파일을 배치해야합니다. 예제 속성 파일은 src / 디렉토리에 Hibernate와 함께 배포됩니다

이러한 jar 및 속성 또는 log4j xml을 클래스 경로에 추가하십시오.

참고 URL : https://stackoverflow.com/questions/11639997/how-do-you-configure-logging-in-hibernate-4-to-use-slf4j

반응형