首页 > 其他分享 >【Rust】使用日志记录利器flexi_logger

【Rust】使用日志记录利器flexi_logger

时间:2024-07-17 22:29:56浏览次数:12  
标签:info 文件 flexi log rs width logger 日志 Rust

Flexi_logger简介

flexi_logger​是一个功能强大且灵活的日志记录库,用于Rust语言的应用程序。它提供了丰富的配置选项和功能,适用于各种日志记录需求,从简单的控制台输出到复杂的文件日志管理。以下是对flexi_logger​的一些关键功能和特性的简介:

主要功能

  • 多种日志目标:支持将日志输出到控制台、文件或同时输出到多个目标
  • 日志文件滚动:支持基于文件大小或时间的日志文件滚动,可以按大小、时间(每天、每小时等)进行切分
  • 日志文件清理:可以配置保留的日志文件数量,自动删除过期的日志文件
  • 日志格式自定义:支持自定义日志格式,可以包含时间戳、日志级别、目标模块等信息
  • 日志级别过滤:支持设置不同的日志级别(如info​、warn​、error​等),只记录满足级别要求的日志消息
  • 异步日志:支持异步写日志,提高性能
  • 日志复制:可以将日志复制到标准输出(stdout)或标准错误(stderr)

使用示例

创建项目

cargo new rs_demo

Cargo.toml

[package]
name = "rs_demo"
version = "0.1.0"
edition = "2021"

[dependencies]
log = "0.4"
flexi_logger = "0.22"
time = "0.3"

main.rs

use log::{trace, debug, info, warn, error};
use flexi_logger::{Duplicate, FileSpec, Logger, WriteMode, Criterion, Naming, Cleanup, detailed_format};

// 定义一个结构体 `Rectangle`
struct Rectangle {
    width: u32,
    height: u32,
}

// 为 `Rectangle` 实现方法
impl Rectangle {
    // 关联函数(类似于静态方法)
    fn new(width: u32, height: u32) -> Rectangle {
        Rectangle { width, height }
    }

    // 实例方法
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // 实例方法
    fn perimeter(&self) -> u32 {
        2 * (self.width + self.height)
    }

    // 修改实例的方法
    fn set_width(&mut self, width: u32) {
        self.width = width;
    }
}

fn main() {
    // 初始化日志记录,配置输出到文件,设置文件大小限制和滚动日志
    let logger = Logger::try_with_str("trace")
        .unwrap()
        .log_to_file(
            FileSpec::default()
                .directory("logs") // 设置日志文件目录
                .basename("app")   // 设置日志文件前缀
                .suffix("log")     // 设置日志文件后缀
        )
        .rotate(
            Criterion::Size(10_000_000), // 设置日志文件大小限制为 10 MB
            Naming::Numbers,             // 使用数字序号进行文件命名
            Cleanup::KeepLogFiles(3),    // 保留最近的 3 个日志文件
        )
        .write_mode(WriteMode::BufferAndFlush) // 设置日志写入模式
        .duplicate_to_stderr(Duplicate::Warn)  // 将警告级别的日志复制到标准错误输出
        .format_for_files(detailed_format)     // 使用详细格式,包含时间戳
        .start()
        .unwrap();

    // 记录不同级别的日志消息
    trace!("This is a trace message.");
    debug!("This is a debug message.");
    info!("This is an info message.");
    warn!("This is a warning message.");
    error!("This is an error message.");

    // 使用关联函数创建一个 `Rectangle`
    let mut rect = Rectangle::new(30, 50);

    // 调用实例方法
    info!("The area of the rectangle is {} square pixels.", rect.area());
    info!("The perimeter of the rectangle is {} pixels.", rect.perimeter());

    // 修改实例的字段
    rect.set_width(40);
    info!("After resizing, the area of the rectangle is {} square pixels.", rect.area());

    // 强制刷新日志缓冲区
    logger.flush();
}

