¿Cómo se configura el inicio de sesión en Hibernate 4 para usar SLF4J?

114

Hibernate 3.x utilizado para la tala. Usos de Hibernate 4.x. Estoy escribiendo una aplicación independiente que usa Hibernate 4 y SLF4J para el registro.

¿Cómo puedo configurar Hibernate para iniciar sesión en SLF4J?

Si eso no es posible, ¿cómo puedo configurar el registro de Hibernate?

La sección del manual de Hibernate 4.1 sobre registro comienza con la advertencia de que es ...

Completamente desactualizado. Hibernate usa JBoss Logging a partir de 4.0. Esto se documentará a medida que migremos este contenido a la Guía para desarrolladores.

... continúa hablando de SLF4J, por lo que es inútil. Ni la guía de introducción ni la guía para desarrolladores hablan en absoluto sobre el registro. Tampoco la guía de migración .

He buscado documentación sobre jboss-logging, pero no he podido encontrar ninguna. La página de GitHub está en silencio , y la página de proyectos comunitarios de JBoss ni siquiera enumera jboss-logging. Me preguntaba si el rastreador de errores del proyecto podría tener algún problema relacionado con el suministro de documentación, pero no es así.

La buena noticia es que cuando utiliza Hibernate 4 dentro de un servidor de aplicaciones, como JBoss AS7, el registro se encarga en gran medida de usted. Pero, ¿cómo puedo configurarlo en una aplicación independiente?

Tom Anderson
fuente
13
+1 por resaltar que los documentos de Hibernate sobre el registro están desactualizados
mhnagaoka
Se puede establecer la propiedad del sistema org.jboss.logging.provide = slf4j. Para obtener más detalles, visite el enlace docs.jboss.org/hibernate/orm/4.3/topical/html/logging/… para la versión de hibernación superior a 3.
Abhishek Ranjan

Respuestas:

60

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

Así posibles valores de org.jboss.logging.providerson: jboss, jdk, log4j, slf4j.

Si no lo configura org.jboss.logging.provider, intenta jboss, luego log4j, luego slf4j (solo si se usa logback) y retrocede a jdk.

Yo uso slf4jcon logback-classic:

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

y todo funciona bien!

ACTUALIZACIÓN Algunos usuarios utilizan en App.java muy principal:

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

pero para las soluciones basadas en contenedores esto no funciona.

ACTUALIZACIÓN 2 Quienes piensan que gestionan Log4j con SLF4J porque jboss-loggingno es exactamente así. jboss-loggingutiliza directamente Log4j sin SLF4J!

Gavenkoa
fuente
1
¿Dónde establecer org.jboss.logging.provider?
Suzan Cioc
1
@SuzanCioc Según lo System.getProperty(LOGGING_PROVIDER_KEY);que necesite, establecer la propiedad del sistema. A través de java -D...=...o consulte los documentos de su contenedor.
gavenkoa
1
Su segunda actualización sobre no poder usar log4j a través de slf4j fue útil. Configurar org.jboss.logging.provider a slf4j me hizo pensar que mi respaldo de log4j se activaría. Sin embargo, no fue así. Tuve que configurarlo directamente en log4j para que funcionara. Impar. Entonces, ¿cuál es el punto de slf4j como una opción para esta configuración?
Travis Spencer
27

Para que SLF4J funcione con JBoss Logging sin Logback como backend, se requiere el uso de una propiedad del sistema org.jboss.logging.provider=slf4j. log4j-over-slf4jLas tácticas no parecen funcionar en este caso porque el registro volverá a JDK si ni Logback ni log4j no están presentes en classpath.

Esto es un poco molesto y para que la autodetección funcione, debe ver que el cargador de clases contiene al menos ch.qos.logback.classic.Loggerdesde logback-classic o org.apache.log4j.Hierarchydesde log4j para engañar a JBoss Logging para que no recurra al registro JDK.

La magia se interpreta en org.jboss.logging.LoggerProviders

ACTUALIZACIÓN: Se ha agregado el soporte del cargador de servicios para que sea posible evitar problemas con la detección automática al declarar META-INF/services/org.jboss.logging.LoggerProvider(con org.jboss.logging.Slf4jLoggerProvidercomo valor). Parece que también se ha añadido soporte log4j2.

