2010-03-22 6 views
41

Ich möchte Logback konfigurieren, um Folgendes zu tun.Wie rolle ich die Protokolldatei beim Start in Logback

  • Log in eine Datei
  • Rollen Sie die Datei, wenn sie 50MB
  • Nur halten 7 Tage im Wert von Protokollen
  • Beim Start erreicht immer eine neue Datei erzeugen (do eine Rolle)

Ich habe alles außer dem letzten Artikel, Startup Roll funktioniert. Weiß jemand, wie man das erreicht? Hier ist die 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> 

Antwort

1

Erstellen Sie Ihre eigene Unterklasse von ch.qos.logback.core.rolling.TimeBasedRollingPolicy und außer Kraft setzen ihre start

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

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

Leider funktioniert das nicht, weil die auslösende Richtlinie Null von getElapsedPeriodsFileName() zurückgibt, die dann den Rollover() in die Luft jagt. –

3

die isTriggeringEvent() -Methode in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP Aufschalten sollte funktionieren schön. Geben Sie "true" beim ersten Aufruf der Methode "triggeringEvent()" zurück.

+0

gibt es eine Möglichkeit, beim Start zu rollen - ohne dass ein Triggerereignis erforderlich ist? Ich habe einen Dateianfänger nur für Fehlermeldungen.Ich möchte, dass die Fehlerprotokolldatei nach jedem Start leer ist - wo normalerweise kein Fehler auftritt. –

+0

Kann ich fragen, was ist der Zweck des Fummelns mit maxFileSize? – Mykro

+0

Hey Ceki, muss das threadsicher sein? Wird isTriggeringEvent von mehr als einem Thread aufgerufen? –

2

Cekis Lösung scheint bei mir nicht zu funktionieren, scheint aber wenigstens Teilweise dort zu sein.

Es explodiert, weil es die Rolling Policy beim Start der TimeBasedFileNamingAndTriggeringPolicyBase nicht sehen kann. Mit etwas Hacker habe ich es geschafft, etwas Logging zu machen, und mit einigen mehr habe ich es geschafft, den Trigger zu beobachten, aber dann ist es wieder kaputt gegangen, weil es eine der Dateinameneigenschaften nicht auflösen konnte ... Das Paket ist ein Logbuch, also ich könnte zu einigen der Interna gelangen, um einige der Logik in SizeAndTimeBasedFNATP#isTriggeringEvent zu replizieren und computeCurrentPeriodsHighestCounterValue anrufen. Ich denke, dass etwas in dieser Richtung funktionieren könnte, habe die magische Kombination noch nicht gefunden. Ich hoffe wirklich, dass ich etwas albernes mache, weil ich sonst denke, dass es entweder das Öffnen von Details für das Unterklassen-Lernen bedeutet, oder das Log-Back als eine weitere rollende/auslösende Strategie.

logback.xml: verschiedene Einstufungen von triggeringPolicy, TimeBasedFileNamingAndTriggeringPolicy innerhalb und außerhalb der rollingPolicy versucht.

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

Die Trigger-Politik:

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

Die Ausnahme:

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

Es funktioniert für mich, die folgende Klasse als timeBasedFileNamingAndTriggeringPolicy mit:

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

ich bekam Folgendes Arbeit (Kombination von Ideen aus früheren Antworten). Hinweis: Ich habe es mit größenbasierten Dateien zu tun, nicht zeitbasiert, aber ich vermute, dass die gleiche Lösung funktioniert.

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

}

23

Keiner der anderen Vorschläge war für meine Situation angemessen ist. Ich wollte keine größen- und zeitbasierte Lösung verwenden, da hierfür ein MaxFileSize konfiguriert werden muss und wir eine strikt zeitbasierte Richtlinie verwenden.Hier ist, wie ich erreicht die Datei beim Start rollen mit einem 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 
     } 
    } 

} 

Der Trick ist, die nextCheck Zeit 0L zu setzen, so dass isTriggeringEvent() werden denken, es ist Zeit, die Protokolldatei zu überschlagen. Es wird somit den Code ausführen, der notwendig ist, um den Dateinamen zu berechnen, sowie den nextCheck-Zeitwert bequem zurücksetzen. Der nachfolgende Aufruf von rollover() bewirkt, dass die Protokolldatei gerollt wird. Da dies nur beim Start passiert, ist es eine optimale Lösung als diejenigen, die einen Vergleich innerhalb von isTriggerEvent() durchführen. Auch wenn dieser Vergleich zu klein ist, verschlechtert er dennoch die Leistung geringfügig, wenn er bei jeder Protokollnachricht ausgeführt wird. Dies zwingt den Rollover sofort beim Start, statt auf das erste Log-Ereignis zu warten.

Die Annotation @NoAutoStart ist wichtig, um zu verhindern, dass Joran die Methode start() ausführt, bevor alle anderen Initialisierungen abgeschlossen sind. Andernfalls erhalten Sie eine NullPointerException. Hier

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

hoffe, das hilft!

+1

Ich habe gekämpft und das ist genau das, was ich will, danke! IMO das sollte ein Standard-Feature sein und zu config ist ein bisschen unintuitiv – vincentlcy

+1

Danke für die Lösung - ich stimme mit @vincentlcy und denke auch, dass dies ein Standard-Feature sein sollte. – dcompiled

+0

