当前位置: 首页 > news >正文

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

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 MBNaming::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 MBNaming::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 KBNaming::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)   // 将所有级别的日志复制到标准输出

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

按时间切分日志文件

Criterion::Age表示按时间切分日志文件,flexi_logger::Age::Day指定了按每天切分日志文件。这样,每天会生成一个新的日志文件

Criterion::Age(flexi_logger::Age::Day), // 设置日志文件按日切分

相关文章:

  • 【系统架构设计师】十一、系统架构设计(层次架构风格|MVC|面向服务的架构风格|ESB)
  • 解决 Failed to get nested archive for entry BOOT-INF/lib/xxx.jar
  • 【编程语言】C++和C的异同点
  • DBA 数据库管理 表管理 数据批量处理。表头约束
  • SAC-IA粗配准算法记录
  • 景联文科技构建高质量心理学系知识图谱,助力大模型成为心理学科专家
  • AI艺术创作:掌握Midjourney和DALL-E的技巧与策略
  • python爬虫实现简单的代理ip池
  • 微信小程序-实现跳转链接并拼接参数(URL拼接路径参数)
  • 网络安全相关竞赛比赛
  • C语言 杂项笔记
  • 【hadoop大数据集群 2】
  • R语言学习笔记9-数据过滤-分组-融合
  • OpenCV 轮廓检测
  • PyTorch 深度学习实践-逻辑斯蒂回归
  • 【译】JS基础算法脚本:字符串结尾
  • [nginx文档翻译系列] 控制nginx
  • Android 控件背景颜色处理
  • ES6系列(二)变量的解构赋值
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • Java基本数据类型之Number
  • mac修复ab及siege安装
  • php面试题 汇集2
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • React+TypeScript入门
  • Terraform入门 - 1. 安装Terraform
  • Vue 动态创建 component
  • 半理解系列--Promise的进化史
  • 对JS继承的一点思考
  • 浮现式设计
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 前端知识点整理(待续)
  • 三栏布局总结
  • 实战|智能家居行业移动应用性能分析
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 原生js练习题---第五课
  • [Shell 脚本] 备份网站文件至OSS服务(纯shell脚本无sdk) ...
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • ​​​​​​​sokit v1.3抓手机应用socket数据包: Socket是传输控制层协议,WebSocket是应用层协议。
  • ​如何在iOS手机上查看应用日志
  • # Panda3d 碰撞检测系统介绍
  • #window11设置系统变量#
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (7) cmake 编译C++程序(二)
  • (搬运以学习)flask 上下文的实现
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (分类)KNN算法- 参数调优
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (计算机网络)物理层
  • (六)DockerCompose安装与配置
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .net core 3.0 linux,.NET Core 3.0 的新增功能