logback TimeBasedRollingPolicy按天生成日志源码解析
作者:codecraft
这篇文章主要为大家介绍了logback TimeBasedRollingPolicy按天生成日志源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
序
本文主要研究一下logback的TimeBasedRollingPolicy
TimeBasedRollingPolicy
public class TimeBasedRollingPolicy<E> extends RollingPolicyBase implements TriggeringPolicy<E> { static final String FNP_NOT_SET = "The FileNamePattern option must be set before using TimeBasedRollingPolicy. "; // WCS: without compression suffix FileNamePattern fileNamePatternWithoutCompSuffix; private Compressor compressor; private RenameUtil renameUtil = new RenameUtil(); Future<?> compressionFuture; Future<?> cleanUpFuture; private int maxHistory = UNBOUNDED_HISTORY; protected FileSize totalSizeCap = new FileSize(UNBOUNDED_TOTAL_SIZE_CAP); private ArchiveRemover archiveRemover; TimeBasedFileNamingAndTriggeringPolicy<E> timeBasedFileNamingAndTriggeringPolicy; boolean cleanHistoryOnStart = false; //...... }
TimeBasedRollingPolicy继承了RollingPolicyBase,它定义了maxHistory、cleanHistoryOnStart、timeBasedFileNamingAndTriggeringPolicy等属性
start
public void start() { // set the LR for our utility object renameUtil.setContext(this.context); // find out period from the filename pattern if (fileNamePatternStr != null) { fileNamePattern = new FileNamePattern(fileNamePatternStr, this.context); determineCompressionMode(); } else { addWarn(FNP_NOT_SET); addWarn(CoreConstants.SEE_FNP_NOT_SET); throw new IllegalStateException(FNP_NOT_SET + CoreConstants.SEE_FNP_NOT_SET); } compressor = new Compressor(compressionMode); compressor.setContext(context); // wcs : without compression suffix fileNamePatternWithoutCompSuffix = new FileNamePattern( Compressor.computeFileNameStrWithoutCompSuffix(fileNamePatternStr, compressionMode), this.context); addInfo("Will use the pattern " + fileNamePatternWithoutCompSuffix + " for the active file"); if (compressionMode == CompressionMode.ZIP) { String zipEntryFileNamePatternStr = transformFileNamePattern2ZipEntry(fileNamePatternStr); zipEntryFileNamePattern = new FileNamePattern(zipEntryFileNamePatternStr, context); } if (timeBasedFileNamingAndTriggeringPolicy == null) { timeBasedFileNamingAndTriggeringPolicy = new DefaultTimeBasedFileNamingAndTriggeringPolicy<>(); } timeBasedFileNamingAndTriggeringPolicy.setContext(context); timeBasedFileNamingAndTriggeringPolicy.setTimeBasedRollingPolicy(this); timeBasedFileNamingAndTriggeringPolicy.start(); if (!timeBasedFileNamingAndTriggeringPolicy.isStarted()) { addWarn("Subcomponent did not start. TimeBasedRollingPolicy will not start."); return; } // the maxHistory property is given to TimeBasedRollingPolicy instead of to // the TimeBasedFileNamingAndTriggeringPolicy. This makes it more convenient // for the user at the cost of inconsistency here. if (maxHistory != UNBOUNDED_HISTORY) { archiveRemover = timeBasedFileNamingAndTriggeringPolicy.getArchiveRemover(); archiveRemover.setMaxHistory(maxHistory); archiveRemover.setTotalSizeCap(totalSizeCap.getSize()); if (cleanHistoryOnStart) { addInfo("Cleaning on start up"); Instant now = Instant.ofEpochMilli(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime()); cleanUpFuture = archiveRemover.cleanAsynchronously(now); } } else if (!isUnboundedTotalSizeCap()) { addWarn("'maxHistory' is not set, ignoring 'totalSizeCap' option with value [" + totalSizeCap + "]"); } super.start(); }
start方法根据fileNamePatternStr创建FileNamePattern,根据compressionMode创建Compressor,对于zip压缩的创建zipEntryFileNamePattern,另外默认设置了DefaultTimeBasedFileNamingAndTriggeringPolicy,然后执行其start,对于maxHistory不为0的,则设置archiveRemover
stop
public void stop() { if (!isStarted()) return; waitForAsynchronousJobToStop(compressionFuture, "compression"); waitForAsynchronousJobToStop(cleanUpFuture, "clean-up"); super.stop(); } private void waitForAsynchronousJobToStop(Future<?> aFuture, String jobDescription) { if (aFuture != null) { try { aFuture.get(CoreConstants.SECONDS_TO_WAIT_FOR_COMPRESSION_JOBS, TimeUnit.SECONDS); } catch (TimeoutException e) { addError("Timeout while waiting for " + jobDescription + " job to finish", e); } catch (Exception e) { addError("Unexpected exception while waiting for " + jobDescription + " job to finish", e); } } }
stop方法执行waitForAsynchronousJobToStop,主要是等待compressionFuture及cleanUpFuture
rollover
public void rollover() throws RolloverFailure { // when rollover is called the elapsed period's file has // been already closed. This is a working assumption of this method. String elapsedPeriodsFileName = timeBasedFileNamingAndTriggeringPolicy.getElapsedPeriodsFileName(); String elapsedPeriodStem = FileFilterUtil.afterLastSlash(elapsedPeriodsFileName); if (compressionMode == CompressionMode.NONE) { if (getParentsRawFileProperty() != null) { renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName); } // else { nothing to do if CompressionMode == NONE and parentsRawFileProperty == // null } } else { if (getParentsRawFileProperty() == null) { compressionFuture = compressor.asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elapsedPeriodStem); } else { compressionFuture = renameRawAndAsyncCompress(elapsedPeriodsFileName, elapsedPeriodStem); } } if (archiveRemover != null) { Instant now = Instant.ofEpochMilli(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime()); this.cleanUpFuture = archiveRemover.cleanAsynchronously(now); } }
rollover方法通过timeBasedFileNamingAndTriggeringPolicy获取elapsedPeriodsFileName,然后将当前文件重命名为elapsedPeriodsFileName,对于archiveRemover不为null的则执行cleanAsynchronously
ArchiveRemover
ch/qos/logback/core/rolling/helper/ArchiveRemover.java
public interface ArchiveRemover extends ContextAware { void clean(Instant instant); void setMaxHistory(int maxHistory); void setTotalSizeCap(long totalSizeCap); Future<?> cleanAsynchronously(Instant now); }
ArchiveRemover定义了clean、setMaxHistory、setTotalSizeCap、cleanAsynchronously方法
TimeBasedArchiveRemover
ch/qos/logback/core/rolling/helper/TimeBasedArchiveRemover.java
public class TimeBasedArchiveRemover extends ContextAwareBase implements ArchiveRemover { static protected final long UNINITIALIZED = -1; // aim for 32 days, except in case of hourly rollover, see // MAX_VALUE_FOR_INACTIVITY_PERIODS static protected final long INACTIVITY_TOLERANCE_IN_MILLIS = 32L * (long) CoreConstants.MILLIS_IN_ONE_DAY; static final int MAX_VALUE_FOR_INACTIVITY_PERIODS = 14 * 24; // 14 days in case of hourly rollover final FileNamePattern fileNamePattern; final RollingCalendar rc; private int maxHistory = CoreConstants.UNBOUNDED_HISTORY; private long totalSizeCap = CoreConstants.UNBOUNDED_TOTAL_SIZE_CAP; final boolean parentClean; long lastHeartBeat = UNINITIALIZED; public TimeBasedArchiveRemover(FileNamePattern fileNamePattern, RollingCalendar rc) { this.fileNamePattern = fileNamePattern; this.rc = rc; this.parentClean = computeParentCleaningFlag(fileNamePattern); } //...... }
TimeBasedArchiveRemover定义了fileNamePattern、rollingCalendar、maxHistory、totalSizeCap属性
clean
public void clean(Instant now) { long nowInMillis = now.toEpochMilli(); // for a live appender periodsElapsed is expected to be 1 int periodsElapsed = computeElapsedPeriodsSinceLastClean(nowInMillis); lastHeartBeat = nowInMillis; if (periodsElapsed > 1) { addInfo("Multiple periods, i.e. " + periodsElapsed + " periods, seem to have elapsed. This is expected at application start."); } for (int i = 0; i < periodsElapsed; i++) { int offset = getPeriodOffsetForDeletionTarget() - i; Instant instantOfPeriodToClean = rc.getEndOfNextNthPeriod(now, offset); cleanPeriod(instantOfPeriodToClean); } } public void cleanPeriod(Instant instantOfPeriodToClean) { File[] matchingFileArray = getFilesInPeriod(instantOfPeriodToClean); for (File f : matchingFileArray) { addInfo("deleting " + f); f.delete(); } if (parentClean && matchingFileArray.length > 0) { File parentDir = getParentDir(matchingFileArray[0]); removeFolderIfEmpty(parentDir); } }
clean方法主要是计算periodsElapsed,然后通过rollingCalendar获取instantOfPeriodToClean,再执行cleanPeriod方法;cleanPeriod方法则通过getFilesInPeriod获取对应的文件,然后挨个执行delete,最后再判断下parentDir是否为空,为空则删除
cleanAsynchronously
public Future<?> cleanAsynchronously(Instant now) { ArhiveRemoverRunnable runnable = new ArhiveRemoverRunnable(now); ExecutorService executorService = context.getExecutorService(); Future<?> future = executorService.submit(runnable); return future; } public class ArhiveRemoverRunnable implements Runnable { Instant now; ArhiveRemoverRunnable(Instant now) { this.now = now; } @Override public void run() { clean(now); if (totalSizeCap != UNBOUNDED_TOTAL_SIZE_CAP && totalSizeCap > 0) { capTotalSize(now); } } }
cleanAsynchronously主要是创建ArhiveRemoverRunnable,然后提交到context的executorService;ArhiveRemoverRunnable实现了Runnable接口,其run方法执行clean,对于totalSizeCap大于0的执行capTotalSize
小结
TimeBasedRollingPolicy包含了RollingPolicy及TriggeringPolicy,其rollover方法主要是委托给timeBasedFileNamingAndTriggeringPolicy获取elapsedPeriodsFileName然后去rename,对于maxHistory不是无限制的设置timeBasedFileNamingAndTriggeringPolicy的archiveRemover的maxHistory及totalSizeCap,执行其cleanAsynchronously方法;其isTriggeringEvent方法也是委托给了timeBasedFileNamingAndTriggeringPolicy。
以上就是logback TimeBasedRollingPolicy按天生成日志源码解析的详细内容,更多关于logback TimeBasedRollingPolicy的资料请关注脚本之家其它相关文章!