Ich möchte nur meinen Dank für eine großartige Lösung hinzufügen. Ich möchte das funktioniert nur (Logback 1.0.13) hinzufügen, wenn Sie einen rohen Dateinamen definiert haben: event.txt Wenn Sie dies aus Ihrer Konfigurations ausschließen, so dass Sie nur 0,0 erhalten, 0,1, .2 usw. indizierte Dateien (dies wird von der Logback-Dokumentation für Windows-Plattformen empfohlen, um Probleme mit Dateisperren/-umbenennen zu vermeiden), führt diese Lösung leider keinen Rollover durch, da in timeBasedRollingPolicy.rollover() der Aufruf von getParentsRawFileProperty () gibt null zurück. – Mykro

1

Ich finde es endlich heraus. Ich kann nach Größe, Zeit und Start rollen. Hier Lösung:

1. Erstellen Sie besitzen Klasse

@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. configure 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

Diese Lösung wirklich funktioniert, vielen Dank. Allerdings gibt es einen lästigen Fehler: Wenn Sie das Programm zum ersten Mal ausführen, wird das Protokoll direkt nach der Erstellung gerollt, wenn es leer oder fast leer ist. Ich schlage also eine Lösung vor: Überprüfen Sie, ob die Protokolldatei existiert und nicht leer ist, wenn die Methode aufgerufen wird. Ein weiterer kosmetischer Fix: Benenne die Variable "started" um, weil sie das geerbte Mitglied mit dem gleichen Namen versteckt.

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

Auch ich glaube, es funktioniert mit logback Version 1.1.4-SNAPSHOT (ich die Quelle bekommen und es selbst kompiliert), aber nicht vollständig mit 1.1.3 Release arbeiten. Mit 1.1.3 werden die Dateien ordnungsgemäß mit der angegebenen Zeitzone benannt, der Rollover wird jedoch immer noch zur Standardzeitzone Mitternacht ausgeführt.

+0

Ich sehe die Version 1.1.7 ist jetzt out, aber diese Funktion ist immer noch nicht da. Gibt es Pläne, es dem Standardpaket hinzuzufügen? Es sieht ziemlich einfach aus. Offensichtlich benutze ich immer noch meine eigene StartupSizeTimeBasedTriggeringPolicy, aber es ist ärgerlich, halten Sie so eine kleine Ergänzung herum. –

5

Ich fand eine andere Lösung für das Rollen der Logdatei einmal, wenn die Anwendung gestartet wird.

Ich benutze Logback RollingFileAppender mit Logback FixedWindowRollingPolicy und meine eigene Implementierung eines TriggeringPolicy<E>.

Die FixedWindowRollingPolicy ruft das fileNamePattern für die neue logFile ab, wobei %1 die neue Nummer der Datei ist. Der maxIndex steht für die maximale Anzahl meiner "Geschichte". Weitere Informationen: FixedWindowRollingPolicy

Meine Implementierungen TriggeringPolicy für die erste Zeit true zurück, wenn isTriggeringEvent (...) aufgerufen wird. Daher rollt die WindowRollingPolicy über die Protokolldateien, wenn die Richtlinie das erste Mal aufgerufen wird, und danach wird sie nicht erneut durchlaufen.

Die XML-Konfiguration für die 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> 

Die 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

Für eine Lösung vorhandenen Komponenten bereits die logback die schlägt eindeutig benannte Dateien: http://logback.qos.ch/manual/appenders.html#uniquelyNamed

Während der Anwendungsentwicklungsphase oder im Fall von kurzlebigen Anwendungen, z.B. Batch-Anwendungen ist es wünschenswert, bei jedem Start einer neuen Anwendung eine neue Protokolldatei zu erstellen. Dies ist ziemlich einfach zu mit Hilfe der <timestamp> Element.

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

AKTUALISIERT für 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> 
0

Die API geändert hat (zB setMaxFileSize existiert nicht mehr) und eine Menge von dem Zeug oben nicht scheinen zu arbeiten, aber ich habe etwas, das für mich gegen Logback 1.1.8 arbeitet (das neueste zu dieser Zeit).

Ich wollte beim Start und rollen auf Größe, aber nicht Zeit. Das macht es:

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

Damit benötigen Sie auch eine rollierende Politik. FixedWindowRollingPolicy würde wahrscheinlich tun, aber ich mag es nicht, weil ich eine große Anzahl von Dateien behalten möchte und das ist sehr ineffizient dafür. Etwas, das schrittweise aufwärts zählt (anstatt wie FixedWindow zu gleiten), funktioniert, aber das existiert nicht. Solange ich meine eigene schreibe, habe ich beschlossen, Zeit zu verwenden statt zu zählen. Ich wollte den aktuellen Logback-Code erweitern, aber für die zeitbasierten Sachen werden die Rolling- und Triggering-Richtlinien oft zu einer Klasse zusammengefasst, und es gibt Protokolle von Verschachtelung und Kreisverkehr und Feldern ohne Getters, also fand ich das eher unmöglich. Also musste ich viel von vorne anfangen. Ich halte es einfach und implementiere keine Funktionen wie die Komprimierung - ich hätte sie gerne, aber ich versuche es einfach zu halten.

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

Und dann Config wie

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

sieht, wenn Sie frustriert sind diese nicht nativ gelöst ist, für ihn stimmen bei

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

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

(es ist Jahre her, und das ist für mich absolut kritischer Spaß ctionality, obwohl ich weiß, dass viele andere Frameworks es auch scheitern)

Verwandte Themen