Как настроить ведение журнала в Hibernate 4 для использования SLF4J

114

Hibernate 3.x используется для регистрации. Hibernate 4.x использует. Я пишу автономное приложение, которое использует Hibernate 4 и SLF4J для ведения журнала.

Как я могу настроить Hibernate для входа в SLF4J?

Если это невозможно, как я могу вообще настроить ведение журнала Hibernate?

Раздел руководства Hibernate 4.1 по ведению журнала начинается с предупреждения, что это ...

Полностью устарело. Hibernate использует ведение журнала JBoss, начиная с версии 4.0. Это будет задокументировано, когда мы перенесем это содержимое в Руководство разработчика.

... продолжает говорить о SLF4J, и поэтому бесполезен. Ни руководство по началу работы, ни руководство разработчика вообще не говорят о ведении журнала. Нет и руководства по миграции .

Я искал документацию по самому jboss-logging, но мне не удалось ее найти. Страница GitHub молчит , а страница проектов сообщества JBoss даже не перечисляет jboss-logging. Мне было интересно, могут ли быть в системе отслеживания ошибок проекта какие-либо проблемы, связанные с предоставлением документации, но это не так.

Хорошая новость заключается в том, что при использовании Hibernate 4 внутри сервера приложений, такого как JBoss AS7, ведение журнала в значительной степени заботится о вас. Но как его настроить в отдельном приложении?

Том Андерсон
источник
13
+1 за то, что подчеркнули, что документы Hibernate по журналированию устарели
mhnagaoka
Можно установить системное свойство org.jboss.logging.provide = slf4j. Для получения дополнительной информации посетите ссылку docs.jboss.org/hibernate/orm/4.3/topical/html/logging/… для версии спящего режима выше 3.
Абхишек Ранджан,

Ответы:

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являются: jboss, jdk, log4j, slf4j.

Если вы не установили, org.jboss.logging.providerон пробует jboss, затем log4j, затем slf4j (только если используется логбэк) и откат к 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!

gavenkoa
источник
1
Где ставить org.jboss.logging.provider?
Suzan Cioc
1
@SuzanCioc По System.getProperty(LOGGING_PROVIDER_KEY);вашему желанию необходимо установить системное свойство. Просмотрите java -D...=...или проверьте документы для вашего контейнера.
gavenkoa
1
Ваше второе обновление о невозможности использовать log4j через slf4j было полезным. Установка org.jboss.logging.provider на slf4j заставила меня подумать, что моя поддержка log4j сработает. Однако этого не произошло. Мне пришлось установить это непосредственно на log4j, чтобы это работало. Странный. В чем тогда смысл slf4j как опции для этой конфигурации?
Трэвис Спенсер
27

Чтобы заставить SLF4J работать с JBoss Logging без Logback в качестве бэкэнда, требуется использование системного свойства org.jboss.logging.provider=slf4j. log4j-over-slf4jВ этом случае тактика, похоже, не работает, потому что ведение журнала вернется к JDK, если ни Logback, ни log4j на самом деле не присутствуют в пути к классам.

Это немного неприятно, и для того, чтобы автоопределение работало, вы должны увидеть, что загрузчик классов содержит по крайней мере 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.

Туомас Кивиахо
источник
1
Где мне установить это системное свойство?
jhegedus
Зависит от ваших настроек, но обычно достаточно переключателя командной строки -Dorg.jboss.logging.provider=slf4j. LoggingProviders.java дает вам лучшее представление о текущих принятых значениях и о том, что ожидается в пути к классам.
Туомас Кивиахо
2
Я не думаю, что подход с загрузкой сервисов работает, потому что Slf4jLoggerProviderэто не publicкласс?
holmis83
Мне нужно установить org.jboss.logging.provider в Weblogic WAR в исходный код, но любой инициализатор статического класса вызывается после LoggingProviders!
Антонио Петрикка
12

Вдохновленный публикацией Лейфа о 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. В этом случае добавьте logback.configurationFile=./path/to/logback.xmlв свою команду систему Java (например mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run).

Если вы все еще получаете "необработанный" консольный стандартный вывод Hibernate (например Hibernate: select ...), тогда может применяться вопрос о переполнении стека: " Отключить ведение журнала гибернации на консоли ".

