动态

详情 返回 返回

Rust的高效易用日誌庫—tklog - 动态 详情

很多人習慣於python,go等語言基礎工具庫的簡單易用;在使用rust時,可能感覺比較麻煩,類似日誌庫這樣的基礎性工具庫。tklog提供用法上,非常類似python等Logger的日誌庫用法,用法簡潔;基於rust的高效性和一些優化策略,tklog的性能非常好,在壓測中,可以達到 3-4 µs/op (微妙/次),這個效率比go最高的性能時候都高一些;在相同的環境下,對go進行無格式日誌輸出壓測,可以達到 3-4µs/op,如果是格式化日誌輸出,則為4µs/op以上。(可以參考《高性能日誌庫go-logger v2.0.3》中對各日誌庫的壓測數據)。
在異步場景中,tklog提供了對應的方法,支持異步調用。異步方法最大的好處並非在性能上,而是它不會阻塞所在線程。但是由於 tklog的常規日誌方法默認使用延遲策略,實際上也不會阻塞所在線程,或者準確説影響非常小,可以忽略不計。所以,異步場景一般也可以直接使用常規日誌打印方法。

相關連接

項目源碼
官網
倉庫

項目引入

[dependencies]
tklog = "0.0.2"   #使用時的實際最新版本;當前0.0.2版本

tklog是rust高性能結構化日誌庫

易用,高效,結構化,控制枱日誌,文件日誌,文件切割,文件壓縮,同步打印,異步打印

功能

  1. 功能支持:控制枱日誌,文件日誌,同步日誌,異步日誌
  2. 日誌級別設置:提供與標準庫同級別日誌打印: trace,debug,info,warn,error,fatal
  3. 格式化輸出:支持自定義日誌的輸出格式,包括日誌級別標識、格式化時間、日誌文件位置 等元素,並支持自定義格式調整。
  4. 按時間文件切割:按小時,天,月份切割日誌文件
  5. 按大小文件切割:按指定大小切割日誌文件
  6. 文件數回滾:指定最大備份文件數,支持自動刪除舊日誌文件,並防止日誌文件數過多。
  7. 文件壓縮:支持壓縮歸檔備份日誌文件。

    使用方法簡述

最簡單常用的方法:直接調用

    use tklog::{trace,debug, error, fatal, info,warn}
    fn testlog() {
        trace!("trace>>>>", "aaaaaaaaa", 1, 2, 3, 4);
        debug!("debug>>>>", "bbbbbbbbb", 1, 2, 3, 5);
        info!("info>>>>", "ccccccccc", 1, 2, 3, 5);
        warn!("warn>>>>", "dddddddddd", 1, 2, 3, 6);
        error!("error>>>>", "eeeeeeee", 1, 2, 3, 7);
        fatal!("fatal>>>>", "ffffffff", 1, 2, 3, 8);
    }

説明:默認打開控制枱日誌,沒有寫日誌文件。打印結果:

[TRACE] 2024-05-26 11:47:22 testlog.rs 27:trace>>>>,aaaaaaaaa,1,2,3,4
[DEBUG] 2024-05-26 11:47:22 testlog.rs 28:debug>>>>,bbbbbbbbb,1,2,3,5
[INFO] 2024-05-26 11:47:22 testlog.rs 29:info>>>>,ccccccccc,1,2,3,5
[WARN] 2024-05-26 11:47:22 testlog.rs 30:warn>>>>,dddddddddd,1,2,3,6
[ERROR] 2024-05-26 11:47:22 testlog.rs 31:error>>>>,eeeeeeee,1,2,3,7
[FATAL] 2024-05-26 11:47:22 testlog.rs 32:fatal>>>>,ffffffff,1,2,3,8

