spring boot迁移计划 第Ⅰ章 --chapter 1. rust hyper 结合rust nacos-client开发nacos网关 part ① tracing 日志

2025-06-13更新,找到一个crate,logroller,可以自定义时区,可以压缩日志,配合tracing很好用(有几个其他的也试过,不是文件名改的奇奇怪怪就是这样那样的问题,这个是最好用的)。按时区滚动分割日志这个需求有人提出几年了,作者说不想引入time或者chrono这些库,因为他们会更新,那加一个i64的秒偏移量选项是有那么难吗?我不能李姐;

2025-06-12 更新,由于tracing用了重写的包导致清理过期日志有问题(测试在windows下似乎没问题),而且不能压缩备份,尝试更换为fastlog,试了下严重影响性能(接口返回时间增长了5倍左右)换回了tracing,还试了下tklog,还是老样子,无法输出包路径,只能输出文件路径,看起来很奇怪;

1. 引子

最近想要迁移一部分java应用至rust,在实际体验了tklog,log4rs,和tracing三款日志框架后,最后选用了tracing,log4rs的文件备份文件名没有时间,不便于管理,tklog的功能稍显简陋,在使用uselog()后会将某些底层包日志输出至终端,即使过滤掉某第三方个包(假设叫A)之后,这个包依赖的第三方包(A依赖的第三方包B)的日志依旧会被显示,但是tklog本身又无法显示包名,只能显示文件名,根本不知道这个日志是从哪个包漏出来的XD,最后在经历多次尝试后最终选定了使用最广泛的tracing!

2. 加入tracing包

#使用log门面
log = "0.4"
#本体
tracing = "0.1"
#滚动日志,package里的是文件滚动的增强,原版的只使用utc+0配置,非utc+0时区的日志时间文件名不正确。说一个好好笑的事情,这个问题存在3年了,有人提了issue给维护者了,维护者考虑再三说想用chrono的时间替代原来的,但是因为chrono好久没更新了,有个cve漏洞没修,所以就一直放着,一直不改,怎么说呢,没勺子不能用筷子吃饭吗?加一个手动设置时间偏移量的函数不行吗?ememem...
tracing-appender = { package = "tracing-appender-plus", version = "0.2", features = ["local-time",] }
#日志订阅,tracing默认不打印日志,需要订阅才会打印
tracing-subscriber = { version = "0.3", features = ["time", "env-filter"] }
#时间包,用来格式化日志和终端的时间显示
time = { version = "0.3", features = ["macros"] }

-----------------分割线------------------
#引入fastlog包
fast_log = {version = "1.7", features = ["zip"]}
fastdate = "0"

-----------------分割线------------------
logroller ={version = "0.1", features = ["tracing"]}
chrono ="0.4" #设置时区用了chrono库,需要引入

3. 上代码

use chrono::FixedOffset;
use logroller::{Compression, LogRollerBuilder, Rotation, RotationAge, TimeZone};
use time::macros::{format_description, offset};
use tracing_appender::
    non_blocking::WorkerGuard
;
use tracing_subscriber::{
    EnvFilter,
    fmt::{time::OffsetTime, writer::MakeWriterExt},
};
pub fn tracing_init() -> (WorkerGuard, WorkerGuard) {
    //格式化时间
    let time_fmt =
        format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond digits:3]");//精确到毫秒
    let timer = OffsetTime::new(offset!(+8), time_fmt);
    //创建滚动日志
    let file_appender = LogRollerBuilder::new("./logs", "service.log")
        .rotation(Rotation::AgeBased(RotationAge::Daily))  // Rotate daily
        .max_keep_files(2)  // Keep a week's worth of logs
        .time_zone(TimeZone::Fix(FixedOffset::east_opt(8 * 3600).unwrap()))  // Use local timezone
        .compression(Compression::Gzip)  // Compress old logs
        .build()
        .expect("failed to initialize rolling file appender");
    //使用非阻塞输出
    let (stdout, guard1) = tracing_appender::non_blocking(std::io::stdout());//异步输出到stdout
    let (file, guard2) = tracing_appender::non_blocking(file_appender);//异步输出到文件

    tracing_subscriber::fmt()
        .with_env_filter(EnvFilter::from(
            "warn,actix_web1=debug,nacos_rust_client=info",
        ))//这里可以自定义某些第三方库的日志是否打印,第一个是全局日志等级,后面的是自定义包
        .with_line_number(true)//显示行数
        .with_thread_ids(true)//显示线程id
        .with_ansi(false)//是否添加颜色信息,对于不支持颜色文本查看器日志文件会有乱码
        .with_timer(timer)//设置时间格式化样式
        .with_writer(file.and(stdout))//设置输出
        .init();//初始化
    (guard1, guard2)//一定要在主函数持有这两个异步缓冲区,否则无法输出
    //2024-12-24 更新,主函数接收时不要使用"_",会被丢弃导致无法输出,使用"_a" 这样带有名字的接收才可以!!!
}
-----------------分割线------------------

// use fast_log::{
//     Config,
//     appender::{Command, FastLogRecord, RecordFormat},
//     plugin::{
//         file_split::{DateType, KeepType, Rolling, RollingType},
//         packer::ZipPacker,
//     },
// };
// use fastdate::DateTime;
// use log::LevelFilter;

// pub fn init_fast_log() {
//     fast_log::init(
//         Config::new()
//             .chan_len(Some(100000))
//             .console()
//             .level(LevelFilter::Info)
//             .file_split(
//                 "./logs/sevice.log",
//                 Rolling::new(RollingType::ByDate(DateType::Day)),
//                 KeepType::KeepNum(30),
//                 ZipPacker {},
//             )
//             .format(CustomFormate {}),
//     )
//     .unwrap();
// }
// struct CustomFormate {}
// impl RecordFormat for CustomFormate {
//     fn do_format(&self, arg: &mut FastLogRecord) {
//         match &arg.command {
//             Command::CommandRecord => {
//                 let now = DateTime::from_system_time(arg.now, DateTime::now().offset()).set_offset(8 * 60 * 60)
//                     .format("YYYY-MM-DD hh:mm:ss.000000");
//                 arg.formated = format!(
//                     "{} [{:>5}] {}[{}]:{} {}\n",
//                     now,
//                     arg.level,
//                     arg.module_path,
//                     arg.line.unwrap_or_default(),
//                     arg.target,
//                     arg.args,
//                 );
//             }
//             Command::CommandExit => {}
//             Command::CommandFlush(_) => {}
//         }
//     }
// }
//同时也试了下面官方文档的方法,会输出双份的日志,一份默认的,一份自定义的,不知道哪里不对
// struct CustomLog {}
// impl LogAppender for CustomLog {
//     fn do_logs(&mut self, records: &[FastLogRecord]) {
//         for record in records {
//             let now = DateTime::from_system_time(record.now, DateTime::now().offset())
//                 .format("YYYY-MM-DD hh:mm:ss.000000+08:00");
//             let data = format!(
//                 "{} [{:>5}]  {}:{}  {}\n",
//                 now,
//                 record.level,
//                 record.module_path,
//                 record.line.unwrap_or_default(),
//                 record.args,
//             );
//             print!("{}", data);
//         }
//     }
// }

4. 参考文献

  1. https://probiecoder.cn/rust/tracing.html
  2. https://blog.csdn.net/qq_54714089/article/details/136717431
posted @ 2024-12-22 01:00  JiajieZeee  阅读(107)  评论(0)    收藏  举报