当前位置: 首页 > 工具软件 > OK Log > 使用案例 >

Rust log库的使用

阎德辉
2023-12-01


日志库一般会实现日志分级、日志过滤、日志输出格式化、日志回滚等功能。
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为例:

#[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");  
}
 类似资料: