Como você configura o registro no Hibernate 4 para usar SLF4J

114

Hibernate 3.x usado para registro. Hibernate 4.x usa. Estou escrevendo um aplicativo autônomo que usa Hibernate 4 e SLF4J para registro.

Como posso configurar o Hibernate para fazer logon no SLF4J?

Se isso não for possível, como posso configurar o log do Hibernate?

A seção do manual do Hibernate 4.1 sobre registro começa com o aviso de que é ...

Totalmente desatualizado. O Hibernate usa o JBoss Logging a partir do 4.0. Isso será documentado à medida que migrarmos este conteúdo para o Guia do desenvolvedor.

... passa a falar sobre SLF4J, e por isso é inútil. Nem o guia de primeiros passos nem o guia do desenvolvedor falam sobre registro. Nem o guia de migração .

Procurei documentação sobre o próprio jboss-logging, mas não consegui encontrar nenhuma. A página do GitHub é silenciosa e a página de projetos da comunidade do JBoss nem mesmo lista o jboss-logging. Gostaria de saber se o rastreador de bugs do projeto pode ter problemas relacionados ao fornecimento de documentação, mas não tem.

A boa notícia é que, ao usar o Hibernate 4 dentro de um servidor de aplicativos, como o JBoss AS7, o registro é feito para você. Mas como posso configurá-lo em um aplicativo autônomo?

Tom Anderson
fonte
13
+1 para destacar que os documentos do Hibernate sobre registro estão desatualizados
mhnagaoka
Pode-se definir a propriedade do sistema org.jboss.logging.provide = slf4j. Para obter mais detalhes, visite o link docs.jboss.org/hibernate/orm/4.3/topical/html/logging/… para versão de hibernação superior a 3.
Abhishek Ranjan

Respostas:

60

Procure 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();
}

Então possíveis valores para org.jboss.logging.providersão: jboss, jdk, log4j, slf4j.

Se você não definir, org.jboss.logging.providerele tenta jboss, então log4j, então slf4j (somente se logback for usado) e fallback para jdk.

Eu uso slf4jcom logback-classic:

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.0.13</version>
        <scope>${logging.scope}</scope>
    </dependency>

e tudo funciona bem!

ATUALIZAÇÃO Alguns usuários usam no App.java principal:

static { //runs when the main class is loaded.
    System.setProperty("org.jboss.logging.provider", "slf4j");
}

mas para soluções baseadas em contêiner, isso não funciona.

ATUALIZAÇÃO 2 Quem pensa que gerencia o Log4j com SLF4J para jboss-loggingele não é exatamente assim. jboss-loggingusa diretamente Log4j sem SLF4J!

Gavenkoa
fonte
1
Onde definir org.jboss.logging.provider?
Suzan Cioc
1
@SuzanCioc De acordo com System.getProperty(LOGGING_PROVIDER_KEY);você precisa definir a propriedade do sistema. Por meio java -D...=...ou verifique os documentos do seu contêiner.
gavenkoa
1
Sua segunda atualização sobre não poder usar o log4j através do slf4j foi útil. Definir org.jboss.logging.provider como slf4j me fez pensar que meu apoio ao log4j entraria em ação. Mas não aconteceu. Tive que definir isso diretamente para log4j para que funcionasse. Ímpar. Qual é o objetivo de slf4j como uma opção para esta configuração então?
Travis Spencer
27

Para fazer o SLF4J funcionar com o JBoss Logging sem o Logback como backend, é necessário o uso de uma propriedade do sistema org.jboss.logging.provider=slf4j. log4j-over-slf4jas táticas não parecem estar funcionando neste caso, porque o registro retornará ao JDK se nem o Logback nem o log4j estiverem realmente presentes no classpath.

Isso é um pouco incômodo e para fazer a autodetecção funcionar, você viu que o classloader contém pelo menos ch.qos.logback.classic.Loggerfrom logback-classic ou org.apache.log4j.Hierarchyde log4j para enganar o JBoss Logging de não retroceder para o log do JDK.

A magia é interpretada em org.jboss.logging.LoggerProviders

ATUALIZAÇÃO: Foi adicionado suporte ao carregador de serviço para que seja possível evitar problemas com autodetecção declarando META-INF/services/org.jboss.logging.LoggerProvider(com org.jboss.logging.Slf4jLoggerProvidercomo um valor). Parece haver adicionado suporte log4j2 também.

