tklog 是Rust语言编写的高性能结构化日志库。[English]

特点:易用高效结构化控制台日志文件日志文件切割文件压缩同步打印异步打印
功能特性
  • 功能:控制台日志、文件日志、同步打印、异步打印
  • 日志级别配置灵活:支持 tracedebuginfowarnerrorfatal 级别的日志输出
  • 格式化输出自定义:可调整日志输出格式,涵盖日志级别标签、时间格式、文件位置等元素
  • 按时间切割日志文件:支持按小时、天、月进行日志文件分割
  • 按大小切割日志文件:根据文件大小自动分割
  • 按时间与文件大小混合模式切割日志文件
  • 文件数管理:可设定最大备份文件数,自动删除旧日志,避免过多日志文件累积
  • 文件压缩功能:支持对归档日志文件进行压缩
  • 支持官方日志库标准API
  • 支持按模块设置独立日志参数
  • 支持按日志级别设置独立日志参数
  • 支持使用环境变量RUST_LOG 设置日志级别

官网

Github

仓库

使用方法简述

Use tklog
[dependencies]
tklog = "0.2.9"   #   "0.x.x" current version

最简单常用的方式:直接调用

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)  
       .set_format(Format::LevelFlag | Format::Time | Format::ShortFileName)  
       .set_cutmode_by_size("tklogsize.txt", 1<<20, 10, true)   
       .set_formatter("{level}{time} {file}:{message}\n");
}

以上是全局单实例打印的示例。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表示不压缩备份的日志文件

备份的文件格式:
  • 按天备份日期文件,如:
  • 按小时备份日志文件,如:
  • 按月份备份日志文件,如:

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

7.按时间大小混合模式分割日志文件

调用 .set_cutmode_by_mixed() 函数,参数:

  • 文件路径
  • 指定文件滚动大小
  • 时间模式
  • 最大备份日志文件数
  • 是否压缩备份的日志文件

示例

let mut log = Logger::new();
log.set_cutmode_by_mixed("/usr/local/tklogs.log",1<<30, MODE::DAY, 10, true)

说明:备份文件路径为: /usr/local/tklogs.log ,1G(1<<30)大小时滚动备份文件, 滚动时间模式为:按天备份,参数10表示最多保留10个最近备份文件,true表示压缩备份日志文件

备份的文件格式:
  • 按天与大小混合备份日期文件,如:
  • 按小时与大小混合备份日志文件,如:
  • 按月份与大小混合备份日志文件,如:

tklog提供常规日志打印 方法为:

  • 全局单例打印
  • 多实例打印

异步日志

  • 全局异步单例打印
  • 多实例异步打印
示例

全局单例异步

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]

支持官方日志库标准API

  1. tklog实现了官方Log接口,支持官方标准化日志API的调用
  2. 实现了官方log库API的异步场景调用。
启用官方log库API的方法:

tklog通过调用 uselog()  函数 来启用官方log的API支持

使用示例

use std::{thread, time::Duration};
use tklog::{Format, LEVEL, LOG};
fn test_synclog() {
    //初始化
    LOG.set_console(true)
        .set_level(LEVEL::Debug)
        .set_cutmode_by_size("logsize.log", 10000, 10, true)
        .uselog();  //启用官方log库
	
	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))
}

异步场景中启用 log库API

use std::{thread, time::Duration};
use tklog::{Format, LEVEL, ASYNC_LOG};
async fn test_synclog() {
    //初始化
    ASYNC_LOG.set_console(false)
        .set_cutmode_by_size("asynclogsize.log", 10000, 10, true).await
        .uselog(); //启用官方log库
	
    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;
}

支持 LogOption 参数集中设置tklog的日志参数

通过设置LogOption,可以达到与调用以下函数相同效果
  • set_console
  • set_level
  • set_format
  • set_formatter
  • set_cutmode_by_size
  • set_cutmode_by_time
  • set_cutmode_by_mixed
LogOption对象属性说明
  • level 日志级别
  • format 日志格式
  • formatter 日志输出自定义格式
  • console 控制台日志设置
  • fileoption 文件日志设置

通过set_option设置LogOption对象, 示例:

以下是配置日志记录器使用不同文件滚动模式和备份策略的示例。每个示例都设置了特定的日志选项,包括日志级别、控制台输出设置和文件滚动行为。

1. 按时间滚动备份文件 (FileTimeMode)

