Closed
Description
I'm trying to migrate from simplelog
to tracing
, however I have a very special case:
I have three writers, different level each (In the real case actually they are three different files).
In my first attempt, I tried to combine multiple fmt::Layer
with Registry
:
use tracing::{debug, info, info_span, trace, trace_span, warn};
use tracing_subscriber::fmt;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::Registry;
fn main() {
let logger = Registry::default()
.with(fmt::Layer::default())
.with(fmt::Layer::default())
.with(fmt::Layer::default());
tracing::subscriber::set_global_default(logger).unwrap();
let x = 1;
let span = info_span!("info", x);
let _guard = span.enter();
let y = 2;
let span = trace_span!("trace", y);
let _guard = span.enter();
info!("ABC");
warn!("DEF");
debug!("1234");
trace!("5678");
}
And the output is:
Feb 22 23:29:02.783 INFO info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: ABC
Feb 22 23:29:02.783 INFO info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: ABC
Feb 22 23:29:02.783 INFO info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: ABC
Feb 22 23:29:02.783 WARN info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: DEF
Feb 22 23:29:02.783 WARN info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: DEF
Feb 22 23:29:02.783 WARN info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: DEF
Feb 22 23:29:02.783 DEBUG info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 1234
Feb 22 23:29:02.783 DEBUG info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 1234
Feb 22 23:29:02.783 DEBUG info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 1234
Feb 22 23:29:02.783 TRACE info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 5678
Feb 22 23:29:02.784 TRACE info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 5678
Feb 22 23:29:02.784 TRACE info{x=1x=1x=1}:trace{y=2y=2y=2}: tt: 5678
With this approach the I found two issues:
- I couldn't apply level filter in the layers
- Notice the duplication:
x=1x=1x=1
andy=2y=2y=2
.
My final approach is:
use tracing::{
debug, info, info_span, metadata::Level, span, trace, trace_span, warn, Event, Subscriber,
};
use tracing_subscriber::fmt;
use tracing_subscriber::layer::{Context, Layer, SubscriberExt};
use tracing_subscriber::registry::LookupSpan;
use tracing_subscriber::Registry;
fn main() {
let logger = Registry::default()
.with(fmt::Layer::default())
.with(FmtWriterLayer::new(Level::DEBUG))
.with(FmtWriterLayer::new(Level::INFO));
tracing::subscriber::set_global_default(logger).unwrap();
let x = 1;
let span = info_span!("info", x);
let _guard = span.enter();
let y = 2;
let span = trace_span!("trace", y);
let _guard = span.enter();
info!("ABC");
warn!("DEF");
debug!("1234");
trace!("5678");
}
struct FmtWriterLayer<S>
where
S: Subscriber + for<'a> LookupSpan<'a>,
{
layer: fmt::Layer<S>,
level: Level,
}
impl<S> FmtWriterLayer<S>
where
S: Subscriber + for<'a> LookupSpan<'a>,
{
fn new(level: Level) -> FmtWriterLayer<S> {
let layer = fmt::Layer::default();
FmtWriterLayer {
layer,
level,
}
}
}
impl<S> Layer<S> for FmtWriterLayer<S>
where
S: Subscriber + for<'a> LookupSpan<'a>,
{
fn new_span(&self, _attrs: &span::Attributes, _id: &span::Id, _ctx: Context<S>) {
// intentionally not implemented
}
fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
self.layer.on_record(id, values, ctx);
}
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
if *event.metadata().level() <= self.level {
self.layer.on_event(event, ctx);
}
}
}
And the output is:
Feb 22 23:34:34.345 INFO info{x=1}:trace{y=2}: tracing_multifmt: ABC
Feb 22 23:34:34.345 INFO info{x=1}:trace{y=2}: tracing_multifmt: ABC
Feb 22 23:34:34.345 INFO info{x=1}:trace{y=2}: tracing_multifmt: ABC
Feb 22 23:34:34.345 WARN info{x=1}:trace{y=2}: tracing_multifmt: DEF
Feb 22 23:34:34.346 WARN info{x=1}:trace{y=2}: tracing_multifmt: DEF
Feb 22 23:34:34.346 WARN info{x=1}:trace{y=2}: tracing_multifmt: DEF
Feb 22 23:34:34.346 DEBUG info{x=1}:trace{y=2}: tracing_multifmt: 1234
Feb 22 23:34:34.346 DEBUG info{x=1}:trace{y=2}: tracing_multifmt: 1234
Feb 22 23:34:34.346 TRACE info{x=1}:trace{y=2}: tracing_multifmt: 5678
This is almost what I expect, however one small issue is that trace
span is printed in all levels.
So, some questions:
- Is this a missing feature? Or is there another way?
- In case of missing feature, how would you like to be added? I was thinking that
add_writer_with_level
could be implemented infmt::Subscriber
. What are your thoughts? Do you have any suggestion?
Metadata
Metadata
Assignees
Labels
No labels