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 -
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.
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();