如何在 Hibernate 4 中配置日志记录以使用 SLF4J
Posted
技术标签:
【中文标题】如何在 Hibernate 4 中配置日志记录以使用 SLF4J【英文标题】:How do you configure logging in Hibernate 4 to use SLF4J 【发布时间】:2012-07-23 07:26:33 【问题描述】:Hibernate 3.x 使用 slf4j 进行日志记录。 Hibernate 4.x 使用jboss-logging。我正在编写一个使用 Hibernate 4 和 SLF4J 进行日志记录的独立应用程序。
如何配置 Hibernate 以登录到 SLF4J?
如果这不可能,我该如何配置 Hibernate 的日志记录?
Hibernate 4.1 手册section on logging 以警告开头...
完全过时了。 Hibernate 从 4.0 开始使用 JBoss Logging。当我们将此内容迁移到开发者指南时,这将被记录下来。
...继续谈论 SLF4J,所以没用。 getting started guide 和 developer guide 都没有谈论日志记录。 migration guide 也没有。
我已经查找了有关 jboss-logging 本身的文档,但我根本找不到任何文档。 GitHub page is silent 和 JBoss 的 community projects page 甚至没有列出 jboss-logging。我想知道项目的bug tracker 是否有与提供文档相关的任何问题,但事实并非如此。
好消息是,当在 JBoss AS7 等应用服务器中使用 Hibernate 4 时,日志记录在很大程度上会为您处理好。但是如何在独立应用程序中配置它?
【问题讨论】:
+1 用于突出显示有关日志记录的 Hibernate 文档已过时 可以设置系统属性org.jboss.logging.provide=slf4j。有关更多详细信息,请访问链接 docs.jboss.org/hibernate/orm/4.3/topical/html/logging/… 获取大于 3 的休眠版本。 【参考方案1】:看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
的可能值为:jboss
、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>
一切正常!
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 作为这个配置的一个选项有什么意义呢?【参考方案2】:
要让 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 日志记录不回退到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 之后调用任何静态类初始化器!【参考方案3】:
受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:slf4j
的provided 范围依赖。
由于我们现在添加了 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>%dHH:mm:ss.SSS [%thread] %-5level %logger36 - %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
【参考方案4】:
首先你确实意识到 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 的工作原理对于能够在意外发生时在现实世界中支持它至关重要。
上面的链接实际上显示了如果那是你真正想看到的会发生什么,所以不要关注......【参考方案5】:
我在独立应用程序中使用 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>
【讨论】:
【参考方案6】:所以,刚刚让它在我的项目中工作。休眠 4,slf4j,logback。我的项目是 gradle,但对于 maven 应该是一样的。
基本上阿卜杜勒是对的。他不正确的地方是,您不必从依赖项中删除 slf4j。
包含编译范围:
org.slf4j:slf4j-api
org.slf4j:log4j-over-slf4j
例如对于 logback (ch.qos.logback:logback-classic, ch.qos.logback:logback-core:1.0.12)
从依赖项中完全排除 log4j 库
结果:通过 slf4j 将日志休眠到 logback。 当然,您应该能够使用与 logback 不同的日志实现
为确保不存在 log4j,请检查类路径或 web-inf/lib 上的库以获取战争文件。
当然,您已经在 logback.xml 中设置了记录器,例如:
<logger name="org.hibernate.SQL" level="TRACE"/>
【讨论】:
有这个确切的问题。 log4j 是作为另一个库的传递依赖项引入的。排除它,休眠日志开始使用 logback 和 slf4j log4j 桥按预期工作【参考方案7】: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
桥。
【讨论】:
【参考方案8】:我使用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=%dABSOLUTE %5p %c1:%L - %m%n
# set log levels
log4j.rootLogger=warn
这会将它放在您的.jar
的根目录下。它就像一个魅力......
【讨论】:
这配置了 log4j 的使用。 OP 不想使用 log4j;他们想使用 slf4j。【参考方案9】:我在将 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>
【讨论】:
【参考方案10】:致任何可能面临与我相同问题的人。如果您尝试了这里解释的所有其他解决方案,但仍然没有看到休眠日志记录与您的 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>
【讨论】:
【参考方案11】:你试过了吗:
- slf4j-log4j12.jar 在 Log4J 的情况下。有关更多详细信息,请参阅 SLF4J 文档。要使用 Log4j,您还需要在类路径中放置一个 log4j.properties 文件。一个示例属性文件与 Hibernate 一起分发在 src/ 目录中
只需在类路径中添加这些 jar 和属性或 log4j xml
【讨论】:
这是来自 Hibernate 3.x 文档的引用。你认为这仍然适用于不使用 SLF4J 的 Hibernate 4.x 吗? 据我所知log4j就足够了以上是关于如何在 Hibernate 4 中配置日志记录以使用 SLF4J的主要内容,如果未能解决你的问题,请参考以下文章
使用 Log4j XML 配置文件配置 Hibernate 日志记录?