diff --git a/linkerd/tracing/src/access_log.rs b/linkerd/tracing/src/access_log.rs index d79ee63771..6e22fd97b3 100644 --- a/linkerd/tracing/src/access_log.rs +++ b/linkerd/tracing/src/access_log.rs @@ -10,8 +10,10 @@ use tracing_subscriber::{ pub const TRACE_TARGET: &str = "_access_log"; -pub(super) type AccessLogLayer = Filtered; +pub(super) type AccessLogLayer = + Filtered + Send + Sync + 'static>, FilterFn, S>; +#[derive(Default)] pub(super) struct Writer { formatter: F, } @@ -21,16 +23,27 @@ pub(super) struct ApacheCommon { _p: (), } +#[derive(Copy, Clone, Debug)] +pub(super) enum Format { + Apache, + Json, +} + struct ApacheCommonVisitor<'writer> { res: fmt::Result, writer: format::Writer<'writer>, } -pub(super) fn build() -> (AccessLogLayer, Directive) +pub(super) fn build(format: Format) -> (AccessLogLayer, Directive) where S: Subscriber + for<'span> LookupSpan<'span>, { - let writer = Writer::new().with_filter( + let writer: Box + Send + Sync + 'static> = match format { + Format::Apache => Box::new(Writer::::default()), + Format::Json => Box::new(Writer::::default()), + }; + + let writer = writer.with_filter( FilterFn::new( (|meta| meta.level() == &Level::INFO && meta.target().starts_with(TRACE_TARGET)) as fn(&Metadata<'_>) -> bool, @@ -49,14 +62,6 @@ where // === impl Writer === -impl Writer { - pub fn new() -> Self { - Self { - formatter: Default::default(), - } - } -} - impl Layer for Writer where S: Subscriber + for<'span> LookupSpan<'span>, @@ -154,3 +159,16 @@ impl field::Visit for ApacheCommonVisitor<'_> { } } } + +// === impl Format === + +impl std::str::FromStr for Format { + type Err = &'static str; + fn from_str(s: &str) -> Result { + match s { + s if s.eq_ignore_ascii_case("json") => Ok(Self::Json), + s if s.eq_ignore_ascii_case("apache") => Ok(Self::Apache), + _ => Err("expected either 'apache' or 'json'"), + } + } +} diff --git a/linkerd/tracing/src/lib.rs b/linkerd/tracing/src/lib.rs index 99da69f464..a9f1e72dfb 100644 --- a/linkerd/tracing/src/lib.rs +++ b/linkerd/tracing/src/lib.rs @@ -29,7 +29,7 @@ const DEFAULT_LOG_FORMAT: &str = "PLAIN"; pub struct Settings { filter: Option, format: Option, - access_log: bool, + access_log: Option, is_test: bool, } @@ -81,7 +81,7 @@ impl Settings { Some(Self { filter, format: std::env::var(ENV_LOG_FORMAT).ok(), - access_log: std::env::var(ENV_ACCESS_LOG).is_ok(), + access_log: Self::access_log_format(), is_test: false, }) } @@ -90,7 +90,7 @@ impl Settings { Self { filter: Some(filter), format: Some(format), - access_log: false, + access_log: Self::access_log_format(), is_test: true, } } @@ -102,6 +102,17 @@ impl Settings { .to_uppercase() } + fn access_log_format() -> Option { + let env = std::env::var(ENV_ACCESS_LOG).ok()?; + match env.parse() { + Ok(format) => Some(format), + Err(err) => { + eprintln!("Invalid {}={:?}: {}", ENV_ACCESS_LOG, env, err); + None + } + } + } + fn mk_json(&self) -> Box + Send + Sync + 'static> where S: Subscriber + for<'span> LookupSpan<'span>, @@ -154,8 +165,8 @@ impl Settings { let mut filter = EnvFilter::new(log_level); // If access logging is enabled, build the access log layer. - let access_log = if self.access_log { - let (access_log, directive) = access_log::build(); + let access_log = if let Some(format) = self.access_log { + let (access_log, directive) = access_log::build(format); filter = filter.add_directive(directive); Some(access_log) } else {