.NetCore中的日誌(1)日誌元件解析

durow發表於2016-09-07

.NetCore中的日誌(1)日誌元件解析

 

0x00 問題的產生

日誌記錄功能在開發中很常用,可以記錄程式執行的細節,也可以記錄使用者的行為。在之前開發時我一般都是用自己寫的小工具來記錄日誌,輸出目標包含控制檯、文字檔案、資料庫,一般都是建立全域性的Logger,在需要記錄日誌的地方呼叫相應的Logger輸出至相應目標。遇到輸出目標多了有時候也感覺挺麻煩的,不過也還能接受。開始學習.NetCore後接觸到了日誌記錄框架(Logging元件),雖然完全可以用之前的方式記錄日誌,不過應該使用更通用的方式,把日誌記錄和具體的輸出目標解耦。所以學習了.NetCore中Logging元件,並嘗試實現了自定義的LoggerProvider,以及在.NetCore的Logging框架中使用現有完善的第三方日誌記錄工具NLog。寫一篇部落格作為學習記錄,同時也希望對有這方面需求的園友有所幫助。

0x01 .NetCore中的Logging

正如在上面部分寫到的那樣,當日志輸出的目標多起來後,寫日誌就會變得麻煩。仔細想一下,日誌輸出這個動作是不變的,變的只是不同的輸出目標(控制檯、文字檔案、資料庫等),所以可以把日誌記錄這個動作抽象出來,日誌記錄器包含多個可輸出目標,當我們呼叫Log方法寫日誌時,由Log方法依次呼叫Logger中的XxxLogger,把日誌寫到具體的目標上。過程如下圖所示:

那麼如何建立出這樣的一個Logger呢,我們可以建立一個工廠叫LoggerFactory用來生產Logger,Logger中包還含了ConsoleLogger、FileLogger等,這些XxxLogger可以通過XxxLoggerProvider建立。進一步的,可以把Logger、LoggerFactory和LoggerProvider的行為抽象為介面ILogger、ILoggerFactory、ILoggerProvider。

其中:

ILogger中的Log()方法可以記錄日誌;

ILoggerProvider可以建立ILogger,用於向特定的目標寫入日誌;

ILoggerFactory可以新增多個IloggerProvider,並可以建立我們最終使用的ILogger;

下圖為使用LoggerFactory中使用AddProvider方法新增ILoggerProvider:

下圖為LoggerFactory中使用CreateLogger方法建立Logger:

 

下圖為Logger的建構函式,使用傳入的LoggerFactory中的providers,依次呼叫其中的ILoggerProvider來建立XxxLogger。

 

這裡需要特別說明一下,ILoggerFactory和ILoggerProvider都產生ILogger,看上去讓人迷惑,但實際上這兩種ILogger的實現細節是不一樣的,不同的實現中Log()方法的意義不同。

對於ILoggerFactory產生的是Logger型別(也就是我們最終使用的Logger),其Log()方法是依次呼叫Logger中包含的_loggers陣列中的ILogger。

而ILoggerProvider產生的為各類不同的XxxLogger(也就是上面說的Logger中的_loggers陣列包含的如ConsoleLogger、DebugLogger),其Log()方法是把日誌寫到具體的目標上去。下圖為ConsoleLogger的Log()方法:

在有時候我們可能不希望某些日誌被寫入到所有的目標上。例如只想把某些特定的日誌寫入資料庫。這時可以在XxxdLoggerProvider建構函式中傳入

Func<string, LogLevel, bool> filter

形式的委託,當返回true時寫入日誌,返回false則不寫入日誌。

此外針對不同的LoggerProvider有不同的配置方式,這裡就不一一說明了。

0x02 泛型的Logger<T>

前面我們看到了,Logger用name來標識其唯一性。在日誌記錄時我們很多情況下都希望記錄日誌產生時所在的名稱空間和型別,因此使用完整的型別名稱來作為Logger的name既保證了唯一性又記錄了日誌產生時所在的名稱空間和型別是一個很好的選擇。當建立Logger<T>物件時,實際上就是建立了一個用T的完整型別名稱作為name的Logger並進行了包裝,把Logger<T>的Log方法原封不動傳入了建立的Logger的Log方法。

這樣一來像NLog這樣基於name的路由也很容易整合了。

0x03 使用日誌記錄

ILoggerFactory預設就已經被新增到IServiceCollection容器中了,我們只需要新增需要的ILoggerProvider即可。為了讓程式碼更簡潔更具備自解釋的能力,Logging元件還給ILoggerFactory新增了擴充套件方法,例如只要使用以下程式碼

就可以完成ConsoleLoggerProvider和DebugLoggerProvider的新增。

此外對Logger複雜的Log方法也進行了封裝(LogTrace、LogDebug、LogError等等),以滿足不同需求。

在使用Logger時可以通過依賴注入的方式獲取Logger,可以有兩種方法獲取:

以及

這兩種方法沒有本質區別,如下圖所示CreateLogger<T>方法也是呼叫Logger<T>建構函式來建立Logger<T>的。

所以只要根據喜好選擇就行。

0x04 寫在最後

.NetCore的Logging元件提供了日誌記錄的框架,只要實現了ILoggerProvider介面的日誌記錄工具都可以整合到Logger中,這極大方便了成熟的第三方日誌記錄工具的整合。通過Logging元件,把日誌記錄邏輯和具體的記錄行為解耦了,可以任意更換日誌記錄工具而不需要修改日誌記錄邏輯,同樣的,只要實現了框架的介面,不同日誌記錄工具也可以混用。所以雖然.NetCore本身只實現了Console、Debug等幾個有限的Logger,但藉助於豐富的第三方日誌記錄工具,我們有非常多的選擇。即使需求極其奇葩,只要實現框架中的介面,我們很容易整合自己寫的日誌記錄工具。下一篇將以NLog為例說一下第三方日誌記錄工具的整合,此外還將編寫和整合一個自己寫的Logger。

 


更多內容歡迎訪問我的部落格:http://www.durow.vip

相關文章