Tuomas Kiviaho
fuente
1
¿Dónde configuro esta propiedad del sistema?
jhegedus
Depende de su configuración, pero normalmente un cambio de línea de comando -Dorg.jboss.logging.provider=slf4jes suficiente. LoggingProviders.java le brinda una mejor información sobre cuáles son los valores aceptados actuales y qué se espera que esté presente en la ruta de clases.
Tuomas Kiviaho
2
No creo que el enfoque del cargador de servicios funcione porque Slf4jLoggerProviderno es una publicclase.
holmis83
Necesito configurar org.jboss.logging.provider en un WAR de weblogic en el código fuente, ¡pero cualquier inicializador de clase estática se invoca después del LoggingProviders!
Antonio Petricca
12

Inspirado por la publicación de Hypoport de Leif , así es como "doblé" Hibernate 4 de nuevo a slf4j:

Supongamos que está utilizando Maven.

  • Agregue org.slf4j:log4j-over-slf4jcomo dependencia a supom.xml
  • Usando el comando mvn dependency:tree, asegúrese de que ninguno de los artefactos que está usando dependa slf4j:slf4j(para ser precisos, ningún artefacto tendrá una dependencia del alcance de compilación o una dependencia del alcance del tiempo de ejecuciónslf4j:slf4j )

Antecedentes: Hibernate 4.x depende del artefacto org.jboss.logging:jboss-logging. De manera transitiva, este artefacto tiene una dependencia de alcance proporcionada en el artefacto slf4j:slf4j.

Como ahora hemos agregado el org.slf4j:log4j-over-slf4jartefacto, org.slf4j:log4j-over-slf4jimita el slf4j:slf4jartefacto. Por lo tanto, todo lo que JBoss Loggingregistre ahora irá a través de slf4j.

Digamos que está usando Logback como su backend de registro. Aquí hay una muestrapom.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>

En su classpath, tenga un logback.xml, como este, ubicado en 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 -->

Es posible que algunos componentes quieran tener acceso logback.xmlen el momento de inicio de la JVM para un registro adecuado, por ejemplo, el complemento Jetty Maven. En ese caso, agregue un sistema Java logback.configurationFile=./path/to/logback.xmla su comando (por ejemplo mvn -Dlogback.configurationFile=./target/classes/logback.xml jetty:run).

En caso de que siga obteniendo la salida estándar de la consola "sin procesar ", puede aplicarse la Hibernate: select ...pregunta de desbordamiento de pila " Desactivar el registro de hibernación en la consola ".

Abdull
fuente
1
Asegúrese de que ninguna otra biblioteca incluya log4j, o esto no funcionará. Ejemplo: activemq-all.jar contiene log4j. Sugerencia: abra su IDE y busque log4j fácilmente en su código.
Dimitri Dewaele
Tuve este problema con JBoss Hibernate4 y un servidor (demasiado) antiguo. Esta publicación, que incluye 1 línea en application.properties, me ayudó. ¡¡¡Entonces TNX !!! Y esa última línea en mis propiedades estaba escrita en otra respuesta aquí:org.jboss.logging.provider=slf4j
Jeroen van Dijk-Jun
8

Primero se da cuenta de que SLF4J no es un derecho de biblioteca de registro, es un contenedor de registro. Por sí mismo no registra nada, simplemente delega a "backends".

Para "configurar" jboss-logging, simplemente agregue cualquier marco de registro que desee usar en su classpath (junto con jboss-logging) y jboss-logging calcula el resto.

Creé una guía centrada en Hibernate para la configuración de JBoss Logging: http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html

Steve Ebersole
fuente
2
Me doy cuenta de que SLF4J es una fachada, sí. Enviar el registro de Hibernate a SLF4J significa que termina en cualquier backend que haya elegido para el resto de mi aplicación, que es lo que quiero.
Tom Anderson
10
Entonces, lo que estás diciendo sobre la configuración es que no hay configuración (¡lo cual es bueno!), Pero ¿jboss-logging de alguna manera detecta y selecciona un backend? Ah, ahora me tomo el tiempo para mirar el código, veo que eso es exactamente lo que sucede . Específicamente, jboss-logging intenta, en orden, JBoss LogManager, log4j, Logback a través de SLF4J y JDK logging. Pero esto se puede anular con la org.jboss.logging.providerpropiedad del sistema.
Tom Anderson
2
Muchos de nosotros hemos sido quemados por commons-logging que se da cuenta de las cosas por usted, por lo que saber exactamente cómo funciona jboss-logging es fundamental para poder respaldarlo en el mundo real cuando sucede algo inesperado.
ams el
1
De hecho, el enlace de arriba muestra exactamente lo que sucede si eso es lo que realmente quieres ver, así que no seguir ...
Steve Ebersole
3