説明:直接調用 debug!等宏進行打印,默認調用全局靜態LOG對象。LOG對象支持初始化。

    use tklog::{
        sync::Logger,
        LEVEL, LOG,
        Format,MODE,
    };
    
    fn log_init() {
            LOG.set_console(true)  //設置控制枱日誌
                .set_level(LEVEL::Info)  //日誌級別,默認Debug
                .set_format(Format::LevelFlag | Format::Time | Format::ShortFileName)  //結構化日誌,定義輸出的日誌信息
                .set_cutmode_by_size("tklogsize.txt", 1<<20, 10, true)  //日誌文件切割模式為文件大小,每1M文件切分一次,保留10個備份日誌文件,並壓縮備份日誌
                .set_formatter("{level}{time} {file}:{message}\n")   //自定義日誌輸出格式。默認:{level}{time} {file}:{message}\n
    }
    
    fn testlog() {
        log_init()  //調用初始化方法
        trace!("trace>>>>", "aaaaaaaaa", 1, 2, 3, 4);   //track日誌級別小於設置的LEVEL::Info ,故無輸出
        info!("info>>>>", "ccccccccc", 1, 2, 3, 5);
    }

以上是全局單實例打印的示例。tklog支持自定義多實例打印。多實例一般應用在系統要求不同打印結構的場景中

多實例打印

use tklog::{
    debugs, errors, fatals, infos,
    sync::Logger,
    LEVEL, LOG,
    traces, warns, Format, MODE,
};
fn testmutlilog() {
    let mut log = Logger::new();
    log.set_console(true)
        .set_level(LEVEL::Debug) //定義日誌級別為Debug
        .set_cutmode_by_time("tklogs.log", MODE::DAY, 10, true)   //分割日誌文件的方式為按天分割,保留最多10個備份,並壓縮備份文件
        .set_formatter("{message} | {time} {file}{level}\n")   //自定義日誌結構信息的輸入順序與附加內容
        
    let mut logger = Arc::clone(&Arc::new(Mutex::new(log)));
    let log = logger.borrow_mut();
    traces!(log, "traces>>>>", "AAAAAAAAA", 1, 2, 3, 4);
    debugs!(log, "debugs>>>>", "BBBBBBBBB", 1, 2, 3, 5);
    infos!(log, "infos>>>>", "CCCCCCCCC", 1, 2, 3, 5);
    warns!(log, "warns>>>>", "DDDDDDDDDD", 1, 2, 3, 6);
    errors!(log, "errors>>>>", "EEEEEEEE", 1, 2, 3, 7);
    fatals!(log, "fatals>>>>", "FFFFFFFF", 1, 2, 3, 8);
    
    thread::sleep(Duration::from_secs(1))
}

執行結果:

debugs>>>>,BBBBBBBBB,1,2,3,5 | 2024-05-26 14:13:25 testlog.rs 70[DEBUG]
infos>>>>,CCCCCCCCC,1,2,3,5 | 2024-05-26 14:13:25 testlog.rs 71[INFO]
warns>>>>,DDDDDDDDDD,1,2,3,6 | 2024-05-26 14:13:25 testlog.rs 72[WARN]
errors>>>>,EEEEEEEE,1,2,3,7 | 2024-05-26 14:13:25 testlog.rs 73[ERROR]
fatals>>>>,FFFFFFFF,1,2,3,8 | 2024-05-26 14:13:25 testlog.rs 74[FATAL]

注意:以上輸入結構化信息由 "{message} | {time} {file}{level}\n" formatter決定。formatter中除了關鍵標識 {message} {time} {file} {level} 外,其他內容原樣輸出,如 | , 空格,換行 等。

tklog使用詳細説明

  1. 日誌級別 : Trace < Debug < Info < Warn < Error < Fatal
    示例:

    LOG.set_level(LEVEL::Info) //日誌級別,設置為Info

  2. 控制枱日誌
    調用 .set_console(bool) 函數

    LOG.set_console(false) // false表示不打印控制枱日誌。默認為true

  3. 日誌格式
  • Format::Nano 無格式
  • Format::Date 輸出日期 :2024-05-26
  • Format::Time 輸出時間,精確到秒:14:13:25
  • Format::Microseconds 輸出時間,精確到微妙:18:09:17.462245
  • Format::LongFileName 長文件信息+行號:tests estlog.rs 25
  • Format::ShortFileName 短文件信息+行號:testlog.rs 25
  • Format::LevelFlag 日誌級別信息: [Debug]

    LOG.set_format(Format::LevelFlag | Format::Time | Format::ShortFileName)  
    

