NodeJS寫日誌_Log4js使用詳解+常見艱難的解決

Hi All:

    今天和大家分享一下NodeJS中寫日誌的一個常用第三方包:Log4js.
    跟隨主流Blog特色,先簡單介紹下Log4js的基本信息.介紹Log4js之前,需要先說一下Log4***,Log4***是由Apache提供的多平臺下多語言下日誌書寫擴展包,目的很簡單就是使日誌書寫更加方便簡潔,同時對不同的業務日誌能夠進行靈活的分文件記錄,同時也包含着詳細的等級配置,爲之後分級輸出,檢索,及程序自動解析提供更加便捷的支持(一家之言,非官方描述,領會精神).Log4***有很多語言的實現,比如Log4cpp,Log4j,Log4net等等,看名字就知道對應是支持什麼的啦.而我們今天要說的Log4js是Log4***針對的NodeJS語言的實現包,除了基本功能外還擴展了一部分專門針對NodeJS而添加的特性.由於沒有深入研究,這裏就不詳細討論啦.
    OK,進入正題,下面我們主要精力放在Log4js在實戰中的詳細使用上.

Log4js的快速上手

    搭建一個簡單工程並安裝Log4js包,並建立一個日誌存儲目錄:
        mkdir Log4jsTest
        cd Log4jsTest
        mkdir logs
        mkdir logs/log_file
        mkdir logs/log_date
        npm install log4js


使用WebStrom將目錄打開並添加配置文件和啓動文件:
    並在工程根目錄添加如下兩個文件
    log4js.json: log4js的配置文件
    log_start.js: 測試程序的啓動文件

編寫配置文件:log4js.json
{
    "appenders":
        [
            {
                "type":"console",
                "category":"console"
            },
            {
                "category":"log_file",
                "type": "file",
                "filename": "./logs/log_file/file.log",
                "maxLogSize": 104800,
                "backups": 100
            },
            {
                "category":"log_date",
                "type": "dateFile",
                "filename": "./logs/log_date/date",
                "alwaysIncludePattern": true,
                "pattern": "-yyyy-MM-dd-hh.log"

            }
        ],
    "replaceConsole": true,
    "levels":
    {
        "log_file":"ALL",
        "console":"ALL",
        "log_date":"ALL"
    }
}
編寫啓動文件,並添加測試代碼:log_start.js
var log4js = require("log4js");
var log4js_config = require("./log4js.json");
log4js.configure(log4js_config);


console.log("log_start start!");

var LogFile = log4js.getLogger('log_file');

LogFile.trace('This is a Log4js-Test');
LogFile.debug('We Write Logs with log4js');
LogFile.info('You can find logs-files in the log-dir');
LogFile.warn('log-dir is a configuration-item in the log4js.json');
LogFile.error('In This Test log-dir is : \'./logs/log_test/\'');

console.log("log_start end!");
輸出效果
    在./logs/log_file/目錄下 生成了一個文件 file.log
    裏面的內容如下:
[2015-01-24 16:38:32.332] [TRACE] log_file - This is a Log4js-Test
[2015-01-24 16:38:32.333] [DEBUG] log_file - We Write Logs with log4js
[2015-01-24 16:38:32.333] [INFO] log_file - You can find logs-files in the log-dir
[2015-01-24 16:38:32.333] [WARN] log_file - log-dir is a configuration-item in the log4js.json
[2015-01-24 16:38:32.333] [ERROR] log_file - In This Test log-dir is : './logs/log_test/'
總結:
  log4js的使用非常簡單:
    1.安包(npm install log4js)
    2.創建日誌目錄(./logs/log_fie/)
    3.添加一個日誌輸出規則的配置文件(log4js.json)
     (這個也是有缺省的,但往往缺省配置是不滿足使用需求的)
    4.代碼中加載log4js,並將配置文件獲取到調用一下配置方法(log4js.configure(cfg.json))
    5.寫日誌log4js.getLogger('log_test').debug("隨便寫日誌啦!!!") 

二.Log4js的配置詳解