Estoy usando Hibernate Core 4.1.7.Final más Spring 3.1.2.RELEASE en una aplicación independiente. Agregué Log4j 1.2.17 a mis dependencias y parece que, como JBoss Logging registra directamente en log4j si está disponible y Spring usa Commons Logging, que también usa Log4j si está disponible, todos los registros se pueden configurar a través de Log4J.

Aquí está mi lista de dependencias 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
fuente
3

así que lo hice funcionar en mi proyecto. hibernate 4, slf4j, logback. mi proyecto es gradle, pero debería ser el mismo para maven.

Básicamente, Abdull tiene razón. Donde NO tiene razón, es que NO tiene que eliminar slf4j de las dependencias.

  1. incluir para compilar el alcance:

    org.slf4j: slf4j-api

    org.slf4j: log4j-over-slf4j

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

  2. excluir completamente las bibliotecas log4j de las dependencias

resultado: hibernar registros a través de slf4j para iniciar sesión. por supuesto, debería poder usar una implementación de registro diferente a la de logback

para asegurarse de que no haya log4j, verifique sus bibliotecas en classpath o web-inf / lib para ver los archivos war.

por supuesto, ha configurado los registradores en logback.xml, por ejemplo:

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

dasAnderl ausMinga
fuente
tenía este problema exacto. log4j se incorporó como una dependencia transitiva de otra biblioteca. Se excluyó y el registro de hibernación comenzó a funcionar como se esperaba usando logback y el puente slf4j log4j
Paul Zepernick
3

Hibernate 4.3 tiene cierta documentación sobre cómo controlar org.jboss.logging:

  • Busca en la ruta de clases un proveedor de registro . Busca slf4j después de buscar log4j. Entonces, en teoría, asegurarse de que su classpath (WAR) no incluya log4j y sí incluya la API slf4j y un back-end debería funcionar.

  • Como último recurso, puede establecer la org.jboss.logging.providerpropiedad del sistema en slf4j.


A pesar de las afirmaciones de la documentación, org.jboss.logginginsistí en intentar usar log4j, a pesar de que log4j estaba ausente y SLF4J estaba presente, lo que resultó en el siguiente mensaje en mi archivo de registro de 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.

Tuve que seguir la sugerencia de la respuesta por dasAnderl ausMinga e incluir el log4j-over-slf4jpuente.

Raedwald
fuente
2

Utilizo maven y agregué la siguiente dependencia:

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

Luego, creé log4j.propertiesarchivos en /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

Esto lo pondrá en la raíz de su .jar. Funciona a las mil maravillas...

Jérôme Verstrynge
fuente
3
Esto configura el uso de log4j. El OP no quiere utilizar log4j; quieren usar slf4j.
Raedwald
1

Tuve un problema al hacer que el registro de hibernate 4 funcionara con weblogic 12c y log4j. La solución es poner lo siguiente en su weblogic-application.xml:

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

A cualquiera que pudiera enfrentar el mismo problema que yo tuve. En caso de que haya probado todas las otras soluciones explicadas aquí y aún no vea que el registro de hibernación funcione con su slf4j, podría deberse a que está utilizando un contenedor que tiene en sus bibliotecas de carpetas el jboss-logging.jar. Esto significa que se carga previamente antes de que pueda establecer cualquier configuración para influir en él. Para evitar este problema en weblogic puede especificar en el archivo weblogic-application.xml en su oído / META-INF para preferir la biblioteca cargada desde la aplicación. Debería haber un mecanismo similar para otros contenedores de servidor. En mi caso tuve que agregar:

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

intentaste esto:

- slf4j-log4j12.jar en el caso de Log4J. Consulte la documentación de SLF4J para obtener más detalles. Para utilizar Log4j, también deberá colocar un archivo log4j.properties en su classpath. Un archivo de propiedades de ejemplo se distribuye con Hibernate en el directorio src /

simplemente agregue estos frascos y propiedades o log4j xml en el classpath

Avihai Marchiano
fuente
4
Esa es una cita de la documentación de Hibernate 3.x. ¿Crees que seguirá funcionando con Hibernate 4.x, que no usa SLF4J?
Tom Anderson
por lo que recuerdo, log4j es suficiente
Avihai Marchiano