it-swarm-eu.dev

Jak przetoczyć plik dziennika podczas uruchamiania w trybie logowania

Chciałbym skonfigurować logback, aby wykonać następujące czynności.

  • Zaloguj się do pliku
  • Rzuć plik, gdy osiągnie 50 MB
  • Realizuj dzienniki tylko przez 7 dni
  • Podczas uruchamiania zawsze generuj nowy plik (zrób rolkę)

Mam wszystko działa, z wyjątkiem ostatniego elementu, roll startu. Czy ktoś wie, jak to osiągnąć? Oto konfiguracja ...

  <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>
42
Mike Q

Żadna z pozostałych sugestii nie była odpowiednia dla mojej sytuacji. Nie chciałem korzystać z rozwiązania opartego na rozmiarze i czasie, ponieważ wymaga ono skonfigurowania MaxFileSize i stosujemy zasady ściśle oparte na czasie. Oto, jak udało mi się przetoczyć plik przy starcie za pomocą 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
        }
    }

}

Sztuczka polega na ustawieniu czasu nextCheck na 0L, aby isTriggeringEvent () pomyślał, że nadszedł czas, aby przerzucić plik dziennika. W ten sposób wykona kod niezbędny do obliczenia nazwy pliku, a także wygodnie zresetuje wartość czasu nextCheck. Kolejne wywołanie funkcji rollover () powoduje wyrzucenie pliku dziennika. Ponieważ dzieje się to tylko przy starcie, jest to rozwiązanie bardziej optymalne niż te, które dokonują porównania wewnątrz isTriggerEvent (). Niezależnie od tego, jak małe jest to porównanie, nadal nieznacznie obniża wydajność, gdy jest wykonywany przy każdym komunikacie dziennika. Zmusza to również do natychmiastowego wystąpienia rollover, zamiast czekać na pierwsze zdarzenie dziennika.

Adnotacja @NoAutoStart jest ważna, aby uniemożliwić Joranowi wykonanie metody start () przed zakończeniem całej innej inicjalizacji. W przeciwnym razie otrzymasz wyjątek NullPointerException.

Oto konfiguracja:

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

Mam nadzieję że to pomoże!

25
Dave

Działa dla mnie, używając następującej klasy jako 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);
    }
}
7
proactif

W przypadku rozwiązania wykorzystującego już istniejące komponenty logback sugeruje pliki o unikalnych nazwach: http://logback.qos.ch/manual/appenders.html#uniquelyNamed

Podczas fazy tworzenia aplikacji lub w przypadku krótkotrwałych aplikacji , Np. aplikacje wsadowe, pożądane jest utworzenie nowego pliku dziennika przy każdym uruchomieniu nowej aplikacji. Jest to dość łatwe do zrobienia Za pomocą elementu <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>

AKTUALIZACJA dla 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
raisercostin

Znalazłem inne rozwiązanie do toczenia pliku dziennika raz, gdy aplikacja się uruchomi. 

Używam RollingFileAppendername logback's z FixedWindowRollingPolicyi moja własna implementacja TriggeringPolicy<E>.

FixedWindowRollingPolicypobiera nazwę pliku fileNazwa dla nowego pliku dziennika, gdzie %1 to nowy numer pliku. MaxIndex oznacza maksymalną liczbę mojej „historii”. Więcej informacji: FixedWindowRollingPolicy

Moje implementacje TriggeringPolicyzwraca true dla first time, gdy wywoływany jest isTriggeringEvent (...). Więc WindowRollingPolicy przewija pliki dziennika, gdy polityka zostanie wywołana po raz pierwszy, a potem nie będzie się ona ponownie przewijać.

Konfiguracja xml dla RollingFileAppendername__:

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

TriggeringPolicyname__:

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

Zastąpienie metody isTriggeringEvent () w ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP powinno działać dobrze. Po prostu zwróć 'true' po pierwszym wywołaniu metody isTriggeringEvent ().

3
Ceki

Rozwiązanie Ceki wydaje się nie działać dla mnie, ale wydaje się być przynajmniej częściowo.

