1. 程式人生 > >log4j使用心得之四 -- 自定義DailyRollingFileAppender歸檔檔名

log4j使用心得之四 -- 自定義DailyRollingFileAppender歸檔檔名

log4j使用DailyRollingFileAppender對日誌檔案按天進行歸檔時,可以使用datePattern指定歸檔檔名格式. 如日誌檔名為error.log,設定datePattern=yyyyMMdd,則歸檔檔名為error.logyyyyMMdd. 

這樣的歸檔檔名沒有統一的字尾名,看起來不是很美觀.於是我想,要是能將歸檔檔名設定為error_yyyyMMdd.log就好了.

分析DailyRollingFileAppender的原始碼,我們重點關注兩個函式

public void activateOptions() {
    super.activateOptions();
    if(datePattern != null && fileName != null) {
      now.setTime(System.currentTimeMillis());
      sdf = new SimpleDateFormat(datePattern);
      int type = computeCheckPeriod();
      printPeriodicity(type);
      rc.setType(type);
      File file = new File(fileName);
      scheduledFilename = fileName+sdf.format(new Date(file.lastModified()));

    } else {
      LogLog.error("Either File or DatePattern options are not set for appender ["
		   +name+"].");
    }
  }

activeOptions函式,在初始化Appender時會被呼叫一次,設定scheduleFilename為當前日誌檔名+datePattern.
void rollOver() throws IOException {

    /* Compute filename, but only if datePattern is specified */
    if (datePattern == null) {
      errorHandler.error("Missing DatePattern option in rollOver().");
      return;
    }

    String datedFilename = fileName+sdf.format(now);
    // It is too early to roll over because we are still within the
    // bounds of the current interval. Rollover will occur once the
    // next interval is reached.
    if (scheduledFilename.equals(datedFilename)) {
      return;
    }

    // close current file, and rename it to datedFilename
    this.closeFile();

    File target  = new File(scheduledFilename);
    if (target.exists()) {
      target.delete();
    }

    File file = new File(fileName);
    boolean result = file.renameTo(target);
    if(result) {
      LogLog.debug(fileName +" -> "+ scheduledFilename);
    } else {
      LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
    }

    try {
      // This will also close the file. This is OK since multiple
      // close operations are safe.
      this.setFile(fileName, false, this.bufferedIO, this.bufferSize);
    }
    catch(IOException e) {
      errorHandler.error("setFile("+fileName+", false) call failed.");
    }
    scheduledFilename = datedFilename;
  }

rollOver函式每隔一段時間執行,首先使用日誌檔名+datePattern表示的當天時間賦值給dateFilename,再將dateFilename與scheduledFilename進行比較.如果兩者相等,則表示不需要進行檔案歸檔. 當一天結束進入下一天時,dateFilename發生變化,此時與scheduledFilename不相等,此時將當前日誌檔名重置成scheduledFilename,進行歸檔

從上面的分析可以看出,首先設定的datePattern只能新增到原檔名的後面.如果我們想實現將error.log檔案歸檔為error_yyyyMMdd.log需要對log4j做一下修改.

首先,修改datePattern,設定為

log4j.appender.error.datePattern='_'yyyyMMdd'.log'

接下來,建立我們自己的Appender,繼承DailyRollingFileAppender,過載上面兩個函式
public void activateOptions() {
	    super.activateOptions();
	    if(datePattern != null && fileName != null) {
	      now.setTime(System.currentTimeMillis());
	      sdf = new SimpleDateFormat(datePattern);
	      int type = computeCheckPeriod();
	      printPeriodicity(type);
	      rc.setType(type);
	      File file = new File(fileName);
	      String tempFileName = fileName.substring(0, fileName.lastIndexOf("."));    
	      scheduledFilename = tempFileName+sdf.format(new Date(file.lastModified()));

	    } else {
	      LogLog.error("Either File or DatePattern options are not set for appender ["
			   +name+"].");
	    }
	  }

