java - JUL a SLF4J Bridge
logback java.util.logging (5)
Como se mencionó en javadocs para SLF4JBridgeHandler.install() , puede instalar SLF4JBridgeHandler mediante programación invocando:
// 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();
o a través de logging.properties
// register SLF4JBridgeHandler as handler for the j.u.l. root logger
handlers = org.slf4j.bridge.SLF4JBridgeHandler
En cuanto al rendimiento, la sección sobre el puente jul-to-slf4j discute este problema. En esencia, como ya está utilizando el registro de retorno, habilitar el logback.qos.ch/manual/configuration.html#LevelChangePropagator debería proporcionar un buen rendimiento independientemente de la carga.
Actualmente estoy observando que una biblioteca de terceros (a saber, restfb) está utilizando java.util.logging y veo que esos registros terminan en STDOUT aunque no tengo un appender de consola SLF4J configurado en mi logback.xml. También tengo el puente de jul-to-slf4j en mi classpath. ¿El puente de jul-to-slf4j solo se registra en los agregadores configurados por el registro de retorno cuando se instala el puente o también se registra en stdout?
Mi solución :
SLF4JBridgeHandler.install();
java.util.logging.LogManager.getLogManager().getLogger("").setLevel( Level.INFO);
colocando jul-to-slf4j en tus librerías de aplicaciones o libretas de glassfish, estas redirigen JUL a SLF4J (y por lo tanto en mi caso a LOG4J)
Entonces para Jersey, podrías hacer algo como:
<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 última configuración es evitar ser contaminado por otros registradores.
Solución que parece agradable (considerando las circunstancias con el puente JUL) y funciona para mí, ya que solo tengo que escribir todo en el archivo logback.groovy .
( Si no está utilizando la configuración logback.groovy o logback en absoluto , por supuesto, debe colocar la parte lógica en alguna clase (por ejemplo, como la
class MyApp { static { /* log init code here */ } ... }
) . )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://.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
(recomendado para mi uso, ya que puede reaccionar con las funciones / funciones de código de Java como puede ver aquí con, por ejemplo, SLF4JBridgeHandler o el directorio de registros con respecto a webappDirName )
(dejó el archivo completo, ya que da una mejor impresión de cómo se puede configurar todo o como una plantilla de inicio)
(puede ser relevante para alguien - my env: slf4j 1.7.5, logback 1.1.2, groovy 2.1.9 )
Uso SLF4J y el nuevo controlador de Postgres 42.0.0
Según el changelog usa java.util.logging.
Para tener registros de controladores es suficiente:
Añadir puente jul-to-slf4j :
<dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>${slf4j.version}</version> <scope>runtime</scope> </dependency>
Añadir en logback.xml (logback-test.xml)
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"> <resetJUL>true</resetJUL> </contextListener> <appender ... <logger name="org.postgresql" level="trace"/>`
Añadir código
static { SLF4JBridgeHandler.install(); }
SLF4JBridgeHandler.install()
llamar a SLF4JBridgeHandler.install()
. También debe habilitar todos los niveles de registro en el registrador raíz (motivo en el extracto a continuación) en java.util.logging y eliminar el agregador de consola predeterminado.
Este controlador redireccionará el registro de julio a SLF4J. Sin embargo, solo los registros habilitados en julio serán redirigidos. Por ejemplo, si una declaración de registro que invoca un registrador jul deshabilitó esa declaración, por definición, no alcanzará ninguna instancia de SLF4JBridgeHandler y no se podrá redirigir.
Todo el proceso se puede llevar a cabo como tal.
import java.util.logging.Logger;
import org.slf4j.bridge.SLF4JBridgeHandler;
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
Logger.getLogger("").setLevel(Level.FINEST); // Root logger, for example.
Puede establecer el nivel en algo más alto que el mejor por razones de rendimiento, pero no podrá activar esos registros sin habilitarlos primero en java.util.logging
(por la razón mencionada anteriormente en el extracto).