【问题标题】:How do you configure logging in Hibernate 4 to use SLF4J如何在 Hibernate 4 中配置日志记录以使用 SLF4J
【发布时间】:2012-07-23 07:26:33
【问题描述】:

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 时,日志记录在很大程度上会为您处理好。但是如何在独立应用程序中配置它?

【问题讨论】:

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


【解决方案1】:

你试过了吗:

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

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

【讨论】:

  • 这是来自 Hibernate 3.x 文档的引用。你认为这仍然适用于不使用 SLF4J 的 Hibernate 4.x 吗?
  • 据我所知log4j就足够了
【解决方案2】:

首先你确实意识到 SLF4J 不是一个日志库,它是一个日志包装器。它本身不记录任何东西,它只是委托给“后端”。

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

我创建了一个以 Hibernate 为中心的 JBoss 日志配置指南:http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html

【讨论】:

  • 我确实意识到 SLF4J 是一个门面,是的。将 Hibernate 日志发送到 SLF4J 意味着它会在我为应用程序的其余部分选择的任何后端结束,这就是我想要的。
  • 那么您所说的配置是没有配置(这很好!),但是 jboss-logging 以某种方式检测并选择了一个后端?啊,现在我花时间实际查看代码,我看到那是exactly what happens。具体来说,jboss-logging 按顺序尝试 JBoss LogManager、log4j、通过 SLF4J 的 Logback 和 JDK 日志记录。但是这个可以org.jboss.logging.provider系统属性覆盖。
  • 我们中的许多人都被 commons-logging 为您找出问题所困扰,因此准确了解 jboss-logging 的工作原理对于能够在意外发生时在现实世界中支持它至关重要。
  • 上面的链接实际上显示了如果那是你真正想看到的会发生什么,所以不要关注......
【解决方案3】:

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

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

然后,我在/src/main/resources 中创建了一个log4j.properties 文件:

# 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 的根目录下。它就像一个魅力......

【讨论】:

  • 这配置了 log4j 的使用。 OP 不想使用 log4j;他们想使用 slf4j。
【解决方案4】:

我在独立应用程序中使用 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】:

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

    假设您使用的是 Maven。

    • org.slf4j:log4j-over-slf4j 添加为pom.xml 的依赖项
    • 使用命令mvn dependency:tree,确保没有您正在使用的工件依赖于slf4j:slf4j(准确地说,任何工件都不应有编译范围依赖或 runtime 范围依赖于 slf4j:slf4j)

    背景:Hibernate 4.x 依赖于工件 org.jboss.logging:jboss-logging。传递地,该工件具有对工件slf4j:slf4jprovided 范围依赖。

    由于我们现在添加了 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 -->
    

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

    如果您仍然获得“原始”控制台标准输出 Hibernate 输出(如 Hibernate: select ...),则可能适用堆栈溢出问题“Turn off hibernate logging to console”。

    【讨论】:

    • 确保没有其他库包含 log4j,否则这将不起作用。示例:activemq-all.jar 包含 log4j。提示:打开 IDE 并在代码中轻松找到 log4j。
    • 我在使用 JBoss Hibernate4 和(太)旧的服务器时遇到了这个问题。这篇文章,包括 application.properties 中的 1 行,对我有用。所以TNX!!!我属性中的最后一行写在另一个答案中:org.jboss.logging.provider=slf4j
    【解决方案6】:

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

    这有点麻烦,为了让自动检测正常工作,你看到类加载器至少包含来自 logback-classic 的 ch.qos.logback.classic.Logger 或来自 log4j 的 org.apache.log4j.Hierarchy 以欺骗 JBoss 日志记录不回退到JDK 日志记录。

    魔法在org.jboss.logging.LoggerProviders解释

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

    【讨论】:

    • 我在哪里设置这个系统属性?
    • 取决于您的设置,但通常命令行开关-Dorg.jboss.logging.provider=slf4j 就足够了。 LoggingProviders.java 让您更好地了解当前接受的值是什么以及类路径中应该出现什么。
    • 我认为服务加载器方法不起作用,因为Slf4jLoggerProvider 不是public 类?
    • 我需要将 weblogic WAR 中的 org.jboss.logging.provider 设置到源代码中,但是在 LoggingProviders 之后调用任何静态类初始化器!
    【解决方案7】:

    所以,刚刚让它在我的项目中工作。休眠 4,slf4j,logback。我的项目是 gradle,但对于 maven 应该是一样的。

    基本上阿卜杜勒是对的。他不对的地方是,您不必从依赖项中删除 slf4j。

    1. 包含编译范围:

      org.slf4j:slf4j-api

      org.slf4j:log4j-over-slf4j

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

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

    结果:通过 slf4j 将日志休眠到 logback。 当然,您应该能够使用与 logback 不同的日志实现

    为确保不存在 log4j,请检查类路径或 web-inf/lib 上的库以获取战争文件。

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

    &lt;logger name="org.hibernate.SQL" level="TRACE"/&gt;

    【讨论】:

    • 有这个确切的问题。 log4j 是作为另一个库的传递依赖项引入的。排除它,休眠日志开始使用 logback 和 slf4j log4j 桥按预期工作
    【解决方案8】:

    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 直接用Log4j,不用SLF4J!

    【讨论】:

    • 在哪里设置org.jboss.logging.provider
    • @SuzanCioc 根据System.getProperty(LOGGING_PROVIDER_KEY);,您需要设置系统属性。通过java -D...=... 或查看容器的文档。
    • 您关于无法通过 slf4j 使用 log4j 的第二次更新很有帮助。将 org.jboss.logging.provider 设置为 slf4j 让我觉得我对 log4j 的支持会起作用。但事实并非如此。我必须将其直接设置为 log4j 才能使其正常工作。奇怪的。那么 slf4j 作为这个配置的一个选项有什么意义呢?
    【解决方案9】:

    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) 中出现以下消息:

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

    【讨论】:

      【解决方案10】:

      我在将 hibernate 4 日志记录与 weblogic 12c 和 log4j 一起工作时遇到了问题。解决方案是将以下内容放在您的 weblogic-application.xml 中:

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

      【讨论】:

        【解决方案11】:

        致任何可能面临与我相同问题的人。如果您尝试了这里解释的所有其他解决方案,但仍然没有看到休眠日志记录与您的 slf4j 一起工作,这可能是因为您使用的容器在他的文件夹库中包含 jboss-logging.jar。这意味着在您甚至可以设置任何配置来影响它之前就已预加载。 为避免 weblogic 中出现此问题,您可以在 ear/META-INF 中的文件 weblogic-application.xml 中指定首选从应用程序加载的库。其他服务器容器应该有类似的机制。 就我而言,我必须添加:

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

        【讨论】:

          猜你喜欢
          • 2011-10-18
          • 2011-03-24
          • 1970-01-01
          • 1970-01-01
          • 2010-09-30
          • 1970-01-01
          • 2012-07-29
          • 2017-06-06
          相关资源
          最近更新 更多