web-dev-qa-db-fra.com

JUL à SLF4J Bridge

J'observe actuellement qu'une bibliothèque tierce (à savoir restfb) utilise Java.util.logging et je vois ces journaux se retrouver dans STDOUT même si je n'ai pas d'appendice de console SLF4J configuré dans mon logback.xml. J'ai également le pont jul-to-slf4j dans mon chemin de classe. Le pont jul-to-slf4j ne se connecte-t-il qu'aux appendereurs configurés par logback lorsque le pont est installé ou se connecte-t-il également à stdout?

61
Taylor Leese

Vous devez appeler SLF4JBridgeHandler.install() . Vous devez également activer tous les niveaux de journalisation dans l'enregistreur racine (raison dans l'extrait ci-dessous) dans Java.util.logging et supprimer l'appendice de console par défaut.

Ce gestionnaire redirigera la journalisation jul vers SLF4J. Cependant, seuls les journaux activés dans j.u.l. sera redirigé. Par exemple, si une instruction log invoquant un j.u.l. l'enregistreur a désactivé cette instruction, par définition, n'atteindra aucune instance SLF4JBridgeHandler et ne peut pas être redirigée.

L'ensemble du processus peut être accompli comme ça

import Java.util.logging.Logger;
import org.slf4j.bridge.SLF4JBridgeHandler;

SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
Logger.getLogger("").setLevel(Level.FINEST); // Root logger, for example.

Vous pouvez définir le niveau sur quelque chose de plus élevé que le meilleur pour des raisons de performances, mais vous ne pourrez pas activer ces journaux sans les activer dans Java.util.logging d'abord (pour la raison mentionnée ci-dessus dans l'extrait).

78
Dev

Comme mentionné dans les javadocs pour SLF4JBridgeHandler , vous obtenez soit installer SLF4JBridgeHandler par programme en appelant:

 // Optionally remove existing handlers attached to j.u.l root logger
 SLF4JBridgeHandler.removeHandlersForRootLogger();  // (since SLF4J 1.6.5)

 // add SLF4JBridgeHandler to j.u.l's root logger, should be done once during
 // the initialization phase of your application
 SLF4JBridgeHandler.install();

ou via logging.properties

 // register SLF4JBridgeHandler as handler for the j.u.l. root logger
 handlers = org.slf4j.bridge.SLF4JBridgeHandler

En ce qui concerne les performances, la section sur jul-to-slf4j bridge traite de ce problème. En substance, puisque vous utilisez déjà la déconnexion, l'activation de LevelChangePropagator devrait donner de bonnes performances quelle que soit la charge.

36
Ceki

J'utilise SLF4J et nouveau pilote Postgres 42.0.

Selon changelog il utilise Java.util.logging

