这个log库给出了日志库的一般抽象,后面具体的日志库需要基于这个抽象实现具体的实例。
系统自带了log宏: error!
, warn!
, info!
, debug!
,trace!
。
//levels of the logging
pub enum LogLevel {
Error, //error是日志分级的最高等级
Warn,
Info,
Debug,
Trace, //trace是最低等级
}
下面的示例展示类log最基本的用法:
[dependencies]
log = "0.4"
use log::{info, trace, warn};
pub fn shave_the_yak(yak: &mut Yak) {
trace!("Commencing yak shaving");
loop {
match find_a_razor() {
Ok(razor) => {
info!("Razor located: {}", razor);
yak.shave(razor);
break;
}
Err(err) => {
warn!("Unable to locate a razor: {}, retrying", err);
}
}
}
}
#[macro_use]
extern crate log;
use log::LogLevel;//日志等级
fn main() {
log_lever_fn();
}
fn log_lever_fn(){
let data=(42,"Forty-two");
let private_data="private";
log!(LogLevel::Error,"Received errors:{},{}",data.0,data.1);
log!(target:"app_events",LogLevel::Warn,"App warning:{},{},{}",data.0,data.1,private_data);
let (err_info,port)=("No connection",22);
error!("Error:{} on port {}",err_info,port);
}
logger 概述
仅仅用log库很多情况下是不能满足功能需求的,为此有不同的logger实现,
为了产生日志输出,可执行文件必须使用与Facade兼容的记录器实现。有许多可用的实现可供选择,以下是一些最受欢迎的实现(常用的logger):[来自log自述文件]
env_logger
通过环境变量进行日志配置simple_logger
常用的loggersimplelog
常用的loggerpretty_env_logger
stderrlog
flexi_logger
可执行文件应选择一个记录器实现,并在程序运行时提早对其进行初始化。记录器的实现通常会包含一个执行此操作的功能。记录器初始化之前生成的任何日志消息都将被忽略。
下面以env_logger为例:
#[macro_use]
extern crate log;
extern crate env_logger;
fn main() {
env_logger_fn();
}
fn env_logger_fn(){
//Initializes the global logger with an env logger.
env_logger::init().unwrap();
info!("starting up");
error!("error:{}",404);
}
//Cargo.toml
[dependencies]
log = "0.3"
env_logger = "0.4.3"
1234
上面提到了env_logger,并且给了一个示例,这里给出env_logger的用法及源代码。
env_logger—日志配置是通过环境变量实现的,通过配置文件的方式去进行日志配置,这也是我们最常用的情况。
日志输出定义:
/// Log target, either stdout or stderr.
#[derive(Debug)]
pub enum LogTarget {
Stdout,
Stderr,
}
123456
Logger定义:
/// The logger.
pub struct Logger {
directives: Vec<LogDirective>,
filter: Option<filter::Filter>,
format: Box<Fn(&LogRecord) -> String + Sync + Send>,
target: LogTarget,
}
impl Logger {
pub fn new() -> Logger {
let mut builder = LogBuilder::new();
if let Ok(s) = env::var("RUST_LOG") {
builder.parse(&s);
}
builder.build()
}
//实现Log特性trait
impl Log for Logger {
fn enabled(&self, metadata: &LogMetadata) -> bool {
self.enabled(metadata.level(), metadata.target())
}
fn log(&self, record: &LogRecord) {
if !Log::enabled(self, record.metadata()) {
return;
}
if let Some(filter) = self.filter.as_ref() {
if !filter.is_match(&*record.args().to_string()) {
return;
}
}
match self.target {
LogTarget::Stdout => println!("{}", (self.format)(record)),
LogTarget::Stderr => {
let _ = writeln!(&mut io::stderr(), "{}", (self.format)(record));
},
};
}
}
log::Log特性trait(A trait encapsulating the operations required of a logger),每个logger都必须实现Log特性:
pub trait Log: Sync + Send {
fn enabled(&self, metadata: &LogMetadata) -> bool;//Determines if a log message with the specified metadata would be logged.
fn log(&self, record: &LogRecord);//Logs the LogRecord.
}
1234
LogBuilder定义(非常重要,可以配置日志输出格式等):
/// LogBuilder acts as builder for initializing the Logger.
/// It can be used to customize the log format , change the enviromental variable used
/// to provide the logging directives and also set the default log level filter.
pub struct LogBuilder {
directives: Vec<LogDirective>,
filter: Option<filter::Filter>,
format: Box<Fn(&LogRecord) -> String + Sync + Send>,
target: LogTarget,
}
impl LogBuilder {
/// Initializes the log builder with defaults
pub fn new() -> LogBuilder {
LogBuilder {
directives: Vec::new(),
filter: None,
format: Box::new(|record: &LogRecord| {
format!("{}:{}: {}", record.level(),
record.location().module_path(), record.args())
}),
target: LogTarget::Stderr,
}
}
......
}
如何配置日志输出格式等,见下例:
#[macro_use]
extern crate log;
extern crate env_logger;
use std::env;
use log::{LogRecord, LogLevelFilter};
use env_logger::LogBuilder;
fn main() {
env_log_builder();
}
#[warn(dead_code)]
fn env_log_builder(){
let format=|record:&LogRecord|{
format!("自定义格式:{}-{}",record.level(),record.args())
};//配置日志输出格式
let mut builder=LogBuilder::new();
builder.format(format).filter(None,log::LogLevelFilter::Info);//设置默认日志level,可以改log::LogLevelFilter::Info为log::LogLevelFilter::Warn,重新编译运行,则INFO级信息就过滤掉了。后面可以通过环境变量修改日志level。
if env::var("RUST_LOG").is_ok(){
builder.parse(&env::var("RUST_LOG").unwrap());
}
builder.init().unwrap();
error!("error message");
info!("info message");
}
编译、运行结果如下:
https://github.com/borntyping/rust-simple_logger
基本是最简单的日志库了。下面是simple_logger的简单示例:
示例1
#[macro_use]
extern crate log;
extern crate simple_logger;
fn main() {
simple_logger_fn();
}
#[warn(dead_code)]
fn simple_logger_fn(){
simple_logger::init().unwrap();
warn!("This is an example message.");
}
12345678910111213
//Cargo.toml
[dependencies]
log = "0.4"
simple_logger = "0.5"
示例2—初始化时改变默认日志level等级
#[macro_use]
extern crate log;
extern crate simple_logger;
fn main() {
simple_logger_level();
}
#[warn(dead_code)]
fn simple_logger_level(){
simple_logger::init_with_level(log::LogLevel::Warn).unwrap();
warn!("This will be logged.");
info!("This will NOT be logged.");//过滤掉了
}
https://github.com/drakulix/simplelog.rs
simplelog的目标旨在提供简单易用的适合中小规模工程的日志方案。
simplelog提供了一些logging facilities如下所示(也是simplelog中最重要的概念):
对应的,simplelog中4个重要的structs:
分析SimpleLogger源代码如下:
//! Module providing the SimpleLogger Implementation
use std::io::{stderr, stdout};
use log::{LogLevel, LogLevelFilter, LogMetadata, LogRecord, SetLoggerError, set_logger, Log};
use ::{Config, SharedLogger};
use super::logging::try_log;
/// The SimpleLogger struct. Provides a very basic Logger implementation
pub struct SimpleLogger {
level: LogLevelFilter,
config: Config,
}
impl SimpleLogger {
/// init function. Globally initializes the SimpleLogger as the one and only used log facility.
///
/// Takes the desired `LogLevel` and `Config` as arguments. They cannot be changed later on.
/// Fails if another Logger was already initialized.
pub fn init(log_level: LogLevelFilter, config: Config) -> Result<(), SetLoggerError> {
set_logger(|max_log_level| {
max_log_level.set(log_level.clone());
SimpleLogger::new(log_level, config)
})
}
/// allows to create a new logger, that can be independently used, no matter what is globally set.
///
/// no macros are provided for this case and you probably
/// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
///
/// Takes the desired `LogLevel` and `Config` as arguments. They cannot be changed later on.
pub fn new(log_level: LogLevelFilter, config: Config) -> Box<SimpleLogger> {
Box::new(SimpleLogger { level: log_level, config: config })
}
}
//实现Log Trait
impl Log for SimpleLogger {
fn enabled(&self, metadata: &LogMetadata) -> bool {
metadata.level() <= self.level
}
fn log(&self, record: &LogRecord) {
if self.enabled(record.metadata()) {
match record.level() {
LogLevel::Error => {
let stderr = stderr();
let mut stderr_lock = stderr.lock();
let _ = try_log(&self.config, record, &mut stderr_lock);
},
_ => {
let stdout = stdout();
let mut stdout_lock = stdout.lock();
let _ = try_log(&self.config, record, &mut stdout_lock);
}
}
}
}
}
//实现SharedLogger Trait
impl SharedLogger for SimpleLogger {
fn level(&self) -> LogLevelFilter {
self.level
}
fn config(&self) -> Option<&Config>
{
Some(&self.config)
}
fn as_log(self: Box<Self>) -> Box<Log> {
Box::new(*self)
}
}
SimpleLogger是代码最简单的一个,其他Structs源代码参看:https://github.com/Drakulix/simplelog.rs/tree/master/src/loggers
用法示例:
#[macro_use]
extern crate log;
extern crate simplelog;
fn main() {
simplelog_fn();
}
#[warn(dead_code)]
fn simplelog_fn(){
use std::fs::File;
use simplelog::*;
CombinedLogger::init(
vec![
TermLogger::new(LogLevelFilter::Warn, Config::default()).unwrap(),//terminal logger
WriteLogger::new(LogLevelFilter::Info, Config::default(), File::create("my_rust_binary.log").unwrap()),//记录日志到"*.log"文件中
]
).unwrap();
error!("Bright red error");
info!("This only appears in the log file");
debug!("This level is currently not enabled for any logger");
}