118

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

如何配置 Hibernate 以登录到 SLF4J?

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

关于日志记录的 Hibernate 4.1 手册部分以警告说它是...

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

...继续谈论 SLF4J,所以没用。入门指南开发者指南都没有谈论日志记录。迁移指南也没有。

我一直在寻找关于 jboss-logging 本身的文档,但我根本找不到任何文档。GitHub 页面是静默的,JBoss 的社区项目页面甚至没有列出 jboss-logging。我想知道项目的错误跟踪器是否有任何与提供文档相关的问题,但事实并非如此。

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

4

11 回答 11

62

查看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.providerjboss, jdk, log4j, slf4j.

如果你不设置 org.jboss.logging.provider它会尝试 jboss,然后 log4j,然后 slf4j(仅当使用 logback 时)并回退到 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-logging不用SLF4J直接用Log4j!

于 2013-10-21T07:31:02.367 回答
27

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

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

魔术被解释为org.jboss.logging.LoggerProviders

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

于 2013-01-10T06:26:56.073 回答
12

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

假设您正在使用 Maven。

  • org.slf4j:log4j-over-slf4j作为依赖添加到您的pom.xml
  • 使用命令mvn dependency:tree,确保您使用的工件都不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在 JVM 启动时访问以进行正确的日志记录,例如 Jetty Maven 插件。在这种情况下,将 Java 系统添加logback.configurationFile=./path/to/logback.xml到您的命令中(例如mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run)。

如果您仍然获得“原始”控制台标准输出 Hibernate 输出(如Hibernate: select ...),则堆栈溢出问题“关闭休眠日志记录到控制台”可能适用。

于 2012-11-09T16:29:28.063 回答
8

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

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

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

于 2012-07-25T03:53:09.700 回答
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>
于 2012-10-18T09:03:04.897 回答
3

所以,刚刚让它在我的项目中工作。休眠 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 中设置了记录器,例如:

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

于 2013-10-18T08:09:17.070 回答
3

Hibernate 4.3 有一些关于如何控制的文档org.jboss.logging

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

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


尽管文档声称org.jboss.logging,尽管 log4j 不存在且 SLF4J 存在,但仍坚持尝试使用 log4j,导致我的 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桥梁。

于 2014-12-15T11:14:06.617 回答
1

我使用 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. 它就像一个魅力......

于 2012-08-17T20:02:45.247 回答
1

我在使 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>
于 2016-08-23T22:46:22.740 回答
0

对于任何可能面临同样问题的人。如果您尝试了这里解释的所有其他解决方案,但仍然没有看到休眠日志记录与您的 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>
于 2017-12-08T13:19:31.243 回答
-3

你试过这个吗:

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

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

于 2012-07-24T22:21:08.000 回答