英文:
How to use `tracing-subscriber` Rust crate to build a mult-writer, global filter subscriber
问题
我正在尝试使用tracing
和tracing-subscriber
构建日志记录设置。然而,我发现tracing
生态系统非常抽象且难以使用。
我正在尝试创建具有以下特性的订阅器:
- 基于目标的顶级过滤器。例如,为
module_a
记录错误级别,为module_b
记录信息级别。 - 两个具有各自层级过滤器的写入器。
但是,我无法使用现有的实现Registry
和FmtSubscriber
创建最终的订阅器。
问题在于Registry
不允许添加env_filter
或顶级过滤器。而FmtSubscriber
不允许添加写入器层。而且对我来说不清楚为什么在它们都实现了Subscriber
特性的情况下这两者都不可能。
总的来说,我发现很难理解tracing
中各个组件是如何配合的。任何解释其工作原理的博客或教程都会有所帮助。
英文:
I'm trying to build a logging setup using the tracing
and tracing-subscriber
. However I'm finding the tracing
ecosystem incredibly abstract and hard to work with.
I'm trying to create Subscriber that has -
- A top level filter based on the target. For e.g. a filter that logs error level for module_a and info level for module_b.^1
- Two writers^2 each with their own layer level filter.
But I'm unable to create the final subscriber with the existing implementations Registry
and FmtSubscriber
.
The problem is that Registry
does not allow adding an env_filter
or a top level filter. While the FmtSubscriber
does not allow adding the writer layers. And it's not clear to me why either of this is not possible when both of them implement the Subscriber
trait.
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();
}
Overall I've found it hard to understand how the the various components in tracing fit together. Any blogs or tutorials explaining how it works will also help.
答案1
得分: -1
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();
英文:
Answered by gusrut in this reddit comment.
EnvFilter implements various levels of filtering and can be added to the subscriber using Subscriber::with
to act as a global filter.
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();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论