这里的配置包括:

  • 日志文件目录:日志文件将被保存到logs目录中
  • 日志文件前缀:日志文件将以app作为前缀
  • 日志文件后缀:日志文件将以.log作为后缀
  • 日志文件滚动策略:当日志文件大小达到10 MB时,日志文件将滚动,新的日志文件将使用时间戳命名
  • 日志文件保留策略:只保留最近的3个日志文件
  • 日志写入模式:使用缓冲并在写入时刷新
  • 日志复制到标准错误输出:将警告级别的日志消息复制到标准错误输出
  • 日志格式:使用详细格式,包含时间戳

在Rust的log库中,不同的日志宏可以记录不同级别的日志消息。这些日志级别分别是:

  • trace!:最详细的日志信息,通常用于跟踪程序的细节流程
  • debug!:用于调试时的信息,比 trace! 略少,但仍然非常详细
  • info!:一般信息,不含调试细节,适合普通运行时的信息
  • warn!:警告信息,表明某些事情可能会出问题,但程序可以继续运行
  • error!:错误信息,表明发生了严重的问题,程序可能无法继续运行

日志文件数据:

[2024-07-17 21:08:07.689886 +08:00] TRACE [rs_demo] src/main.rs:55: This is a trace message.
[2024-07-17 21:08:07.691157 +08:00] DEBUG [rs_demo] src/main.rs:56: This is a debug message.
[2024-07-17 21:08:07.691170 +08:00] INFO [rs_demo] src/main.rs:57: This is an info message.
[2024-07-17 21:08:07.697314 +08:00] WARN [rs_demo] src/main.rs:58: This is a warning message.
[2024-07-17 21:08:07.707785 +08:00] ERROR [rs_demo] src/main.rs:59: This is an error message.
[2024-07-17 21:08:07.707804 +08:00] INFO [rs_demo] src/main.rs:65: The area of the rectangle is 1500 square pixels.
[2024-07-17 21:08:07.707809 +08:00] INFO [rs_demo] src/main.rs:66: The perimeter of the rectangle is 160 pixels.
[2024-07-17 21:08:07.707814 +08:00] INFO [rs_demo] src/main.rs:70: After resizing, the area of the rectangle is 2000 square pixels.

自定义日志的输出格式

使用format_for_files函数可以用于自定义日志的输出格式。定义一个名为custom_format的函数,并将其传递给format_for_files以使用自定义格式记录日志

custom_format中:

  • w:一个实现了Write trait的可写对象,日志消息将被写入这个对象
  • record:一个Record对象,包含了日志记录的详细信息
use log::{info};
use flexi_logger::{DeferredNow, Duplicate, FileSpec, Logger, Record, WriteMode, Criterion, Naming, Cleanup};
use std::io::Write;
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;

// 定义一个结构体 `Rectangle`
struct Rectangle {
    width: u32,
    height: u32,
}

// 为 `Rectangle` 实现方法
impl Rectangle {
    // 关联函数(类似于静态方法)
    fn new(width: u32, height: u32) -> Rectangle {
        Rectangle { width, height }
    }

    // 实例方法
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // 实例方法
    fn perimeter(&self) -> u32 {
        2 * (self.width + self.height)
    }

    // 修改实例的方法
    fn set_width(&mut self, width: u32) {
        self.width = width;
    }
}

fn custom_format(
    w: &mut dyn Write,
    _now: &mut DeferredNow,
    record: &Record,
) -> std::io::Result<()> {
    let now = OffsetDateTime::now_utc().format(&Rfc3339).unwrap();
    write!(
        w,
        "{} [{}] - {} - {}",
        now,
        record.level(),
        record.target(),
        record.args()
    )
}

