Logback中異步壓縮任務(wù)實(shí)現(xiàn)

有些時(shí)候我們需要在業(yè)務(wù)主流程外做一些不影響主流程的操作,比如發(fā)生通知,開啟一個(gè)異步任務(wù),我們不關(guān)心這些額外操作的執(zhí)行成功與否,但不能影響主流程。一般這種場(chǎng)景下,都會(huì)使用異步線程處理,下面帶著源碼,來看下Logback在進(jìn)行日志歸檔的過程中如何通過異步任務(wù)實(shí)現(xiàn)日志壓縮。希望大家舉一反三,領(lǐng)會(huì)其設(shè)計(jì)精髓,方便以后運(yùn)行在自己的代碼中。

場(chǎng)景描述

Logback在進(jìn)行日志歸檔過程中主要處理一下幾件事:
1.文件名轉(zhuǎn)換,將當(dāng)前活動(dòng)文件名轉(zhuǎn)換成歸檔文件名。執(zhí)行該步驟的條件是<appender>配置了<file> 屬性,當(dāng)前活動(dòng)文件名是<file> 屬性值,歸檔文件名是<fileNamePatternStr>的格式。
2.歸檔文件壓縮,執(zhí)行該步驟的條件是<fileNamePatternStr>屬性值中以.gz/.zip等后綴結(jié)尾。
3.歷史歸檔文件刪除,執(zhí)行該步驟的條件是配置了<maxHistory>。

// ch.qos.logback.core.rolling.TimeBasedRollingPolicy#rollover
//文件歸檔操作
public void rollover() throws RolloverFailure {
    //歸檔文件名全路徑,如logs/test.log
    String elapsedPeriodsFileName = timeBasedFileNamingAndTriggeringPolicy.getElapsedPeriodsFileName();
    //歸檔文件名稱,如test.log
    String elapsedPeriodStem = FileFilterUtil.afterLastSlash(elapsedPeriodsFileName);
    //判斷是否配置壓縮
    if (compressionMode == CompressionMode.NONE) {
        //判斷<appender>中是否配置了<file>屬性
        if (getParentsRawFileProperty() != null) {
            //將當(dāng)前活動(dòng)文件名轉(zhuǎn)換為歸檔文件名
            renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName);
         } 
     } else {
        if (getParentsRawFileProperty() == null) {
            //直接將歸檔文件壓縮
            compressionFuture = compressor.asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elapsedPeriodStem);
        } else {
            //先根據(jù)<file>創(chuàng)建一個(gè)臨時(shí)文件和一個(gè)新的<file>文件,再將臨時(shí)文件名轉(zhuǎn)換為歸檔文件名,然后將歸檔文件壓縮
            compressionFuture = renameRawAndAsyncCompress(elapsedPeriodsFileName, elapsedPeriodStem);
        }
    }
    //判斷是否配置<maxHistory>
    if (archiveRemover != null) {
        Date now = new Date(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime());
        this.cleanUpFuture = archiveRemover.cleanAsynchronously(now);
     }
}

這里面歸檔文件的壓縮和歷史文件的刪除都使用的是異步任務(wù)。壓縮操作使用Compressor類處理,刪除操作使用ArchiveRemover類處理

//ch.qos.logback.core.rolling.helper.Compressor#asyncCompress
public Future<?> asyncCompress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) throws RolloverFailure {
    //創(chuàng)建異步任務(wù)
    CompressionRunnable runnable = new CompressionRunnable(nameOfFile2Compress, nameOfCompressedFile, innerEntryName);
    //獲取任務(wù)線程池
    ExecutorService executorService = context.getScheduledExecutorService();
    //執(zhí)行異步任務(wù)
    Future<?> future = executorService.submit(runnable);
    return future;
 }

//ch.qos.logback.core.rolling.helper.Compressor.CompressionRunnable
class CompressionRunnable implements Runnable {
    final String nameOfFile2Compress;
    final String nameOfCompressedFile;
    final String innerEntryName;

    public CompressionRunnable(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) {
      this.nameOfFile2Compress = nameOfFile2Compress;
      this.nameOfCompressedFile = nameOfCompressedFile;
      this.innerEntryName = innerEntryName;
     }

    public void run() {
        //調(diào)用Compressor實(shí)例中的compress方法壓縮文件
        Compressor.this.compress(nameOfFile2Compress, nameOfCompressedFile, innerEntryName);
    }
 }

CompressionRunnable 實(shí)際上是沒有返回值的,但是asyncCompress方法還是返回了任務(wù)執(zhí)行結(jié)果,那這個(gè)空的結(jié)果有什么用呢?

  //ch.qos.logback.core.rolling.TimeBasedRollingPolicy#stop
@Override
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 {
       // 等待指定時(shí)間,如果任務(wù)還未執(zhí)行完,就拋出異常
         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);
       }
    }
}

在日志系統(tǒng)停止時(shí),如果壓縮操作還在進(jìn)行,等待一定時(shí)間,超過該時(shí)間拋出異常。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,591評(píng)論 19 139
  • Ubuntu的發(fā)音 Ubuntu,源于非洲祖魯人和科薩人的語(yǔ)言,發(fā)作 oo-boon-too 的音。了解發(fā)音是有意...
    螢火蟲de夢(mèng)閱讀 100,718評(píng)論 9 468
  • logback詳解 說明:下面內(nèi)容從網(wǎng)上搜集整理而來 與log4j對(duì)比 更快的執(zhí)行速度: 基于我們先前在log4j...
    億萬(wàn)年星空閱讀 3,169評(píng)論 1 1
  • 一、logback的介紹Logback是由log4j創(chuàng)始人設(shè)計(jì)的另一個(gè)開源日志組件,官方網(wǎng)站: http://lo...
    Running小琦閱讀 870評(píng)論 0 8
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,275評(píng)論 6 342

友情鏈接更多精彩內(nèi)容