針對快速上手中的工程,我們將詳細分析一下log4js各個屬性的作用和使用發放,此處只針對用法上的討論,實現原理和性能上的深入研究有興趣的可以直接看一下源碼.
1.appenders屬性
appenders是配置文件的一級屬性:它的作用是配置輸出源.後續我們真正輸出日誌的對象就是log4js的下屬的輸出源.舉個例子說一下這個模式:一個組織要打掃衛生,那麼組織本身是一個機構不能打掃衛生,只能由組織內各個員工來做打掃衛生的事.整個log4js可以理解成一個負責日誌輸出的組織,那麼真正的日誌輸出是依靠的員工們就是appenders數組,appenders內每一個對象就是一個日誌輸出員工,基於這樣的結構,我們自然也不難想出,每個員工都有自己的特性,他們輸出的日誌規則是不一樣的.我繼續討論appenders的子屬性.
1.1 category配置
category翻譯過來叫做種類.實際上更簡單的理解成這個寫日誌員工的名字.
當我們有多個員工時就依靠與這個字段來區分,前面例子中,寫日誌前有這樣一行code:
log4js.getLogger(‘log_file’).debug(…);
這個getLogger()的參數就是category的配置內容,可以是任意字符串(吐槽:我沒有實驗中文或者特殊符號是否支持,因爲No zuo No die,針對zuo的設計我一向是避開而不是去驗證是否可zuo!)
1.2 type配置
type字段是控制日誌輸出對象的是什麼類型的,比較常用的配置有三個:
a.”type”:”console”:
type配置爲console表示控制檯,在此種配置下,往往用於調試時.細節參見2.replaceConsole中的描述.
b.”type”:”file”:
type配置爲file表示日誌輸出爲普通文件,在此種配置下,日誌會輸出到目標文件夾的目標文件中,並會隨着文件大小的變化自動份文件.
該模式下的具體生成文件方法:
相關有效配置包含:maxLogSize,backups,filename
相關無效配置包含:pattern,alwaysIncludePattern
求助:
c.”type”:”datefile”
type配置爲datefile表示是輸出按時間分文件的日誌,在此種配置下,日誌會輸出到目標目錄下,並以時間格式命名,隨着時間的推移,以時間格式命名的文件如果尚未存在,則自動創建新的文件.
該模式下的具體生成文件方法:
相關有效配置包含:pattern,alwaysIncludePattern,filename
相關無效配置包含:maxLogSize,backups
求助:
在datefile模式下,我暫時沒有找到同一時間下文件過大後自動分文件的方法.在type爲file模式下,我暫時沒有找到可以追加時間標籤的命名方法.
這個需求很實用,我個人認爲log4js應該實現這樣的需求,但目前我沒發現.如果那位朋友深入瞭解log4js可以告知我配置方法,或者明確告訴我不支持此種配置,萬分感謝!

1.3 filename配置
a.filename是一個目錄加上文件名,路徑就是日誌文件存儲的路徑.
b.此路徑可以是相對路徑也可以絕對路徑,當是相對路徑時,是相對於工程根目錄.
c.無論是相對路徑還是絕對路徑,路徑過程中的所有文件夾必須事先手動創建好,log4js不會自動創建,如路徑不存在則會報錯.
d.最後的文件名就是輸出文件的名字模版,真實的名字會一定的修改,
d1:type:datefile 時會加上時間標籤,如 [log-2015-01-24 , log-2015-01-25]
d2:type:file時 如果文件過大,份文件後會增加一個編號標籤. [log.1 log.2 log.3 …]
1.4 maxLogSize配置
這個只在type:file模式有效.表示文件多大時纔會創建下一個文件,單位是字節.實際設置時具體的值根據業務來定,但是不推薦大於100Mb.
1.5 pattern配置
這個只在type:datefile模式有效.表示一個文件的時間命名模式.在生成文件中會依照pattern配置來在filename的文件結尾追加一個時間串來命名文件.上個例子:
配置文件內容:

      {
                "category":"log_date",
                "type": "dateFile",
                "filename": "./logs/log_date/date",
                "alwaysIncludePattern": true,
                "pattern": "-yyyy-MM-dd-hh:mm:ss.log"
            }

