#log-level #log-file #log #log-debug #log-format #logging #console-log

tklog

轻量级且高效的 Rust 结构化日志库,支持日志级别、文件碎片、压缩归档

11 个版本

0.1.0 2024 年 8 月 24 日
0.0.10 2024 年 8 月 15 日
0.0.8 2024 年 6 月 20 日
0.0.3 2024 年 5 月 30 日

#185调试

Download history 353/week @ 2024-05-24 195/week @ 2024-05-31 186/week @ 2024-06-07 410/week @ 2024-06-14 69/week @ 2024-06-21 4/week @ 2024-06-28 40/week @ 2024-07-05 21/week @ 2024-07-12 2/week @ 2024-07-19 11/week @ 2024-07-26 121/week @ 2024-08-02 131/week @ 2024-08-09 62/week @ 2024-08-16

每月 325 次下载

Apache-2.0

110KB
2K SLoC

tklog 是一个高性能的 Rust 结构化日志库 [中文]

tklog 具有易用性、效率丰富的功能集。它支持控制台日志记录、文件日志记录、同步和异步日志记录模式,以及像按时间或大小切片日志和压缩备份日志文件这样的高级功能。

功能

  • 支持功能包括控制台日志记录、文件日志记录、同步日志记录、异步日志记录。
  • 日志级别设置与标准库相同:跟踪、调试、信息、警告、错误、致命。
  • 具有自定义格式的格式化输出,可以包括日志级别标志、格式化时间戳和日志文件位置。
  • 按时间间隔切片日志文件:按小时、按天或按月。
  • 按指定文件大小切片日志文件。
  • 文件滚动机制,当达到最大备份次数时自动删除旧日志文件,以防止日志过多。
  • 压缩归档的备份日志文件。
  • 支持官方日志库标准 API

官方网站


简单使用说明

使用 tklog
[dependencies]
tklog = "0.0.10"   #   "0.0.x" current version

使用 tklog 最简单的方法是直接使用宏调用

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
对于初始化和自定义,tklog 提供了配置选项的方法,例如控制台输出、日志级别、格式化样式、切割策略和自定义格式化程序。
use tklog::{
    sync::Logger,LEVEL, LOG,
    Format, MODE,
};

fn log_init() {
    LOG.set_console(true)       // Enables console logging
        .set_level(LEVEL::Info)  // Sets the log level; default is Debug
        .set_format(Format::LevelFlag | Format::Time | Format::ShortFileName)  // Defines structured log output with chosen details
        .set_cutmode_by_size("tklogsize.txt", 1<<20, 10, true)  // Cuts logs by file size (1 MB), keeps 10 backups, compresses backups
        .set_formatter("{level}{time} {file}:{message}\n");   // Customizes log output format; default is "{level}{time} {file}:{message}"
}

这展示了全局、单例式日志设置。此外,tklog 还支持自定义的多实例日志配置,这对于需要在不同组件之间具有不同日志结构的系统非常有用。


多实例日志

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) //Set the log level to Debug
        .set_cutmode_by_time("tklogs.log", MODE::DAY, 10, true)   //Split log files daily, keep up to 10 backups, and compress them
        .set_formatter("{message} | {time} {file}{level}\n");  //Customize the log structure's output format and additional content
    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" 的格式。格式化器包括如 {message}、{time}、{file}、{level} 以及这些占位符之外任何额外的文本或分隔符。

详细使用指南

1. 日志级别:Trace < Debug < Info < Warn < Error < Fatal。

示例

   LOG.set_level(LEVEL::Info) //Sets the log level to Info

2. 控制台日志:通过 .set_console(bool) 启用或禁用。

   LOG.set_console(false) //Disables console logging (default is true)

3. 日志格式