Tuomas Kiviaho
fonte
1
Onde eu defino esta propriedade do sistema?
jhegedus
Depende da sua configuração, mas normalmente uma opção de linha de comando -Dorg.jboss.logging.provider=slf4jé suficiente. LoggingProviders.java oferece melhores percepções sobre quais são os valores aceitos atualmente e o que se espera que esteja presente no caminho de classe.
Tuomas Kiviaho
2
Não acho que a abordagem do carregador de serviço funcione porque Slf4jLoggerProvidernão é uma publicclasse?
holmis83 de
Preciso definir org.jboss.logging.provider em um WAR do weblogic no código-fonte, mas qualquer inicializador de classe estática é invocado após o LoggingProviders!
Antonio Petricca
12

Inspirado na postagem do Hypoport de Leif , é assim que "dobrei" o Hibernate 4 de volta ao slf4j:

Vamos supor que você esteja usando o Maven.

  • Adicione org.slf4j:log4j-over-slf4jcomo uma dependência ao seupom.xml
  • Usando o comando mvn dependency:tree, certifique-se de que nenhum dos artefatos que você está usando depende slf4j:slf4j(para ser preciso, nenhum artefato deve ter uma compilação dependência de escopo de ou dependência de escopo de tempo de execuçãoslf4j:slf4j )

Histórico: o Hibernate 4.x depende do artefato org.jboss.logging:jboss-logging . Transitivamente, esse artefato tem uma dependência de escopo fornecida no artefato slf4j:slf4j.

Como agora adicionamos o org.slf4j:log4j-over-slf4j artefato, ele org.slf4j:log4j-over-slf4jimita o slf4j:slf4jartefato. Portanto, tudo o que JBoss Loggingregistra agora irá, na verdade, via slf4j.

Digamos que você esteja usando Logback como back-end de registro. Aqui está um exemplopom.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>

Em seu classpath, tenha um logback.xml , como este localizado em 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 -->

Alguns componentes podem querer ter acesso a logback.xml no momento da inicialização da JVM para o registro adequado, por exemplo, o plug-in Jetty Maven. Nesse caso, adicione um sistema Java logback.configurationFile=./path/to/logback.xmlao seu comando (por exemplo mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run).

No caso de você ainda estar obtendo uma saída "bruta" do console stdout do Hibernate (como Hibernate: select ...), então a pergunta do Stack Overflow " Desligue o registro de hibernação no console " pode ser aplicada.

Abdull
fonte
1
Certifique-se de que nenhuma outra biblioteca inclui o log4j, ou isso não funcionará. Exemplo: activemq-all.jar contém log4j. Dica: Abra seu IDE e encontre log4j facilmente em seu código.
Dimitri Dewaele
Eu tive esse problema com o JBoss Hibernate4 e um servidor (muito) antigo. Este post, incluindo 1 linha em application.properties, funcionou para mim. Então, TNX !!! E essa última linha em minhas propriedades foi escrita em outra resposta aqui:org.jboss.logging.provider=slf4j
Jeroen van Dijk-Jun
8

Primeiro você percebe que SLF4J não é uma biblioteca de log, é um wrapper de log. Ele próprio não registra nada, ele simplesmente delega para "back-ends".

Para "configurar" o jboss-logging, você apenas adiciona qualquer estrutura de log que deseja usar em seu classpath (junto com o jboss-logging) e o jboss-logging descobre o resto.

Eu criei um guia focado no Hibernate para a configuração do JBoss Logging: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html

Steve Ebersole
fonte
2
Eu sei que SLF4J é uma fachada, sim. Enviar o registro do Hibernate para SLF4J significa que ele termina em qualquer backend que eu escolhi para o resto do meu aplicativo, que é o que eu quero.
Tom Anderson
10
Então, o que você está dizendo sobre a configuração é que não há configuração (o que é bom!), Mas que o jboss-logging de alguma forma detecta e seleciona um backend? Ah, agora aproveito para realmente olhar o código, vejo que é exatamente o que acontece . Especificamente, o jboss-logging tenta, em ordem, JBoss LogManager, log4j, Logback via SLF4J e log JDK. Mas isso pode ser substituído pela org.jboss.logging.providerpropriedade do sistema.
Tom Anderson
2
Muitos de nós foram queimados por commons-logging descobrir coisas para você, então saber exatamente como o jboss-logging funciona é crítico para ser capaz de suportá-lo no mundo real quando o inesperado acontecer.
ams
1
O link acima mostra exatamente o que acontece se isso é o que você realmente quer ver, então não seguir ...
Steve Ebersole
3