此時生成的文件名就是date-2015-01-24-14:24:12.log
pattern精確到ss(秒)就是一秒一個文件,精確到mm(分)就是一分一個文件,一次類推:hh(小時),dd(天),MM(月),yyyy(年),yy(年後兩位),注意大小寫!
pattern是有默認配置的,默認配置是”.yyyy-MM-dd”
1.6 alwaysIncludePattern:
這個只在type:datefile模式有效.
這個是個開關配置 ture(默認值)是開啓pattern,false是不開啓pattern,不開啓時datefile文件將無任何時間後綴,也不會分文件.
1.7 backups配置
這個只在type:file模式有效,表示備份的文件數量,如果文件過多則會將最舊的刪除.
type:file模式下log4js的命名規則:正在寫的文件就叫filename中配置的文件名,文件過大後會追加數字 例如 log.1 log.2 log.3 , 直至文件數量達到backups時會把最舊的刪除.
當創建一個新的文件時,log4js會把所有之前的文件的.數字編號都順延一位,最後將剛剛出現的大文件後面追加.1; 這種模式下應該注意大文件拷貝時對命名的影響,所以maxLogSize不要設置過大.

2.replaceConsole配置
這個配置是表示是否替換控制檯輸出.當配置文件中配置了appenders中配置了type:console的員工,並且replaceConsole:true時,代碼中控制檯輸出(console.log console.error)的內容將會以log4js格式輸出到控制檯中.
再說一個很實用的小技巧:log4js的時時調試輸出:
當我們把實際生產環境的log4js.json配置好後,在調試階段,日誌會輸出到各個文件中,試試調試起來很不方便,那麼我們可以將各個日誌輸出員工的type配置爲console,這樣日誌信息就會全都彙總到控制檯輸出.
此時如果再添加一個如下日誌員工配置,則代碼中nodejs系統提供的console.log也會輸出到控制檯中.

     {
         "type":"console",
         "category":"console"
     }

其中category的名字必須叫console,否則無效,
replaceConsole:ture時如果不加這行,nodejs系統提供的console.log()輸出的內容將不會顯示
我把這部分內容的配置重新貼一下:
配置如下:

{
    "appenders":
        [
            {
                "type":"console",
                "category":"console"
            },
            {
                "category":"log_file",
                "type": "console",
                "filename": "./logs/log_file/file.log",
                "maxLogSize": 104800,
                "backups": 100
            },
            {
                "category":"log_date",
                "type": "console",
                "filename": "./logs/log_date/date",
                "alwaysIncludePattern": true,
                "pattern": "-yyyy-MM-dd-hh.log"
            }
        ],
    "replaceConsole": true,
    "levels":
    {
        "log_file":"ALL",
        "console":"ALL",
        "log_date":"ALL"
    }
}

日誌輸出:

/usr/local/bin/node log_start.js
[2015-01-24 15:20:53.395] [INFO] console - log_start start!
[2015-01-24 15:20:53.401] [TRACE] log_file - This is a Log4js-Test
[2015-01-24 15:20:53.402] [DEBUG] log_file - We Write Logs with log4js
[2015-01-24 15:20:53.402] [INFO] log_file - You can find logs-files in the log-dir
[2015-01-24 15:20:53.402] [WARN] log_file - log-dir is a configuration-item in the log4js.json
[2015-01-24 15:20:53.402] [ERROR] log_file - In This Test log-dir is : './logs/log_test/'
[2015-01-24 15:20:53.402] [INFO] console - log_start end!
Process finished with exit code 0

WebStrom中看這部分日誌是有顏色的!很方便!!!

3.levels配置
levels配置也是一個一級屬性,它控制着日誌的輸出級別.在發佈的程序,如果很穩定,一些不重要的日誌是需要隱去的,但當調試階段或者環境異常時我們需要重現所有流程,就需要全面的日誌.
levels的結構中配置着若干個屬性,一般與appenders中的員工對應,其中屬性名是appenders中的員工名(也就是category的值),屬性值是一個表示等級的字符串.
log4js的levels配置共分爲8個等級(也就是日誌等級),由低到高分別爲:ALL TRACE DEBUG INFO WARN ERROR FATAL OFF.
只有大於等於日誌配置級別的信息才能輸出出來.
舉個例子:我們把剛纔的log_file的日誌輸級別修改爲ERROR.
那麼最終輸出的日誌爲如下內容:

