我正在try 使用tracingtracing-subscriber构建日志(log)记录设置.然而,我发现tracing生态系统非常抽象,很难处理.

我在试着创建订阅者-

  • 基于目标的顶级过滤器.例如,用于记录模块a的错误级别和模块b.^1的信息级别的过滤器
  • 两个写入器^2,每个写入器都有自己的层级过滤器.

但我无法使用现有的实现RegistryFmtSubscriber创建最终订阅者.

问题是,Registry不允许添加env_filter或顶级过滤器.而FmtSubscriber不允许添加写入器层.我不清楚,当它们都实现Subscriber特性时,为什么这两个都不可能.

use tracing::{instrument::WithSubscriber, metadata::LevelFilter, subscriber, Level, Subscriber};
use tracing_appender::{
    non_blocking::WorkerGuard,
    rolling::{RollingFileAppender, Rotation},
};
use tracing_subscriber::{
    filter::filter_fn, fmt, layer::Filter, prelude::*, registry::LookupSpan, Registry,
};

fn main() {
    // layer 1 is the file writer
    let rolling_log = RollingFileAppender::new(Rotation::NEVER, "hey", "cool.og");
    let (non_blocking, _) = tracing_appender::non_blocking(rolling_log);
    let layer1 = fmt::Layer::default()
        .with_writer(non_blocking)
        .with_filter(LevelFilter::from(Level::INFO));

    // layer 2 is the stdout writer
    let (non_blocking, _) = tracing_appender::non_blocking(std::io::stdout());
    let layer2 = fmt::Layer::default()
        .with_writer(non_blocking)
        .with_filter(LevelFilter::from(Level::ERROR));

    let top_level_filter: String = "module_a=info,module_b=error".to_string();
    // can't add env_filter/top level filter
    Registry::default().with(layer1).with(layer2).init();
    // can't add multiple writer layers
    fmt().with_env_filter(top_level_filter).init();
}

总的来说,我发现很难理解跟踪中的各种组件是如何组合在一起的.任何解释它如何工作的博客或教程也会有所帮助.

推荐答案

在这reddit comment个答案中,有gusrut个回答.

EnvFilter实现了各种级别的过滤,并且可以使用Subscriber::with作为全局过滤器添加到订户.

use tracing_subscriber::filter::EnvFilter;

let layer1 = ...;
let layer2 = ...;

let global_filter: EnvFilter = "module_a=info,module_b=error".parse()?;
Registry::default().with(layer1).with(layer2).with(global_filter).init();

Rust相关问答推荐

Tauri tauri—apps/plugin—store + zustand

如果A == B,则将Rc A下推到Rc B

何时可以在Rust中退出异步操作?

在自身功能上实现类似移动的行为,以允许通过大小的所有者进行呼叫(&;mut;self)?

带扫描的铁 rust 使用滤镜

Rust类似功能是C++命名空间吗?

同时从不同线程调用DLL的不同函数会出现分段错误或产生STATUS_STACK_BUFFER_OVERRUN

为什么这是&q;,而让&q;循环是无限循环?

如何正确重新排列代码以绕过铁 rust 借入判断器?

AXUM一路由多个不包括URL的参数类型

解析程序无法在Cargo 发布中 Select 依赖版本

Rust 中什么时候可以返回函数生成的字符串切片&str?

在 Rust 中,为什么 10 个字符的字符串的 size_of_val() 返回 24 个字节?

如何正确使用git2::Remote::push?

为什么我可以使用 &mut (**ref) 创建两个实时 &mut 到同一个变量?

在 Rust 中实现资源消耗的安全包装器

如何将参数传递给Rust 的线程?

隐式类型闭包的错误生命周期推断

Rust 中的运行时插件

这个 match 语句的默认值应该是什么,还有一种方法可以解开 Some case (chess in rust)