Estou usando o Hibernate Core 4.1.7.Final mais Spring 3.1.2.RELEASE em um aplicativo independente. Eu adicionei Log4j 1.2.17 às minhas dependências e parece que, como o JBoss Logging registra diretamente no log4j se disponível e Spring usa Commons Logging, que também usa Log4j se disponível, todo o Logging pode ser configurado via Log4J.

Esta é minha lista de dependências relevantes:

<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>
Stefan Scheidt
fonte
3

então, acabei de fazê-lo funcionar no meu projeto. hibernar 4, slf4j, logback. meu projeto é gradle, mas deve ser o mesmo para o maven.

Basicamente, Abdull está certo. Onde ele NÃO está certo, é que você NÃO tem que remover slf4j das dependências.

  1. inclua para compilar o escopo:

    org.slf4j: slf4j-api

    org.slf4j: log4j-over-slf4j

    por exemplo, para logback (ch.qos.logback: logback-classic, ch.qos.logback: logback-core: 1.0.12)

  2. excluir completamente as bibliotecas log4j das dependências

resultado: hibernar logs via slf4j para logback. claro que você deve ser capaz de usar uma implementação de log diferente de logback

para ter certeza de que nenhum log4j está presente, verifique sua biblioteca em classpath ou web-inf / lib para arquivos war.

é claro que você configurou os registradores em logback.xml, por exemplo:

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

dasAnderl ausMinga
fonte
teve exatamente esse problema. log4j estava sendo trazido como uma dependência transitiva de outra biblioteca. Excluído, e o registro de hibernação começou a funcionar como esperado usando logback e a ponte slf4j log4j
Paul Zepernick
3

O Hibernate 4.3 tem alguma documentação sobre como controlar org.jboss.logging:

  • Ele pesquisa o caminho da classe para um provedor de registro . Ele pesquisa slf4j após pesquisar log4j. Portanto, em teoria, garantir que seu classpath (WAR) não inclua log4j e inclua a API slf4j e um back-end deve funcionar.

  • Como último recurso, você pode definir a org.jboss.logging.providerpropriedade do sistema como slf4j.


Apesar das reclamações da documentação, org.jboss.logginginsistiu em tentar usar log4j, apesar de log4j estar ausente e SLF4J estar presente, resultando na seguinte mensagem em meu arquivo de log do 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.

Tive que seguir a sugestão da resposta de dasAnderl ausMinga e incluir a log4j-over-slf4jponte.

Raedwald
fonte
2

Eu uso o maven e adicionei a seguinte dependência:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.6</version>
</dependency>

Então, criei um log4j.propertiesarquivo em /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

Isso vai colocá-lo na raiz do seu .jar. Ele funciona como um encanto...

Jérôme Verstrynge
fonte
3
Isso configura o uso de log4j. O OP não deseja usar log4j; eles querem usar slf4j.
Raedwald
1

Tive um problema para fazer o registro do hibernate 4 funcionar com o weblogic 12c e o log4j. A solução é colocar o seguinte em seu weblogic-application.xml:

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

Para qualquer pessoa que pudesse enfrentar o mesmo problema que eu tive. Caso você tenha tentado todas as outras soluções explicadas aqui e ainda não veja o registro de hibernação funcionando com seu slf4j, pode ser porque você está usando um contêiner que tem em suas bibliotecas de pastas o jboss-logging.jar. Isso significa que ele é pré-carregado antes mesmo de você definir qualquer configuração para influenciá-lo. Para evitar este problema no weblogic você pode especificar no arquivo weblogic-application.xml em seu ear / META-INF para preferir a biblioteca carregada do aplicativo. deve haver um mecanismo semelhante para outros recipientes de servidor. No meu caso, tive que adicionar:

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

você tentou isto:

- slf4j-log4j12.jar no caso de Log4J. Consulte a documentação do SLF4J para obter mais detalhes. Para usar o Log4j, você também precisará colocar um arquivo log4j.properties em seu classpath. Um exemplo de arquivo de propriedades é distribuído com o Hibernate no diretório src /

basta adicionar esses jars e propriedades ou log4j xml no classpath

Avihai Marchiano
fonte
4
Essa é uma citação da documentação do Hibernate 3.x. Você acha que ainda funcionará com o Hibernate 4.x, que não usa SLF4J?
Tom Anderson
tanto quanto me lembro log4j é suficiente
Avihai Marchiano