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方法根據(jù)fileNamePatternStr創(chuàng)建FileNamePattern,根據(jù)compressionMode創(chuàng)建Compressor,對于zip壓縮的創(chuàng)建zipEntryFileNamePattern,另外默認(rèn)設(shè)置了DefaultTimeBasedFileNamingAndTriggeringPolicy,然后執(zhí)行其start,對于maxHistory不為0的,則設(shè)置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方法執(zhí)行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,然后將當(dāng)前文件重命名為elapsedPeriodsFileName,對于archiveRemover不為null的則執(zhí)行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,再執(zhí)行cleanPeriod方法;cleanPeriod方法則通過getFilesInPeriod獲取對應(yīng)的文件,然后挨個執(zhí)行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主要是創(chuàng)建ArhiveRemoverRunnable,然后提交到context的executorService;ArhiveRemoverRunnable實現(xiàn)了Runnable接口,其run方法執(zhí)行clean,對于totalSizeCap大于0的執(zhí)行capTotalSize
小結(jié)
TimeBasedRollingPolicy包含了RollingPolicy及TriggeringPolicy,其rollover方法主要是委托給timeBasedFileNamingAndTriggeringPolicy獲取elapsedPeriodsFileName然后去rename,對于maxHistory不是無限制的設(shè)置timeBasedFileNamingAndTriggeringPolicy的archiveRemover的maxHistory及totalSizeCap,執(zhí)行其cleanAsynchronously方法;其isTriggeringEvent方法也是委托給了timeBasedFileNamingAndTriggeringPolicy。
以上就是logback TimeBasedRollingPolicy按天生成日志源碼解析的詳細(xì)內(nèi)容,更多關(guān)于logback TimeBasedRollingPolicy的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實現(xiàn)一個達(dá)達(dá)租車系統(tǒng)的步驟詳解
這篇文章主要給大家介紹了利用Java實現(xiàn)一個達(dá)達(dá)租車系統(tǒng)的步驟,文中給出了詳細(xì)的實現(xiàn)思路和示例代碼,并在文末給出了完整的源碼供大家學(xué)習(xí)下載,需要的朋友可以參考借鑒,下面來一起看看吧。2017-04-04Java?@Scheduled定時任務(wù)不執(zhí)行解決辦法
這篇文章主要給大家介紹了關(guān)于Java?@Scheduled定時任務(wù)不執(zhí)行解決的相關(guān)資料,當(dāng)@Scheduled定時任務(wù)不執(zhí)行時可以根據(jù)以下步驟進(jìn)行排查和解決,需要的朋友可以參考下2023-10-10Java判斷字符串是否是整數(shù)或者浮點數(shù)的方法
今天小編就為大家分享一篇Java判斷字符串是否是整數(shù)或者浮點數(shù)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07Java語法基礎(chǔ)之選擇結(jié)構(gòu)的if語句、switch語句詳解
這篇文章主要為大詳細(xì)介紹了Java語法基礎(chǔ)之選擇結(jié)構(gòu)的if語句、switch語句,感興趣的小伙伴們可以參考一下2016-09-09