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>