Rust中记录日志:fast_log
在Rust程序中记录日志,可以使用fast_log
。
根据fast_log 的介绍,这是一个性能非常高的日志实现,还支持文件追加模式、压缩、切分与回滚等操作。
而且,这个库记录日志是异步的,即不会因为日志而影响程序的运行。只有当必要的时候,才需要应用层手动调用log::logger().flush()
刷到文件。
引入
使用cargo管理的项目,只要通过cargo的add命令即可引入fast_log
,当然还需要log
。
cargo add fast_log
cargo add log
初始化
使用的方法也非常简单,只要通过它的init()
函数进行初始化,之后就可以使用日志记录相关的宏了。
init()
的参数为一个fast_log::config::Config
结构。
这个结构使用了Builder模式,它的new()
函数只是调用了它的default()
函数,生成了一个默认的结构,之后就可以调用Build的函数进行自定义。
如以下代码,构造了一个输出到终端的Config。
use fast_log::{self, config::Config};fn main() {let config = Config::new().console();fast_log::init(config).expect("init log error");info!("test log info !!!");
}
Config支持各种日志输出。
如:
- console() 输出到终端
- file() 输出到文件
- file_loop() 输出到循环的文件
- file_split() 输出到回滚文件
- custom() 自定义输出
输出到回滚文件
输出到回滚文件的时候,file_split()
的原型如下:
pub fn file_split< R: CanRollingPack + 'static, K: Keep + 'static, P: Packer + Sync + 'static,
>( self, file_path: &str, rolling: R, keeper: K, packer: P,
) -> Self
其中,file_path
是文件路径,CanRolling
、Keep
与Packer
分别是三个特性。一般地,我们可以使用fast_log
中预定义的结构就好。
如以下代码,定义了一个按照文件大小回滚的输出,每个文件200M,保存5个:
file_split("target/logs/",Rolling::new(RollingType::BySize(LogSize::MB(200))),KeepType::KeepNum(5),LogPacker {},))
以下代码,定义了一个按照日期回滚的输出,保存30天:
file_split("target/logs/",Rolling::new(RollingType::ByDate(DateType::Day)),KeepType::KeepNum(30),LogPacker {},))
自定义输出
自定义输出的时候,使用custom()
方法,注册一个实现了LogAppender
特性的结构。
LogAppender
特定的定义如下:
pub trait LogAppender:Send { /// Batch write log, or do nothing fn do_logs(&mut self, records: &[FastLogRecord]);
}
可以看到,就是实现do_logs
方法。其中,records
是一个FastLogRecord
的数组。
FastLogRecord
结构的定义如下:
#[derive(Clone, Debug)]
pub struct FastLogRecord { pub command: Command, pub level: log::Level, pub target: String, pub args: String, pub module_path: String, pub file: String, pub line: Option<u32>, pub now: SystemTime, pub formated: String,
}
其中,level是日志的等级,file和line分别是相应的源代码文件与行数,now是日志时间,formated是日志信息。
以下的自定义输出,按照不同的等级,打印了不同格式的信息到标准输出:
struct CustomLog {}impl LogAppender for CustomLog {fn do_logs(&mut self, records: &[FastLogRecord]) {for record in records {let now = DateTime::from(record.now);let data;match record.level {Level::Warn | Level::Error => {data = format!("{} {} {} - {} {}\n",now, record.level, record.module_path, record.args, record.formated);}_ => {data = format!("{} {} {} - {}\n",&now, record.level, record.module_path, record.args);}}print!("{}", data);}}
}
日志等级
fast_log::config::Config
结构的构造方法里有一个level()
,可以设置日志等级,参数类型是LevelFilter。
LevelFilter是一个enum。
#[repr(usize)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum LevelFilter {Error = 1,Warn,Info,Debug,Trace,
}
以下代码设置了日志等级为Info:
let config = Config::new().console().level(LogLevel::Info);
记录日志的宏log!
,第一个参数就是日志等级。当等级高于设置的级别时,不会被记录。
以上代码设置了Info级,则只有Error、Warn、Info会被记录,Debug和Trace等级的日志都被抛弃了。
相对应的,有几个宏可以替代log!
宏,分别是:error!
、warn!
、info!
、debug!
、trace!
。
如果使用log!
宏,就需要在第一个参数中指定日志级别,其它几个宏是log!的简化版。
名字空间
需要注意的是,fast_log
的名字空间有点儿复杂 。
比如,file_split
一个函数,就需要use几行东西。
其中,Rolling相关的、日期类型(DateType)、保存类型(KeepType)在fast_log::plugin::file_split
里,LogSize在fast_log::consts
里,而LogPacker又在fast_log::plugin::packer
里。
use fast_log::plugin::file_split::{Rolling, RollingType, DateType, KeepType};
use fast_log::plugin::packer::LogPacker;
use fast_log::consts::LogSize;
而记录日志的过滤等级,又直接使用的log模块里的定义,配置Config的时候,需要:
use fast_log::config::Config;
use log::LevelFilter;let config = Config::new().level(LevelFilter::Info);