fn main() {
    // 初始化日志记录,配置输出到文件,设置文件大小限制和滚动日志
    let logger = Logger::try_with_str("info")
        .unwrap()
        .log_to_file(
            FileSpec::default()
                .directory("logs") // 设置日志文件目录
                .basename("app")   // 设置日志文件前缀
                .suffix("log")     // 设置日志文件后缀
        )
        .rotate(
            Criterion::Size(10_000_000), // 设置日志文件大小限制为 10 MB
            Naming::Numbers,             // 使用数字序号进行文件命名
            Cleanup::KeepLogFiles(3),    // 保留最近的 3 个日志文件
        )
        .write_mode(WriteMode::BufferAndFlush) // 设置日志写入模式
        .duplicate_to_stderr(Duplicate::Warn)  // 将警告级别的日志复制到标准错误输出
        .format_for_files(custom_format)       // 使用自定义格式
        .start()
        .unwrap();

    // 记录不同级别的日志消息
    info!("This is an info message.");

    // 使用关联函数创建一个 `Rectangle`
    let mut rect = Rectangle::new(30, 50);

    // 调用实例方法
    info!("The area of the rectangle is {} square pixels.", rect.area());
    info!("The perimeter of the rectangle is {} pixels.", rect.perimeter());

    // 修改实例的字段
    rect.set_width(40);
    info!("After resizing, the area of the rectangle is {} square pixels.", rect.area());

    // 强制刷新日志缓冲区
    logger.flush();
}
2024-07-17T12:28:34.701362Z [INFO] - rs_demo - This is an info message.
2024-07-17T12:28:34.7024068Z [INFO] - rs_demo - The area of the rectangle is 1500 square pixels.
2024-07-17T12:28:34.7024153Z [INFO] - rs_demo - The perimeter of the rectangle is 160 pixels.
2024-07-17T12:28:34.7024181Z [INFO] - rs_demo - After resizing, the area of the rectangle is 2000 square pixels.

验证日志文件大小和保留日志文件个数

下面通过一个无限循环不断地写入日志消息,从而测试日志文件的滚动和清理功能。这种设置在实际应用中可能用于持续记录应用程序的运行状态或调试信息

use log::info;
use flexi_logger::{Logger, FileSpec, Criterion, Naming, Cleanup, WriteMode, Duplicate, detailed_format};
use std::thread;
use std::time::Duration;

fn main() {
    // 初始化日志记录,配置输出到文件,设置文件大小限制和滚动日志
    let _logger = Logger::try_with_str("info")
        .unwrap()
        .log_to_file(
            FileSpec::default()
                .directory("logs") // 设置日志文件目录
                .basename("app") // 设置日志文件前缀
                .suffix("log")     // 设置日志文件后缀
        )
        .rotate(
            Criterion::Size(5_000), // 设置日志文件大小限制为 5 KB
            Naming::Timestamps,         // 使用时间戳进行文件命名
            Cleanup::KeepLogFiles(3),   // 保留最近的 3 个日志文件
        )
        .write_mode(WriteMode::BufferAndFlush) // 设置日志写入模式
        .duplicate_to_stderr(Duplicate::Warn)  // 将警告级别的日志复制到标准错误输出
        .format_for_files(detailed_format)     // 使用详细格式,包含时间戳
        .start()
        .unwrap();

    // 无限循环,不断写入日志
    loop {
        info!("This is an info message.");
      
        // 模拟一些工作,等待一段时间
        thread::sleep(Duration::from_secs(1));
    }
}

运行程序数分钟,查看日志文件夹,文件夹目录结构如下,“rCURRENT.log”代表当前程序正在写入的日志文件,剩余的三个日志文件为程序保留的三个日志文件,日志文件都含有时间戳,并且不会随着程序运行的时间延长而新增文件个数

├─logs
│      app_r2024-07-17_20-44-24.log
│      app_r2024-07-17_20-45-19.log
│      app_r2024-07-17_20-46-15.log
│      app_rCURRENT.log

日志输出到控制台和文件

使用duplicate_to_stdout(Duplicate::All)方法,将所有级别的日志复制到标准输出(控制台)

.duplicate_to_stdout(Duplicate::All)   // 将所有级别的日志复制到标准输出

这样,控制台能看到所有输出到日志文件的日志信息

标签:info,文件,flexi,log,rs,width,logger,日志,Rust
From: https://www.cnblogs.com/vinciyan/p/18308423

