• Rust 实现日志记录功能


    log 日志库标准#

    log 是 Rust 的日志门面库,由官方积极维护可以放心使用。它是Rust的日志门面,相应的日志 API 已成为事实上的标准被其它日志框架所使用,有了日志门面开发者可以很方便切换自己的日志框架。

    简单示例#

    创建一个名为 log_test 二进制项目:

    cargo new log_test
    

    执行以下命令,引入 log 依赖:

    cargo add log
    

    修改 main.rs 的代码如下:

    use log::{info, warn,error,trace};
    
    fn main() {
        // 记录日志
        info!("This is an info message");
        warn!("This is a warning message");
        error!("This is an error message");
        trace!("This is an trace message");
    }
    
    

    运行上面的示例,实际上看不到任何输出。因为 log 仅仅是日志门面库,它并不具备完整的日志库功能

    使用方法#

    因为 log 仅仅是日志门面库,对于库和应用的开发者来说使用方法是有区别的,这也是 log 包这么设计的优势所在。

    库的开发者#

    作为库的开发者,你只要在库中使用门面库即可,将具体的日志库交给用户去选择和绑定:

    use log::{info, trace, warn};
    pub fn deal_with_something() {
        // 开始处理
    
        // 记录一些日志
        trace!("a trace log");
        info!("a info long: {}", "abc");
        warn!("a warning log: {}, retrying", err);
    
        // 结束处理
    }
    

    应用开发者#

    如果是应用开发者,就需要去选择一个具体的日志库了。

    目前已经有了不少日志库实现,官方在 github 上也推荐了一些 ,主要分为以下几类:

    • 简单的最小记录器,如 env_logger 等
    • 复杂的可配置框架,如 log4rs 等
    • 其他设施的适配器,如 syslog、db_logger 等
    • 对于 WebAssembly 二进制文件:console_log
    • 对于动态库:需要在日志上构造一个 FFI 安全包装器,以便在库中进行初始化。
    • 实用程序,如 alterable_logger 等

    log 还提供了 set_logger 函数用于设置日志库,set_max_level 用于设置最大日志级别。但是选用的具体日志库往往会提供更高级的 API,无需手动调用这两个函数。

    日志库开发者#

    对于日志库开发者而言,自然要实现自己的 Log 特征:

    use log::{Record, Level, Metadata};
    struct SimpleLogger;
    impl log::Log for SimpleLogger {
        fn enabled(&self, metadata: &Metadata) -> bool {
            metadata.level() <= Level::Info
        }
        fn log(&self, record: &Record) {
            if self.enabled(record.metadata()) {
                println!("{} - {}", record.level(), record.args());
            }
        }
        fn flush(&self) {}
    }
    

    除此之外,还需要包装下 set_logger 和 set_max_level:

    use log::{SetLoggerError, LevelFilter};
    static LOGGER: SimpleLogger = SimpleLogger;
    pub fn init() -> Result<(), SetLoggerError> {
        log::set_logger(&LOGGER)
            .map(|()| log::set_max_level(LevelFilter::Info))
    }
    

    然后再main函数里面设置全局记录器:

    use log::{info, warn,error,trace};
    
    fn main() {
        //设置日志
        init();
        // 记录日志
        info!("This is an info message");
        warn!("This is a warning message");
        error!("This is an error message");
        trace!("This is an trace message");
    }
    

    运行后终端输出如下,因为设置日志等级为Info,所以没有输出Trace等级日志:

    INFO - This is an info message
    WARN - This is a warning message
    ERROR - This is an error message
    

    使用 log4rs#

    log4rs 是一个高度可配置的日志框架,以 Java 的 Logback 和 log4j 库为模型。

    添加依赖#

    为项目添加 log4rs 依赖:

    cargo add log4rs
    

    配置文件#

    在项目根目录下,创建一个 log4rs.yaml 配置文件,并添加以下内容:

    refresh_rate: 30 seconds
    
    appenders:
      stdout:
        kind: console
        encoder:
          pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{l}] {t} - {m}{n}"
      
      rolling_file:
        kind: rolling_file
        path: logs/test.log
        append: true 
        encoder:
          pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{l}] {t} - {m}{n}"
        policy:
          kind: compound
          trigger:
            kind: size
            limit: 10 mb
          roller:        
            kind: fixed_window
            pattern: logs/test.{}.log
            base: 1
            count: 5
            
    root:
      level: info 
      appenders:
        - stdout
        - rolling_file
    

    上面配置文件设定日志输出到控制台、文件,文件按10 mb大小滚动,只保留最近五个文件。各个配置字段的具体含义可以参考配置

    • refresh_rate:用于确定 log4rs 扫描配置文件以查找更改的频率,如果发现更改,记录器将自动重新配置
    • appender: 负责将日志收集到文件、控制台或系统日志, 可配置多个
    • stdout、rolling_file:追加器的唯一标识字符串,自己随便定义,它的 kind 字段只支持consolefilerolling_file 三种实现
    • encoder: 负责将 log 信息转换为合适的格式, 如固定格式的平文本或json
    • pattern:编码模板,格式可配置,具体格式详见pattern
    • policy:策略字段,策略必须具有 kind 字段,默认(且仅受支持)策略为 kind: compound
    • trigger:触发器字段用于指示何时滚动日志文件,支持 sizetime 两种类型,这里使用的是按大小

    运行项目#

    修改main.rs内容如下:

    use log::*;
    use log4rs;
    
    fn main() {
        log4rs::init_file("log4rs.yaml", Default::default()).unwrap();
    
        for i in 1..=1000 {
            info!("This is loop iteration {}", i);
        }
    }
    

    运行结果:

    2024-04-01 15:43:28.596832500 [INFO] hello_world - This is loop iteration 1
    

    参考文章#

  • 相关阅读:
    MT8735/MTK8735安卓核心板规格参数介绍
    【MyBatis Plus】深入探索 MyBatis Plus 的条件构造器,自定义 SQL语句,Service 接口的实现
    电脑重装系统打印机脱机状态怎么恢复正常
    Javaweb 路线之JDBC的理解笔记
    8+非肿瘤+线粒体+实验生信思路解析
    如何搭建一个好的知识库管理系统?
    Django(二)精美博客搭建(11)实现文章列表分页查询及首页简单优化
    Webpack Chunk 分包规则
    Jenkins部署失败:JDK ‘jdk1.8.0_381‘ not supported to run Maven projects
    Leetcoder Day32| 贪心算法part05
  • 原文地址:https://www.cnblogs.com/timefiles/p/18108881