Как настроить вход в Hibernate 4 для использования SLF4J?
Hibernate 3.x использовал slf4j для регистрации. Hibernate 4.x использует /questions/tagged/jboss-logging. Я пишу отдельное приложение, которое использует Hibernate 4 и SLF4J для ведения журнала.
Как я могу настроить Hibernate для входа в SLF4J?
Если это невозможно, как я могу настроить ведение журнала Hibernate?
Раздел руководства Hibernate 4.1 по ведению журнала начинается с предупреждения о том, что...
Полностью устаревший. Hibernate использует JBoss Logging начиная с 4.0. Это будет задокументировано, когда мы перенесем этот контент в Руководство разработчика.
... продолжает говорить о SLF4J, и поэтому бесполезен. Ни в руководстве по началу работы, ни в руководстве разработчика вообще не говорится о ведении журнала. Миграция не помогает.
Я искал документацию по самой jboss-logging, но я не смог найти ее вообще. На странице GitHub ничего не сказано, а на странице проектов сообщества JBoss нет даже регистрации jboss. Я задавался вопросом, могут ли у системы отслеживания ошибок этого проекта какие-либо проблемы, связанные с предоставлением документации, но это не так.
Хорошей новостью является то, что при использовании Hibernate 4 внутри сервера приложений, такого как JBoss AS7, ведение журнала в значительной степени позаботится о вас. Но как я могу настроить его в автономном приложении?
11 ответов
Просмотрите 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>
и все работает отлично!
ОБНОВЛЕНИЕ Некоторые пользователи используют в основном App.java:
static { //runs when the main class is loaded.
System.setProperty("org.jboss.logging.provider", "slf4j");
}
но для контейнерных решений это не работает.
ОБНОВЛЕНИЕ 2 Те, кто думает, что они управляют Log4j с SLF4J для jboss-logging
это не совсем так. jboss-logging
напрямую использует Log4j без SLF4J!
Чтобы заставить SLF4J работать с JBoss Logging без Logback, поскольку бэкэнд требует использования системного свойства org.jboss.logging.provider=slf4j
, log4j-over-slf4j
тактика, похоже, не работает в этом случае, потому что ведение журнала возвращается к JDK, если ни Logback, ни log4j фактически не присутствуют в classpath.
Это немного неприятно, и чтобы заставить автоопределение работать, вы видите, что загрузчик классов содержит по крайней мере ch.qos.logback.classic.Logger
от logback-classic или org.apache.log4j.Hierarchy
от log4j, чтобы обмануть ведение журнала JBoss, чтобы не возвращаться к ведению журнала JDK.
Магия интерпретируется в org.jboss.logging.LoggerProviders
ОБНОВЛЕНИЕ: добавлена поддержка загрузчика служб, поэтому можно избежать проблем с автоматическим определением, объявив META-INF/services/org.jboss.logging.LoggerProvider
(с org.jboss.logging.Slf4jLoggerProvider
как значение). Кажется, добавлена поддержка log4j2.
Вдохновленный постом Лейфа о Hypoport, я "наклонил" Hibernate 4 обратно к slf4j:
Давайте предположим, что вы используете Maven.
- добавлять
org.slf4j:log4j-over-slf4j
как зависимость от вашегоpom.xml
- Используя команду
mvn dependency:tree
убедитесь, что ни один из используемых вами артефактов не зависит от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>
На вашем classpath, есть 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 Plugin. В этом случае добавьте систему Java logback.configurationFile=./path/to/logback.xml
к вашей команде (например, mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run
).
Если вы все еще получаете "сырой" вывод консоли Hibernate (например, Hibernate: select ...
), затем может возникнуть вопрос переполнения стека " Отключить вход в спящий режим в консоль ".
Сначала вы понимаете, что SLF4J - это не библиотека журналов, а оболочка для журналов. Само по себе ничего не регистрирует, просто делегирует "бэкендам".
Чтобы "настроить" jboss-logging, вы просто добавляете любую структуру журнала, которую вы хотите использовать в вашем classpath (вместе с jboss-logging), и jboss-logging выясняет остальное.
Я создал руководство по настройке JBoss Logging, ориентированное на Hibernate: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html
Я использую Hibernate Core 4.1.7.Final plus 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>
Hibernate 4.3 имеет некоторую документацию о том, как контролировать org.jboss.logging
:
Он ищет путь к классу для провайдера журналов. Он ищет slf4j после поиска log4j. Итак, теоретически, обеспечение того, чтобы ваш classpath (WAR) не включал log4j и включал в себя API-интерфейс slf4j и серверную часть, должен работать.
В крайнем случае вы можете установить
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
мост.
Так что, просто заработал в моем проекте. hibernate 4, slf4j, выход из системы. мой проект gradle, но должен быть таким же для maven.
В основном Абдулл прав. Где он НЕ прав, так это то, что вы НЕ ДОЛЖНЫ удалять slf4j из зависимостей.
включить для компиляции области:
org.slf4j: SLF4J-апи
org.slf4j:log4j-над-SLF4J
например, для logback (ch.qos.logback:logback-classic, ch.qos.logback:logback-core:1.0.12)
полностью исключить библиотеки log4j из зависимостей
результат: вход в спящий режим через slf4j для выхода из системы. конечно, вы должны иметь возможность использовать другую реализацию журнала, чем logback
чтобы убедиться, что log4j отсутствует, проверьте свои библиотеки на classpath или web-inf/lib на наличие файлов war.
конечно, вы установили регистраторы в logback.xml, например:
<logger name="org.hibernate.SQL" level="TRACE"/>
Я использую 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
, Отлично работает...
У меня возникла проблема с работой журналирования 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>
Для любого, кто может столкнуться с той же проблемой, что и я. Если вы опробовали все другие решения, описанные здесь, и все еще не видите, что ведение журнала гибернации работает с вашим slf4j, это может быть связано с тем, что вы используете контейнер, в библиотеках его папок которого находится файл jboss-logging.jar. Это означает, что он предварительно загружен, прежде чем вы сможете настроить какую-либо конфигурацию для его влияния. Чтобы избежать этой проблемы в weblogic, вы можете указать в файле weblogic-application.xml в вашем ухе /META-INF, чтобы предпочесть библиотеку, загруженную из приложения. должен быть похожий механизм для других контейнеров сервера. В моем случае мне пришлось добавить:
<?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>
Ты пробовал это:
- slf4j-log4j12.jar в случае Log4J. Смотрите документацию SLF4J для более подробной информации. Чтобы использовать Log4j, вам также необходимо поместить файл log4j.properties в ваш путь к классам. Пример файла свойств распространяется с Hibernate в каталоге src/
просто добавьте эти jar и свойства или log4j xml в classpath