log4net面面觀之工作原理


    要知道Log4net究竟是咋幹活的,咱們可以從下面這個脈絡簡圖入手。你的程序中的語句log4net.LogManager.GetLogger().Info(“hello world!”); 就會引發log4net如下內部工作流程。不要管上面的對象(Appender/Filter等等)是什麼東東,先看着這個流程,我們來摸摸log4net工作的脈絡,然後我們再按關節一一打通。



1.  第一件事就是找調度(LogManager)要個幹活的工人(Logger,寫日誌的對象),當然,方法是調用LogManager.GetLogger()。找個什麼樣工人,究竟是那個工人會被挑中,這裏面有些曲折,會涉及到Repository(高級話題,下回分解)。咱先不管這麼多,知道有個能幹活的工人(Logger) 肯定是被找來了。
    另外有些麻煩事兒,這工人有經紀人ILoggerWrapper(Logger需要實現ILogger, 而ILoggerWrapper唯一的方法就是得到ILogger實例),經紀人又有代理ILog(ILog繼承於ILoggerWrapper)。代理ILog存在的意義在於給你提供方便的接口函數(Info,Warn等等),而不是工人提供的void Log(string callerFullName, Level level, object message, Exception t)。 不管關係多複雜,雖然你讓幹什麼活都得先對代理說,但最後還都是告訴了工人,一個字也沒落。

2.  你通過Info(“hello”)告訴工人幹活了,工人Logger一定先看看這事能不能幹。你的配置裏說只寫Info這個級別以上的信息,咱就不能寫Debug和Warn。這種情況你需要付出性能代價(一個函數調用和一個整數形式的級別比較)。然後,工人Logger就創建一個任務包LoggingEvent,把你要做的事兒用任務包的形式包起來,以後的流程就都針對任務包LoggingEvent處理了。
    任務包LoggingEvent裏信息豐富,包含:時間代碼位置、工人的名字、信息、線程名、用戶名、信息、異常、上下文等等。 

3.  接下來,Appender們登場了。原來工人自己不幹具體的活,手裏拽着一堆馬仔,自己成了工頭,告訴Appender去DoAppend(),讓馬仔們幹活。注意,這裏說得是“馬仔們”,就是說同時會有多個馬仔都在寫東東。究竟那些馬仔能被選中完成這光榮的任務,還要由客戶您來決定,如:<appender-ref ref="ConsoleAppender" />
     這些馬仔及其特長:     

馬仔

特長

ConsoleAppender

在控制檯上寫日誌

ColoredConsoleAppender

ConsoleAppender的徒弟,青出於藍,寫出來的東東還可以帶顏色,花花綠綠的,煞是好看

FileAppender

往文件裏寫日誌

RollingFileAppender

往可滾動的文件裏寫日誌,就是說它會按客戶要求控制文件大小和數量,一個文件寫滿就幫你再開另一個接着寫

ForwardingAppender

幫其他Appender傳任務包的人,當然自己可以幹一點雁過拔毛的事(做一些過濾的事情,比如說你要寫的東東里包含不雅的詞彙,它可以讓你變得文明一些)

NetSendAppender

往Windows的Messager寫日誌

ASPNetTraceAppender

在Asp.Net的Trace裏寫日誌

ADONetAppender

往數據庫裏寫日誌

EventLogAppender

往Windows事件裏寫日誌

RemotingAppender

把日誌轉給另外的Remoting服務,如:一個專門的集中的日誌服務器

SmtpAppender

通過郵件把日誌發出去

SmtpPickupDirAppender

把日誌包成郵件,發在指定目錄,等待專門的Smtp代理去發送

TelnetAppender

把日誌發到Telnet控制檯

UdpAppender

通過UDP協議把日誌發給另外的一個主機,或者組播給一些主機

     當然,你可以自己搞個馬仔,比如發個短信什麼的,可以取名叫MobilePagerAppender(從AppenderSkeleton繼承),通過配置告訴log4net就行。  

