日志庫的設計思路


一、基本思路

日志庫的設計,抓住最核心的一條,就是日志從產生到到達最終目的地期間的處理流程。
一般而言,為了設計一個靈活可擴展,可配置的日志庫,可將日志庫抽象為4個部分:記錄器、過濾器、格式化器、輸出器四部分。

  • 記錄器——負責產生日志記錄的原始信息,比如(原始信息,日志等級,時間,記錄的位置)等信息
  • 過濾器——負責按指定的過濾條件過濾掉我們不需要的日志(比如按日志等級過濾)
  • 格式化器——負責對原始日志信息按照我們想要的格式去格式化
  • 輸出器——負責將將要進行記錄的日志(一般經過過濾器及格式化器的處理后)記錄到日志目的地(例如:輸出到文件中)

通過將日志庫分為4個抽象,使之成了一個較為靈活可擴展的日志庫。比如你想實現輸出到文件和輸出到TCP中這兩個功能,你只需分別實現這兩個輸出器的實例即可。

實現了上面的抽象就基本實現日志庫的核心功能。在具體實現上,需要設計一個Logger,將上面的抽象組合起來。另外還有一些其他的工作需要完善,比如讀取日志配置文件,根據配置文件中的配置條件去構建相應的代碼等等其他工作。

二、一條日志的生命周期

可能到目前對日志庫是怎么工作的還有些模糊,下面以一條日志的生命周期為例來說明日志庫是怎么工作的:

  1. 產生。info!("log information.");
  2. 經過記錄器。記錄器去獲取日志發生的時間,位置,線程信息等等信息,會有一個數據結構去存儲你需要的信息(例如:msg:"log information.",time:2018-3-20 10:00:00,level:info,location:main.rs:3 lines
  3. 經過過濾器。決定是否記錄(例如,過濾條件設為info級以下的過濾掉,這里條日志信息等級是info,滿足條件,繼續。)
  4. 經過格式化器。假設我們想輸出為2018-3-22 10:00:00 [info] log information.
  5. 到輸出器。例如輸出到文件中,我們就將這條信息寫到文件上(File::write(....);,文件中會記錄2018-3-22 10:00:00 [info] log information.).
  6. 假如你還實現了日志回滾等功能的話,在日志寫入文件之后,還要判斷是否觸發日志回滾操作,如果滿足了日志回滾的條件(比如文件Size超過某一大小),則進行日志回滾操作。
  7. 這條日志的生命周期結束了。

三、偽代碼實現:

  1. 從配置文件中讀取配置(可通過序列化或其他方式),生成Config。
  2. LoggerBuilder根據Config去構造Logger。
  3. 由Logger實現日志庫的核心功能。
//配置
struct Config {
    level:Level,
    ...
}

//Logger建造者
struct LoggerBuilder {
    ...
}

//Logger
struct Logger {
    record:Recorder,
    filter:Filter,
    formater:Formater,
    output:Output,
}
......

四、更多功能細節

上面是日志庫設計的主干,可能我們還需要更多的功能,比如日志回滾、運行時修改配置等......

對於日志回滾,可抽象為兩部分,一個是觸發回滾操作的條件,一個是何種具體的回滾操作。比如,我們希望當文件大小為1G時就觸發回滾操作,回滾的具體操作是刪除舊的內容從新開始記錄。這里需要你做的就是實現(觸發條件+具體操作)這兩個抽象。

對於運行時修改配置,實質是根據最新的配置重新生成日志實例,具體實現時可設置一個定時器,定時去讀取新的配置,依據新的配置重新生成日志實例,再用這個日志實例記錄日志......

五、后記

是不是設計日志庫的時候功能越多越好呢?個人認為不是的,功能越多,抽象越復雜,代碼越臃腫,比如日志回滾功能的實現,實現過程中會不可避免的增加了鎖等,造成性能的下降,所以,夠用就好。

各種語言對應的日志庫已經有很多了,一般都能夠滿足需要,如果不滿需要,也可以加以擴展已滿足自己的項目需要。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM