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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2492022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 08:23:15  来源:igfitidea点击:

How to roll the log file on startup in logback

javastartuplogbackappender

提问by Mike Q

I would like to configure logback to do the following.

我想配置 logback 以执行以下操作。

  • Log to a file
  • Roll the file when it reaches 50MB
  • Only keep 7 days worth of logs
  • On startup always generate a new file (do a roll)
  • 登录到文件
  • 当文件达到 50MB 时滚动文件
  • 只保留 7 天的日志
  • 在启动时总是生成一个新文件(做一个滚动)

I have it all working except for the last item, startup roll. Does anyone know how to achieve that? Here's the 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>

回答by Alexander Pogrebnyak

Create your own subclass of ch.qos.logback.core.rolling.TimeBasedRollingPolicyand override its start

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

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

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

回答by Ceki

Overriding the isTriggeringEvent() method in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP should work nicely. Just return 'true' the first time isTriggeringEvent() method is called.

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

回答by Joe Kearney

Ceki's solution doesn't appear to work for me, but seems to be part way there at least.

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

It blows up because it can't see the rolling policy when starting the TimeBasedFileNamingAndTriggeringPolicyBase. With some hackery I got it to do some logging, and with some more I got it to observe the trigger, but then it broke again because it couldn't resolve one of the filename properties... The package is a logback one so I could get to some of the internals, to replicate some of the logic in SizeAndTimeBasedFNATP#isTriggeringEventand call computeCurrentPeriodsHighestCounterValue. I think something along those lines might work, just haven't found the magic combination yet. I really hope I'm doing something silly, because otherwise I think it will mean either opening up some of the details for subclassing, or putting this straight into logback as another rolling/triggering policy.

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

logback.xml: tried various orderings of triggeringPolicy, TimeBasedFileNamingAndTriggeringPolicyinside and outside the rollingPolicy.

logback.xml:尝试各种排序triggeringPolicyTimeBasedFileNamingAndTriggeringPolicy内外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>

The trigger policy:

触发策略:

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

The exception:

例外:

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]

回答by proactif

It works for me, using the following class as timeBasedFileNamingAndTriggeringPolicy :

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

回答by djechlin

I got the following to work (combining ideas from previous answers). Note I was dealing with size-based files, not time-based, but I am guessing the same solution works.

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

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

}

}

回答by Dave

None of the other suggestions was appropriate for my situation. I didn't want to use a size-and-time-based solution, because it requires configuring a MaxFileSize, and we are using a strictly time-based policy. Here is how I accomplished rolling the file on startup with a TimeBasedRollingPolicy:

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

}

The trick is to set the nextCheck time to 0L, so that isTriggeringEvent() will think it's time to roll the log file over. It will thus execute the code necessary to calculate the filename, as well as conveniently resetting the nextCheck time value. The subsequent call to rollover() causes the log file to be rolled. Since this only happens at startup, it is a more optimal solution than the ones that perform a comparison inside isTriggerEvent(). However small that comparison, it still degrades performance slightly when executed on every log message. This also forces the rollover to occur immediately at startup, instead of waiting for the first log event.

诀窍是将 nextCheck 时间设置为 0L,这样 isTriggeringEvent() 就会认为是时候翻转日志文件了。因此,它将执行计算文件名所需的代码,并方便地重置 nextCheck 时间值。随后对 rollover() 的调用导致日志文件被滚动。由于这仅在启动时发生,因此它是比在 isTriggerEvent() 中执行比较的解决方案更理想的解决方案。无论这种比较有多小,当对每条日志消息执行时,它仍然会略微降低性能。这也强制翻转在启动时立即发生,而不是等待第一个日志事件。

The @NoAutoStart annotation is important to prevent Joran from executing the start() method before all the other initialisation is complete. Otherwise, you get a NullPointerException.

@NoAutoStart 注释对于防止 Joran 在所有其他初始化完成之前执行 start() 方法很重要。否则,您会收到 NullPointerException。

Here is the 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> 

Hope this helps!

希望这可以帮助!

回答by Perlos

I finally figure it out. I can roll by size, time and start up. Here is solution:

我终于想通了。我可以按大小、时间滚动并启动。这是解决方案:

1st create you own class

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

2nd configure logback

第二个配置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>

回答by Leonid Ilyevsky

This solution really works, thanks a lot. However, there is one annoying glitch: when you run the program first time, the log is rolled right after it is created, when it is empty or almost empty. So I suggest a fix: check whether the log file exists and is not empty at the time the method is called. Also, one more cosmetic fix: rename the "started" variable, because it is hiding the inherited member with the same name.

这个解决方案确实有效,非常感谢。但是,有一个恼人的故障:当您第一次运行程序时,日志在创建后立即滚动,当它为空或几乎为空时。所以我建议修复:在调用方法时检查日志文件是否存在并且不为空。此外,还有一个修饰性的修复:重命名“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);
    }
}

Also, I believe it works properly with logback version 1.1.4-SNAPSHOT (I got the source and compiled it myself), but it does not fully work with 1.1.3 release. With 1.1.3, it names the files properly with the specified time zone, but rollover still happens at default time zone midnight.

另外,我相信它可以与 logback 版本 1.1.4-SNAPSHOT 一起正常工作(我得到了源代码并自己编译了它),但它不能完全与 1.1.3 版本一起使用。在 1.1.3 中,它使用指定的时区正确命名文件,但翻转仍然发生在默认时区午夜。

回答by duffy356

I found another solution for rolling the logFile once, when the application starts.

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

I use logback's RollingFileAppenderwith logback's FixedWindowRollingPolicyand my own implementation of a TriggeringPolicy<E>.

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

The FixedWindowRollingPolicygets the fileNamePattern for the new logFile, where %1is the new number of the file. The maxIndex stands for the maximum number of my "history". More information: FixedWindowRollingPolicy

FixedWindowRollingPolicy新的日志文件,在那里得到fileNamePattern%1是文件的新号码。maxIndex 代表我的“历史”的最大数量。更多信息:FixedWindowRollingPolicy

My implementations TriggeringPolicyreturns true for the firsttime, when isTriggeringEvent(...) gets called. So the WindowRollingPolicy rolls over the logfiles, when the Policy gets called the first time, and afterwards it will not roll over again.

当 isTriggeringEvent(...) 被调用时,我的实现一次TriggeringPolicy返回 true 。因此 WindowRollingPolicy 会在第一次调用 Policy 时滚动日志文件,之后不会再次滚动。

The xml-configuration for the RollingFileAppender:

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

The TriggeringPolicy:

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

回答by raisercostin

For a solution using already existing components the logback suggests the uniquely named files: http://logback.qos.ch/manual/appenders.html#uniquelyNamed

对于使用现有组件的解决方案,logback 建议使用唯一命名的文件http: //logback.qos.ch/manual/appenders.html#uniquelyNamed

During the application development phase or in the case of short-lived applications, e.g. batch applications, it is desirable to create a new log file at each new application launch. This is fairly easy to do with the help of the <timestamp>element.

在应用程序开发阶段或在短期应用程序(例如批处理应用程序)的情况下,希望在每次新应用程序启动时创建一个新的日志文件。在<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>


UPDATED for logback-1.2.1

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