0
点赞
收藏
分享

微信扫一扫

Rust log库的使用


文章目录

  • ​​一、Rust log​​
  • ​​二、env_logger库详解​​
  • ​​三、simple_logger库详解​​
  • ​​四、simplelog库详解​​


日志库一般会实现日志分级、日志过滤、日志输出格式化、日志回滚等功能。


Rust log【github地址】:

​​https://github.com/rust-lang/log​​


日志相关知识:

​​https://rustmagazine.github.io/rust_magazine_2021/chapter_2/rust_error_handle_and_log.html​​

一、Rust log

这个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​​ 常用的logger
  • ​​simplelog​​   常用的logger
  • ​​pretty_env_logger​​
  • ​​stderrlog​​
  • ​​flexi_logger​​
  • 复杂的可配置框架:
  • ​​log4rs​​
  • ​​fern​​
  • 其他设施的适配器:
  • ​​syslog​​
  • ​​slog-stdlog​​
  • ​​android_log​​
  • ​​win_dbg_logger​​
  • 对于WebAssembly二进制文件:
  • ​​console_log​​

可执行文件应选择一个记录器实现,并在程序运行时提早对其进行初始化。记录器的实现通常会包含一个执行此操作的功能。记录器初始化之前生成的任何日志消息都将被忽略。

下面以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的用法及源代码。

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

编译、运行结果如下:

三、simple_logger库详解

​​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.");//过滤掉了
}

四、simplelog库详解

​​https://github.com/drakulix/simplelog.rs​​ simplelog的目标旨在提供简单易用的适合中小规模工程的日志方案。

simplelog提供了一些logging facilities如下所示(也是simplelog中最重要的概念):

  • SimpleLogger—— very basic logger that logs to stderr/out, should never fail
  • TermLogger ——advanced terminal logger, that splits to stderr/out and has color support (can be excluded on unsupported platforms)
  • WriteLogger ——logs to a given struct implementing Write. e.g. a file
  • CombinedLogger ——can be used to form combinations of the above loggers

对应的,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");
}


举报

相关推荐

0 条评论