Как накатить файл журнала при запуске в logback - PullRequest
43 голосов
/ 22 марта 2010

Я бы хотел настроить logback для выполнения следующих действий.

  • Вход в файл
  • Сверните файл, когда он достигнет 50 МБ
  • Храните журналы только за 7 дней
  • При запуске всегда генерировать новый файл (делать бросок)

У меня все работает, за исключением последнего пункта, стартового броска. Кто-нибудь знает, как этого добиться? Вот конфиг ...

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

Ответы [ 11 ]

26 голосов
/ 13 сентября 2012

Ни одно из других предложений не соответствовало моей ситуации. Я не хотел использовать решение на основе размера и времени, потому что оно требует настройки MaxFileSize, а мы используем политику строго на основе времени. Вот как я выполнил прокрутку файла при запуске с 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
        }
    }

}

Хитрость в том, чтобы установить время nextCheck в 0L, чтобы isTriggeringEvent () подумал, что пора перевернуть файл журнала. Таким образом, он выполнит код, необходимый для вычисления имени файла, а также для удобного сброса значения времени nextCheck. Последующий вызов rollover () вызывает откат файла журнала. Поскольку это происходит только при запуске, это более оптимальное решение, чем те, которые выполняют сравнение внутри isTriggerEvent (). Каким бы небольшим это сравнение ни было, оно все же несколько снижает производительность при выполнении каждого сообщения журнала. Это также заставляет одновременное переключение при запуске вместо ожидания первого события журнала.

Аннотация @NoAutoStart важна для предотвращения выполнения Джораном метода start () до завершения всей остальной инициализации. В противном случае вы получите исключение NullPointerException.

Вот конфиг:

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

Надеюсь, это поможет!

7 голосов
/ 01 февраля 2011

Это работает для меня, используя следующий класс как 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);
    }
}
5 голосов
/ 21 сентября 2016

Для решения, использующего уже существующие компоненты, при входе в систему предлагается файл с уникальным именем : http://logback.qos.ch/manual/appenders.html#uniquelyNamed

На этапе разработки приложения или в случае кратковременного приложения, например пакетных приложений, желательно создать новый файл журнала при каждом запуске нового приложения. Это довольно легко сделать с помощью элемента <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>

ОБНОВЛЕНО для 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 голосов
/ 25 августа 2015

Я нашел другое решение для прокрутки logFile один раз, когда приложение запускается.

Я использую logback RollingFileAppender с logback's FixedWindowRollingPolicy и мою собственную реализацию TriggeringPolicy<E>.

FixedWindowRollingPolicy получает fileNamePattern для нового файла журнала, где %1 - новый номер файла. MaxIndex обозначает максимальное количество моей «истории». Дополнительная информация: FixedWindowRollingPolicy

Мои реализации TriggeringPolicy возвращает true для первого времени, когда вызывается isTriggeringEvent (...). Поэтому WindowRollingPolicy переворачивает файлы журналов, когда политика вызывается в первый раз, и после этого она не перевернется снова.

xml-конфигурация для 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>

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;
    }
}
3 голосов
/ 22 марта 2010

Переопределение метода isTriggeringEvent () в ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP должно работать хорошо.Просто верните true в первый раз, когда вызывается метод isTriggeringEvent ().

2 голосов
/ 15 апреля 2010

Решение Ceki, похоже, не работает для меня, но, по крайней мере, похоже, частично.

Он взрывается, потому что не может видеть скользящую политику при запуске TimeBasedFileNamingAndTriggeringPolicyBase. С некоторой хакерской атакой я заставил его выполнить некоторую регистрацию, а с помощью некоторого другого я заставил его наблюдать за триггером, но затем он снова сломался, потому что не смог разрешить одно из свойств имени файла ... можно было бы добраться до некоторых внутренних устройств, скопировать часть логики в SizeAndTimeBasedFNATP#isTriggeringEvent и вызвать computeCurrentPeriodsHighestCounterValue. Я думаю, что-то в этом роде может сработать, но пока не нашел волшебную комбинацию. Я действительно надеюсь, что делаю что-то глупое, потому что в противном случае я думаю, что это будет означать либо раскрытие некоторых деталей для создания подклассов, либо внесение этого прямо в logback в качестве другой скользящей / запускающей политики.

logback.xml: пробовал различные порядки triggeringPolicy, TimeBasedFileNamingAndTriggeringPolicy внутри и снаружи 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>

Политика триггера:

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

Исключение:

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]
1 голос
/ 10 июля 2015

Это решение действительно работает, спасибо большое. Однако есть один неприятный глюк: когда вы запускаете программу в первый раз, журнал катится сразу после его создания, когда он пуст или почти пуст. Поэтому я предлагаю исправить: проверить, существует ли файл журнала и не является ли он пустым во время вызова метода. Кроме того, еще одно косметическое исправление: переименуйте переменную «begin», потому что она скрывает унаследованный элемент с тем же именем.

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

Кроме того, я считаю, что он корректно работает с версией logback 1.1.4-SNAPSHOT (я получил исходный код и сам скомпилировал его), но он не полностью работает с выпуском 1.1.3. В версии 1.1.3 он правильно называет файлы с указанным часовым поясом, но перенос по-прежнему происходит в полночь часового пояса по умолчанию.

1 голос
/ 12 июня 2015

Я наконец понял это.Я могу катиться по размеру, времени и запуску.Вот решение:

1-й создать свой собственный класс

@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-й настроить 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>
1 голос
/ 26 августа 2012

Я получил следующее для работы (объединение идей из предыдущих ответов). Обратите внимание, что я имел дело с файлами на основе размера, а не на основе времени, но я предполагаю, что то же решение работает.

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

}

1 голос
/ 22 марта 2010

Создайте свой собственный подкласс ch.qos.logback.core.rolling.TimeBasedRollingPolicy и переопределите его start

public class MyPolicy
    extends ch.qos.logback.core.rolling.TimeBasedRollingPolicy
{

    public void start ( )
    {
        super.start( );
        rollover( );
    }
}
...