pattern logger example java startup logback appender

java - logger - logback pattern



Cómo pasar el archivo de registro al inicio en logback (11)

Me gustaría configurar logback para hacer lo siguiente.

  • Inicie sesión en un archivo
  • Haga rodar el archivo cuando llegue a 50 MB
  • Solo guarde 7 días de registros
  • Al inicio, siempre genere un nuevo archivo (haga un rollo)

Lo tengo todo funcionando, excepto por el último elemento, la tirada de inicio. ¿Alguien sabe cómo lograr eso? Aquí está la configuración ...

<appender name="File" class="ch.qos.logback.core.rolling.RollingFileAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg /(%file:%line/)%n</Pattern> </layout> <File>server.log</File> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>server.%d{yyyy-MM-dd}.log</FileNamePattern> <!-- keep 7 days'' worth of history --> <MaxHistory>7</MaxHistory> <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <MaxFileSize>50MB</MaxFileSize> </TimeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender>


Anular el método isTriggeringEvent () en ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP debería funcionar bien. Simplemente devuelve ''verdadero'' la primera vez que se llama al método TriggeringEvent ().


Conseguí lo siguiente para trabajar (combinando ideas de respuestas anteriores). Tenga en cuenta que estaba tratando con archivos basados ​​en tamaño, no basados ​​en el tiempo, pero supongo que la misma solución funciona.