Pour avoir des journaux de pilotes, il suffit:

  1. Ajouter pont jul-to-slf4j :

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jul-to-slf4j</artifactId>
        <version>${slf4j.version}</version>
        <scope>runtime</scope>
    </dependency>
    
  2. Ajoutez logback.xml (logback-test.xml)

    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
        <resetJUL>true</resetJUL>
    </contextListener>
    
    <appender ...
    
    <logger name="org.postgresql" level="trace"/>`
    
  3. Ajouter du code

    static {
        SLF4JBridgeHandler.install();
    }
    
12
GKislin

Ma solution:

SLF4JBridgeHandler.install();
Java.util.logging.LogManager.getLogManager().getLogger("").setLevel( Level.INFO);

en plaçant jul-to-slf4j sur vos librairies d'application ou librairies glassfish, celles-ci redirigent JUL vers SLF4J (et donc dans mon cas vers LOG4J)

alors pour Jersey, vous pourriez faire quelque chose comme:

<logger name="com.Sun.jersey" additivity="false">
    <level value="WARN" />
    <appender-ref ref="JVM" />
    <appender-ref ref="CONSOLE" />
</logger>   

<logger name="com.Sun.common.util.logging" additivity="false">
    <level value="ERROR" />
    <appender-ref ref="JVM" />
    <appender-ref ref="CONSOLE" />
</logger>

la dernière config est d'éviter d'être polluée par d'autres loggers

3
Benjamin Fuentes

Solution qui semble agréable (compte tenu des circonstances avec le pontage JUL) et qui fonctionne pour moi, car je n'ai qu'à tout écrire dans le logback.groovy fichier.

  1. (Si vous n'utilisez pas la configuration logback.groovy ou logback du tout, bien sûr vous devez mettre la partie logique dans une classe (par exemple comme class MyApp { static { /* log init code here */ } ... }).)

  2. src/logback.groovy:

    import org.slf4j.bridge.SLF4JBridgeHandler
    import ch.qos.logback.classic.jul.LevelChangePropagator
    
    // for debug: just to see it in case something is logging/initialized before
    System.out.println( 'my myapp logback.groovy is loading' )
    
    // see also: http://logback.qos.ch/manual/configuration.html#LevelChangePropagator
    // performance speedup for redirected JUL loggers
    def lcp = new LevelChangePropagator()
    lcp.context = context
    lcp.resetJUL = true
    context.addListener(lcp)
    
    // needed only for the JUL bridge: http://stackoverflow.com/a/9117188/1915920
    Java.util.logging.LogManager.getLogManager().reset()
    SLF4JBridgeHandler.removeHandlersForRootLogger()
    SLF4JBridgeHandler.install()
    Java.util.logging.Logger.getLogger( "global" ).setLevel( Java.util.logging.Level.FINEST )
    
    def logPattern = "%date |%.-1level| [%thread] %20.20logger{10}|  %msg%n"
    
    appender("STDOUT", ConsoleAppender) {
        encoder(PatternLayoutEncoder) {
            pattern = logPattern
        }
    }
    
    /*// outcommenting in dev will not create dummy empty file
    appender("ROLLING", RollingFileAppender) {  // prod
        encoder(PatternLayoutEncoder) {
            Pattern = "%date %.-1level [%thread] %20.20logger{10}  %msg%n"
        }
        rollingPolicy(TimeBasedRollingPolicy) {
            FileNamePattern = "${WEBAPP_DIR}/log/orgv-fst-gwt-%d{yyyy-MM-dd}.Zip"
        }
    }
    */
    
    appender("FILE", FileAppender) {  // dev
    
        // log to myapp/tmp (independent of running in dev/prod or junit mode:
    
        //System.out.println( 'DEBUG: WEBAPP_DIR env prop:  "."='+new File('.').absolutePath+',  \${WEBAPP_DIR}=${WEBAPP_DIR},  env=' + System.getProperty( "WEBAPP_DIR" ))
        String webappDirName = "war"
        if ( new File( "./../"+webappDirName ).exists() )  // we are not running within a junit test
            file = "../tmp/myapp.log"
        else  // junit test
            file = "tmp/myapp-junit-tests.log"
    
        encoder(PatternLayoutEncoder) { pattern = logPattern }
    }
    
    // without JUL bridge:
    //root(WARN, ["STDOUT", "ROLLING"])  // prod
    //root(DEBUG, ["STDOUT", "FILE"])  // dev
    
    // with JUL bridge: (workaround: see links above)
    def rootLvl = WARN
    root(TRACE, [/*"STDOUT",*/ "FILE"])
    // I manually added all "root package dirs" I know my libs are based on to apply
    // the root level to the second "package dir level" at least
    // depending on your libs used you could remove entries, but I would recommend
    // to add common entries instead (feel free to edit this post if you like to
    // enhance it anywhere)
    logger( "antlr", rootLvl )
    logger( "de", rootLvl )
    logger( "ch", rootLvl )
    logger( "com", rootLvl )
    logger( "Java", rootLvl )
    logger( "javassist", rootLvl )
    logger( "javax", rootLvl )
    logger( "junit", rootLvl )
    logger( "groovy", rootLvl )
    logger( "net", rootLvl )
    logger( "org", rootLvl )
    logger( "Sun", rootLvl )
    
    
    // my logger setup
    
    logger( "myapp", DEBUG )
    
    
    //logger( "org.hibernate.SQL", DEBUG )  // debug: log SQL statements in DEBUG mode
    //logger( "org.hibernate.type", TRACE )  // debug: log JDBC parameters in TRACE mode
    logger( "org.hibernate.type.BasicTypeRegistry", WARN )  // uninteresting
    
    scan("30 seconds")  // reload/apply-on-change config every x sec
    

(recommandé d'être utilisé par moi car vous pouvez réagir avec Java code vars/fonctions comme vous pouvez le voir ici, par exemple SLF4JBridgeHandler ou le répertoire du journal concernant webappDirName )

(laissé le fichier complet car il donne une meilleure impression de la façon dont tout peut être configuré ou en tant que modèle de démarrage)

(peut être pertinent pour quelqu'un - mon env: slf4j 1.7.5, logback 1.1.2, groovy 2.1.9 )

2
Andreas Dietrich