Serilog 源碼解析——總覽

背景

大家好,考慮到在最近這些天,閑來無事,找了個類庫好好研究下別人寫的高品質程式碼,頗有收穫,打算和大家分享下。考慮到最近在自學 ASP.NET Core 的相關開發,對 Serilog 這個日誌記錄庫使用較多,好奇其內部的實現原理,趁著這段鹹魚時間好好地研究了下 Serilog 的源碼,順帶複習了一些常用的設計模式。目前計劃寫成一個系列介紹 Serilog 的實現,如有錯誤還請指正。

日誌記錄

在分析源碼前,我們首先要知道 Serilog 是什麼,它的功能是什麼,能做什麼事。俗話說知己知彼,百戰不殆。對對方都完全不了解,更別說去分析內部機理了。按照其官方定義,Serilog 是一個結構化的日誌記錄器。那麼,首先,日誌是什麼?

日誌,按照維基百科的說法,就是記錄了在系統運行期間發生的事件,以便於了解系統活動和診斷問題。換句話來說,日誌資訊揭露了部分的軟體運行流程。如果日誌記錄使用得當的話,它甚至還可以記錄當時日誌所處的上下文資訊,為未來系統分析提供了方便。舉個例子,用戶在登錄系統時,如果在登錄流程對登錄事件進行合適記錄的話,我們在後期維護或者檢索時就可以知曉曾經有某個用戶嘗試登錄該系統以及是否登錄成功。

// 偽程式碼
登錄流程
{
      記錄日誌:嘗試登錄
      判斷驗證碼是否正確;
      記錄日誌:驗證碼正確/錯誤(返回);
      嘗試連接用戶資料庫;
      記錄日誌:用戶資料庫連接成功/失敗(返回);
      查找用戶名和密碼匹配情況;
      記錄日誌:用戶密碼驗證成功/失敗(返回);
      檢測用戶許可權;
      記錄日誌:用戶登錄成功/失敗;
}

上面是用戶登錄過程的偽程式碼,我們通過安插幾條日誌記錄語句來記錄該登錄流程的具體走向。比如說我們發現有一個用戶始終登錄失敗,通過查詢其日誌的記錄資訊可以快速得知它在哪個過程出現了錯誤。這裡如果記錄用戶登錄失敗這條語句,就可能表明該用戶的用戶名和密碼沒有問題,但是沒有足夠的許可權登錄該系統。

那麼,何為結構化日誌呢?在以往的日誌記錄中,向日誌記錄器中只需要將日誌消息(log message)字元串傳入,由記錄器向各目的地寫入對應的字元串即可。然而,這樣的操作有其不方便性,日誌資訊的格式由調用方控制,沒有統一的日誌記錄格式,此外,數據被寫死在日誌字元串中,不利於通過根據數據去查詢對應的日誌資訊(常利用正則去查詢匹配字元串的日誌),缺乏靈活性。結構化的日誌是採用某種格式來記錄日誌而非原始的文本字元串資訊,比如說Json、xml格式等,這種方法處理的好處在於具有更加靈活的格式控制以及查詢方法等。結構化日誌通常是包含日誌的文本和數據,二者共同組成日誌事件(log event),一次日誌記錄產生一個日誌事件,而日誌事件如何渲染成日誌,由具體的日誌實現所決定。

思路

雖然說這篇部落格的標題叫做 Serilog 源碼解析,但是一上來就直接說 xxx 類做了什麼、xxx 類擔任了什麼職責容易讓別人一頭霧水,在對功能都未清晰的情況下,直接拆解源碼會讓未接觸過的人更加難以理解。因此,本系列並不打算一上來就對源碼做拆解。

這裡,計劃通過以一個小 demo 為開頭,通過提需求的方式不斷改進 demo 來作為開篇。這樣做的好處有兩個,一個是能夠了解日誌記錄的核心功能有哪些,另一個是通過demo為後續的源碼分析提供了基礎,快速理解類庫中的核心功能的實現邏輯。

這裡放出了 demo 的源碼。源碼採用git來管理,並為不同版本添加了 tag,每個版本使用 v[num] 的形式,比如說v2版本就是 v2。只要用以下命令就可以查看不同版本的源碼。

git clone //github.com/iskcal/LogDemo
git checkout v[num]

之後,介紹下 Serilog 常用的使用方法以及源碼相關的準備工作,為後續的解析做鋪墊。最後,剩餘部分的內容將按照 Serilog 的功能對源碼進行拆解。

目錄

未完待續……

總結

目前,Serilog 是一個非常廣泛應用在各種項目系統中的日誌類庫。Serilog 具有非常強的擴展性,它並沒有將所有功能全部放在Serilog這一個項目中而使得項目變得臃腫,相反,它通過將各種功能以擴展的形式分散成若干小項目,彼此單獨演化,不僅保持了最核心部分功能的穩定,也保證了使用時最小包大小的效果。從Serilog組織所維護的項目中可以發現,圍繞Serilog有60多子項目。在下一篇文章中,我會通過一個 demo 來展示下 Serilog 中最為核心的部分設計。