Abdull
источник
1
Убедитесь, что никакая другая библиотека не содержит log4j, иначе это не сработает. Пример: activemq-all.jar содержит log4j. Подсказка: откройте свою среду IDE и легко найдите log4j в своем коде.
Dimitri Dewaele
У меня была эта проблема с JBoss Hibernate4 и (слишком) старым сервером. Этот пост, включая 1 строку в application.properties, помог мне. Итак TNX !!! И эта последняя строка в моих свойствах была написана здесь в другом ответе:org.jboss.logging.provider=slf4j
Йерун ван Дейк - июн
8

Сначала вы понимаете, что SLF4J - это не библиотека для ведения журнала, а его оболочка для ведения журнала. Сам он ничего не регистрирует, он просто делегирует "бэкэндам".

Чтобы «настроить» jboss-logging, вы просто добавляете любую структуру журналов, которую хотите использовать в своем пути к классам (вместе с jboss-logging), а jboss-logging вычисляет все остальное.

Я создал ориентированное на Hibernate руководство по конфигурации JBoss Logging: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html

Стив Эберсол
источник
2
Я понимаю, что SLF4J - это фасад, да. Отправка журнала Hibernate в SLF4J означает, что он попадает в любой бэкэнд, который я выбрал для остальной части моего приложения, чего я и хочу.
Tom Anderson
10
Итак, что вы говорите о конфигурации, так это то, что конфигурации нет (что приятно!), Но что jboss-logging каким-то образом обнаруживает и выбирает бэкэнд? Ах, теперь я нахожу время, чтобы действительно взглянуть на код, я вижу, что именно это и происходит . В частности, jboss-logging пытается, по порядку, JBoss LogManager, log4j, Logback через SLF4J и JDK logging. Но это можно изменить с помощью org.jboss.logging.providerсистемного свойства.
Tom Anderson
2
Многие из нас были обожжены общедоступным журналированием вещей, поэтому знание того, как именно работает jboss-logging, имеет решающее значение для поддержки его в реальном мире, когда случаются непредвиденные обстоятельства.
AMS,
1
Ссылка выше на самом деле показывает, что именно произойдет, если это то, что вы действительно хотите увидеть, так что не следите за ...
Стив Эберсол
3

Я использую Hibernate Core 4.1.7.Final плюс Spring 3.1.2.RELEASE в отдельном приложении. Я добавил Log4j 1.2.17 к своим зависимостям, и, похоже, поскольку JBoss Logging ведет журнал напрямую в log4j, если он доступен, а Spring использует Commons Logging, ведьма также использует 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-апи

    org.slf4j: log4j-over-slf4j

    например, для входа в систему (ch.qos.logback: logback-classic, ch.qos.logback: logback-core: 1.0.12)

  2. полностью исключить библиотеки log4j из зависимостей

результат: журналы гибернации через slf4j для возврата. конечно, вы должны иметь возможность использовать другую реализацию журнала, чем logback

чтобы убедиться, что log4j отсутствует, проверьте свои библиотеки в пути к классам или в web-inf / lib на наличие файлов war.

конечно, вы установили регистраторы в logback.xml, например:

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

dasAnderl ausMinga
источник
была именно эта проблема. log4j вводился как транзитивная зависимость от другой библиотеки. Исключил его, и ведение журнала гибернации начало работать должным образом с использованием логбэка и моста slf4j log4j
Пол Зеперник,
3

В Hibernate 4.3 есть документация о том, как управлять org.jboss.logging:

  • Он ищет путь к классу для поставщика журналов . Он ищет slf4j после поиска log4j. Итак, теоретически убедитесь, что ваш путь к классам (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мост.

Raedwald
источник
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
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>
гозер
источник
0

Всем, кто мог столкнуться с той же проблемой, что и я. Если вы пробовали все другие решения, описанные здесь, и по-прежнему не видите, что ведение журнала гибернации работает с вашим 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>
Massimo
источник
-2

ты пробовал это:

- slf4j-log4j12.jar в случае Log4J. См. Документацию SLF4J для более подробной информации. Чтобы использовать Log4j, вам также необходимо поместить файл log4j.properties в путь к классам. Пример файла свойств распространяется вместе с Hibernate в каталоге src /.

просто добавьте эти банки и свойства или log4j xml в путь к классам

Авихай Марчиано
источник
4
Это цитата из документации Hibernate 3.x. Как вы думаете, он по-прежнему будет работать с Hibernate 4.x, который не использует SLF4J?
Tom Anderson
Насколько я помню, достаточно log4j
Авихай Марчиано