此配置根据指定的时间模式(例如,按天)来滚动日志文件。

tklog::LOG.set_option(LogOption {
    level: Some(LEVEL::Debug), // 设置日志级别为 Debug
    console: Some(false),     // 禁用控制台输出
    format: None,             // 使用默认日志格式
    formatter: None,          // 使用默认日志格式化器
    fileoption: Some(Box::new(FileTimeMode::new(
        "day.log",            // 日志文件名
        tklog::MODE::DAY,     // 每天滚动一次
        10,                   // 最多保留10个备份文件
        true                  // 压缩备份文件
    ))),
});

2. 按大小滚动备份文件 (FileSizeMode)

此配置在日志文件达到指定大小限制时进行滚动。

tklog::LOG.set_option(LogOption {
    level: Some(LEVEL::Debug), // 设置日志级别为 Debug
    console: Some(false),     // 禁用控制台输出
    format: None,             // 使用默认日志格式
    formatter: None,          // 使用默认日志格式化器
    fileoption: Some(Box::new(FileSizeMode::new(
        "day.log",            // 日志文件名
        1 << 30,              // 文件大小达到1GB (1<<30字节)时滚动
        10,                   // 最多保留10个备份文件
        true                  // 压缩备份文件
    ))),
});

3. 按大小与时间混合滚动备份文件 (FileMixedMode)

此配置结合了大小和时间两个标准来进行日志文件的滚动。

tklog::LOG.set_option(LogOption {
    level: Some(LEVEL::Debug), // 设置日志级别为 Debug
    console: Some(false),     // 禁用控制台输出
    format: None,             // 使用默认日志格式
    formatter: None,          // 使用默认日志格式化器
    fileoption: Some(Box::new(FileMixedMode::new(
        "day.log",            // 日志文件名
        1 << 30,              // 文件大小达到1GB (1<<30字节)时滚动
        tklog::MODE::DAY,     // 同时每天滚动一次
        10,                   // 最多保留10个备份文件
        true                  // 压缩备份文件
    ))),
});

说明

  • 日志级别 (level):指定了最低的日志严重性级别,只有不低于该级别的消息才会被记录。这里设置为 Debug,意味着所有调试级别及更高级别的消息都会被记录。
  • 控制台输出 (console):决定了日志是否也打印到控制台。在此处设置为禁用 (false)。
  • 格式和格式化器 (format, formatter):这些字段设置为 None,表示将使用默认的日志格式和格式化器。
  • 文件选项 (fileoption):这个字段指定了处理日志文件的策略,包括:FileTimeMode:基于时间表(如每日)滚动日志文件。FileSizeMode:当文件达到一定大小(如1GB)时滚动日志文件。FileMixedMode:结合大小和时间两个条件滚动日志文件。

每个 fileoption 接受定义日志文件名、滚动条件(大小或时间)、最多保留的备份文件数量以及是否压缩备份文件的参数。对于 FileMixedMode,还需要一个时间模式参数来指定时间滚动模式。

通过这些配置,可以灵活地管理和优化日志文件的生成和存储方式,以满足不同的应用场景需求。


模块设置独立日志参数 set_mod_option

  1. tklog支持通过set_mod_option 设置指定mod的日志参数
  2. set_mod_option可以指定具体模块名并设置该模块特定的日志参数,只作用与该模块
  3. set_mod_option支持前缀匹配的设置模式,如 "testlog::*",指作用与模块testlog下的所有子模块
  4. 在项目中,可以使用全局LOG对象,同时对多个mod设置独立的日志参数
  5. 异步全局对象ASYNC_LOG的mod日志参数设置与同步LOG相同
set_mod_option 示例1:
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 为设置的模块名,可以通过rust内置宏 module_path!() 打印出当前模块名
  • 当tklog在模块 testlog::module1 中使用时,将tklog将使用该LogOption对象
set_mod_option 示例2:
tklog::LOG.set_mod_option("testlog::*",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::* tklog支持用*匹配所有子模块,testlog::*表示testlog的所有子模块
  • testlog::module1::* 表示testlog::module1的所有子模块

完整的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))) });
        tklog::debug!("module1,tklog api,LOG debug log>>", 123);
        tklog::info!("module1,tklog api,LOG info log>>", 456);
        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))) });
    }
    mod m2 {
        pub fn testmod() {
            tklog::debug!("module2,tklog api,LOG debug log>>", 123);
            tklog::info!("module2,tklog api,LOG info log>>", 456);
            thread::sleep(Duration::from_secs(1))
        }
    }
}