相关文章

  • Django使用 DoesNotExist 异常和 Logger 来记录异常情况
     代码不仅处理了特定的异常类型,还可以添加更多的调试信息来帮助诊断问题。可以使用DoesNotExist异常和Logger来记录异常情况。fromdjango.core.exceptionsimportObjectDoesNotExistimportlogginglogger=logging.getLogger(__name__)try:rst=CU009HModel......
  • rust各种库
    ndarrayndarray是NumPy库中的一个核心数据结构,它是一个用于表示多维数组的对象。ndarray在存储和操作大型多维数组时非常高效,广泛应用于科学计算、数据分析、机器学习等领域。在Rust开发中,ndarray库可以作为替代 NumPy库。Github地址:https://github.com/rust-ndarra......
  • Rust 中的枚举有啥不同
    提问Rust中的枚举有啥不同回答枚举中每一项可以有自己的数据类型enumMessage{Quit,Move{x:i32,y:i32},Write(String),ChangeColor(i32,i32,i32),}可以用来做统一流程处理类似于其他语言中的接口同一化类型最后,再用一个实际项目中的......
  • rust+openGL
    如果是C语言,适合用Nuklear如果是C++语言,适合用ElementsC++GUIlibrary如果是Go语言,适合用therecipe/qt如果是Python,适合用Tkinter如果是JS,用Vue+Bootstrap+ElementUI最为简单如果是小程序,用官方组件+WeUI组件如果是C#,直接用.NetFramework就可以了但是,每个语言都有自己擅长做的......
  • 0181-汇编调用 Rust
    环境Time2022-11-12WSL-Ubuntu22.04QEMU6.2.0NASM2.15.05Rust1.67.0-nightly前言说明参考:https://os.phil-opp.com/set-up-rust/目标从汇编代码中调用Rust代码。该篇基于之前编写的进入64位模式的汇编代码。切换到nightly版本切换命令:rustupoverridese......
  • 提升漏洞挖掘效率:详解RustScan端口快速扫描工具
    在漏洞挖掘过程中,梳理目标站点的资产面是至关重要的一步。这一过程通常需要进行全量端口扫描,以发现目标站点上所有可能的开放端口。然而,传统的端口扫描工具往往需要大量时间来完成这一任务,特别是在面对大量端口时。这不仅延长了整个漏洞挖掘的时间,还可能导致关键漏洞的发现......
  • leetcode简单题21 N.104 二叉树的最大深度 rust描述
     //[3,9,20,null,null,15,7]3//[1,null,2]2usestd::rc::Rc;usestd::cell::RefCell;//Definitionforabinarytreenode.#[derive(Debug,PartialEq,Eq)]pubstructTreeNode{pubval:i32,publeft:Option<Rc<RefCell<TreeNode>>......
  • Windows系统安装RustDesk Server的详细步骤和客户端设置
    Windows系统安装RustDeskServer的详细步骤在Windows系统上安装RustDeskServer涉及几个关键步骤,包括安装必要的依赖、下载RustDeskServer程序、配置并启动服务。以下是详细的步骤:1.安装Node.js和PM2RustDeskServer的某些版本可能需要Node.js环境来运行,而PM2是一个常用的Nod......
  • Code-Logger-替换标准输出和标准错误,并通过宏使能输出
    Code-Logger-替换标准输出和标准错误,并通过宏使能输出需求:替换标准输出和标准错误,并通过宏使能输出classLogger#ifndefENABLE_LOGS#defineENABLE_LOGS1//设置为1表示启用日志输出,0则禁用#endif#include<iostream>#include<sstream>classLogger{public:......
  • rust跨平台
    目前常见的跨平台方案C++很多公司的跨平台移动基础库基本都有C++的影子,如微信,腾讯会议,还有早期的Dropbox,知名的开源库如微信的Mars等。好处是一套代码多端适配,但是需要大公司对C++有强大的工具链支持,还需要花重金聘请C++研发人员,随着团队人员变动,产品维护成本也不可忽......