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


114

使用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-记录。我想知道项目的Bug跟踪程序是否可能与提供文档有关,但没有。

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


13
+1以突出显示有关记录的Hibernate文档已过时
mhnagaoka 2013年

可以设置系统属性org.jboss.logging.provide = slf4j。欲了解更多详情,请访问该链接docs.jboss.org/hibernate/orm/4.3/topical/html/logging/...对Hibernate的版本大于3
阿布舍克兰詹

Answers:


60

查看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管理Log4j的人jboss-logging并非完全如此。jboss-logging直接使用Log4j而不使用SLF4J!


1
在哪里设置org.jboss.logging.provider
Suzan Cioc 2014年

1
@SuzanCioc根据System.getProperty(LOGGING_PROVIDER_KEY);您的需要设置系统属性。通过java -D...=...或检查您的容器的文档。
gotnkoa 2014年

1
关于无法通过slf4j使用log4j的第二次更新很有帮助。将org.jboss.logging.provider设置为slf4j会让我觉得我对log4j的支持将会开始。我必须直接将其设置为log4j才能正常工作。奇。那么,slf4j作为此配置的选项有什么意义呢?
特拉维斯·斯宾塞

27

要使SLF4J在不使用Logback作为后端的情况下与JBoss Logging一起使用,需要使用系统属性org.jboss.logging.provider=slf4jlog4j-over-slf4j这种情况下策略似乎不起作用,因为如果在类路径中实际上没有Logback和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的支持。


1
在哪里设置此系统属性?
jhegedus 2014年

取决于您的设置,但是通常使用命令行开关-Dorg.jboss.logging.provider=slf4j就足够了。LoggingProviders.java使您可以更好地了解当前接受的值是什么以及类路径中应该出现的值。
Tuomas Kiviaho 2014年

2
我认为服务加载器方法Slf4jLoggerProvider不起作用,因为不是public类吗?
holmis83 '16

我需要将Weblogic WAR中的org.jboss.logging.provider设置为源代码,但是在LoggingProviders之后会调用任何静态类intiializer!
Antonio Petricca,

12

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

假设您正在使用Maven。

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

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


1
确保没有其他库遮挡log4j,否则将无法正常工作。示例:activemq-all.jar包含log4j。提示:打开您的IDE并在代码中轻松找到log4j。
Dimitri Dewaele 2013年

我在JBoss Hibernate4和(太旧的)服务器上遇到了这个问题。这篇文章(包括application.properties中的1行)对我有用。TNX !!!我财产的最后一行写在这里的另一个答案中:org.jboss.logging.provider=slf4j
Jeroen van Dijk-Jun

8

首先,您确实意识到SLF4J不是日志库,而是日志包装器。它本身不记录任何内容,仅将其委托给“后端”。

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

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


2
我确实意识到SLF4J是一个外观,是的。将Hibernate日志发送到SLF4J意味着它最终会在我为我的其余应用程序选择的任何后端上实现,这正是我想要的。
汤姆·安德森

10
因此,您对配置的意思是没有配置(很好!),但是jboss-logging以某种方式检测并选择了后端?啊,我现在花时间来实际看代码,我看这是什么情况。具体来说,jboss-logging依次尝试JBoss LogManager,log4j,通过SLF4J进行Logback和JDK日志记录。但这可以org.jboss.logging.provider系统属性覆盖。
汤姆·安德森

2
我们许多人都被公共日志记录所困扰,无法为您解决问题,因此准确了解jboss日志记录的工作方式对于在意外情况下能够在现实世界中提供支持至关重要。
2012年

1
实际上,上面的链接准确地显示了如果那是您真正想要看到的,那么该怎么办,所以不要关注……
Steve Ebersole

3

我在一个独立的应用程序中使用了Hibernate Core 4.1.7.Final和Spring 3.1.2.RELEASE。我将Log4j 1.2.17添加到了我的依赖项中,似乎,因为JBoss Logging将日志直接记录到log4j(如果可用),而Spring使用Commons Logging,witch也使用Log4j(如果可用),则可以通过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>

3

因此,只需在我的项目中使用它即可。休眠4,slf4j,重新登录。我的项目是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不同的日志实现

要确保没有log4j存在,请检查您在classpath或web-inf / lib上的库是否包含war文件。

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

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


有这个确切的问题。log4j作为传递依赖关系从另一个库引入。排除了它,休眠日志使用logback和slf4j log4j网桥按预期开始工作
Paul Zepernick

3

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

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

  • 作为最后的选择,您可以将org.jboss.logging.providersystem属性设置为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桥。


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


3
这将配置log4j的使用。OP不想使用log4j。他们想使用slf4j。
Raedwald 2014年

1

我在使休眠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>

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>

-2

您是否尝试过:

-如果是Log4J,则为slf4j-log4j12.jar。有关更多详细信息,请参见SLF4J文档。要使用Log4j,您还需要在类路径中放置一个log4j.properties文件。Hibernate在src /目录中分发了一个示例属性文件

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


4
这是来自Hibernate 3.x文档的引文。您是否认为该方法仍适用于不使用SLF4J的Hibernate 4.x?
汤姆·安德森

据我记得log4j够了
Avihai Marchiano
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.