#[test]
fn testmod2() {
    module1::testmod();
    module2::m2::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 支持自定义多实例格式化 format!与 异步format!

示例:
#[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
异步 formats示例
#[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 支持自定义日志处理函数 set_custom_handler

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不再执行tklog的打印程序。直接返回。如示例中所示,当年日志级别为Debug时,返回false,所以,tklog的Debug日志,不再打印出来。

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

tklog 通过 set_separator() 设置分隔符

#[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 通过 set_level_option() 设置日志级别的独立日志参数

set_level_option() 接收 任意实现 OptionTrait特征的对象

示例1 :参数 LevelOption 对象,可以设置日志格式化输出
#[test]
fn testlog() {
    //将Info级别的日志格式设置为 Format::LevelFlag
    //将Fatal级别的日志格式设置为 Format::LevelFlag | 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
示例2 参数 LogOption 对象,可以设置更多参数,包括设置日志文件
#[test]
fn testlog() {
    LOG.set_level_option(LEVEL::Info, LogOption { format: Some(Format::LevelFlag), formatter: None, level:None, console: None, fileoption: Some(Box::new(FileTimeMode::new("0200time.log", tklog::MODE::DAY, 0, false))) })
    .set_level_option(LEVEL::Fatal, LogOption { format: Some(Format::LevelFlag | Format::Date), formatter: None, level: None, console: None, fileoption: Some(Box::new(FileSizeMode::new("0200size.log", 1<<10, 0, false)))});

    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))
}

示例说明:

  1. Info级别的文件日志设置为按天分割,文件名 0200time.log
  2. Fatal级别的文件日志设置为按大小分割,文件名 0200size.log


tklog 支持对日志属性标识进行格式化设置 set_attr_format

通过 set_attr_format 函数设置日志标识与时间格式
示例:
fn testlog() {
    tklog::LOG.set_attr_format(|fmt| {
        fmt.set_level_fmt(|level| {
            match level {
                LEVEL::Trace => "[T]",
                LEVEL::Debug => "[D]",
                LEVEL::Info => "[I]",
                LEVEL::Warn => "[W]",
                LEVEL::Error => "[E]",
                LEVEL::Fatal => "[F]",
                LEVEL::Off => "",
            }.to_string()
        });

        fmt.set_time_fmt(|| {
            let now: DateTime<Local> = Local::now();
            (now.format("%Y/%m/%d").to_string(), now.format("%H:%M:%S").to_string(), "".to_string())
        });

        fmt.set_console_body_fmt(|level, body| {
            //处理body的末尾换行符
            let trimmed_body = if body.ends_with('\n') { format!("{}{}", body.as_str()[..body.len() - 1].to_string(), "\x1b[0m\n") } else { format!("{}{}", body, "\x1b[0m\n") };

            match level {
                LEVEL::Trace => format!("{}{}", "\x1b[34m", trimmed_body), //蓝色
                LEVEL::Debug => format!("{}{}", "\x1b[36m", trimmed_body), //青色
                LEVEL::Info => format!("{}{}", "\x1b[32m", trimmed_body),  //绿色
                LEVEL::Warn => format!("{}{}", "\x1b[33m", trimmed_body),  //黄色
                LEVEL::Error => format!("{}{}", "\x1b[31m", trimmed_body), //红色
                LEVEL::Fatal => format!("{}{}", "\x1b[41m", trimmed_body), //背景红
                LEVEL::Off => "".to_string(),
            }
        });

        fmt.set_body_fmt(|level, body| {
            //处理body的末尾换行符
            let trimmed_body = if body.ends_with('\n') { format!("{}{}", body.as_str()[..body.len() - 1].to_string(), "\x1b[0m\n") } else { format!("{}{}", body, "\x1b[0m\n") };
            match level {
                LEVEL::Trace => format!("{}{}", "\x1b[44m", trimmed_body), //背景蓝色
                LEVEL::Debug => format!("{}{}", "\x1b[46m", trimmed_body), //背景青色
                LEVEL::Info => format!("{}{}", "\x1b[42m", trimmed_body),  //背景绿色
                LEVEL::Warn => format!("{}{}", "\x1b[43m", trimmed_body),  //背景黄色
                LEVEL::Error => format!("{}{}", "\x1b[41m", trimmed_body), //背景红色
                LEVEL::Fatal => format!("{}{}", "\x1b[45m", trimmed_body), //背景紫色
                LEVEL::Off => "".to_string(),
            }
        });

    });

    trace!("trace!", "this is sync log");
    debug!("debug!","this is sync log");
    info!("info!","this is sync log");
    warn!("warn!","this is sync log");
    error!("error!","this is sync log");
    fatal!("fata!","this is sync log");
    thread::sleep(Duration::from_secs(1))
}
执行结果:
[D] 2024/10/17 19:41:20 test_0230.rs 32:debug!this is sync log
[I] 2024/10/17 19:41:20 test_0230.rs 33:info!this is sync log
[W] 2024/10/17 19:41:20 test_0230.rs 34:warn!this is sync log
[E] 2024/10/17 19:41:20 test_0230.rs 35:error!this is sync log
[F] 2024/10/17 19:41:20 test_0230.rs 36:fata!this is sync log


