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

Hibernate 3.x 使用 进行日志记录。Hibernate 4.x 使用 。我正在编写一个绿色软体,它使用 Hibernate 4和 SLf4J 进行日志记录。

How can i configure Hibernate to log to SLF4J?

如果这不可能,我怎么能配置 Hibernate 的日志呢?

Hibernate 4.1手动 关于测井的章节以警告开始,它是..。

完全过时了。Hibernate 从4.0开始使用 JBoss 日志记录。这将在我们将这些内容迁移到开发人员指南时得到记录。

... 继续谈论 SLF4J,所以是没有用的。无论是 开始指南还是 开发指南都不谈论日志记录。迁徙指南也是如此。

我已经查找了关于 jboss 日志记录本身的文档,但是完全没有找到任何文档。GitHub 页面是静默的和 JBoss 的 社区项目网页甚至没有列出 JBoss 日志记录。我想知道这个项目的 bug tracker是否有任何与提供文档相关的问题,但是它没有。

好消息是,当在应用服务器(比如 JBossAS7)中使用 Hibernate 4时,日志记录将在很大程度上为您解决。但是我怎样才能在绿色软体中配置它呢?

64540 次浏览

你试过这个吗:

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

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

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

要“配置”jboss 日志记录,只需在类路径上添加任何想要使用的日志框架(以及 jboss 日志记录) ,然后 jboss 日志记录就可以解决剩下的问题。

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

我使用了 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的根。它像一个魅力..。

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.

下面是我列出的相关依赖项:

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

利夫的 Hypoport 邮报的启发,下面是我如何将 Hibernate 4“弯曲”回 slf4j:

让我们假设你正在使用 Maven。

  • org.slf4j:log4j-over-slf4j作为依赖项添加到 pom.xml
  • 使用命令 mvn dependency:tree,确保您正在使用的工件的 none依赖于 slf4j:slf4j(确切地说,任何工件都不应该具有 compile作用域依赖关系或 运行时间作用域依赖关系)

背景: 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作为日志后端

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

Some components may want to have access to logback.xml at JVM start-up time for proper logging, for instance the Jetty Maven Plugin. In that case, add a Java system logback.configurationFile=./path/to/logback.xml to your command (e.g. mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run).

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

To get SLF4J to work with JBoss Logging without Logback as backend requires usage of a system property org.jboss.logging.provider=slf4j. log4j-over-slf4j tactics doesn't seem to be working in this case because the logging will fall back to JDK if neither Logback nor log4j isn't actually present in classpath.

这有点麻烦,为了让自动检测正常工作,您可以看到类加载器至少包含 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.LoggerProvider(以 org.jboss.logging.Slf4jLoggerProvider作为值)来避免自动检测问题。似乎还增加了对 log4j2的支持。

所以,只是让它工作在我的项目。休眠4,slf4j,日志。我的项目是 gradle 但 Maven 也应该是一样的。

基本上阿卜杜勒是正确的。他不正确的地方是,你不必从依赖关系中删除 slf4j。

  1. 包括编译范围:

    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. 从依赖项中完全排除 log4j 库

Result: hibernate 通过 slf4j 将日志记录回日志。 当然,您应该能够使用与 logback 不同的日志实现

为了确保不存在 log4j,请检查类路径或 web-inf/lib 中的 war 文件。

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

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

看看 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");
}

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

那些认为他们用 SLF4J 为 jboss-logging管理 Log4j 的人并不完全是这样。jboss-logging直接使用 Log4j 而不使用 SLF4J!

Hibernate 4.3 has 一些文件 about how to control org.jboss.logging:

  • 它在类路径中搜索 日志记录供应商。它在搜索 log4j 之后搜索 slf4j。因此,在理论上,确保类路径(WAR)不包含 log4j,而包含 slf4j API 和后端应该是可行的。

  • 作为最后的手段,您可以将 org.jboss.logging.provider系统属性设置为 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 (咒语) and include the log4j-over-slf4j bridge.

我在使用 weblogic12c 和 log4j 进行 hibernate 4日志记录时遇到了一个问题。解决方案是将以下内容放在您的 weblogic 应用程序中。Xml:

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

对任何可能面临和我一样问题的人。如果您已经尝试了这里介绍的所有其他解决方案,但仍然看不到使用 slf4j 进行 Hibernate 日志记录,这可能是因为您使用的容器的文件夹库中包含了 jboss-logging.jar。这意味着,在您可以设置任何配置来影响它之前,就已经预先加载了。 为了避免在 weblogic 中出现这个问题,您可以在 ear/META-INF 中的 weblogic-application.xml 文件中指定,以选择从应用程序加载的库。其他服务器容器应该有类似的机制。 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>