public class StartupSizeBasedTriggeringPolicy<E> extends ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy<E> { private final AtomicReference<Boolean> isFirstTime = new AtomicReference<Boolean>(true); @Override public boolean isTriggeringEvent(final File activeFile, final E event) { //this method appears to have side-effects so always call boolean result = super.isTriggeringEvent(activeFile, event); return isFirstTime.compareAndSet(true, false) || result; }

}


Cree su propia subclase de ch.qos.logback.core.rolling.TimeBasedRollingPolicy y anule su start

public class MyPolicy extends ch.qos.logback.core.rolling.TimeBasedRollingPolicy { public void start ( ) { super.start( ); rollover( ); } }


Encontré otra solución para rodar el archivo de registro una vez, cuando se inicia la aplicación.

Utilizo RollingFileAppender de RollingFileAppender con FixedWindowRollingPolicy de FixedWindowRollingPolicy y mi propia implementación de una TriggeringPolicy<E> .

FixedWindowRollingPolicy obtiene el FixedWindowRollingPolicy para el nuevo archivo de registro, donde %1 es el nuevo número del archivo. El maxIndex representa el número máximo de mi "historial". Más información: FixedWindowRollingPolicy

Mis implementaciones TriggeringPolicy devuelven true por primera vez, cuando se llama aTriggeringEvent (...). Por lo tanto, WindowRollingPolicy pasa por encima de los archivos de registro, cuando se llama a la Política por primera vez y luego no se reinicia.

La configuración xml para RollingFileAppender :

<configuration> ... <appender name="FILE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logFile.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>logFile.%i.log</fileNamePattern> <minIndex>1</minIndex> <maxIndex>4</maxIndex> </rollingPolicy> <triggeringPolicy class="my.classpath.RollOncePerSessionTriggeringPolicy"/> </appender> ... </configuration>

La TriggeringPolicy :

package my.classpath; import ch.qos.logback.core.rolling.TriggeringPolicyBase; import java.io.File; public class RollOncePerSessionTriggeringPolicy<E> extends TriggeringPolicyBase<E> { private static boolean doRolling = true; @Override public boolean isTriggeringEvent(File activeFile, E event) { // roll the first time when the event gets called if (doRolling) { doRolling = false; return true; } return false; } }


Esta solución realmente funciona, muchas gracias. Sin embargo, hay un problema técnico molesto: cuando ejecuta el programa por primera vez, el registro se lanza inmediatamente después de que se crea, cuando está vacío o casi vacío. Así que sugiero una solución: compruebe si el archivo de registro existe y no está vacío en el momento en que se llama al método. Además, una corrección más cosmética: cambie el nombre de la variable "iniciada", ya que está ocultando el miembro heredado con el mismo nombre.

@NoAutoStart public class StartupSizeTimeBasedTriggeringPolicy<E> extends SizeAndTimeBasedFNATP<E> { private boolean policyStarted; @Override public boolean isTriggeringEvent(File activeFile, E event) { if (!policyStarted) { policyStarted = true; if (activeFile.exists() && activeFile.length() > 0) { nextCheck = 0L; return true; } } return super.isTriggeringEvent(activeFile, event); } }

Además, creo que funciona correctamente con la versión de logback 1.1.4-SNAPSHOT (obtuve la fuente y la compilé yo mismo), pero no funciona completamente con la versión 1.1.3. Con 1.1.3, nombra los archivos correctamente con la zona horaria especificada, pero la transferencia continúa en la zona horaria predeterminada, medianoche.


Finalmente lo descubro. Puedo rodar por tamaño, tiempo y comenzar. Aquí hay una solución:

Primero crea tu propia clase

@NoAutoStart public class StartupSizeTimeBasedTriggeringPolicy<E> extends SizeAndTimeBasedFNATP<E> { private boolean started = false; @Override public boolean isTriggeringEvent( File activeFile, E event ) { if ( !started ) { nextCheck = 0L; return started = true; } return super.isTriggeringEvent( activeFile, event ); }; }

2nd configura logback

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOGS_DIR}/${FILE_NAME}.log</file> <encoder> <pattern>%d [%thread] %-5level %logger{50} - %msg%n</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOGS_DIR}/${FILE_NAME}.%d{yyyy-MM-dd}_%d{HHmmss,aux}.%i.log.zip</fileNamePattern> <maxHistory>30</maxHistory> <TimeBasedFileNamingAndTriggeringPolicy class="my.StartupSizeTimeBasedTriggeringPolicy"> <MaxFileSize>250MB</MaxFileSize> </TimeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender>


Funciona para mí, usando la siguiente clase como timeBasedFileNamingAndTriggeringPolicy:

import java.io.File; import java.util.concurrent.atomic.AtomicBoolean; import ch.qos.logback.core.joran.spi.NoAutoStart; import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP; @NoAutoStart public class Trigger<E> extends SizeAndTimeBasedFNATP<E> { private final AtomicBoolean trigger = new AtomicBoolean(); public boolean isTriggeringEvent(final File activeFile, final E event) { if (trigger.compareAndSet(false, true) && activeFile.length() > 0) { String maxFileSize = getMaxFileSize(); setMaxFileSize("1"); super.isTriggeringEvent(activeFile, event); setMaxFileSize(maxFileSize); return true; } return super.isTriggeringEvent(activeFile, event); } }


La API ha cambiado (por ejemplo, setMaxFileSize ya no existe) y muchas de las cosas anteriores no parecen funcionar, pero tengo algo que funciona para mí contra logback 1.1.8 (la última en este momento).

Quería rodar en el inicio y rodar el tamaño, pero no el tiempo. Esto lo hace:

public class RollOnStartupAndSizeTriggeringPolicy<E> extends SizeBasedTriggeringPolicy<E> { private final AtomicBoolean firstTime = new AtomicBoolean(); public boolean isTriggeringEvent(final File activeFile, final E event) { if (firstTime.compareAndSet(false, true) && activeFile != null && activeFile.length() > 0) { return true; } return super.isTriggeringEvent(activeFile, event); } }

Con esto también necesita una política continua. FixedWindowRollingPolicy probablemente funcionaría, pero no me gusta porque quiero mantener una gran cantidad de archivos y es muy ineficiente para eso. Algo que aumenta gradualmente (en lugar de deslizarse como FixedWindow) funcionaría, pero eso no existe. Mientras escribo el mío, decidí utilizar el tiempo en lugar de contar. Quería extender el código de logback actual, pero para las cosas basadas en tiempo las políticas de rolling y triggering a menudo se combinan en una clase, y hay registros de cosas anidadas y circulares y campos sin getters, así que me pareció bastante imposible. Entonces tuve que hacer mucho desde cero. Lo mantengo simple y no implementé características como la compresión. Me encantaría tenerlas, pero solo intento mantenerlas simples.

public class TimestampRollingPolicy<E> extends RollingPolicyBase { private final RenameUtil renameUtil = new RenameUtil(); private String activeFileName; private String fileNamePatternStr; private FileNamePattern fileNamePattern; @Override public void start() { super.start(); renameUtil.setContext(this.context); activeFileName = getParentsRawFileProperty(); if (activeFileName == null || activeFileName.isEmpty()) { addError("No file set on appender"); } if (fileNamePatternStr == null || fileNamePatternStr.isEmpty()) { addError("fileNamePattern not set"); fileNamePattern = null; } else { fileNamePattern = new FileNamePattern(fileNamePatternStr, this.context); } addInfo("Will use the pattern " + fileNamePattern + " to archive files"); } @Override public void rollover() throws RolloverFailure { File f = new File(activeFileName); if (!f.exists()) { return; } if (f.length() <= 0) { return; } try { String archiveFileName = fileNamePattern.convert(new Date(f.lastModified())); renameUtil.rename(activeFileName, archiveFileName); } catch (RolloverFailure e) { throw e; } catch (Exception e) { throw new RolloverFailure(e.toString(), e); } } @Override public String getActiveFileName() { return activeFileName; } public void setFileNamePattern(String fnp) { fileNamePatternStr = fnp; } }

Y luego la configuración parece

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> <file>/tmp/monitor.log</file> <rollingPolicy class="my.log.TimestampRollingPolicy"> <fileNamePattern>/tmp/monitor.%d{yyyyMMdd-HHmmss}.log</fileNamePattern> </rollingPolicy> <triggeringPolicy class="my.log.RollOnStartupAndSizeTriggeringPolicy"> <maxFileSize>1gb</maxFileSize> </triggeringPolicy> </appender>

si estás frustrado, esto no se resuelve de forma nativa, vótelo en

http://jira.qos.ch/browse/LOGBACK-204

http://jira.qos.ch/browse/LOGBACK-215

(Han pasado años, y para mí esta es una funcionalidad absolutamente crítica, aunque sé que muchos otros marcos también fallan)


La solución de Ceki no parece funcionar para mí, pero parece estar en parte al menos allí.

Se dispara porque no puede ver la política de rodadura cuando se inicia TimeBasedFileNamingAndTriggeringPolicyBase . Con algunos hackers logré hacer un poco de registro, y con algunos más conseguí observar el disparador, pero luego se rompió nuevamente porque no podía resolver una de las propiedades del nombre de archivo ... El paquete es un logback uno, así que podría llegar a algunas de las SizeAndTimeBasedFNATP#isTriggeringEvent internas, para replicar parte de la lógica en SizeAndTimeBasedFNATP#isTriggeringEvent y llamar a computeCurrentPeriodsHighestCounterValue . Creo que algo en ese sentido podría funcionar, pero aún no hemos encontrado la combinación mágica. Realmente espero estar haciendo algo tonto, porque de lo contrario creo que significará abrir algunos de los detalles para la creación de subclases, o poner esto directamente en logback como otra política de rodadura / activación.

logback.xml: intentó varias ordenaciones de triggeringPolicy , TimeBasedFileNamingAndTriggeringPolicy dentro y fuera de rollingPolicy .

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_DIR}/${LOG_FILE_BASE}.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_DIR}/${LOG_FILE_BASE}.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <MaxHistory>7</MaxHistory> <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.RollOnStartupPolicy" /> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <encoder> <pattern>%msg%n</pattern> </encoder> </appender>

