51

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

12 回答 12

30

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

希望这可以帮助!

于 2012-09-13T14:20:49.417 回答
12

对于使用现有组件的解决方案,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>
于 2016-09-21T08:47:33.423 回答
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);
    }
}
于 2011-02-01T14:16:49.220 回答
7

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

我将 logbackRollingFileAppender与 logbackFixedWindowRollingPolicy以及我自己的TriggeringPolicy<E>.

FixedWindowRollingPolicy获取新 logFile 的 fileNamePattern,其中是%1文件的新编号。maxIndex 代表我的“历史”的最大数量。更多信息:FixedWindowRollingPolicy

当 isTriggeringEvent(...) 被调用时,我的实现TriggeringPolicy一次返回 true 。因此,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;
    }
}
于 2015-08-25T12:16:59.207 回答
3

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

于 2010-03-22T20:39:11.910 回答
2

Ceki 的解决方案似乎对我不起作用,但至少似乎是其中的一部分。

它爆炸了,因为它在启动时看不到滚动策略TimeBasedFileNamingAndTriggeringPolicyBase。有了一些hackery,我让它做一些日志记录,还有一些我让它观察触发器,但后来它又坏了,因为它无法解析其中一个文件名属性......这个包是一个logback包,所以我可以访问一些内部结构,复制一些逻辑SizeAndTimeBasedFNATP#isTriggeringEvent并调用computeCurrentPeriodsHighestCounterValue. 我认为沿着这些思路可能会起作用,只是还没有找到神奇的组合。我真的希望我在做一些愚蠢的事情,否则我认为这将意味着要么为子类化开放一些细节,要么将其作为另一个滚动/触发策略直接放入 logback。

triggeringPolicylogback.xml:尝试了.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]
于 2010-04-15T17:15:02.293 回答
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;
}

}

于 2012-08-26T16:41:17.053 回答
1

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

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

    public void start ( )
    {
        super.start( );
        rollover( );
    }
}
于 2010-03-22T12:25:42.880 回答
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>
于 2015-06-12T11:13:05.157 回答
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 中,它使用指定的时区正确命名文件,但翻转仍会在默认时区午夜发生。

于 2015-07-10T03:46:33.617 回答
1

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

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

于 2017-01-13T01:29:26.173 回答
0

我找到了一种不需要将自定义类注入配置的方法。它利用测试 API 来欺骗 appender 认为是时候滚动文件了。

此示例假定您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);
于 2020-12-04T23:29:13.990 回答