Log4js原理解析
Log4js原理解析
?
基于log4js?0.6.14版本
?
? ? Log4js總共三篇博客
? ? 《Log4js原理解析》http://blog.csdn.net/hfty290/article/details/42844085
? ? 《Log4js配置詳解》http://blog.csdn.net/hfty290/article/details/42843737
? ? 《Log4js多進(jìn)程陷阱與避免》http://blog.csdn.net/hfty290/article/details/42843303
一、概述
? ? 網(wǎng)絡(luò)上有不少關(guān)于Log4j的源碼解析文章,但是到目前為止還未見到一個log4js的源碼解析,雖然這兩者有其共同之處,但是在實現(xiàn)原理是存在顯著的差別。作為在node.js世界里最流行的日志模塊,了解其內(nèi)部設(shè)計與實現(xiàn)還是挺有意義的。本篇將描述log4js的架構(gòu)與實現(xiàn),先簡要說明log4js中出現(xiàn)的元素,接著為每個元素做詳細(xì)說明,最后分析元素的協(xié)同工作。
二、設(shè)計元素簡述
? ? 在log4js中出現(xiàn)的設(shè)計元素包括:level、layout、appender、logger;請看下面表格:
?
?
三、色彩繽紛的Appender
? ? 不同的Appender實現(xiàn)不同的日志寫入方式,所有的Appender都在源碼的?lib/appenders目錄下,目前l(fā)og4js提供了很多種的寫入方式,有file、datefile、multiprocess、console、clustered、gelf、hookio、loggly、smtp。本文將依次介紹前五種Appender。每個Appender的js文件都會導(dǎo)出appender和configure兩個函數(shù),file與dateFile還會導(dǎo)出shutdown函數(shù)。
appender函數(shù)返回的是一個閉包函數(shù),該閉包函數(shù)實現(xiàn)將內(nèi)容寫入到日志。典型的appender函數(shù)實現(xiàn)如下:
function fileAppender (file, layout, logSize, numBackups) {…….var logFile = openTheStream(file, logSize, numBackups); return function(loggingEvent) {logFile.write(layout(loggingEvent) + eol, "utf8"); }; }
? ? 而configure函數(shù)根據(jù)參數(shù)提供配置信息,去調(diào)用對應(yīng)的appender函數(shù),將appender函數(shù)的返回值作為自己的返回值,如下:
function configure(config, options) {……return fileAppender(config.filename, layout, config.maxLogSize, config.backups); }
? ? 因此configure返回值是一個閉包函數(shù),通過該函數(shù)可以實現(xiàn)將日志寫入到文件之中。
?
? ? 下面將依次介紹每個Appender的實現(xiàn):
1、file:實現(xiàn)將日志寫入到文本文件之中,同時支持日志文件按照大小滾動。
?
?
2、datefile:實現(xiàn)將日志寫入到文本文件之中,日志按照日期進(jìn)行滾動。
?
?
3、console:實現(xiàn)將日志寫入到控制臺。
?
?
4、multiprocess:實現(xiàn)多進(jìn)程同步方式寫日志,具體是在master(自主配置)進(jìn)程上開啟一個監(jiān)聽端口,所有的worker進(jìn)程將日志通過tcp發(fā)送給master,由master將日志寫入到文件中。注意:這種模式只支持配置一個appender,不能配置多個。
Master配置參數(shù):
?
?
Worker配置參數(shù):
?
5、clustered:用于node的cluster環(huán)境之中,實現(xiàn)方式與multiprocess類似,真正的寫日志是在Master中,Worker只是將日志發(fā)送給Master。Worker和Master的配置一樣,內(nèi)部根據(jù)cluster.isMaster可以自動判斷。
配置參數(shù):
?
?
四、布局Layout
?
? ? Layout實現(xiàn)每條日志記錄的格式化,log4js提供了多種的格式化樣式可供選擇,有basicLayout、messagePassThroughLayout、patternLayout、colouredLayout、coloredLayout,默認(rèn)情況下會使用basicLayout。所有的Layout都在源碼的lib/layouts.js中定義。layouts.js文件除了導(dǎo)出上述說到的這些Layout,還導(dǎo)出一個layout函數(shù),定義如下:
layout: function(name, config) {return layoutMakers[name] && layoutMakers[name](config); }layoutMakers = {"messagePassThrough": function() { return messagePassThroughLayout; }, "basic": function() { return basicLayout; }, "colored": function() { return colouredLayout; }, "coloured": function() { return colouredLayout; }, "pattern": function (config) {return patternLayout(config && config.pattern, config && config.tokens);} }
實現(xiàn)將一個文本描述的Layout轉(zhuǎn)換成內(nèi)部定義的Layout函數(shù)。使用起來就像這樣: layout = layouts.layout(config.layout.type, config.layout); 其中的config.layout.type字段表示Layout的名稱,而config.layout中的其他字段為對應(yīng)Layout的配置信息。只有創(chuàng)建pattern類型的Layout時才需要其他配置。
下面依次介紹每種Layout的功能。
1、basicLayout:最基礎(chǔ)的Layout,一個message通過該basicLayout會變成如下樣子:
[startTime] [logLevel] categoryName - message\n
2、 colouredLayout 、c oloredLayout :格式化日志內(nèi)容,其中包括了顏色信息,顏色是根據(jù)每條日志的級別預(yù)定義的。每條記錄內(nèi)容與basicLayout一樣:
[startTime] [logLevel] categoryName - message\n
3、 messagePassThroughLayout :日志內(nèi)容只包括消息,沒有其他字段:
message\n
4、patternLayout:實現(xiàn)日志按照配置進(jìn)行格式化,該Layout需要兩個參數(shù),pattern、tokens;其中的pattern表示格式化字符串,tokens表示自定義函數(shù)。
預(yù)定義格式化有:
var replacers = {'c': categoryName,'d': formatAsDate,'h': hostname,'m': formatMessage,'n': endOfLine,'p': logLevel,'r': startTime,'[': startColour,']': endColour,'%': percent,'x': userDefined};
?
例如,一個patternLayout的配置如下:
"pattern":?"%[%r?(%x{pid})?%p?%c?-%]?%m%n",
"tokens":?{
"pid"?:?function()?{?return?process.pid;?}
}
? ? 其中自定義了tokens為pid,通過%x{pid}來引用。注意pattern的的?%[?與?%]?表示顏色的開始于結(jié)束。上述配置打印出來的日志如下:
18:13:39 (19556) INFO app - Test log message
?
五、Logger對象
?
? ? Logger對象實現(xiàn)對日志Level的管理,并定義了對外的寫日志接口。客戶端通過log4js.getLogger()獲取的就是該Logger對象。Logger類從events.EventEmitter繼承,因此Logger對象具有發(fā)生事件的能力。在log4js之中,寫日志是通過在log事件上注冊對應(yīng)的appender來實現(xiàn)的。
Logger對象的組成:
?
?
?
?
六、log4js
?
? ? log4js源碼文件為lib/log4js.js,里面包含了一些函數(shù)來實現(xiàn)對appender的加載,日志的管理等操作。所有外面要使用log4js中的對象,都采用export的方式導(dǎo)出,可以直接引用,導(dǎo)出的成員如下:
?
?
1、日志管理
? ? log4js中為日志進(jìn)行類別劃分,每個類別下最多可以創(chuàng)建一個Logger。同樣每個appender實例也有歸屬的類別,但是一個appender實例可以同時屬于多個類別。如圖1:
?
?
?
? ? 圖1:有兩個category分別為cheese與bread;每個category最多對應(yīng)著一個logger對象。圖中有三個appender,cheese.log與cheese1.log類型為file,另外還有一個console。console這個appender同時指向了cheese和bread,也就是這兩個日志都會使用到console。另外cheese有三個appender指向它,意味著,如果想cheese分類的日志中寫日志,會同時向三個地方寫入,cheese.log,?cheese1.log,?console.
2、log事件
? ? 前面已經(jīng)說明,調(diào)用Logger實例的寫日志操作,會觸發(fā)log事件。appender在log事件中被調(diào)用,從而實現(xiàn)記錄寫入到日志文件中。如圖1中類型為Cheese的Logger,關(guān)聯(lián)著三個appender實例,fileAppender-cheese.log,fileAppender-cheese1.log,console。那么當(dāng)調(diào)用該logger寫日志函數(shù),如logger.info時,觸發(fā)了log事件,與其關(guān)聯(lián)的三個appender實例被調(diào)用,最終這條日志內(nèi)容被寫入到三個地方。
?
?? ? 圖2:Logger的事件監(jiān)聽機(jī)制;用戶在調(diào)用logger.info(‘hello');?觸發(fā)了Logger實例的log事件,所有類別為Cheese的Appender實例(有三個),都會監(jiān)聽到該事件,實現(xiàn)將日志記錄寫入到三個位置。另外還有一種為all的分類,如果指定一個appender的類型為all,那么將收到所有l(wèi)ogger的log事件,log4js默認(rèn)加載的console就是類型為all的appender。
3、替換console
? ? 在開發(fā)的過程中,為了方便可能直接將日志直接以console.log方式打印出來,使用log4js可以將console的日志重定向到日志文件中。log4js導(dǎo)出了兩個函數(shù):
?
?
4、日志配置定期檢查更新
? ? log4js提供了自動重新加載日志配置,更新所有的appender與日志級別的信息,是一項非常使用的功能。log4js導(dǎo)出的configure函數(shù)中,第二個參數(shù)如果設(shè)置了reloadSecs,則會在指定的間隔秒數(shù)之后,重載配置。如下:
log4js.configure('file.json', { reloadSecs: 300 });
5、其他導(dǎo)出函數(shù)說明
?
?
?
? ? Log4js總共三篇博客
? ? 《Log4js原理解析》http://blog.csdn.net/hfty290/article/details/42844085
? ? 《Log4js配置詳解》http://blog.csdn.net/hfty290/article/details/42843737
? ? 《Log4js多進(jìn)程陷阱與避免》http://blog.csdn.net/hfty290/article/details/42843303
??
?
?
總結(jié)
以上是生活随笔為你收集整理的Log4js原理解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Latex 会议模板基础上编辑中文
- 下一篇: 爱立信与RDK管理公司宣布将MediaF