/usr/local/bin/node log_start.js
[2015-01-24 15:24:27.537] [INFO] console - log_start start!
[2015-01-24 15:24:27.540] [ERROR] log_file - In This Test log-dir is : './logs/log_test/'
[2015-01-24 15:24:27.540] [INFO] console - log_start end!
Process finished with exit code 0
只有ERROR輸出出來啦.(ERROR上下的兩行不是log_file員工輸出來的,是console員工輸出出來的,而它的輸出級別是ALL,最低級,全部輸出)

三.Log4js的常見問題和小技巧

配置文件的格式設定
配置文件其實就是一個js對象,json,js,或者自己通過各種set方法賦值出來一個都一樣
最開始說需要將配置文件與配置文件log4js.json與log4js模塊關聯,也就是調用configure()函數加載配置,其實此時就是需要一個JavaScript對象而已,既然如此,我們完全可以把配置文件寫成js格式的文件,類似於這樣的:
module.exports = { … 這裏面的內容就是上面貼的json啦};
這種模型的優勢是如果配置中有動態信息,可以在配置中添加函數,比如用文件名以pid命名,在配置時可以動態獲取pid然後字符串拼接到filename上.另一個優勢是json不支持註釋,寫成js後可以添加註釋.
這適用於比較複雜的應用環境中.
小技巧:新日誌用法
我們新添加一個功能,新功能出問題的概率高一些,我們希望新功能的日誌更加全面,但是又不希望把levels的日誌輸出級別降低,這樣會導致全程序日誌量暴增,這個時候我們可以使用一個小技巧,log4js提供好幾個級別的日誌體系,我們將其中的某一個較高的體系協商好不在正常邏輯中使用,而是留給新功能的日誌來使用,由於它的級別是足夠高的,所以會有全面的輸出,等業務穩定後在將各個日誌還原回理應所在的版本就可以啦!我目前就習慣將ERROR級別的log用作新日誌getLogger(“test”).error(“…”),

四.附加:真實項目中Log4js的詳細配置舉例:

應用場景:
這是一個任務系統,有大量用戶連接並獲取信息.業務是以客戶端發送消息爲驅動的,一個消息一組任務,各個任務之間沒有關聯關係.
配置文件:
我的真實項目中我設置了6個日誌輸出員工,其中一個是console類型(console),一個是file類型(log_info),其餘4個是datefile類型(log_stat,log_trace,log_error,log_todo).
console 類型用於捕捉到不小心寫成系統日誌內容(console.log),
log_info: 詳細日誌,主體日誌都在這裏,使用file類型,100MB一本,根據我的贏盤量我保存100本.
log_stat: 用於輸出一些統計信息,統計信息數量固定,不依賴於用戶量變化,且較少,所以設置爲 datefile,按天輸出看起來也清晰.
log_trace: 有海量用戶並消息驅動處理業務,所以添加trace業務,每個消息記錄一條,包含用戶名,便於快速定位一個用戶的所有操作,考慮到我現在的業務量這個一天一本還是可以接收的,故使用datefile格式
log_error: 異常信息,數量不會特別多,使用datefile格式
log_todo: 記錄一些需要人工處理業務,日誌量不會很多,使用datefile格式

細節如下:

{
    "appenders":
        [
            {
                "category":"console",
                "type":"console"
            },
            {
                "category":"log_info",
                "type": "file",
                "filename": "./logs/log_info/info.log",
                "maxLogSize": 104857500,
                "backups": 100
            },
            {
                "category": "log_stat",
                "type": "datefile",
                "filename": "./logs/log_stat/stat"
            },
            {
                "category": "log_trace",
                "type": "datefile",
                "filename": "./logs/log_trace/trace"
            },
            {
                "category": "log_error",
                "type": "datefile",
                "filename": "./logs/log_error/error"

  },
       {
           "category": "log_todo",
           "type": "datefile",
           "filename": "./logs/log_todo/todo"
       }
   ],
"replaceConsole": true,
"levels":
{
   "log_info":"ALL",
   "log_stat": "ALL",
   "log_trace":"ALL",
   "log_error":"ALL",
   "log_todo":"ALL"
}
}

實際使用中的其他細節的簡略概要
配置文件我配置了三套,分別是
開發調試環境的,所有type都是console
內網測試環境,如上
線上環境配置,路徑和日誌級別有所改動.

相關鏈接:
https://github.com/nomiddlename/log4js-node Log4js的GitHub的源碼
稍後我會把我的例子也上傳到GitHub上

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章