Me gustaría configurar logback hacer lo siguiente.

  • De registro a un archivo
  • Rollo el archivo cuando llega a 50MB
  • Sólo mantener los 7 días de la pena de registros
  • En el inicio siempre generar un nuevo archivo (hacer un rollo)

Tengo todo trabajo, excepto para el último elemento, el inicio del rollo. ¿Alguien sabe cómo lograrlo? Aquí está la config…

  <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>
InformationsquelleAutor Mike Q | 2010-03-22

11 Comentarios

  1. 26

    Ninguna de las otras sugerencias que era apropiado para mi situación. Yo no quería usar un tamaño-y-tiempo-basado en la solución, debido a que se requiere la configuración de un MaxFileSize, y estamos utilizando estrictamente basado en el tiempo de la política. He aquí cómo se logra rodar el archivo en el inicio con una 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 es establecer la nextCheck tiempo a 0 L, por lo que isTriggeringEvent() va a pensar que es hora de rodar el archivo de registro más. Por lo tanto, será ejecutar el código necesario para calcular el nombre de archivo, así como muy bien restablecimiento de la nextCheck valor de tiempo. La siguiente llamada a una renovación() hace que el archivo de registro para ser lanzado. Ya que esto sólo sucede en el inicio, es una mejor solución que la que realizar una comparación dentro de isTriggerEvent(). Sin embargo los pequeños que de la comparación, todavía se degrada el rendimiento ligeramente cuando se ejecuta en cada mensaje de registro. Esto también obliga a que la reinversión se produzca inmediatamente en el inicio, en lugar de esperar para el primer evento de registro.

    La @NoAutoStart anotación es importante para evitar que Joran de ejecutar el método start() antes de todas las otras inicialización es completa. De lo contrario, se obtiene un NullPointerException.

    Aquí es la config:

      <!-- 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!

    • Yo estaba luchando y esto es exactamente lo que quiero, gracias! OMI esto debe ser una característica estándar y de configuración es un poco intuitivo
    • Gracias por la solución – estoy de acuerdo con @vincentlcy y también creo que esto debería ser una característica estándar.
    • Sólo quiero añadir mi agradecimiento por una gran solución. Quiero añadir esto sólo funciona (Logback 1.0.13) si ha definido un nombre de archivo raw: <archivo>evento.txt</archivo> Si se excluye a este a partir de su configuración, de manera que sólo se consigue .0,.1,.2,etc archivos indexados (esto es realmente recomendado por el Logback documentación para las plataformas de Windows para evitar encontrarse de bloqueo de archivo/cambiar el nombre de problemas), entonces esta solución por desgracia, no realmente realizan un vuelco porque en TimeBasedRollingPolicy.rollover() la llamada a getParentsRawFileProperty() devuelve null.
    • Esto parece romper el cleanHistoryOnStart. He utilizado esta técnica para un corto corriendo herramienta para generar un archivo de registro independiente para cada carrera, y el aviso de que el configurado maxHistory no está funcionando. Este podría ser alguna condición de carrera?
    • Desde mi requisito es una herramienta de línea de comandos, no necesito basado en el tiempo de disparo, así que fue capaz de llegar a trabajar por el cambio a FixedWindowRollingPolicy y una costumbre TriggeringPolicy clase con un isTriggering método que devuelve true sólo una vez.
    • Por alguna razón esto causa varios archivos de registro se crea en el inicio en lugar de rodar solo.
    • Esta solución no funciona para mí, usar logback 1.2.3. La configuración de TimeBasedFileNamingAndTriggeringPolicy en el archivo XML hace que la clase de su elección para ser instanciado, pero luego se reemplaza con otra instancia. start no se invoca cuando anotado con @NoAutoStart, nunca. Publicaremos mi solución.

  2. 7

    A mí me funciona, utilizando 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);
        }
    }
  3. 5

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

    Yo uso logback del RollingFileAppender con logback del FixedWindowRollingPolicy y mi propia implementación de un TriggeringPolicy<E>.

    La FixedWindowRollingPolicy obtiene el fileNamePattern 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 «historia». Más información: FixedWindowRollingPolicy

    Mi implementaciones TriggeringPolicy devuelve true para el primera tiempo, cuando isTriggeringEvent(…) se llama. Así que el WindowRollingPolicy rollos de más de los ficheros, cuando la Política se llama el primer tiempo, y después no va a rodar de nuevo.

    El xml de configuración para el 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;
        }
    }
  4. 5

    Para una solución con la ya existente de los componentes de la logback sugiere la nombre único archivos: http://logback.qos.ch/manual/appenders.html#uniquelyNamed

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

    <?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>
  5. 3

    Primordial de la isTriggeringEvent() en el método ch.qos.logback.núcleo.rodando.SizeAndTimeBasedFNATP debe trabajar muy bien. Acabo de volver de la ‘verdadera’ la primera vez que isTriggeringEvent() llama al método.

    • es allí una manera de rodar sobre inicio – sin la necesidad de un disparo-evento? Tengo un fileappender para los mensajes de error sólo. Quiero que el error-el archivo de registro se vacía después de cada arranque – donde generalmente no se produce ningún error.
    • Puedo preguntar, ¿cuál es el propósito de tocar el violín con maxFileSize?
    • Hey Ceki, no es necesario ser seguro para subprocesos? Es isTriggeringEvent se llama desde más de un hilo?
    • Por desgracia, esto no parece funcionar. ¿Cuál es la forma recomendada para solucionar este problema en el 2015, por favor?
  6. 2

    Ceki la solución no parece funcionar para mí, pero parece ser parte del camino que hay al menos.

    Que se explota porque no puede ver a los rolling política al iniciar el TimeBasedFileNamingAndTriggeringPolicyBase. Con algunos trucos que yo tengo que hacer algunas de registro, y con algunos más que me tengo que observar el gatillo, pero luego se rompió de nuevo porque no podía resolver una de las propiedades de nombre de archivo… El paquete es un logback uno para que yo pudiera llegar a algunos de los componentes internos, para replicar la lógica en SizeAndTimeBasedFNATP#isTriggeringEvent y llame a computeCurrentPeriodsHighestCounterValue. Creo que algo similar podría funcionar, simplemente no han encontrado la magia de la combinación todavía. Realmente espero que yo estoy haciendo algo tonto, porque de lo contrario creo que va a significar la apertura de algunos de los detalles para crear subclases, o poner de esta recta en logback como otro de rodadura/activación de la política.

    logback.xml: probado varios órdenes de triggeringPolicy, TimeBasedFileNamingAndTriggeringPolicy dentro y fuera de la 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>

    El gatillo de la política:

    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]
  7. 1

    Crear una subclase de ch.qos.logback.core.rolling.TimeBasedRollingPolicy y anular su start

    public class MyPolicy
        extends ch.qos.logback.core.rolling.TimeBasedRollingPolicy
    {
    
        public void start ( )
        {
            super.start( );
            rollover( );
        }
    }
    • Lamentablemente esto no funciona porque el accionar de la política devuelve null de getElapsedPeriodsFileName (), que luego se sopla por el desplazamiento().
  8. 1

    Tengo el siguiente trabajo (combinación de ideas de las anteriores respuestas). Tenga en cuenta que estaba tratando con basado en el tamaño de los archivos, no basado en el tiempo, pero supongo que el mismo funciona de la solución.

    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;
    }

    }

  9. 1

    Esta solución funciona de verdad, muchas gracias.
    Sin embargo, hay un molesto inconveniente: al ejecutar el programa por primera vez, el registro se detiene justo después de su creación, cuando está vacío o casi vacío.
    Por lo tanto, 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.
    También, uno de los más estéticos revisión: cambiar el nombre de los «pasos» de la variable, porque se esconde, 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);
        }
    }

    También, creo que funciona correctamente con logback versión 1.1.4-INSTANTÁNEA (yo tengo la fuente y compilado yo mismo), pero no trabajar con la versión 1.1.3. Con la 1.1.3, nombres de los archivos correctamente con la zona horaria especificada, pero rollover todavía sucede en la zona horaria predeterminada de la medianoche.

    • Puedo ver la versión 1.1.7 es ahora, pero esta característica todavía no existe. ¿Hay planes para agregar al paquete estándar? Parece ser bastante simple. Obviamente sigo usando mi propio StartupSizeTimeBasedTriggeringPolicy, pero es molesto mantener una pequeña adición a su alrededor.
  10. 1

    Finalmente averiguar. Puedo rodar por el tamaño, el tiempo de inicio y de seguridad. Aquí está la solución:

    1º de crear su 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 );
        };
    }

    2º configurar 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>
  11. 0

    La API ha cambiado (por ejemplo setMaxFileSize ya no existe) y que muchas de las cosas de arriba no parece funcionar, pero tengo algo que me está funcionando contra logback 1.1.8 (la última en este momento).

    Que quería rodar en el inicio y el rollo en tamaño, pero no de tiempo. Esto 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 se necesita un balanceo de la política. FixedWindowRollingPolicy probablemente haría, pero no me gusta porque quiero mantener un gran número de archivos y es muy ineficiente para eso. Algo que los números de forma incremental (en lugar de deslizamiento como FixedWindow) iba a funcionar, pero que no existe. Mientras estoy escribiendo mi propia he decidido utilizar el tiempo en lugar de contar. Quería extender actual logback código, pero por el momento basado en material de los rolling y la activación de las políticas a menudo se combinan en una sola clase, y hay registros de anidación y circular cosas y campos sin captadores, así que me pareció que más bien imposible. Así que he tenido que hacer un montón de cero. I keep it simple y no implementar características como la compresión – me encantaría tenerlos, pero sólo estoy tratando de mantener la sencillez.

    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, a continuación, config 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, a votar por ella en

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

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

    (hace años, y para mí esto es absolutamente crítico funcionalidad, aunque sé que muchos otros marcos de fallar en él también)

Dejar respuesta

Please enter your comment!
Please enter your name here