web-dev-qa-db-ja.com

起動時にlogbackでログファイルをロールする方法

以下を実行するようにlogbackを構成したいと思います。

  • ファイルにログ
  • 50MBに達したときにファイルをロールする
  • 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>
48
Mike Q

他の提案はどれも私の状況に適していませんでした。 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アノテーションは、他のすべての初期化が完了する前にJoranが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> 

お役に立てれば!

26
Dave

次のクラスを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

既存のコンポーネントを使用するソリューションの場合、ログバックは一意の名前のファイルを提案します: 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
raisercostin

アプリケーションの起動時にlogFileを1回ローリングする別の解決策を見つけました。

私はlogbackのRollingFileAppenderをlogbackのFixedWindowRollingPolicyと一緒に使用し、自分のTriggeringPolicy<E>

FixedWindowRollingPolicyは、新しいlogFileのfileNamePatternを取得します。ここで、%1はファイルの新しい番号です。 maxIndexは、私の「履歴」の最大数を表します。詳細: FixedWindowRollingPolicy

私の実装TriggeringPolicyは、isTriggeringEvent(...)が呼び出されたときに、first時間の間trueを返します。そのため、WindowRollingPolicyは、ポリシーが最初に呼び出されたときにログファイルをロールオーバーし、その後再びロールオーバーすることはありません。

RollingFileAppenderのxml構成:

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

Ch.qos.logback.core.rolling.SizeAndTimeBasedFNATPのisTriggeringEvent()メソッドをオーバーライドすると、うまく機能するはずです。 isTriggeringEvent()メソッドが初めて呼び出されたときに「true」を返すだけです。

3
Ceki

Cekiの解決策は私にはうまくいかないようですが、少なくともその方法の一部であるようです。

TimeBasedFileNamingAndTriggeringPolicyBaseの起動時にローリングポリシーを表示できないため、爆発します。いくつかのハッカーでログを記録し、さらにいくつかでトリガーを監視しましたが、ファイル名のプロパティの1つを解決できなかったため、再度壊れました...パッケージはログバックです。内部のいくつかに到達し、SizeAndTimeBasedFNATP#isTriggeringEventのロジックの一部を複製してcomputeCurrentPeriodsHighestCounterValueを呼び出すことができます。私はそれらの線に沿った何かがうまくいくかもしれないと思います、魔法の組み合わせをまだ見つけていません。私は本当にばかげたことをやっていると本当に思います。それ以外の場合は、サブクラス化の詳細の一部を開くか、これを別のローリング/トリガーポリシーとしてログバックに直接入れることを意味するからです。

logback.xml:triggeringPolicyの内側と外側でTimeBasedFileNamingAndTriggeringPolicyrollingPolicyのさまざまな順序を試しました。

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

このソリューションは本当に役に立ちます。ただし、厄介な問題が1つあります。プログラムを初めて実行すると、ログが作成された直後、ログが空またはほとんど空の場合にログがロールされます。したがって、修正を提案します。ログファイルが存在し、メソッドが呼び出されたときに空ではないかどうかを確認します。また、もう1つの表面的な修正:「started」変数の名前を変更します。これは、継承されたメンバーを同じ名前で非表示にするためです。

@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
Leonid Ilyevsky

私は次のものを機能させました(以前の回答からのアイデアを組み合わせます)。時間ベースではなくサイズベースのファイルを扱っていましたが、同じソリューションが機能していると思います。

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

ch.qos.logback.core.rolling.TimeBasedRollingPolicyの独自のサブクラスを作成し、そのstartをオーバーライドします

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

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

私はついにそれを理解します。サイズ、時間、立ち上げで転がります。これが解決策です:

最初に自分のクラスを作成する

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

APIが変更され(たとえば、setMaxFileSizeが存在しなくなった)、上記の多くの機能が動作しないようですが、私はlogback 1.1.8(現時点で最新)に対して機能しているものを持っています。

私は、スタートアップではなく、サイズでロールしたかったが、時間ではなかった。これはそれをします:

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

これには、ローリングポリシーも必要です。 FixedWindowRollingPolicyはおそらく機能しますが、大量のファイルを保持する必要があり、そのために非常に非効率であるため、私はそれが好きではありません。 (FixedWindowのようにスライドするのではなく)番号が少しずつ増えていきますが、それは存在しません。私が自分で書いている限り、カウントではなく時間を使うことにしました。私は現在のログバックコードを拡張したかったのですが、時間ベースのものについては、ローリングポリシーとトリガーポリシーが1つのクラスにまとめられることが多く、ゲッターのないネストされた循環のものとフィールドのログがあるため、かなり不可能であることがわかりました。だから私はゼロからたくさんしなければなりませんでした。私はそれを単純に保ち、圧縮のような機能を実装しませんでした-私はそれらを持っているのが大好きですが、私はそれを単純に保つようにしています。

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

そして、設定は次のようになります

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

イライラしている場合、これはネイティブに解決されていません。投票してください

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

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

(それは何年も前であり、私にとってこれは絶対に重要な機能ですが、他の多くのフレームワークでも失敗することは知っています)

0
dlipofsky