scheduledFilename會將當前檔案字尾名去掉,再拼接上datePattern,當然也可以按需要自定義.
void rollOver() throws IOException {

	    /* Compute filename, but only if datePattern is specified */
	    if (datePattern == null) {
	      errorHandler.error("Missing DatePattern option in rollOver().");
	      return;
	    }

	    String tempFileName = fileName.substring(0, fileName.lastIndexOf("."));    
	    String datedFilename = tempFileName+sdf.format(now);
	    // It is too early to roll over because we are still within the
	    // bounds of the current interval. Rollover will occur once the
	    // next interval is reached.
	    if (scheduledFilename.equals(datedFilename)) {
	      return;
	    }

	    // close current file, and rename it to datedFilename
	    this.closeFile();

	    File target  = new File(scheduledFilename);
	    if (target.exists()) {
	      target.delete();
	    }

	    File file = new File(fileName);
	    boolean result = file.renameTo(target);
	    if(result) {
	      LogLog.debug(fileName +" -> "+ scheduledFilename);
	    } else {
	      LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
	    }

	    try {
	      // This will also close the file. This is OK since multiple
	      // close operations are safe.
	      this.setFile(fileName, false, this.bufferedIO, this.bufferSize);
	    }
	    catch(IOException e) {
	      errorHandler.error("setFile("+fileName+", false) call failed.");
	    }
	    scheduledFilename = datedFilename;
	  }

rollOver函式中,同樣對datedFilename,也需要做同樣的處理,當發生歸檔時,會將歸檔檔名設定為scheduledFilename,再將datedFilename複製給scheduledFilename,準備下一次的歸檔.

通過過載,我們可以完全按照我們的自定義DailyRollingFileAppender的歸檔檔名了

相關推薦

log4j使用心得 -- 定義DailyRollingFileAppender歸檔檔名

log4j使用DailyRollingFileAppender對日誌檔案按天進行歸檔時,可以使用datePattern指定歸檔檔名格式. 如日誌檔名為error.log,設定datePattern=yyyyMMdd,則歸檔檔名為error.logyyyyMMdd.  這樣的

flask_admin 筆記 定義視圖

urn eat 類名 color mas 限制 html模板 創建 nds 定義自己的視圖 對於您的要求非常具體的情況,您很難用內置的ModelView類來滿足這些需求,Flask-Admin使您可以輕松地完全控制並將自己的視圖添加到界面中。 1)獨立視圖 可以通過擴展

JEPLUSAPP定義插件——JEPLUS軟件快速開發平臺

otto fff 使用 jid editor style img circle ckeditor JEPLUS之APP自定義插件 在JEPLUS中我們可以創建APP,但是創建的APP都是依賴於平臺功能在我們業務中有些需求並不是都要按照平臺

數據庫系列mysql 定義函數function,函數和存儲過程的區別

0.11 必須 def cte fec return語句 cit 新的 too mysql 自定義函數function,函數和存儲過程的區別 https://blog.csdn.net/u010365819/article/details/80470448 1.MySQL自

Log4Net 定義屬性記錄到文件中 (三)

hive days bsp 文本 處理 message homepage layout backup 即解決了將自定義屬性記錄到數據庫之後。一個新的想法冒了出來,自定義屬性同樣也能記錄到文件中嗎?答案是肯定的,因為Log4Net既然已經考慮到了數據庫記錄方式,當然也一定考慮

小程式學習旅----定義元件toast例項

components目錄下新建資料夾toast,新建component,之後修改toast.js和toast.wxml <!--components/toast/toast.wxml--> <view class='wx_toast_container' hidden="{{!

009-Ambari二次開發新增定義元件Redis(二)

上一篇我們主要介紹了Ambari新增元件的答題流程並以REDIS為例說明了流程,本篇在上一篇的基礎上,進一步完善說明流程並介紹如何給元件新增metric 掃描二維碼,關注BearData,獲取最新文章 上篇中,我們已經制作出了redis的rpm包,並重新編譯了我們修改後的Ambar

008-Ambari二次開發新增定義元件Redis(一)

Ambari目前支援的元件有HDFS、YARN、HBase、Hive、Pig、ZooKeeper、Sqoop、Storm、Flume、Tez、Oozie、Falcon、Storm、Altas、Knox、Spark、Ranger、Mahout、Kerberos等,已經涵蓋了從大資料應用的

車機開發新增定義