4.自定義格式輸出
默認:"{level}{time} {file}:{message}\n"

{level} 日誌級別信息:如[Debug]
{time} 日誌時間信息
{file} 文件位置行號信息
{message} 日誌內容

LOG.set_formatter("{message} | {time} {file}{level}\n");  //自定義日誌結構信息的輸入順序與附加內容

説明:除了關鍵標識 {message} {time} {file} {level} 外,其他內容原樣輸出,如 | , 空格,換行 等。

5.按時間分割日誌文件
時間標識:MODE::HOUR,MODE::DAY,MODE::MONTH

分別是:小時,天,月份

調用 .set_cutmode_by_time() 函數,參數:

  • 文件路徑
  • 時間模式
  • 最大備份日誌文件數
  • 是否壓縮備份的日誌文件

示例

let mut log = Logger::new();
log.set_cutmode_by_time("/usr/local/tklogs.log", MODE::DAY, 0, false)

説明:備份文件路徑為: /usr/local/tklogs.log ,時間模式為:按天備份,參數0表示不限制備份文件數,false表示不壓縮備份的日誌文件

備份的文件格式:

  • 按天備份日期文件,如:

    • tklogs_20240521.log
    • tklogs_20240522.log
  • 按小時備份日誌文件,如:

    • tklogs_2024052110.log
    • tklogs_2024052211.log
  • 按月份備份日誌文件,如:

    • tklogs_202403.log
    • tklogs_202404.log

6.按大小分割日誌文件
調用 .set_cutmode_by_size() 函數,參數:

  • 文件路徑
  • 指定文件滾動大小
  • 最大備份日誌文件數
  • 是否壓縮備份的日誌文件

示例

let mut log = Logger::new();
log.set_cutmode_by_time("tklogs.log", 100<<20, 10, true)

説明:備份文件路徑為:tklogs.log ,按100M大小備份文件,參數10表示只保留最新10個備份文件,true表示壓縮備份的日誌文件

備份的文件格式:

  • tklogs_1.log.gz
  • tklogs_2.log.gz
  • tklogs_3.log.gz

tklog提供常規日誌打印 方法為:

全局單例打印

1. trace!
2. debug!
3. info!
4. warn!
5. error!
6. fatal!

多實例打印

1. traces!
2. debugs!
3. infos!
4. warns!
5. errors!
6. fatals!

異步日誌

全局異步單例打印

1. async_trace!
2. async_debug!
3. async_info!
4. async_warn!
5. async_error!
6. async_fatal!

多實例異步打印

1. async_traces!
2. async_debugs!
3. async_infos!
4. async_warns!
5. async_errors!
6. async_fatals!

異步方法使用示例

全局單例異步調用

use tklog::{
    async_debug,  async_error,  async_fatal,  async_info,  async_trace,  async_warn,  LEVEL, Format, ASYNC_LOG
 };

