如何在Hibernate 4中配置日志记录以使用SLF4J

时间:2012-07-24 22:02:27

标签: hibernate logging slf4j hibernate-4.x jboss-logging

Hibernate 3.x使用进行日志记录。 Hibernate 4.x使用。我正在编写一个独立的应用程序,它使用Hibernate 4和SLF4J进行日志记录。

如何配置Hibernate以登录SLF4J?

如果那不可能,我该如何配置Hibernate的日志记录?

Hibernate 4.1手册section on logging首先警告它是......

  

完全过时了。 Hibernate从4.0开始使用JBoss Logging。当我们将此内容迁移到开发人员指南时,这将记录在案。

...继续谈论SLF4J,所以没用。 getting started guidedeveloper guide都没有谈论日志记录。 migration guide也没有。

我已经查找了有关jboss-logging本身的文档,但我根本找不到任何文档。 GitHub page is silent和JBoss的community projects page甚至没有列出jboss-logging。我想知道项目的bug tracker是否可能有任何与提供文档相关的问题,但事实并非如此。

好消息是,当在应用程序服务器(如JBoss AS7)中使用Hibernate 4时,很大程度上会记录日志记录。但是我如何在独立应用程序中配置它呢?

11 个答案:

答案 0 :(得分:56)

查看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的可能值为:jbossjdklog4jslf4j

如果你没有设置org.jboss.logging.provider它会尝试jboss,那么log4j,然后是slf4j(仅当使用了logback)并且回退到jdk。

我将slf4jlogback-classic

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

一切正常!

UPDATE 有些用户在非常主要的App.java中使用:

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

但对于基于容器的解决方案,这是行不通的。

更新2 那些认为他们使用SLF4J为jboss-logging管理Log4j的人并非如此。 jboss-logging直接使用没有SLF4J的Log4j!

答案 1 :(得分:27)

要使SLF4J与没有Logback的JBoss Logging一起使用,因为后端需要使用系统属性org.jboss.logging.provider=slf4j。在这种情况下,log4j-over-slf4j策略似乎并不起作用,因为如果Logback和log4j实际上都不存在于类路径中,则日志记录将回退到JDK。

这有点令人讨厌,为了使自动检测工作,您已经看到类加载器至少包含来自logback-classic的ch.qos.logback.classic.Logger或来自log4j的org.apache.log4j.Hierarchy来欺骗JBoss Logging不要退回到JDK日志记录。

魔法在org.jboss.logging.LoggerProviders

解释

更新:添加了服务加载程序支持,因此可以通过声明META-INF/services/org.jboss.logging.LoggerProviderorg.jboss.logging.Slf4jLoggerProvider作为值)来避免自动检测出现问题。似乎还增加了对log4j2的支持。

答案 2 :(得分:12)

Leif's Hypoport post的启发,这就是我将Hibernate 4“弯曲”回slf4j的方式:

我们假设你正在使用Maven。

  • org.slf4j:log4j-over-slf4j作为依赖关系添加到pom.xml
  • 使用命令mvn dependency:tree,确保您使用的工件的依赖于slf4j:slf4j(确切地说,没有工件应该具有编译范围依赖关系或运行时范围依赖于slf4j:slf4j

背景:Hibernate 4.x依赖于工件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

某些组件可能希望在JVM启动时有权访问logback.configurationFile=./path/to/logback.xml以进行正确的日志记录,例如Jetty Maven插件。在这种情况下,请在命令中添加Java系统mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run(例如Hibernate: select ...)。

如果您仍然获得“原始”控制台标准输出Hibernate输出(如{{1}}),则Stack Overflow问题“Turn off hibernate logging to console”可能适用。

答案 3 :(得分:8)

首先,您确实意识到SLF4J不是正确的日志记录库,它是一个日志记录包装器。它本身不会记录任何内容,它只是委托“后端”。

要“配置”jboss-logging,你只需在类路径中添加你想要使用的任何日志框架(以及jboss-logging),jboss-logging会计算其余部分。

我创建了一个专注于Hibernate的JBoss Logging配置指南:http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html

答案 4 :(得分:3)

我在一个独立的应用程序中使用Hibernate Core 4.1.7.Final和Spring 3.1.2.RELEASE。我将Log4j 1.2.17添加到我的依赖项中,看起来,JBoss Logging直接记录到log4j(如果可用),Spring使用Commons Logging,如果可用的话,还使用Log4j,所有Logging都可以通过Log4J配置。

这是我的相关依赖项列表:

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

答案 5 :(得分:3)

Hibernate 4.3有some documentation关于如何控制org.jboss.logging

  • 它在类路径中搜索日志记录提供程序。它在搜索log4j后搜索slf4j。因此,理论上,确保您的类路径(WAR)不包含log4j,并且确实包含slf4j API和后端应该可以工作。

  • 作为最后的手段,您可以将org.jboss.logging.provider系统属性设置为slf4j


尽管有文档声明,org.jboss.logging坚持尝试使用log4j,尽管缺少log4j并且存在SLF4J,导致我的Tomcat日志文件(/var/log/tomcat/catalina.out)中出现以下消息:< / p>

 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.

我必须按照dasAnderl ausMinga的回答建议,并加入log4j-over-slf4j桥。

答案 6 :(得分:2)

我使用maven并添加了以下依赖项:

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

然后,我在log4j.properties中创建了/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

这将把它放在.jar的根部。它就像一个魅力......

答案 7 :(得分:2)

所以,让它在我的项目中工作。 hibernate 4,slf4j,logback。我的项目是gradle,但对于maven应该是相同的。

基本上Abdull是对的。在他不对的地方,你是不是必须从依赖中移除slf4j。

  1. 包括编译范围:

    org.slf4j:SLF4J-API

    org.slf4j:log4j的-过SLF4J

    例如用于logback(ch.qos.logback:logback-classic,ch.qos.logback:logback-core:1.0.12)

  2. 完全从依赖项中排除log4j库

  3. 结果:hibernate通过slf4j登录到logback。 当然,您应该能够使用与logback不同的日志实现

    要确保没有log4j,请检查classpath或web-inf / lib上的libs以获取war文件。

    当然你已经在logback.xml中设置了记录器,例如:

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

答案 8 :(得分:1)

我在使用weblogic 12c和log4j进行hibernate4日志记录时遇到了问题。解决方案是将以下内容放在weblogic-application.xml中:

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

答案 9 :(得分:0)

任何可能面临同样问题的人。如果你已经尝试了这里解释的所有其他解决方案,但仍然没有看到hibernate日志记录与你的slf4j一起工作,那可能是因为你正在使用一个容器,在他的文件夹库中有jboss-logging.jar。这意味着在您甚至可以设置任何配置以影响它之前预先加载。 要在weblogic中避免此问题,您可以在ear ear / META-INF中的weblogic-application.xml文件中指定优先选择从应用程序加载的库。其他服务器容器应该有类似的机制。 在我的情况下,我不得不补充:

test.jar

答案 10 :(得分:-2)

你尝试过这个:

- 在Log4J的情况下为slf4j-log4j12.jar。有关更多详细信息,请参阅SLF4J文档。要使用Log4j,您还需要在类路径中放置log4j.properties文件。 Hibernate在src /目录

中分发了一个示例属性文件

只需在类路径中添加这些jar和属性或log4j xml