Format::Nano : No formatting
Format::Date  : Outputs date (e.g., 2024-05-26)
Format::Time  : Outputs time to seconds (e.g., 14:13:25)
Format::Microseconds :Outputs time with microseconds (e.g., 18:09:17.462245)
Format::LongFileName :Full file path with line number (e.g., tests/testlog.rs 25)
Format::ShortFileName : Abbreviated file path with line number (e.g., testlog.rs 25)
Format::LevelFlag : Log level marker (e.g., [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")

提醒:在 {level}{time}{file}{message} 标签之外的文字将原样输出,包括分隔符、空格和换行符。

5. 基于时间的日志文件轮转

模式:MODE::HOURMODE::DAYMODE::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,每日轮转,无备份限制,且不压缩每日日志。

备份命名约定

  • 每日
    • 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_size("tklogs.log", 100<<20, 10, true);

在此,tklogs.log 表示路径,每个文件滚动 100 MB,保留 10 个备份,并压缩它们。

备份文件命名约定

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

日志打印方法

  • 全局单例

    • trace!debug!info!warn!error!fatal!
  • 多个实例

    • traces!debugs!infos!warns!errors!fatals!

异步日志

  • 全局单例异步

    • async_trace!async_debug!async_info!async_warn!async_error!async_fatal!
  • 多个实例异步

    • async_traces!async_debugs!async_infos!async_warns!async_errors!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() {
    // Configure global singleton
    ASYNC_LOG
        .set_console(false) // Disable console output
        .set_level(LEVEL::Trace) // Set log level to Trace
        .set_format(Format::LevelFlag | Format::Time | Format::ShortFileName) // Define structured logging output
        .set_cutmode_by_size("tklog_async.txt", 10000, 10, false) // Rotate log files by size, every 10,000 bytes, with 10 backups
        .await;
}

#[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() {
    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]

支持官方日志库标准 API

  1. tklog 实现了官方 Log 接口 API 的常规使用
  2. 实现官方日志库 API,用于异步场景
如何启用官方日志库 API:
tklog 通过调用 uselog() 函数启用官方日志的 API 支持
使用示例
use std::{thread, time::Duration};
use tklog::{Format, LEVEL, LOG};
fn test_synclog() {
    //init  LOG
    LOG.set_console(true)
        .set_level(LEVEL::Debug)
        .set_cutmode_by_size("logsize.log", 10000, 10, true)
        .uselog();  //Enable the official log library
	
	log::trace!("trace>>>>{}{}{}{}{}", "aaaa", 1, 2, 3, 4);
	log::debug!("debug>>>>{}{}",1,2);
    log::info!("info log");
    log::warn!("warn log");
    log::error!("error log");
	thread::sleep(Duration::from_secs(1))
}

在异步场景中启用日志库 API

use std::{thread, time::Duration};
use tklog::{Format, LEVEL, ASYNC_LOG};
async fn test_synclog() {
    //init ASYNC  LOG 
    ASYNC_LOG.set_console(false)
        .set_cutmode_by_size("asynclogsize.log", 10000, 10, true).await
        .uselog(); //Enable the official log library
	
    log::trace!("trace async log>>>>{}{}{}{}{}", "aaaaaaaaa", 1, 2, 3, 4);
    log::debug!("debug async log>>>>{}{}",1,2);
	log::info!("info async log");
    log::warn!("warn async log");
    log::error!("error async log");
    tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
}

模块设置日志参数

  1. tklog 提供 set_optionset_mod_option 来设置 Logger 对象的全局日志参数和指定模块的日志参数
  2. 在项目中,您可以使用全局 LOG 对象同时为多个 mod 设置日志参数
  3. 不同的 mod 可以设置不同的日志级别、日志格式、日志文件等
  4. ASYNC_LOG 的 mod 日志参数与 LOG 对象相同
set_option 示例:
tklog::LOG.set_option(LogOption{level:Some(LEVEL::Debug),console: Some(false),format:None,formatter:None,fileoption: Some(Box::new(FileTimeMode::new("day.log",tklog::MODE::DAY,0,true)))});
LogOption 指令
  • level 日志级别
  • format 日志格式
  • formatter 用户定义的日志输出格式
  • console 控制台日志设置
  • fileoption 文件日志设置
set_mod_option 文件日志设置:
tklog::LOG.set_mod_option("testlog::module1",LogOption{level:Some(LEVEL::Debug),console: Some(false),format:None,formatter:None,fileoption: Some(Box::new(FileTimeMode::new("day.log", tklog::MODE::DAY, 0,true)))});
  • testlog::module1 是模块名称,您可以使用 module_path!() 打印当前模块名称
  • 当在 testlog::module1 模块中使用 tklog 时,tklog 将使用 LogOption 对象

完整的 mod 示例

mod module1 {
    use std::{thread, time::Duration};
    use tklog::{handle::FileTimeMode, LogOption, LEVEL};
    pub fn testmod() {
        tklog::LOG.set_mod_option("testlog::module1", LogOption { level: Some(LEVEL::Debug), format: None, formatter: None, console: None, fileoption: Some(Box::new(FileTimeMode::new("module1.log", tklog::MODE::DAY, 0, true))) }).uselog();
        tklog::debug!("module1,tklog api,LOG debug log>>", 123);
        tklog::info!("module1,tklog api,LOG info log>>", 456);
        log::debug!("module1,log api,debug log>>{}", 111);
        log::info!("module1,log api,info log>>{}", 222);
        thread::sleep(Duration::from_secs(1))
    }
}

mod module2 {
    use std::{thread, time::Duration};
    use tklog::{handle::FileTimeMode, LogOption, LEVEL};
    pub fn testmod() {
        tklog::LOG.set_mod_option("testlog::module2", LogOption { level: Some(LEVEL::Info), format: None, formatter: None, console: None, fileoption: Some(Box::new(FileTimeMode::new("module2.log", tklog::MODE::DAY, 0, true))) }).uselog();
        tklog::debug!("module2,tklog api,LOG debug log>>", 123);
        tklog::info!("module2,tklog api,LOG info log>>", 456);
        log::debug!("module2,log api,debug log>>{}", 111);
        log::info!("module2,log api,info log>>{}", 222);
        thread::sleep(Duration::from_secs(1))
    }
}

#[test]
fn testmod2() {
    module1::testmod();
    module2::testmod();
}
执行结果
[DEBUG] 2024-06-19 10:54:07 testlog.rs 54:module1,tklog api,LOG debug log>>,123
[INFO] 2024-06-19 10:54:07 testlog.rs 55:module1,tklog api,LOG info log>>,456
[DEBUG] 2024-06-19 10:54:07 testlog.rs 56:module1,log api,debug log>>111
[INFO] 2024-06-19 10:54:07 testlog.rs 57:module1,log api,info log>>222
[INFO] 2024-06-19 10:54:08 testlog.rs 68:module2,tklog api,LOG info log>>,456
[INFO] 2024-06-19 10:54:08 testlog.rs 70:module2,log api,info log>>222

示例 2:异步日志


mod module3 {
    use tklog::{handle::FileTimeMode, Format, LogOption, LEVEL};
    pub async fn testmod() {
        tklog::ASYNC_LOG.set_mod_option("testlog::module3", LogOption { level: Some(LEVEL::Debug), format: Some(Format::Date), formatter: None, console: None, fileoption: Some(Box::new(FileTimeMode::new("module3.log", tklog::MODE::DAY, 0, true))) }).await.uselog();
        tklog::async_debug!("async module3,tklog api,LOG debug log>>", 123);
        tklog::async_info!("async module3,tklog api,LOG info log>>", 456);
        log::debug!("async module3,log api,debug log>>{}", 333);
        log::info!("async module3,log api,info log>>{}", 444);
        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    }
}

mod module4 {
    use tklog::{handle::FileTimeMode, Format, LogOption, LEVEL};
    pub async fn testmod() {
        tklog::ASYNC_LOG.set_mod_option("testlog::module4", LogOption { level: Some(LEVEL::Info), format: Some(Format::Date), formatter: None, console: None, fileoption: Some(Box::new(FileTimeMode::new("module4.log", tklog::MODE::DAY, 0, true))) }).await.uselog();
        tklog::async_debug!("async module4,tklog api,LOG debug log>>", 123);
        tklog::async_info!("async module4,tklog api,LOG info log>>", 456);
        log::debug!("async module4,log api,debug log>>{}", 333);
        log::info!("async module4,log api,info log>>{}", 444);
        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    }
}

#[tokio::test]
async fn testmod4() {
    module3::testmod().await;
    module4::testmod().await;
}
执行结果
[DEBUG] 2024-06-19 10:59:26 testlog.rs 85:async module3,tklog api,LOG debug log>>,123
[INFO] 2024-06-19 10:59:26 testlog.rs 86:async module3,tklog api,LOG info log>>,456
[DEBUG] 2024-06-19 10:59:26 testlog.rs 87:async module3,log api,debug log>>333
[INFO] 2024-06-19 10:59:26 testlog.rs 88:async module3,log api,info log>>444
[INFO] 2024-06-19 10:59:27 testlog.rs 98:async module4,tklog api,LOG info log>>,456
[INFO] 2024-06-19 10:59:27 testlog.rs 100:async module4,log api,info log>>444


tklog 支持多实例格式化格式!并支持异步格式!

示例:
#[test]
fn testformats() {
    let mut log = Logger::new();
    log.set_console(true)
        .set_level(LEVEL::Debug)
        .set_cutmode_by_time("tklogs.log", MODE::DAY, 10, true);
    let mut logger = Arc::clone(&Arc::new(Mutex::new(log)));
    let log = logger.borrow_mut();

    let v = vec![1, 2, 3];
    tklog::formats!(log, LEVEL::Debug, "Debug>>>{},{}>>>{:?}", 1, 2, v);

    let v2 = vec!['a', 'b'];
    tklog::formats!(log, LEVEL::Info, "Info>>>{},{}>>{:?}", 1, 2, v2);
    tklog::formats!(log, LEVEL::Warn, "Warn>>>{},{}", 1, 2);
    tklog::formats!(log, LEVEL::Error, "Error>>>{},{}", 1, 2);
    tklog::formats!(log, LEVEL::Fatal, "Fatal>>>{},{}", 1, 2);

    thread::sleep(Duration::from_secs(1))
}
执行结果
[DEBUG] 2024-06-06 15:54:07 testsynclog.rs 80:Debug>>>1,2>>>[1, 2, 3]
[INFO] 2024-06-06 15:54:07 testsynclog.rs 83:Info>>>1,2>>['a', 'b']
[WARN] 2024-06-06 15:54:07 testsynclog.rs 84:Warn>>>1,2
[ERROR] 2024-06-06 15:54:07 testsynclog.rs 85:Error>>>1,2
[FATAL] 2024-06-06 15:54:07 testsynclog.rs 86:Fatal>>>1,2
异步示例
#[tokio::test]
async fn testformats() {
    let mut log = tklog::Async::Logger::new();
    log.set_console(true)
        .set_level(LEVEL::Debug)
        .set_cutmode_by_time("tklogasyncs.log", MODE::DAY, 10, true)
        .await;
    let mut logger = Arc::clone(&Arc::new(Mutex::new(log)));
    let log = logger.borrow_mut();

    let v = vec![1, 2, 3];
    tklog::async_formats!(log, LEVEL::Debug, "Debug>>>{},{}>>>{:?}", 1, 2, v);

    let v2 = vec!['a', 'b'];
    tklog::async_formats!(log, LEVEL::Info, "Info>>>{},{}>>{:?}", 1, 2, v2);
    tklog::async_formats!(log, LEVEL::Warn, "Warn>>>{},{}", 1, 2);
    tklog::async_formats!(log, LEVEL::Error, "Error>>>{},{}", 1, 2);
    tklog::async_formats!(log, LEVEL::Fatal, "Fatal>>>{},{}", 1, 2);

    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}
执行结果
[DEBUG] 2024-06-06 16:09:26 testasynclog.rs 61:Debug>>>1,2>>>[1, 2, 3]
[INFO] 2024-06-06 16:09:26 testasynclog.rs 64:Info>>>1,2>>['a', 'b']
[WARN] 2024-06-06 16:09:26 testasynclog.rs 65:Warn>>>1,2
[ERROR] 2024-06-06 16:09:26 testasynclog.rs 66:Error>>>1,2
[FATAL] 2024-06-06 16:09:26 testasynclog.rs 67:Fatal>>>1,2

tklog 支持自定义日志处理函数。

tklog 允许通过 set_custom_handler() 添加外部自定义函数,以控制日志处理流程和逻辑。
示例
#[test]
fn test_custom() {
    fn custom_handler(lc: &LogContext) -> bool {
        println!("level >>>>>>>>>>>>>>>>>{:?}", lc.level);
        println!("message >>>>>>>>>>>>>>>>>{:?}", lc.log_body);
        println!("filename >>>>>>>>>>>>>>>>>{:?}", lc.filename);
        println!("line >>>>>>>>>>>>>>>>>{:?}", lc.line);
        println!("modname >>>>>>>>>>>>>>>>>{:?}", lc.modname);
        if lc.level == LEVEL::Debug {
            println!("{}", "debug now");
            return false;
        }
        true
    }

    LOG.set_custom_handler(custom_handler);
    debug!("000000000000000000");
    info!("1111111111111111111");
    thread::sleep(Duration::from_secs(1))
}
执行结果
---- test_custom stdout ----
level >>>>>>>>>>>>>>>>>Debug
message >>>>>>>>>>>>>>>>>"000000000000000000"
filename >>>>>>>>>>>>>>>>>"tests\\testsynclog.rs"
line >>>>>>>>>>>>>>>>>143
modname >>>>>>>>>>>>>>>>>"testsynclog"
debug now
level >>>>>>>>>>>>>>>>>Info
message >>>>>>>>>>>>>>>>>"1111111111111111111"
filename >>>>>>>>>>>>>>>>>"tests\\testsynclog.rs"
line >>>>>>>>>>>>>>>>>144
modname >>>>>>>>>>>>>>>>>"testsynclog"
[INFO] 2024-08-05 15:39:07 testsynclog.rs 144:1111111111111111111
说明

当函数 fn custom_handler(lc: &LogContext) -> bool 返回 true 时,tklog 调用 custom_handler 执行自定义函数,然后继续 tklog 的日志过程。当它返回 false 时,tklog 不继续其日志过程,并直接返回。如示例所示,当日志级别为 Debug 时,它返回 false,所以 tklog 不打印 Debug 日志。

tklog 支持自定义日志多参数分隔符

tklog 允许使用 set_separator() 方法设置自定义分隔符

以下 Rust 代码演示了如何在 tklog 框架中配置和使用自定义分隔符来设置日志条目

#[test]
fn testlog() {
    log_init();
    trace!("trace>>>>", "aaaaaaaaa", 1, 2, 3, 4);
    debug!("debug>>>>", "bbbbbbbbb", 1, 2, 3, 5);
    LOG.set_separator("|");
    info!("info>>>>", "ccccccccc", 1, 2, 3, 5);
    warn!("warn>>>>", "dddddddddd", 1, 2, 3, 6);
    LOG.set_separator(",");
    error!("error>>>>", "eeeeeeee", 1, 2, 3, 7);
    fatal!("fatal>>>>", "ffffffff", 1, 2, 3, 8);
    thread::sleep(Duration::from_secs(1))
}
执行结果

测试日志函数生成的输出展示了设置不同分隔符对日志消息的影响

---- testlog stdout ----
[TRACE] 2024-08-15 14:14:19.289590 tests\testsynclog.rs 22:trace>>>>aaaaaaaaa1234
[DEBUG] 2024-08-15 14:14:19.289744 tests\testsynclog.rs 23:debug>>>>bbbbbbbbb1235
[INFO] 2024-08-15 14:14:19.289761 tests\testsynclog.rs 25:info>>>>|ccccccccc|1|2|3|5
[WARN] 2024-08-15 14:14:19.289774 tests\testsynclog.rs 26:warn>>>>|dddddddddd|1|2|3|6
[ERROR] 2024-08-15 14:14:19.289789 tests\testsynclog.rs 28:error>>>>,eeeeeeee,1,2,3,7
[FATAL] 2024-08-15 14:14:19.289802 tests\testsynclog.rs 29:fatal>>>>,ffffffff,1,2,3,8

tklog 支持为日志级别设置独立的日志格式参数

通过 set_level_option() 设置 tklog 的独立日志格式参数,以适应不同的日志级别
#[test]
fn testlog() {
    // Set the log format for Info level to include Format::LevelFlag.
    // Set the log format for Fatal level to include Format::LevelFlag and Format::Date.
    LOG.set_level_option(LEVEL::Info, LevelOption { format: Some(Format::LevelFlag), formatter: None })
    .set_level_option(LEVEL::Fatal, LevelOption { format: Some(Format::LevelFlag | Format::Date), formatter: None});

    trace!("this is trace log");
    debug!("this is debug log");
    info!("this is info log");
    warn!("this is warn log");
    error!("this is error log");
    fatal!("this is fatal log");
    thread::sleep(Duration::from_secs(1))
}

执行结果

---- testlog stdout ----
[DEBUG] 2024-08-24 15:06:02 test_0100.rs 17:this is debug log
[INFO] this is info log
[WARN] 2024-08-24 15:06:02 test_0100.rs 19:this is warn log
[ERROR] 2024-08-24 15:06:02 test_0100.rs 20:this is error log
[FATAL] 2024-08-24 this is fatal log

基准测试

log_benchmark           time:   [2.9703 µs 2.9977 µs 3.0256 µs]
                        change: [-95.539% -95.413% -95.268%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  4 (4.00%) high mild
  5 (5.00%) high severe
log_benchmark           time:   [2.9685 µs 3.0198 µs 3.0678 µs]
                        change: [-3.6839% -1.2170% +1.0120%] (p = 0.34 > 0.05)
                        No change in performance detected.
Found 7 outliers among 100 measurements (7.00%)
  7 (7.00%) high mild
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
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
说明:时间范围提供了三个数据点,分别代表最小测试执行时间(2.9055 微秒)、接近平均值的值(2.9444 微秒 - 3.8881 微秒)和最大值(3.9408 微秒)。

结论:日志打印函数性能:2 µs/op - 3.9 µs/op(微秒/操作)

依赖项

~6–13MB
~142K SLoC