async fn async_log_init() {
    // 全局單例設置參數
   ASYNC_LOG
        .set_console(false)   //控制枱
        .set_level(LEVEL::Trace)  //日誌級別
        .set_format(Format::LevelFlag | Format::Time | Format::ShortFileName)  //結構化日誌,定義輸出的日誌信息
        .set_cutmode_by_size("tklog_async.txt", 10000, 10, false).await;  //日誌文件切割模式為文件大小,每10000字節切割一次,保留10個備份日誌文件
  
#[tokio::test]
async fn testlog() {
    async_log_init().await;  //參數設置
    async_trace!("trace>>>>", "aaaaaaa", 1, 2, 3);
    async_debug!("debug>>>>", "aaaaaaa", 1, 2, 3);
    async_info!("info>>>>", "bbbbbbbbb", 1, 2, 3);
    async_warn!("warn>>>>", "cccccccccc", 1, 2, 3);
    async_error!("error>>>>", "ddddddddddddd", 1, 2, 3);
    async_fatal("fatal>>>>", "eeeeeeeeeeeeee", 1, 2, 3);
    tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
}

輸出結果:

[TRACE] 20:03:32 testasynclog.rs 20:trace>>>>,aaaaaaa,1,2,3
[DEBUG] 20:03:32 testasynclog.rs 21:debug>>>>,aaaaaaa,1,2,3
[INFO] 20:03:32 testasynclog.rs 22:info>>>>,bbbbbbbbb,1,2,3
[WARN] 20:03:32 testasynclog.rs 23:warn>>>>,cccccccccc,1,2,3
[ERROR] 20:03:32 testasynclog.rs 24:error>>>>,ddddddddddddd,1,2,3
[FATAL] 20:03:32 testasynclog.rs 25:fatal>>>>,eeeeeeeeeeeeee,1,2,3

多實例異步

use std::sync::Arc;

use tklog::{
     async_debugs,  async_errors,  async_fatals,  async_infos,  async_traces,  async_warns, LEVEL, Format, ASYNC_LOG, MODE
};
#[tokio::test]
async fn testmultilogs() {
    //新建 Async::Logger 對象
    let mut log = tklog::Async::Logger::new();
    log.set_console(false)
        .set_level(LEVEL::Debug)
        .set_cutmode_by_time("tklogasync.log", MODE::DAY, 10, true) 
        .await
        .set_formatter("{message} | {time} {file}{level}\n");

    let mut logger = Arc::clone(&Arc::new(Mutex::new(log)));
    let log = logger.borrow_mut();
    async_traces!(log, "async_traces>>>>", "AAAAAAAAAA", 1, 2, 3);
    async_debugs!(log, "async_debugs>>>>", "BBBBBBBBBB", 1, 2, 3);
    async_infos!(log, "async_infos>>>>", "CCCCCCCCCC", 1, 2, 3);
    async_warns!(log, "async_warns>>>>", "DDDDDDDDDD", 1, 2, 3);
    async_errors!(log, "async_errors>>>>", "EEEEEEEEEEE", 1, 2, 3);
    async_fatals!(log, "async_fatals>>>>", "FFFFFFFFFFFF", 1, 2, 3);
    tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
}

輸出結果:

async_debugs>>>>,BBBBBBBBBB,1,2,3 | 2024-05-26 20:10:24 testasynclog.rs 45[DEBUG]
async_infos>>>>,CCCCCCCCCC,1,2,3 | 2024-05-26 20:10:24 testasynclog.rs 46[INFO]
async_warns>>>>,DDDDDDDDDD,1,2,3 | 2024-05-26 20:10:24 testasynclog.rs 47[WARN]
async_errors>>>>,EEEEEEEEEEE,1,2,3 | 2024-05-26 20:10:24 testasynclog.rs 48[ERROR]
async_fatals>>>>,FFFFFFFFFFFF,1,2,3 | 2024-05-26 20:10:24 testasynclog.rs 49[FATAL]

基準壓力測試

test_debug              time:   [3.3747 µs 3.4599 µs 3.5367 µs]
                        change: [-69.185% -68.009% -66.664%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  6 (6.00%) high mild
  3 (3.00%) high severe
説明:時間範圍給出了三個數據點,分別代表了測試執行時間的最小值(3.3747微秒)、平均值附近的值(3.4599微秒)、以及最大值(3.5367微秒)
test_debug              time:   [3.8377 µs 3.8881 µs 3.9408 µs]
                        change: [-66.044% -65.200% -64.363%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
説明:測試運行的時間範圍是從3.8377微秒到3.9408微秒,覆蓋了一個大概的分佈情況,其中3.8881微秒大約是這段時間內的平均或中位數執行時間

結論:日誌打印函數性能:3 µs/op — 4 µs/op (微妙/次)

user avatar segmentfault 头像 eolink 头像 tssc 头像 chaoxi_67109d31bc42f 头像 shouke 头像 vipstone 头像 god23bin 头像 java_3y 头像 best_6455a509a2177 头像 ucrx2py9 头像 javalover 头像 dns1 头像
点赞 39 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.