Uderza, ponieważ nie widzi widocznej zasady podczas uruchamiania TimeBasedFileNamingAndTriggeringPolicyBase. Z jakimś hackerem mam go do zrobienia, a przy kilku innych dostałem go do obserwacji wyzwalacza, ale potem znowu się załamał, ponieważ nie mógł rozwiązać jednej z właściwości nazwy pliku ... Pakiet jest logbackiem, więc ja może dostać się do niektórych elementów wewnętrznych, aby odtworzyć część logiki w SizeAndTimeBasedFNATP#isTriggeringEvent i wywołać computeCurrentPeriodsHighestCounterValue. Myślę, że coś takiego może zadziałać, ale jeszcze nie znalazłem magicznej kombinacji. Naprawdę mam nadzieję, że robię coś głupiego, ponieważ w przeciwnym razie myślę, że będzie to oznaczało albo otwarcie niektórych szczegółów dla podklasy, albo wprowadzenie tego prostego do logbacku jako kolejnej polityki toczenia/wyzwalania.

logback.xml: wypróbował różne porządki triggeringPolicy, TimeBasedFileNamingAndTriggeringPolicy wewnątrz i na zewnątrz 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>

Polityka wyzwalacza:

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

Wyjątek:

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]
2
Joe Kearney

To rozwiązanie naprawdę działa, dziękuję bardzo. Istnieje jednak jedna irytująca usterka: po uruchomieniu programu po raz pierwszy dziennik jest przewijany zaraz po utworzeniu, gdy jest pusty lub prawie pusty. Proponuję więc poprawkę: sprawdź, czy plik dziennika istnieje i nie jest pusty w momencie wywołania metody. Również jedna poprawka kosmetyczna: zmień nazwę zmiennej „rozpoczęty”, ponieważ ukrywa się odziedziczony członek o tej samej nazwie.

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

Ponadto uważam, że działa poprawnie z wersją 1.1.4-SNAPSHOT z logbackiem (sam dostałem źródło i skompilowałem je), ale nie działa w pełni z wersją 1.1.3. W wersji 1.1.3 nazwy plików są poprawne w określonej strefie czasowej, ale najazd nadal odbywa się w domyślnej strefie czasowej o północy.

1
Leonid Ilyevsky

Do pracy doszedłem (łącząc pomysły z poprzednich odpowiedzi). Uwaga: Miałem do czynienia z plikami opartymi na rozmiarze, a nie na czasie, ale zgaduję, że to samo rozwiązanie działa.

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
djechlin

Utwórz własną podklasę ch.qos.logback.core.rolling.TimeBasedRollingPolicy i zastąp jej start

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

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

W końcu to zrozumiałem. Mogę toczyć według rozmiaru, czasu i startu. Oto rozwiązanie:

1. stwórz własną klasę

@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. konfiguracja 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
Perlos

API się zmieniło (na przykład setMaxFileSize już nie istnieje) i wiele z powyższych rzeczy nie działa, ale mam coś, co działa dla mnie w porównaniu z logback 1.1.8 (najnowszy w tym czasie).

Chciałem toczyć się po starcie i zmieniać rozmiar, ale nie czas. To robi:

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

W tym celu potrzebujesz także polityki kroczącej. FixedWindowRollingPolicy prawdopodobnie to zrobi, ale nie podoba mi się, ponieważ chcę zachować dużą liczbę plików i jest to bardzo nieefektywne. Coś, co wzrasta stopniowo (zamiast przesuwać jak FixedWindow), zadziałałoby, ale to nie istnieje. Dopóki piszę własną, postanowiłem wykorzystać czas zamiast liczyć. Chciałem rozszerzyć bieżący kod logowania, ale dla rzeczy opartych na czasie reguły toczenia i wyzwalania są często łączone w jedną klasę i istnieją logi zagnieżdżania i okrągłych rzeczy i pól bez getterów, więc stwierdziłem, że jest to raczej niemożliwe. Więc musiałem zrobić dużo od zera. Utrzymuję to w prosty sposób i nie zaimplementowałem funkcji takich jak kompresja - chciałbym je mieć, ale staram się po prostu zachować prostotę.

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

A potem wygląda jak config

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

jeśli jesteś sfrustrowany, nie rozwiązuje się tego natywnie, zagłosuj na niego w

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

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

(minęły lata, a dla mnie jest to absolutnie krytyczna funkcjonalność, chociaż wiem, że wiele innych ram zawodzi również)

0
dlipofsky