Skip to content

Commit e1b6fd7

Browse files
hawkwolix0r
authored andcommitted
tracing: simplify subscriber construction with Boxed layers (#1304)
Currently, the way the `tracing` subscriber is constructed is somewhat convoluted, due to potentially constructing formatting layers with different types (either plaintext logging or JSON). Because of this, we can't simply have methods that return the `fmt` layer. Instead, we have to pass the `Registry` into the methods that construct the `fmt` layers and return a type-erased `Dispatch` after adding the `fmt` layers. This is kind of not great. In particular, it makes adding additional layers difficult, such as access logging (#601) and (eventually) `tokio-console` support. This branch refactors the subscriber construction to use the (recently-added) `impl Layer<S> for Box<dyn Layer<S>>` in `tracing-subscriber`. Now, we can erase the types of the JSON and plaintext `fmt` layers and return them from the methods that construct them, and layer them onto the `Registry` in `tracing::Settings::build()`. This makes the `tracing` setup significantly easier, and will enable changes I want to make in #601. Boxing these layers does add slight overhead of dynamic dispatch + a pointer dereference. However, I doubt this has a huge performance impact in practice... (cherry picked from commit 3bb7ec4) Signed-off-by: Oliver Gould <[email protected]>
1 parent fdba26c commit e1b6fd7

File tree

1 file changed

+27
-22
lines changed

1 file changed

+27
-22
lines changed

linkerd/tracing/src/lib.rs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@ mod uptime;
88
use self::uptime::Uptime;
99
use linkerd_error::Error;
1010
use std::{env, str};
11-
use tracing::Dispatch;
12-
use tracing_subscriber::{fmt::format, layer::Layered, prelude::*, reload, EnvFilter};
13-
14-
type Registry =
15-
Layered<reload::Layer<EnvFilter, tracing_subscriber::Registry>, tracing_subscriber::Registry>;
11+
use tracing::{Dispatch, Subscriber};
12+
use tracing_subscriber::{fmt::format, prelude::*, registry::LookupSpan, reload, EnvFilter, Layer};
1613

1714
const ENV_LOG_LEVEL: &str = "LINKERD2_PROXY_LOG";
1815
const ENV_LOG_FORMAT: &str = "LINKERD2_PROXY_LOG_FORMAT";
@@ -94,14 +91,11 @@ impl Settings {
9491
.to_uppercase()
9592
}
9693

97-
fn mk_registry(&self) -> (Registry, level::Handle) {
98-
let log_level = self.filter.as_deref().unwrap_or(DEFAULT_LOG_LEVEL);
99-
let (filter, level) = reload::Layer::new(EnvFilter::new(log_level));
100-
let reg = tracing_subscriber::registry().with(filter);
101-
(reg, level::Handle::new(level))
102-
}
103-
104-
fn mk_json(&self, registry: Registry) -> Dispatch {
94+
fn mk_json<S>(&self) -> Box<dyn Layer<S> + Send + Sync + 'static>
95+
where
96+
S: Subscriber + for<'span> LookupSpan<'span>,
97+
S: Send + Sync,
98+
{
10599
let fmt = tracing_subscriber::fmt::format()
106100
.with_timer(Uptime::starting_now())
107101
.with_thread_ids(!self.is_test)
@@ -121,32 +115,43 @@ impl Settings {
121115
.fmt_fields(format::JsonFields::default());
122116

123117
if self.is_test {
124-
registry.with(fmt.with_test_writer()).into()
118+
Box::new(fmt.with_test_writer())
125119
} else {
126-
registry.with(fmt).into()
120+
Box::new(fmt)
127121
}
128122
}
129123

130-
fn mk_plain(&self, registry: Registry) -> Dispatch {
124+
fn mk_plain<S>(&self) -> Box<dyn Layer<S> + Send + Sync + 'static>
125+
where
126+
S: Subscriber + for<'span> LookupSpan<'span>,
127+
S: Send + Sync,
128+
{
131129
let fmt = tracing_subscriber::fmt::format()
132130
.with_timer(Uptime::starting_now())
133131
.with_thread_ids(!self.is_test);
134132
let fmt = tracing_subscriber::fmt::layer().event_format(fmt);
135133
if self.is_test {
136-
registry.with(fmt.with_test_writer()).into()
134+
Box::new(fmt.with_test_writer())
137135
} else {
138-
registry.with(fmt).into()
136+
Box::new(fmt)
139137
}
140138
}
141139

142140
pub fn build(self) -> (Dispatch, Handle) {
143-
let (registry, level) = self.mk_registry();
141+
let log_level = self.filter.as_deref().unwrap_or(DEFAULT_LOG_LEVEL);
142+
let (filter, level) = reload::Layer::new(EnvFilter::new(log_level));
143+
let level = level::Handle::new(level);
144144

145-
let dispatch = match self.format().as_ref() {
146-
"JSON" => self.mk_json(registry),
147-
_ => self.mk_plain(registry),
145+
let logger = match self.format().as_ref() {
146+
"JSON" => self.mk_json(),
147+
_ => self.mk_plain(),
148148
};
149149

150+
let dispatch = tracing_subscriber::registry()
151+
.with(filter)
152+
.with(logger)
153+
.into();
154+
150155
(dispatch, Handle(Some(level)))
151156
}
152157
}

0 commit comments

Comments
 (0)