self4j日誌框架設計之從無到有(結合logback的實現)


日誌框架也是一個系統,我們下面也分別從建模以及實現架構兩個角度去加以分析。

業務建模

記錄日誌其實是一個動作,但是它包含了許多內容,包括當前的上下文信息、日誌數據(告警級別、內容)、業務標識(唯一標識符name,標籤marker)、記錄行爲。記錄時需要知道記錄的動作怎麼做,在哪個線程操作。

這裏寫圖片描述

使用者只要關心調用日誌記錄動作,傳遞數據以及業務標識。一個系統要劃分爲許多業務塊,每條日誌輸出要嚴格地屬於某一個業務name;同時系統要對這些日誌進行多角度的劃分、關聯,這就是標籤的概念marker。name這個概念是嚴格的統一劃分,好比數據庫的表,正好面向對象的設計中被調用者需要一個載體,我們就設計出一個Logger的概念,與name進行掛鉤。
這樣使用者需要用到的場景就分爲兩步:
1、logger的獲取
2、logger.log(level,marker,content)

總結來說分別是配置、組件的加載和日誌行爲的發生。前者是圍繞後者的設計的,日誌行爲包含着許多要應對場景。

架構設計

下面介紹一下self4j這個日誌框架的設計過程以及設計結果。

流程描述

寫日誌,需要調用者傳遞過來的信息以及當前的上下文信息(比如當前的類、行數、線程等),將其封裝成一個類LoggingEvent。有了信息,怎麼輸出,引出appender的概念;io慢怎麼辦,不能影響業務代碼的執行,要考慮異步的實現,需要維護線程池。
這是正常的流程,如果寫日誌的時候日誌配置、組件尚未加載完成怎麼辦?需要先加入到隊列中,引出SubstituteLogger的概念,先記錄下要記錄的行爲,等待加載完成後再寫。
如果寫日誌的過程中出現異常怎麼辦?要重試嗎?重試機制怎麼做?這涉及到開閉原則,這些部分的實現留給具體的日誌實現去做。

理清頭緒

這麼多情況,怎麼設計?我們先只考慮正常的流程,要獲取logger,怎麼獲取?這麼多logger,需要一個承擔builder的類。在獲取這個logger時可能會報錯,因爲logger還包含了appenders等信息,可能還沒初始化完,但作爲日誌框架,要對這種情況加以處理而不是拋出異常。我們採取延緩執行的策略,返回一個特定的logger,這個logger不做實際的日誌記錄工作。這樣這個流程就通了。
但是什麼時候觸發這些留待執行的任務,這裏需要一個隊列,在調用logger.log()方法的時候就把日誌記錄行爲加入到隊列中,在組件加載完成後執行。

組件加載

1、分析

組件的加載什麼時候進行?日誌的配置和組件是不依賴項目的,並且加載一次就好,所以在jvm啓動過程中就可以通過靜態代碼來進行加載,那麼有哪些組件呢?

TODO
有logger、logger的構造者以及執行者。
對於使用者來說,一個對象載體及其方法足矣,但是我們需要根據某種維度對logger進行劃分,這樣使用者不用重複傳入基礎的標示信息;因爲根據配置的不同、加載的成功與否,logger的行爲也會不同,這裏通過工廠的方式來獲取logger;最後logger動作的執行,這一塊涉及到日誌內容的解析、目的地的選擇以及寫入的實現,需要一個執行器組件。日誌的動作不能對主流程造成干擾,所以很多時候日誌動作需要異步執行,這就需要在獨立於業務線程的單獨線程來執行真正的寫入動作。

組件加載可以放到logger的builer類裏嗎?從責任角度說,這是builder在初始化前要做的工作。我們上文說到在配置沒有加載完成的時候還需要返回一種特殊的logger,看來這個應該是一個抽象工廠模式了,根據不同的加載情況來返回不同的logger獲取工廠,最後再獲取對應的logger。

2、self4j的實現

到這裏爲止,加載配置的任務還是可以直接放到loggerFactory那裏,但self4j的實現是放到StaticLoggerBinder中的,這是什麼玩意?StaticLoggerBinder是LoggerFactoryBinder的一個實現,self4j允許自定義loggerFactory,將類名與loggerFactory綁定,這就是LoggerFactoryBinder的概念。StaticLoggerBinder是單例,通過靜態代碼塊加載,在加載完成之後執行等待隊列裏的動作(需要寫日誌的動作)。
在這裏插入圖片描述
在這裏插入圖片描述

log操作

核心的操作部分嵌套不多,分爲兩步,首先構建參數,包括調用者傳遞過來的以及當前的上下文信息,然後將內容輸出到該logger綁定的appender上。appender的維護也是一個值得深挖的地方.TODO

架構概圖
在這裏插入圖片描述

現有官方實現的流程

1、通過靜態代碼塊加載logger的配置

在這裏插入圖片描述

這個過程包括配置的解析以及相應動作的執行
在這裏插入圖片描述
這個分爲三種saxevent
在這裏插入圖片描述

將SaxEvent轉化爲具體的動作是重點所在:
在這裏插入圖片描述

2、在加載配置的過程中,如果要寫日誌怎麼辦,官方的做法是將日誌動作記錄下來,在加載完成後統一執行

2.1 如果還沒加載好,就返回這個
在這裏插入圖片描述

2.2 獲取logger時實際返回的是
在這裏插入圖片描述
它會將日誌動作加到隊列裏
在這裏插入圖片描述

2.3 在加載完成後執行隊列裏的動作
在這裏插入圖片描述

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