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,對(duì)于zip壓縮的創(chuàng)建zipEntryFileNamePattern,另外默認(rèn)設(shè)置了DefaultTimeBasedFileNamingAndTriggeringPolicy,然后執(zhí)行其start,對(duì)于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方法通過(guò)timeBasedFileNamingAndTriggeringPolicy獲取elapsedPeriodsFileName,然后將當(dāng)前文件重命名為elapsedPeriodsFileName,對(duì)于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方法主要是計(jì)算periodsElapsed,然后通過(guò)rollingCalendar獲取instantOfPeriodToClean,再執(zhí)行cleanPeriod方法;cleanPeriod方法則通過(guò)getFilesInPeriod獲取對(duì)應(yīng)的文件,然后挨個(gè)執(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實(shí)現(xiàn)了Runnable接口,其run方法執(zhí)行clean,對(duì)于totalSizeCap大于0的執(zhí)行capTotalSize
小結(jié)
TimeBasedRollingPolicy包含了RollingPolicy及TriggeringPolicy,其rollover方法主要是委托給timeBasedFileNamingAndTriggeringPolicy獲取elapsedPeriodsFileName然后去rename,對(duì)于maxHistory不是無(wú)限制的設(shè)置timeBasedFileNamingAndTriggeringPolicy的archiveRemover的maxHistory及totalSizeCap,執(zhí)行其cleanAsynchronously方法;其isTriggeringEvent方法也是委托給了timeBasedFileNamingAndTriggeringPolicy。
以上就是logback TimeBasedRollingPolicy按天生成日志源碼解析的詳細(xì)內(nèi)容,更多關(guān)于logback TimeBasedRollingPolicy的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- logback標(biāo)記日志過(guò)濾器MarkerFilter源碼解讀
- logback使用MDCFilter日志過(guò)濾源碼解讀
- logback的DuplicateMessageFilter日志過(guò)濾操作源碼解讀
- Java面試Logback打印日志如何獲取當(dāng)前方法名稱題解
- logback的isDebugEnabled日志配置級(jí)別源碼解析
- Logback MDCAdapter日志跟蹤及自定義效果源碼解讀
- logback FixedWindowRollingPolicy固定窗口算法重命名文件滾動(dòng)策略
- logback?EvaluatorFilter日志過(guò)濾器源碼解讀
相關(guān)文章
Java SpringBoot安全框架整合Spring Security詳解
這篇文章主要介紹了Spring Boot整合Spring Security的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2021-09-09
Java字符串格式化,{}占位符根據(jù)名字替換實(shí)例
這篇文章主要介紹了Java字符串格式化,{}占位符根據(jù)名字替換實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10
IntelliJ?IDEA教程之clean或者install?Maven項(xiàng)目的操作方法
這篇文章主要介紹了IntelliJ?IDEA教程之clean或者install?Maven項(xiàng)目的操作方法,本文分步驟給大家介紹兩種方式講解如何調(diào)試出窗口,需要的朋友可以參考下2023-04-04
Spring?@Cacheable指定失效時(shí)間實(shí)例
這篇文章主要介紹了Spring?@Cacheable指定失效時(shí)間實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
jvm之java類加載機(jī)制和類加載器(ClassLoader)的用法
這篇文章主要介紹了jvm之java類加載機(jī)制和類加載器(ClassLoader)的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09
MyBatisPlus中批量插入之如何通過(guò)開(kāi)啟rewriteBatchedStatements=true
這篇文章主要介紹了MyBatisPlus中批量插入之如何通過(guò)開(kāi)啟rewriteBatchedStatements=true問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03