S700平臺即安卓5.1.1系統新增額外的自定義鍵值按鍵: 在Android的原生系統中鍵值預設情況下是92個,從0-91;一般情況下,這些鍵值是夠用的,但是如果想擴充的話,還是需要新增新的鍵值的;像我們做車機專案的,新增新按鍵鍵值太易見了,比如將倒車檢測做成新自定義鍵值按鍵,我們需要到多個

javawebEL定義函式

1.什麼是EL自定義函式 EL自定義函式是在EL表示式中呼叫的某個java類的靜態方法,這個靜態方法需在web應用程式中進行配置才可以被EL表示式呼叫。EL自定義函式可以擴充套件EL表示式的功能,讓EL表示式完成普通java程式程式碼所能完成的功能。 2.EL自定義函式開發步驟 編寫EL自定義函式

小程式填坑路--定義模態彈窗(已解決)

信我,這次只講技術! 實現效果(點選“更換手機號”,背景變暗,彈出輸入框): 嗯,我懶,就用了上一篇文章小程式填坑之路--彈窗修改手機號後的更新(已解決)的圖。 先上wxml的程式碼, <view class="weui-vcode-btn" bindtap="

一道面試題關於定義Json解析器

最近在群裡裡面有哥們說在面試的時候,要求上機寫一個簡單的Json解析器,看到這個題目的時候,心裡慌得一比,因為感覺有些力不從心,不知道從哪裡下手,所以趕緊查了一下Gson原始碼,看看有什麼啟示沒有。當然,這篇扯淡並不是介紹Gson原始碼,而是想自定義一個簡單的Json解析器,來熟悉一下J

並發編程學習筆記構建定義的同步工具(十一)

利用 追蹤 這不 temp sets nor rac lse 情況下 概述: 在並發編程學習筆記之並發工具類(四)中,為大家介紹了幾種同步工具(同步工具就是依靠自己的狀態,調節線程是阻塞還是運行用的.),閉鎖、FutureTask、信號量、關卡. 使用以上的同步工具大部分時

併發程式設計學習筆記構建定義的同步工具(十一)

概述: 在併發程式設計學習筆記之併發工具類(四)中,為大家介紹了幾種同步工具(同步工具就是依靠自己的狀態,調節執行緒是阻塞還是執行用的.),閉鎖、FutureTask、訊號量、關卡. 使用以上的同步工具大部分時候可以滿足我們的需求,但是如果沒能滿足我們需要的功能,可以使用語言和類庫提供的底層

MT5客戶端CTP接入 國內期貨定義交易品種 實時資料接收

實時接收資料大概分為2種方式 方式1:直接通過webrequest方式去請求, 例如 void OnStart() { string cookie=NULL,headers; char post[],result[]; string url="htt

MT5客戶端CTP接入 國內期貨定義交易品種 歷史資料匯入

方法1: 介面插入歷史資料 1.  選中產品與資料週期 2 選擇歷史資料檔案 將資料插入 3. 檢視匯入歷史資料情況 切換1小時週期 資料自然推算出來 good! 4.  K線效果圖   手工匯入成功

SpringBoot系列使用定義註解校驗使用者是否登入

記得今年年初剛開始面試的時候,被問的最多的就是你知道Spring的兩大核心嘛?那你說說什麼是AOP,什麼是IOC?我相信你可能也被問了很多次了。 1、到底是什麼是AOP? 所謂AOP也就是面向切面程式設計,能夠讓我們在不影響原有業務功能的前提下,橫切擴充套件新的功能。這裡面有一個比較顯眼的詞

微信小程式 動畫 —— 定義底部彈出層

wxml: <view class='buy' bindtap='showBuyModal'>立即購買</view> <!-- 點選立即購買 彈出購買遮罩層 --> <view class="cover_screen" bindtap="hideBuyModal"

微信小程序 動畫 —— 定義底部彈出層

modals num view radi let art time cit 點擊 wxml: <view class='buy' bindtap='showBuyModal'>立即購買</view> <!--

MRpartition定義分割槽器

maptask執行的結果都會放到一個分割槽檔案中,這個分割槽檔案有自己的編號,這個編號是通過一個hash演算法來生成的,通過對context.write(k,v)中的k進行hash會產生一個值,相同的key產生的值是一樣的,所以這種辦法能將相同的key值放到一個分割槽中。分割槽中的值會發送給