Rust日志学习(四)——simplelog

来源:互联网 发布:淘宝冷光美白仪有用么 编辑:程序博客网 时间:2024/06/16 14:10

simplelog——A simple and easy-to-use logging facility for Rust’s log crate.

simplelog的目标不是提供非常丰富的特性,也不是提供最佳日志方案,而是旨在提供简单易用的适合中小规模工程的日志方案。原文如下:
simplelog does not aim to provide a rich set of features, nor to provide the best logging solution. It aims to be a maintainable, easy to integrate facility for small to medium sized projects, that find env_logger to be somewhat lacking in features. In those cases simplelog should provide an easy alternative.

Github地址:https://github.com/drakulix/simplelog.rs

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 Implementationuse 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 implementationpub 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 Traitimpl 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
另外,因为下面的用法示例用到了CombinedLogger,所以把它的源代码也列出来学习一下:

//! Module providing the CombinedLogger Implementationuse log::{LogLevelFilter, LogMetadata, LogRecord, SetLoggerError, set_logger, Log};use ::{SharedLogger, Config};/// The CombinedLogger struct. Provides a Logger implementation that proxies multiple Loggers as one.////// The purpose is to allow multiple Loggers to be set globallypub struct CombinedLogger {    level: LogLevelFilter,    logger: Vec<Box<SharedLogger>>,}impl CombinedLogger {    /// init function. Globally initializes the CombinedLogger as the one and only used log facility.    ///    /// Takes all used Loggers as a Vector argument. None of those Loggers should already be set globally.    ///    /// All loggers need to implement `log::Log` and `logger::SharedLogger` and need to provide a way to be    /// initialized without calling `set_logger`. All loggers of this library provide a `new(..)`` method    /// for that purpose.    /// Fails if another logger is already set globally.    pub fn init(logger: Vec<Box<SharedLogger>>) -> Result<(), SetLoggerError> {        set_logger(|max_log_level| {            let result = CombinedLogger::new(logger);            max_log_level.set(result.level());            result        })    }    /// allows to create a new logger, that can be independently used, no matter whats 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 all used loggers as a Vector argument. The log level is automatically determined by the    /// lowest log level used by the given loggers.    ///    /// All loggers need to implement log::Log.    pub fn new(logger: Vec<Box<SharedLogger>>) -> Box<CombinedLogger> {        let mut log_level = LogLevelFilter::Off;        for log in &logger {            if log_level < log.level() {                log_level = log.level();            }        }        Box::new(CombinedLogger { level: log_level, logger: logger })    }}//实现Log Traitimpl Log for CombinedLogger {    fn enabled(&self, metadata: &LogMetadata) -> bool {        metadata.level() <= self.level    }    fn log(&self, record: &LogRecord) {        if self.enabled(record.metadata()) {            for log in &self.logger {                log.log(record);            }        }    }}//实现SharedLogger Traitimpl SharedLogger for CombinedLogger {    fn level(&self) -> LogLevelFilter {        self.level    }    fn config(&self) -> Option<&Config>    {        None    }    fn as_log(self: Box<Self>) -> Box<Log> {        Box::new(*self)    }}

这里面有个Config structs,对应源代码如下:

use log::LogLevel;/// Configuration for the Loggers////// All loggers print the message in the following form:/// `00:00:00 [LEVEL] crate::module: [lib.rs::100] your_message`/// Every space delimited part except the actual message is optional.////// Pass this struct to your logger to change when these information shall/// be logged. Every part can be enabled for a specific LogLevel and is then/// automatically enable for all lower levels as well.////// The Result is that the logging gets more detailed the more verbose it gets./// E.g. to have one part shown always use `LogLevel::Error`. But if you/// want to show the source line only on `Trace` use that./// Passing `None` will completely disable the part.#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub struct Config{    ///At which level and below the current time shall be logged    pub time: Option<LogLevel>,    ///At which level and below the level itself shall be logged    pub level: Option<LogLevel>,    ///At which level and below the target shall be logged    pub target: Option<LogLevel>,    ///At which level and below a source code reference shall be logged    pub location: Option<LogLevel>,}impl Default for Config {    fn default() -> Config {        Config {            time: Some(LogLevel::Error),            level: Some(LogLevel::Error),            target: Some(LogLevel::Debug),            location: Some(LogLevel::Trace),        }    }}

用法示例:

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

运行结果:
终端显示如下:
这里写图片描述
日志文件内容如下:
这里写图片描述

原创粉丝点击