Rust 日志记录库 tracing

发布时间 2023-09-26 21:10:29作者: qi-xmu

Rust 日志记录库 tracing

​#2023-09-26#​ #日志#​ #tracing#

一个好用的日志跟踪系统,可以帮助我们很快的定位程序中的 bug。tracing 不仅仅可以作为一个日志库去使用,还可以作为一个程序追踪库,帮助我们分析程序中存在的问题。

tracing - Rust

tracing 各个模块

  • tracing​​: 作用域内的结构化日志记录和诊断系统。

  • tracing_appender​: 记录事件和跨度的编写者。也就是将日志写入文件或者控制台。

  • tracing_error​: 增强错误处理跟踪诊断信息的实用工具。

  • tracing_flame​: 用于生成折叠堆栈跟踪以生成Inferno火焰图和火焰图表的跟踪订阅者。

  • tracing_log​: 用于连接标准库日志系统和tracing系统的连接器。

  • tracing_subscriber​: 用于实现和组成tracing订阅者的工具集合。

常规使用思路

使用tracing_appender​创建控制台输出层文件输出层。然后使用tracing_subscriber​进行事件的订阅。

在使用的时候可以使用tracing​进行日志和程序跟踪,也可使用标准log​库结合tracing_log​一同使用。

项目配置方法

在Cargo.toml文件中,添加依赖库

[dependencies]
# 日志系统
tracing = "0.1"
tracing-error = "0.2"
tracing-subscriber = { version = "0.3", features = ["std", "local-time"] }
tracing-appender = "0.2"
# color-eyre = "0.6"

日志系统初始化代码如下:

use tracing_appender::{non_blocking, rolling};
use tracing_error::ErrorLayer;
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, Layer, Registry};

pub fn logger_init() {
	// 格式化输出层,并且输出到终端。
    let formatting_layer = fmt::layer().pretty().with_writer(std::io::stdout);
    // 文件输出层
	let file_appender = rolling::daily("logs/", "log");
    let (non_blocking_appender, _guard) = non_blocking(file_appender); // 输出非阻塞
    let file_layer = fmt::layer()
         .with_ansi(false)
         .with_writer(non_blocking_appender)
         .with_filter(tracing_subscriber::filter::LevelFilter::INFO) // 文件输出日志等级
         .boxed();

    Registry::default()
        .with(ErrorLayer::default())
        .with(formatting_layer)
        .with(file_layer)
        .init();
    // color_eyre::install().unwrap();
}

在代码中使用日志

tracing的过程分为两个部分,span​和event​。

span​负责记录事件发生的地点和上下文信息,如果作用域内没有event​发生,span​不会输出任何信息。如果作用域内有event​发生,在输出event​信息的同时,也会将进入的span​信息从近到远依次输出,携带相关的上下文信息。

event​用于记录事件发生的情况,可以携带事件发生时产生的数据。

span:作用域记录

标记事件发生的上下文信息。有很多宏定义可以直接使用:

  • span!​:
  • tracing_span!​:

或者时函数标记instructment

#[instructment]
fn func(){
	...
}

例如

use tracing::{span, Level};
let span = span!(Level::TRACE, "my_span");
// `enter` returns a RAII guard which, when dropped, exits the span. this
// indicates that we are in the span for the current lexical scope.
// 	`enter`是一个 RAII(Resource Acquisition Is Initialization)守卫,
// 当这个变量被获取的时候,资源同时会被获取;变量被释放的时候,资源被释放。
let _enter = span.enter();
// perform some work in the context of `my_span`...

event:事件记录

use tracing::{event, Level}

event!(Level::INFO, passwd = "passwd");