La política de disparo:

package ch.qos.logback.core.rolling; public class RollOnStartupPolicy<E> extends SizeAndTimeBasedFNATP<E> { private final AtomicBoolean firstTime = new AtomicBoolean(true); @Override public boolean isTriggeringEvent(File activeFile, E event) { if (!firstTime.get()) { // fast path return false; } if (firstTime.getAndSet(false)) { return true; } return false; } }

La excepción:

java.lang.NullPointerException at at ch.qos.logback.core.rolling.TimeBasedFileNamingAndTriggeringPolicyBase.start(TimeBasedFileNamingAndTriggeringPolicyBase.java:46) at at ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP.start(SizeAndTimeBasedFNATP.java:36) at at ch.qos.logback.core.joran... [snip joran config]


Ninguna de las otras sugerencias fue apropiada para mi situación. No quería usar una solución basada en el tamaño y el tiempo, ya que requiere la configuración de MaxFileSize, y estamos utilizando una política estrictamente basada en el tiempo. Así es como logré rodar el archivo al inicio con TimeBasedRollingPolicy:

@NoAutoStart public class StartupTimeBasedTriggeringPolicy<E> extends DefaultTimeBasedFileNamingAndTriggeringPolicy<E> { @Override public void start() { super.start(); nextCheck = 0L; isTriggeringEvent(null, null); try { tbrp.rollover(); } catch (RolloverFailure e) { //Do nothing } } }

El truco consiste en establecer el próximo control de tiempo en 0L, por lo que isTriggeringEvent () pensará que es hora de pasar el archivo de registro. De este modo, ejecutará el código necesario para calcular el nombre del archivo, así como restablecer convenientemente el siguiente valor de tiempo de comprobación. La llamada subsiguiente a rollover () hace que se lance el archivo de registro. Como esto solo ocurre al inicio, es una solución más óptima que las que realizan una comparación dentro de isTriggerEvent (). Por pequeña que sea la comparación, aún degrada ligeramente el rendimiento cuando se ejecuta en cada mensaje de registro. Esto también obliga a que la transferencia se produzca inmediatamente al inicio, en lugar de esperar el primer evento de registro.

La anotación @NoAutoStart es importante para evitar que Joran ejecute el método start () antes de que se complete la otra inicialización. De lo contrario, obtienes una NullPointerException.

Aquí está la configuración:

<!-- Daily rollover appender that also appends timestamp and rolls over on startup --> <appender name="startupDailyRolloverAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_FILE}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}.%d{yyyyMMdd}_%d{HHmmss,aux}</fileNamePattern> <TimeBasedFileNamingAndTriggeringPolicy class="my.package.StartupTimeBasedTriggeringPolicy" /> </rollingPolicy> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender>

¡Espero que esto ayude!


Para una solución que utiliza componentes ya existentes, el logback sugiere los archivos con nombres únicos : http://logback.qos.ch/manual/appenders.html#uniquelyNamed

Durante la fase de desarrollo de la aplicación o en el caso de aplicaciones de corta duración, por ejemplo, aplicaciones por lotes, es deseable crear un nuevo archivo de registro en cada lanzamiento de la nueva aplicación. Esto es bastante fácil de hacer con la ayuda del elemento <timestamp> .

<?xml version="1.0" encoding="UTF-8"?> <configuration> <timestamp key="startTimestamp" datePattern="yyyyMMddHHmmssSSS"/> <appender name="File" class="ch.qos.logback.core.rolling.RollingFileAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg /(%file:%line/)%n</Pattern> </layout> <file>server-${startTimestamp}.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>server-${startTimestamp}-%d{yyyy-MM-dd}-%i.log</FileNamePattern> <!-- keep 7 days'' worth of history --> <MaxHistory>7</MaxHistory> <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <MaxFileSize>1KB</MaxFileSize> </TimeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <root level="DEBUG"> <appender-ref ref="File" /> </root> </configuration>

ACTUALIZADO para logback-1.2.1

<?xml version="1.0" encoding="UTF-8"?> <configuration> <timestamp key="startTimestamp" datePattern="yyyyMMddHHmmssSSS"/> <appender name="File" class="ch.qos.logback.core.rolling.RollingFileAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg /(%file:%line/)%n</Pattern> </layout> <file>server-${startTimestamp}.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>server-${startTimestamp}-%d{yyyy-MM-dd}-%i.log</fileNamePattern> <maxFileSize>10MB</maxFileSize> <!-- keep 7 days'' worth of history --> <maxHistory>7</maxHistory> <totalSizeCap>20GB</totalSizeCap> </rollingPolicy> </appender> <root level="DEBUG"> <appender-ref ref="File" /> </root> </configuration>