tklog 基准压力测试

log_benchmark           time:   [2.3949 µs 2.4428 µs 2.4941 µs]
                        change: [-0.5586% +1.9685% +4.4040%] (p = 0.14 > 0.05)
                        No change in performance detected.
Found 3 outliers among 100 measurements (3.00%)
  1 (1.00%) high mild
  2 (2.00%) high severe

mod_benchmark           time:   [2.1946 µs 2.2325 µs 2.2718 µs]
                        change: [-2.5723% +0.0728% +2.8784%] (p = 0.96 > 0.05)
                        No change in performance detected.
Found 7 outliers among 100 measurements (7.00%)
  3 (3.00%) high mild
  4 (4.00%) high severe
log_benchmark           time:   [2.3992 µs 2.4307 µs 2.4632 µs]
                        change: [-12.388% -9.7287% -6.8751%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  1 (1.00%) low mild
  5 (5.00%) high mild
  1 (1.00%) high severe

mod_benchmark           time:   [2.2126 µs 2.2508 µs 2.2920 µs]
                        change: [-11.895% -9.0113% -6.2389%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) high mild
  2 (2.00%) high severe
log_benchmark           time:   [2.4525 µs 2.5059 µs 2.5632 µs]
                        change: [-10.548% -7.0786% -3.6963%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  3 (3.00%) high mild

mod_benchmark           time:   [2.2603 µs 2.3113 µs 2.3693 µs]
                        change: [-12.539% -9.5519% -6.4982%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  4 (4.00%) high mild
  1 (1.00%) high severe
log_benchmark           time:   [2.5650 µs 2.6194 µs 2.6775 µs]
                        change: [-3.5311% -0.4742% +3.3119%] (p = 0.79 > 0.05)
                        No change in performance detected.
Found 6 outliers among 100 measurements (6.00%)
  5 (5.00%) high mild
  1 (1.00%) high severe

mod_benchmark           time:   [2.4908 µs 2.5655 µs 2.6440 µs]
                        change: [-1.3617% +1.9010% +5.2711%] (p = 0.29 > 0.05)
                        No change in performance detected.
Found 4 outliers among 100 measurements (4.00%)
  4 (4.00%) high mild
log_benchmark
测试编号最小时间 (µs)最大时间 (µs)平均时间 (µs)变化百分比 (%)p 值
12.39492.49412.4428-0.5586%0.14
22.39922.46322.4307-12.388%0.00
32.45252.56322.5059-10.548%0.00
42.56502.67752.6194-3.5311%0.79
mod_benchmark
测试编号最小时间 (µs)最大时间 (µs)平均时间 (µs)变化百分比 (%)p 值
12.19462.27182.2325-2.5723%0.96
22.21262.29202.2508-11.895%0.00
32.26032.36932.3113-12.539%0.00
42.49082.64402.5655-1.3617%0.29

2. 总结统计

  • log_benchmark最小时间: 2.3949 µs最大时间: 2.6775 µs平均时间: 2.5160 µs变化幅度: 从 -0.5586% 到 -12.388%p 值: 大部分测试显著性强(p < 0.05)。
  • mod_benchmark最小时间: 2.1946 µs最大时间: 2.6440 µs平均时间: 2.3430 µs变化幅度: 从 -2.5723% 到 -12.539%p 值: 大部分测试显著性强(p < 0.05)。

性能统计数据(每次响应时间)

  1. 最小时间: 2.1946 µs
  2. 最大时间: 2.6775 µs
  3. 平均时间: 2.3946 µs