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

Java 如何在logback中启动时滚动日志文件,java,startup,logback,appender,Java,Startup,Logback,Appender,我想将logback配置为执行以下操作 登录到文件 当文件达到50MB时滚动文件 只保存7天的日志 启动时始终生成新文件(滚动) 除了最后一个项目,启动卷,我所有的工作。有人知道如何做到这一点吗?这是配置 %d{HH:mm:ss.SSS}[%thread]-5级别%logger{36}-%msg\(%文件:%line\)%n server.log 服务器%d{yyyy-MM-dd}.log 7. 50MB 创建自己的ch.qos.logback.core.rolling.TimeBased

我想将logback配置为执行以下操作

  • 登录到文件
  • 当文件达到50MB时滚动文件
  • 只保存7天的日志
  • 启动时始终生成新文件(滚动)
除了最后一个项目,启动卷,我所有的工作。有人知道如何做到这一点吗?这是配置


%d{HH:mm:ss.SSS}[%thread]-5级别%logger{36}-%msg\(%文件:%line\)%n
server.log
服务器%d{yyyy-MM-dd}.log
7.
50MB

创建自己的
ch.qos.logback.core.rolling.TimeBasedRollingPolicy的子类
,并覆盖它的
开始

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

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

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

Ceki的解决方案似乎对我不起作用,但至少在某种程度上似乎起到了作用

启动
TimebasedFileName和TriggeringPolicyBase
时,它无法看到滚动策略,因此会发生故障。通过一些黑客技术,我让它做了一些日志记录,再加上一些,我让它观察触发器,但后来它又坏了,因为它无法解析其中一个文件名属性。。。该包是一个logback包,因此我可以访问一些内部,以复制
SizeAndTimeBasedFNATP#isTriggeringEvent
中的一些逻辑,并调用
computeCurrentPeriodsHighestCounterValue
。我认为这些方法可能会奏效,只是还没有找到神奇的组合。我真的希望我在做一些愚蠢的事情,因为否则我认为这将意味着要么为子类打开一些细节,要么将其作为另一个滚动/触发策略直接放回日志中

logback.xml:尝试了
触发策略
基于时间的事件和触发策略
滚动策略
内外的各种顺序


${LOG\u DIR}/${LOG\u FILE\u BASE}.LOG
${LOG\u DIR}/${LOG\u FILE\u BASE}.%d{yyyy-MM-dd}.%i.LOG
7.
信息
%消息%n
触发策略:

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

它适用于我,使用以下类作为TimeBasedFileName和TriggeringPolicy:

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);
    }
}
导入java.io.File;
导入java.util.concurrent.AtomicBoolean;
导入ch.qos.logback.core.joran.spi.NoAutoStart;
导入ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP;
@无自动启动
公共类触发器扩展SizeAndTimeBasedFNATP
{
私有最终AtomicBoolean触发器=新的AtomicBoolean();
公共布尔isTriggeringEvent(最终文件activeFile,最终E事件){
if(trigger.compareAndSet(false,true)&&activeFile.length()>0){
字符串maxFileSize=getMaxFileSize();
setMaxFileSize(“1”);
super.isTriggeringEvent(activeFile,event);
setMaxFileSize(maxFileSize);
返回true;
}
返回super.isTriggeringEvent(activeFile,event);
}
}

我做了以下工作(结合前面答案的想法)。注意,我处理的是基于大小的文件,而不是基于时间的文件,但我猜同样的解决方案也适用

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;
}
公共类StartupSizeBaedTriggeringPolicy扩展了ch.qos.logback.core.rolling.SizeBaedTriggeringPolicy{
私有最终原子引用isFirstTime=新原子引用(true);
@凌驾
公共布尔isTriggeringEvent(最终文件activeFile,最终E事件){
//此方法似乎有副作用,因此始终调用
布尔结果=super.isTriggeringEvent(activeFile,event);
返回是第一次。比较数据集(真、假)| |结果;
}

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

}
@NoAutoStart
公共类StartupTimeBasedTriggeringPolicy
扩展DefaultTimeBasedFileName和TriggeringPolicy{
@凌驾
公开作废开始(){
super.start();
nextCheck=0升;
isTriggeringEvent(null,null);
试一试{
tbrp.rollover();
}捕捉(翻转失败){
//无所事事
}
}
}
诀窍是将nextCheck time设置为0L,以便isTriggeringEvent()认为是时候将日志文件回滚了。因此,它将执行计算文件名所需的代码,并方便地重置nextCheck时间值。对rollover()的后续调用将导致滚动日志文件。由于这只发生在启动时,因此它比在isTriggerEvent()中执行比较的解决方案更为理想。无论这种比较有多小,当在每个日志消息上执行时,它仍然会略微降低性能。这还强制在启动时立即发生滚动,而不是等待第一个日志事件

@NoAutoStart注释对于防止Joran在所有其他初始化完成之前执行start()方法非常重要。否则,将得到一个NullPointerException

以下是配置:


${LOG_文件}
${LOG_FILE}.%d{yyyyymmdd}{uu%d{HHmmss,aux}
%d{HH:mm:ss.SSS}[%thread]-5级别%logger{36}-%msg%n

希望这有帮助

我终于明白了。我可以按大小、时间和启动进行滚动。以下是解决方案:

首先创建自己的类

@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 );
    };
}
@NoAutoStart
公共类StartupSizeTimeBasedTriggeringPolicy扩展了SizeAndTimeBasedFNATP{
private boolean start=false;
@凌驾
公共布尔isTriggeringEvent(文件activeFile,E事件){
如果(!已启动){
nextCheck=0升;
返回开始=t
@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>
@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);
    }
}
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;
    }
}
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);
    }
}
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>
<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);