4.  說到這兒,檢查員Filter登場。這活最終究竟幹不幹,馬仔還得通過Decide()再問問檢查員們。注意,這裏說得是“檢查員們”,就是說所有在冊的檢查員都點頭,這話才能幹。如何讓檢查員在冊,看配置文件,如:
       <appender name="FF" type="log4net.Appender.ForwardingAppender" >
                     <filter type="log4net.Filter.LevelRangeFilter">
                            <param name="LevelMin" value="DEBUG"/>
                            <param name="LevelMax" value="INFO"/>
                     </filter>
                     <appender-ref ref="ConsoleAppender" />
      </appender>

    雁過拔毛的馬仔ForwardingAppender和檢查員LevelRangeFilter配合工作,把大於Debug和小於Info的東東通知給馬仔ConsoleAppender,讓它寫到控制檯上。

    每個檢查員都有自己的關注點,如下: 

檢查員

特長

LevelMatchFilter

日誌級別等於指定的級別才放行

LevelRangeFilter

按日誌級別範圍做比較,可取區間內的放行。如必須大於Warn小於Info

StringMatchFilter

對你的言論進行檢查,符合字符串比對條件的放行。如:必須包含“芝麻開門”的字符串才讓寫。

比對條件可以是簡單的帶通配符的字符串,也可以是正則表達式(帥!)

PropertyFilter

StringMatchFilter的徒弟,對LoggingEvent的某個屬性進行檢查,符合字符串匹配條件才放行

LoggerMatchFilter

檢查工頭(Logger)的名字,如果是以指定的字符串開頭的才放行。如:只要是姓“張”的工頭發下來的任務包,都讓過。

DenyAllFilter

這個檢查員最黑,什麼都不讓過

5.  檢查員們點頭後,這事就必須要乾了。怎麼幹?客戶要寫的東東究竟用什麼格式輸出?這活由排版員Layout來幹。下面是排版員的名單:

排版員

特長

ExceptionLayout

對LoggingEvent中的異常信息message進行排版

PatternLayout

最常用的排版員,通過一堆標識符來決定版式。

如:"%date %-5level- %message" 表示要以此輸出日誌日期、級別(5個字母的寬度)、信息

SimpleLayout

最簡單的版式:  [level] - [message]

XmlLayout

把日誌寫到XML文件中去,寫成一個Element

XmlLayoutSchemaLog4j

把日誌寫到XML文件中去,寫成一個Element,其格式需符合log4j對事件定義的DTD.

    排版員需要排版LoggingEvent的信息的字符串內容RenderedMessage,例如文章開頭的“hello world!”。除了“hello world!”這樣的字符串,信息message還可以是任意的對象。因此需要針對對象進行專門的排版,由Render(對象打印機)來幹。
    你可以針對自己的信息對象搞Render。如打印訂單信息的OrderRenader,一旦在訂單處理中發生錯誤,把訂單的主要信息打印出來,方便調試。別忘了:OrderRenader必須實現log4net.ObjectRenderer.IObjectRenderer。 

6.  一切就緒,各個馬仔就做最後的輸出,有打印屏幕的,有寫文件的,有在網絡上發數據的,八仙過海,各顯神通。 

    整個流程走完,相信我們接觸到的Logger、Appender、Filter、Layout、Render都已不再陌生。log4net良好的實現了事件過濾、格式排版的高度擴展性和可配置性。
    log4net的這處理模式可以看作是一種擴展的Publish/Subscribe模式,完全可以應用到我們自己的應用程序中去,比如說訂單處理,可以實現對不同訂單的過濾,實現不同的訂單的提交目的地(寫數據庫、發郵件、短信通知等等)。

    最後,給出Repository、Appender、Filter、Layout、Render的關係簡圖:
       

    雖然,Repository在下回分解,但這裏還需要簡單說兩句。Repository可以說成基於一個log4net配置節創建的log4net容器,它根據log4net配置節的指示創建以上其他的對象並保有他們的實例,隨時爲你所用。一般而言,你的應用程序不需要關心它,用缺省的容器即可。

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