如何在logback中启动时滚动日志文件

时间:2010-03-22 12:06:53

标签: java startup logback appender

我想配置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>

12 个答案:

答案 0 :(得分:25)

其他建议都不适合我的情况。我不想使用基于大小和时间的解决方案,因为它需要配置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> 

希望这有帮助!

答案 1 :(得分:7)

它适用于我,使用以下类作为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);
    }
}

答案 2 :(得分:5)

当应用程序启动时,我找到了另一种滚动logFile的解决方案。

我使用logback&#39; ViewHolder (android.widget.TextView) in ViewHolder cannot be applied to (android.view.View) RollingFileAppender以及FixedWindowRollingPolicy我自己的实现。

TriggeringPolicy<E>获取新logFile的fileNamePattern,其中FixedWindowRollingPolicy是文件的新编号。 maxIndex代表我的&#34;历史记录&#34;的最大数量。更多信息:FixedWindowRollingPolicy

我的实现%1第一个时间返回true,当调用isTriggeringEvent(...)时。因此,当第一次调用策略时,WindowRollingPolicy将覆盖日志文件,之后它将不再翻转。

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

答案 3 :(得分:5)

对于使用现有组件的解决方案,logback会建议唯一命名的文件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>

答案 4 :(得分:3)

覆盖ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP中的isTriggeringEvent()方法应该可以很好地工作。只需在第一次调用isTriggeringEvent()方法时返回'true'。

答案 5 :(得分:2)

Ceki的解决方案似乎对我不起作用,但似乎至少在那里有所作为。

它爆炸了,因为它在启动TimeBasedFileNamingAndTriggeringPolicyBase时看不到滚动策略。有一些hackery我得到它做一些日志记录,并有一些我得到它来观察触发器,但然后它再次破坏,因为它无法解析其中一个文件名属性...包是一个logback所以我可以到达一些内部,复制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]

答案 6 :(得分:1)

创建自己的ch.qos.logback.core.rolling.TimeBasedRollingPolicy子类并覆盖其start

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

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

答案 7 :(得分:1)

我得到了以下工作(结合以前答案的想法)。注意我正在处理基于大小的文件,而不是基于时间的,但我猜相同的解决方案有效。

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

}

答案 8 :(得分:1)

我终于明白了。我可以按大小,时间和启动来滚动。这是解决方案:

1st创建自己的类

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

第二次配置回溯

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

答案 9 :(得分:1)

这个解决方案确实有效,非常感谢。 但是,有一个令人讨厌的故障:当您第一次运行程序时,日志在创建后立即滚动,当它为空或几乎为空时。 所以我建议修复:检查日志文件是否存在,并且在调用方法时不是空的。 此外,还有一个美化修复:重命名“已启动”变量,因为它隐藏了具有相同名称的继承成员。

@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中,它使用指定的时区正确命名文件,但在午夜的默认时区仍然会发生翻转。

答案 10 :(得分:0)

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那样滑动)会起作用,但这并不存在。只要我自己写作,我决定用时间代替计数。我想扩展当前的logback代码,但对于基于时间的东西,滚动和触发策略通常组合成一个类,并且有嵌套和循环的东西和没有getter的字段的日志,所以我发现这是不可能的。所以我不得不从头开始做很多事情。我保持简单,并没有实现压缩等功能 - 我很乐意拥有它们,但我只是想保持简单。

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

(它已经好几年了,对我来说这绝对是关键功能,虽然我知道很多其他框架也失败了)

答案 11 :(得分:0)

我找到了一种方法,不需要在配置中注入自定义类。它利用测试API诱使添加程序认为是时候滚动文件了。

此示例假设您在名为RollingFileAppender的XML中配置了ROLLING,并将其设置为使用SizeAndTimeBasedRollingPolicy进行每日翻转:

<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>./logs/${app-name}.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <fileNamePattern>./logs/${app-name}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
        <maxFileSize>100MB</maxFileSize>
        <maxHistory>5</maxHistory>
        <totalSizeCap>5GB</totalSizeCap>
    </rollingPolicy>
    <encoder>
        <pattern>${LOG_PATTERN}</pattern>
    </encoder>
</appender>

下面的代码将找到滚动策略并触发滚动。请注意,这将在短时间内全局改写追加器的时钟,因此在任何其他线程可能潜在地写入消息时,请勿调用它。

// get the root logger
ch.qos.logback.classic.Logger _logger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);

// get the triggering policy from the rolling appender
RollingFileAppender<?> _appender = (RollingFileAppender<?>)_logger.getAppender("ROLLING");
SizeAndTimeBasedRollingPolicy<?> _policy = (SizeAndTimeBasedRollingPolicy<?>)_appender.getRollingPolicy();
TimeBasedFileNamingAndTriggeringPolicy<?> _trigger = _policy.getTimeBasedFileNamingAndTriggeringPolicy();

// trick the appender into thinking it is time to rollover
_trigger.setCurrentTime(System.currentTimeMillis() + 24*60*60*1000);

// this message will trigger the rollover
LOG.info("Initializing log for app: {}", _appName);

// turn off fake time
_trigger.setCurrentTime(0);