diff --git a/contrib/dyn_templates/src/template.rs b/contrib/dyn_templates/src/template.rs index 9b4f6a31f6..3c92aa93f8 100644 --- a/contrib/dyn_templates/src/template.rs +++ b/contrib/dyn_templates/src/template.rs @@ -7,7 +7,7 @@ use rocket::fairing::Fairing; use rocket::response::{self, Responder}; use rocket::http::{ContentType, Status}; use rocket::figment::{value::Value, error::Error}; -use rocket::trace::Traceable; +use rocket::trace::Trace; use rocket::serde::Serialize; use crate::Engines; diff --git a/contrib/sync_db_pools/lib/src/connection.rs b/contrib/sync_db_pools/lib/src/connection.rs index d152f1a59a..b5f030e54a 100644 --- a/contrib/sync_db_pools/lib/src/connection.rs +++ b/contrib/sync_db_pools/lib/src/connection.rs @@ -6,7 +6,7 @@ use rocket::fairing::{AdHoc, Fairing}; use rocket::request::{Request, Outcome, FromRequest}; use rocket::outcome::IntoOutcome; use rocket::http::Status; -use rocket::trace::Traceable; +use rocket::trace::Trace; use rocket::tokio::time::timeout; use rocket::tokio::sync::{OwnedSemaphorePermit, Semaphore, Mutex}; diff --git a/core/lib/Cargo.toml b/core/lib/Cargo.toml index 1c3a34334d..004115a681 100644 --- a/core/lib/Cargo.toml +++ b/core/lib/Cargo.toml @@ -84,7 +84,7 @@ thread_local = { version = "1.1", optional = true } version = "0.3.18" optional = true default-features = false -features = ["fmt", "tracing-log"] +features = ["fmt", "tracing-log", "parking_lot"] [dependencies.rocket_codegen] version = "0.6.0-dev" diff --git a/core/lib/src/config/config.rs b/core/lib/src/config/config.rs index 134e5867a1..cbf984e50f 100644 --- a/core/lib/src/config/config.rs +++ b/core/lib/src/config/config.rs @@ -10,7 +10,7 @@ use crate::config::{ShutdownConfig, Ident, CliColors}; use crate::request::{self, Request, FromRequest}; use crate::http::uncased::Uncased; use crate::data::Limits; -use crate::trace::Traceable; +use crate::trace::{Trace, TraceFormat}; /// Rocket server configuration. /// @@ -26,9 +26,10 @@ use crate::trace::Traceable; /// the debug profile while [`Config::release_default()`] the default values for /// the release profile. The [`Config::default()`] method automatically selects /// the appropriate of the two based on the selected profile. With the exception -/// of `log_level`, which is `normal` in `debug` and `critical` in `release`, -/// and `secret_key`, which is regenerated from a random value if not set in -/// "debug" mode only, all default values are identical in all profiles. +/// of `log_level` and `log_format`, which are `info` / `pretty` in `debug` and +/// `error` / `compact` in `release`, and `secret_key`, which is regenerated +/// from a random value if not set in "debug" mode only, all default values are +/// identical in all profiles. /// /// # Provider Details /// @@ -124,6 +125,8 @@ pub struct Config { /// Max level to log. **(default: _debug_ `info` / _release_ `error`)** #[serde(with = "crate::trace::level")] pub log_level: Option, + /// Format to use when logging. **(default: _debug_ `pretty` / _release_ `compact`)** + pub log_format: TraceFormat, /// Whether to use colors and emoji when logging. **(default: /// [`CliColors::Auto`])** pub cli_colors: CliColors, @@ -193,6 +196,7 @@ impl Config { secret_key: SecretKey::zero(), shutdown: ShutdownConfig::default(), log_level: Some(Level::INFO), + log_format: TraceFormat::Pretty, cli_colors: CliColors::Auto, __non_exhaustive: (), } @@ -217,6 +221,7 @@ impl Config { Config { profile: Self::RELEASE_PROFILE, log_level: Some(Level::ERROR), + log_format: TraceFormat::Compact, ..Config::debug_default() } } @@ -354,6 +359,9 @@ impl Config { /// The stringy parameter name for setting/extracting [`Config::log_level`]. pub const LOG_LEVEL: &'static str = "log_level"; + /// The stringy parameter name for setting/extracting [`Config::log_format`]. + pub const LOG_FORMAT: &'static str = "log_format"; + /// The stringy parameter name for setting/extracting [`Config::shutdown`]. pub const SHUTDOWN: &'static str = "shutdown"; @@ -364,8 +372,8 @@ impl Config { pub const PARAMETERS: &'static [&'static str] = &[ Self::WORKERS, Self::MAX_BLOCKING, Self::KEEP_ALIVE, Self::IDENT, Self::IP_HEADER, Self::PROXY_PROTO_HEADER, Self::LIMITS, - Self::SECRET_KEY, Self::TEMP_DIR, Self::LOG_LEVEL, Self::SHUTDOWN, - Self::CLI_COLORS, + Self::SECRET_KEY, Self::TEMP_DIR, Self::LOG_LEVEL, Self::LOG_FORMAT, + Self::SHUTDOWN, Self::CLI_COLORS, ]; /// The stringy parameter name for setting/extracting [`Config::profile`]. diff --git a/core/lib/src/error.rs b/core/lib/src/error.rs index 8d8934f6f8..5f56af39af 100644 --- a/core/lib/src/error.rs +++ b/core/lib/src/error.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use figment::Profile; use crate::listener::Endpoint; -use crate::trace::Traceable; +use crate::trace::Trace; use crate::{Ignite, Orbit, Phase, Rocket}; /// An error that occurs during launch. diff --git a/core/lib/src/lifecycle.rs b/core/lib/src/lifecycle.rs index 26f17ed664..6dccd0580a 100644 --- a/core/lib/src/lifecycle.rs +++ b/core/lib/src/lifecycle.rs @@ -1,7 +1,7 @@ use futures::future::{FutureExt, Future}; use crate::{route, catcher, Rocket, Orbit, Request, Response, Data}; -use crate::trace::Traceable; +use crate::trace::Trace; use crate::util::Formatter; use crate::data::IoHandler; use crate::http::{Method, Status, Header}; diff --git a/core/lib/src/rocket.rs b/core/lib/src/rocket.rs index 5eb8c649e1..c2c047c555 100644 --- a/core/lib/src/rocket.rs +++ b/core/lib/src/rocket.rs @@ -11,7 +11,7 @@ use figment::{Figment, Provider}; use futures::TryFutureExt; use crate::shutdown::{Stages, Shutdown}; -use crate::trace::{Traceable, TraceableCollection}; +use crate::trace::{Trace, TraceAll}; use crate::{sentinel, shield::Shield, Catcher, Config, Route}; use crate::listener::{Bind, DefaultListener, Endpoint, Listener}; use crate::router::Router; @@ -247,7 +247,7 @@ impl Rocket { B::Error: fmt::Display, M: Fn(&Origin<'a>, T) -> T, F: Fn(&mut Self, T), - T: Clone + Traceable, + T: Clone + Trace, { let mut base = match base.clone().try_into() { Ok(origin) => origin.into_owned(), diff --git a/core/lib/src/server.rs b/core/lib/src/server.rs index 6820dda48a..7cf265289c 100644 --- a/core/lib/src/server.rs +++ b/core/lib/src/server.rs @@ -17,7 +17,7 @@ use crate::error::log_server_error; use crate::data::{IoStream, RawStream}; use crate::util::{spawn_inspect, FutureExt, ReaderStream}; use crate::http::Status; -use crate::trace::{Traceable, TraceableCollection}; +use crate::trace::{Trace, TraceAll}; type Result = std::result::Result; @@ -34,6 +34,7 @@ impl Rocket { upgrade: Option, connection: ConnectionMeta, ) -> Result>, http::Error> { + connection.trace_debug(); let request = ErasedRequest::new(self, parts, |rocket, parts| { Request::from_hyp(rocket, parts, connection).unwrap_or_else(|e| e) }); diff --git a/core/lib/src/trace/level.rs b/core/lib/src/trace/level.rs index 0c256b3cad..8b7079fc9c 100644 --- a/core/lib/src/trace/level.rs +++ b/core/lib/src/trace/level.rs @@ -10,7 +10,7 @@ pub fn serialize(level: &Option, s: S) -> Result>(de: D) -> Result, D::Error> { struct Visitor; - const E: &str = r#"one of "off", "error", "warn", "info", "debug", "trace", or a number 0-5"#; + const E: &str = r#"one of "off", "error", "warn", "info", "debug", "trace", or 0-5"#; impl<'de> de::Visitor<'de> for Visitor { type Value = Option; diff --git a/core/lib/src/trace/mod.rs b/core/lib/src/trace/mod.rs index 82de549621..12972da306 100644 --- a/core/lib/src/trace/mod.rs +++ b/core/lib/src/trace/mod.rs @@ -9,15 +9,24 @@ pub mod subscriber; pub(crate) mod level; #[doc(inline)] -pub use traceable::{Traceable, TraceableCollection}; +pub use traceable::{Trace, TraceAll}; #[doc(inline)] pub use macros::*; -pub fn init<'a, T: Into>>(_config: T) { - #[cfg(all(feature = "trace", debug_assertions))] - subscriber::RocketFmt::::init(_config.into()); +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)] +#[serde(crate = "rocket::serde")] +pub enum TraceFormat { + #[serde(rename = "pretty")] + #[serde(alias = "PRETTY")] + Pretty, + #[serde(rename = "compact")] + #[serde(alias = "COMPACT")] + Compact +} - #[cfg(all(feature = "trace", not(debug_assertions)))] - subscriber::RocketFmt::::init(_config.into()); +#[cfg_attr(nightly, doc(cfg(feature = "trace")))] +pub fn init<'a, T: Into>>(config: T) { + #[cfg(feature = "trace")] + crate::trace::subscriber::RocketDynFmt::init(config.into()) } diff --git a/core/lib/src/trace/subscriber/common.rs b/core/lib/src/trace/subscriber/common.rs index f99796555f..376abedf9d 100644 --- a/core/lib/src/trace/subscriber/common.rs +++ b/core/lib/src/trace/subscriber/common.rs @@ -1,27 +1,23 @@ use std::fmt; use std::cell::Cell; -use std::sync::OnceLock; -use tracing::{Level, Metadata}; use tracing::field::Field; - -use tracing_subscriber::prelude::*; -use tracing_subscriber::layer::Layered; -use tracing_subscriber::{reload, filter, Layer, Registry}; +use tracing::{Level, Metadata}; +use tracing_subscriber::filter; use tracing_subscriber::field::RecordFields; use thread_local::ThreadLocal; use yansi::{Condition, Paint, Style}; -use crate::config::{Config, CliColors}; -use crate::trace::subscriber::{RecordDisplay, RequestId, RequestIdLayer}; +use crate::config::CliColors; +use crate::trace::subscriber::RecordDisplay; use crate::util::Formatter; mod private { - pub trait FmtKind: Default + Copy + Send + Sync + 'static { } + pub trait FmtKind: Send + Sync + 'static { } - impl FmtKind for crate::trace::subscriber::Pretty {} - impl FmtKind for crate::trace::subscriber::Compact {} + impl FmtKind for crate::trace::subscriber::Pretty { } + impl FmtKind for crate::trace::subscriber::Compact { } } #[derive(Default)] @@ -32,9 +28,7 @@ pub struct RocketFmt { pub(crate) style: Style, } -pub type Handle = reload::Handle, Layered>; - -impl RocketFmt { +impl RocketFmt { pub(crate) fn state(&self) -> K { self.state.get_or_default().get() } @@ -45,33 +39,9 @@ impl RocketFmt { update(&mut old); cell.set(old); } +} - pub(crate) fn init_with(config: Option<&Config>, handle: &OnceLock>) - where Self: Layer> - { - // Do nothing if there's no config and we've already initialized. - if config.is_none() && handle.get().is_some() { - return; - } - - let workers = config.map(|c| c.workers).unwrap_or(num_cpus::get()); - let cli_colors = config.map(|c| c.cli_colors).unwrap_or(CliColors::Auto); - let log_level = config.map(|c| c.log_level).unwrap_or(Some(Level::INFO)); - - let formatter = RocketFmt::new(workers, cli_colors, log_level); - let (layer, reload_handle) = reload::Layer::new(formatter); - let result = tracing_subscriber::registry() - .with(RequestId::layer()) - .with(layer) - .try_init(); - - if result.is_ok() { - assert!(handle.set(reload_handle).is_ok()); - } if let Some(handle) = handle.get() { - assert!(handle.modify(|layer| layer.reset(cli_colors, log_level)).is_ok()); - } - } - +impl RocketFmt { pub fn new(workers: usize, cli_colors: CliColors, level: Option) -> Self { Self { state: ThreadLocal::with_capacity(workers), diff --git a/core/lib/src/trace/subscriber/compact.rs b/core/lib/src/trace/subscriber/compact.rs index 5dee0b03d4..4a01830cb1 100644 --- a/core/lib/src/trace/subscriber/compact.rs +++ b/core/lib/src/trace/subscriber/compact.rs @@ -1,21 +1,20 @@ -use std::num::NonZeroU64; - use std::fmt; -use std::sync::OnceLock; use std::time::Instant; +use std::num::NonZeroU64; -use time::OffsetDateTime; use tracing::{Event, Level, Metadata, Subscriber}; use tracing::span::{Attributes, Id, Record}; - use tracing_subscriber::layer::{Layer, Context}; use tracing_subscriber::registry::LookupSpan; use tracing_subscriber::field::RecordFields; +use time::OffsetDateTime; use yansi::{Paint, Painted}; use crate::util::Formatter; -use crate::trace::subscriber::{Data, Handle, RocketFmt}; +use crate::trace::subscriber::{Data, RocketFmt}; +use crate::http::{Status, StatusClass}; +use super::RecordDisplay; #[derive(Debug, Default, Copy, Clone)] pub struct Compact { @@ -27,6 +26,7 @@ pub struct Compact { pub struct RequestData { start: Instant, fields: Data, + item: Option<(String, String)>, } impl RequestData { @@ -34,17 +34,12 @@ impl RequestData { Self { start: Instant::now(), fields: Data::new(attrs), + item: None, } } } impl RocketFmt { - pub fn init(config: Option<&crate::Config>) { - static HANDLE: OnceLock> = OnceLock::new(); - - Self::init_with(config, &HANDLE); - } - fn request_span_id(&self) -> Option { self.state().request.map(Id::from_non_zero_u64) } @@ -69,8 +64,9 @@ impl RocketFmt { .then_some(meta.target()) .unwrap_or(meta.name()); + let pad = self.level.map_or(0, |lvl| lvl.as_str().len()); let timestamp = self.timestamp_for(OffsetDateTime::now_utc()); - Formatter(move |f| write!(f, "{} {:>5} {} ", + Formatter(move |f| write!(f, "{} {:>pad$} {} ", timestamp.paint(style).primary().dim(), meta.level().paint(style), name.paint(style).primary())) @@ -101,11 +97,17 @@ impl LookupSpan<'a>> Layer for RocketFmt { fn on_event(&self, event: &Event<'_>, ctxt: Context<'_, S>) { if let Some(id) = self.request_span_id() { - if event.metadata().name() == "response" { + let name = event.metadata().name(); + if name == "response" { let req_span = ctxt.span(&id).expect("on_event: req does not exist"); let mut exts = req_span.extensions_mut(); let data = exts.get_mut::().unwrap(); event.record(&mut data.fields); + } else if name == "catcher" || name == "route" { + let req_span = ctxt.span(&id).expect("on_event: req does not exist"); + let mut exts = req_span.extensions_mut(); + let data = exts.get_mut::().unwrap(); + data.item = event.find_map_display("name", |v| (name.into(), v.to_string())) } if !self.in_debug() { @@ -175,16 +177,49 @@ impl LookupSpan<'a>> Layer for RocketFmt { let datetime = OffsetDateTime::now_utc() - elapsed; let timestamp = self.timestamp_for(datetime); - let style = self.style(span.metadata()); + let s = self.style(span.metadata()); let prefix = self.prefix(span.metadata()); let chevron = self.chevron(span.metadata()); - - println!("{prefix}{chevron} ({} {}ms) {} {} => {}", - timestamp.paint(style).primary().dim(), + let arrow = "→".paint(s.primary().bright()); + + let status_class = data.fields["status"].parse().ok() + .and_then(Status::from_code) + .map(|status| status.class()); + + let status_style = match status_class { + Some(StatusClass::Informational) => s, + Some(StatusClass::Success) => s.green(), + Some(StatusClass::Redirection) => s.magenta(), + Some(StatusClass::ClientError) => s.yellow(), + Some(StatusClass::ServerError) => s.red(), + Some(StatusClass::Unknown) => s.cyan(), + None => s.primary(), + }; + + let autohandle = Formatter(|f| { + match data.fields.get("autohandled") { + Some("true") => write!(f, " {} {}", "via".paint(s.dim()), "GET".paint(s)), + _ => Ok(()) + } + }); + + let item = Formatter(|f| { + match &data.item { + Some((kind, name)) => write!(f, + "{} {} {arrow} ", + kind.paint(s), + name.paint(s.bold()), + ), + None => Ok(()) + } + }); + + println!("{prefix}{chevron} ({} {}ms) {}{autohandle} {} {arrow} {item}{}", + timestamp.paint(s).primary().dim(), elapsed.as_millis(), - &data.fields["method"].paint(style), + &data.fields["method"].paint(s), &data.fields["uri"], - &data.fields["status"], + &data.fields["status"].paint(status_style), ); } } diff --git a/core/lib/src/trace/subscriber/dynamic.rs b/core/lib/src/trace/subscriber/dynamic.rs new file mode 100644 index 0000000000..ed9b09e35e --- /dev/null +++ b/core/lib/src/trace/subscriber/dynamic.rs @@ -0,0 +1,96 @@ +use std::sync::OnceLock; + +use tracing::{Dispatch, Event, Level, Metadata}; +use tracing::subscriber::{Subscriber, Interest}; +use tracing::span::{Attributes, Id, Record}; +use tracing_subscriber::registry::{Registry, LookupSpan}; +use tracing_subscriber::layer::{Context, Layer, Layered, SubscriberExt}; +use tracing_subscriber::reload; +use tracing_subscriber::util::SubscriberInitExt; + +use crate::config::{Config, CliColors}; +use crate::trace::subscriber::{Compact, Pretty, RequestId, RequestIdLayer, RocketFmt}; +use crate::trace::TraceFormat; + +pub struct RocketDynFmt { + inner: either::Either, RocketFmt>, +} + +impl From> for RocketDynFmt { + fn from(value: RocketFmt) -> Self { + RocketDynFmt { inner: either::Either::Left(value) } + } +} + +impl From> for RocketDynFmt { + fn from(value: RocketFmt) -> Self { + RocketDynFmt { inner: either::Either::Right(value) } + } +} + +impl RocketDynFmt { + pub fn init(config: Option<&Config>) { + type Handle = reload::Handle>; + + static HANDLE: OnceLock = OnceLock::new(); + + // Do nothing if there's no config and we've already initialized. + if config.is_none() && HANDLE.get().is_some() { + return; + } + + let workers = config.map(|c| c.workers).unwrap_or(num_cpus::get()); + let colors = config.map(|c| c.cli_colors).unwrap_or(CliColors::Auto); + let level = config.map(|c| c.log_level).unwrap_or(Some(Level::INFO)); + let format = config.map(|c| c.log_format).unwrap_or(TraceFormat::Pretty); + + let formatter = |format| match format { + TraceFormat::Pretty => Self::from(RocketFmt::::new(workers, colors, level)), + TraceFormat::Compact => Self::from(RocketFmt::::new(workers, colors, level)), + }; + + let (layer, reload_handle) = reload::Layer::new(formatter(format)); + let result = tracing_subscriber::registry() + .with(RequestId::layer()) + .with(layer) + .try_init(); + + if result.is_ok() { + assert!(HANDLE.set(reload_handle).is_ok()); + } if let Some(handle) = HANDLE.get() { + assert!(handle.modify(|layer| *layer = formatter(format)).is_ok()); + } + } + + pub fn reset(&mut self, cli_colors: CliColors, level: Option) { + either::for_both!(&mut self.inner, f => f.reset(cli_colors, level)) + } +} + +macro_rules! forward { + ($T:ident => $(& $r:tt)? $method:ident ( $($p:ident : $t:ty),* ) $(-> $R:ty)?) => { + #[inline(always)] + fn $method(& $($r)? self $(, $p : $t)*) $(-> $R)? { + match & $($r)* self.inner { + either::Either::Left(layer) => Layer::<$T>::$method(layer, $($p),*), + either::Either::Right(layer) => Layer::<$T>::$method(layer, $($p),*), + } + } + }; +} + +impl LookupSpan<'a>> Layer for RocketDynFmt { + forward!(S => on_register_dispatch(subscriber: &Dispatch)); + forward!(S => &mut on_layer(subscriber: &mut S)); + forward!(S => register_callsite(metadata: &'static Metadata<'static>) -> Interest); + forward!(S => enabled(metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool); + forward!(S => on_new_span(attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>)); + forward!(S => on_record(_span: &Id, _values: &Record<'_>, _ctx: Context<'_, S>)); + forward!(S => on_follows_from(_span: &Id, _follows: &Id, _ctx: Context<'_, S>)); + forward!(S => event_enabled(_event: &Event<'_>, _ctx: Context<'_, S>) -> bool); + forward!(S => on_event(_event: &Event<'_>, _ctx: Context<'_, S>)); + forward!(S => on_enter(_id: &Id, _ctx: Context<'_, S>)); + forward!(S => on_exit(_id: &Id, _ctx: Context<'_, S>)); + forward!(S => on_close(_id: Id, _ctx: Context<'_, S>)); + forward!(S => on_id_change(_old: &Id, _new: &Id, _ctx: Context<'_, S>)); +} diff --git a/core/lib/src/trace/subscriber/mod.rs b/core/lib/src/trace/subscriber/mod.rs index ed2d71fb46..9990d4dad6 100644 --- a/core/lib/src/trace/subscriber/mod.rs +++ b/core/lib/src/trace/subscriber/mod.rs @@ -1,6 +1,7 @@ mod visit; mod pretty; mod compact; +mod dynamic; mod common; mod request_id; @@ -8,6 +9,6 @@ pub use pretty::Pretty; pub use compact::Compact; pub use common::RocketFmt; pub use request_id::{RequestId, RequestIdLayer}; +pub use dynamic::RocketDynFmt; -pub(crate) use common::Handle; pub(crate) use visit::{RecordDisplay, Data}; diff --git a/core/lib/src/trace/subscriber/pretty.rs b/core/lib/src/trace/subscriber/pretty.rs index c020b3f403..c914c6793a 100644 --- a/core/lib/src/trace/subscriber/pretty.rs +++ b/core/lib/src/trace/subscriber/pretty.rs @@ -1,18 +1,16 @@ use std::fmt; -use std::sync::OnceLock; +use tracing::field::Field; use tracing::{Event, Level, Metadata, Subscriber}; use tracing::span::{Attributes, Id, Record}; -use tracing::field::Field; - use tracing_subscriber::layer::{Layer, Context}; use tracing_subscriber::registry::LookupSpan; use tracing_subscriber::field::RecordFields; use yansi::{Paint, Painted}; -use crate::trace::subscriber::{Data, RecordDisplay, Handle, RocketFmt}; use crate::util::Formatter; +use crate::trace::subscriber::{Data, RecordDisplay, RocketFmt}; #[derive(Debug, Default, Copy, Clone)] pub struct Pretty { @@ -20,12 +18,6 @@ pub struct Pretty { } impl RocketFmt { - pub fn init(config: Option<&crate::Config>) { - static HANDLE: OnceLock> = OnceLock::new(); - - Self::init_with(config, &HANDLE); - } - fn indent(&self) -> &'static str { static INDENT: &[&str] = &["", " ", " "]; INDENT.get(self.state().depth as usize).copied().unwrap_or(" ") diff --git a/core/lib/src/trace/subscriber/visit.rs b/core/lib/src/trace/subscriber/visit.rs index eeafc312fd..2d4b5808ae 100644 --- a/core/lib/src/trace/subscriber/visit.rs +++ b/core/lib/src/trace/subscriber/visit.rs @@ -7,6 +7,7 @@ use tracing_subscriber::field::RecordFields; use crate::util::Formatter; pub trait RecordDisplay: RecordFields { + fn find_map_display T>(&self, name: &str, f: F) -> Option; fn record_display(&self, f: F); } @@ -53,6 +54,12 @@ impl Visit for Data { } impl RecordDisplay for T { + fn find_map_display V>(&self, name: &str, f: F) -> Option { + let mut value = None; + self.record_display(|field, item| if field.name() == name { value = Some(f(item)); }); + value + } + fn record_display(&self, f: F) { struct DisplayVisit(F); diff --git a/core/lib/src/trace/traceable.rs b/core/lib/src/trace/traceable.rs index e0334c0da4..6816241f09 100644 --- a/core/lib/src/trace/traceable.rs +++ b/core/lib/src/trace/traceable.rs @@ -1,5 +1,6 @@ use std::error::Error as StdError; +use crate::request::ConnectionMeta; use crate::sentinel::Sentry; use crate::util::Formatter; use crate::{route, Catcher, Config, Error, Request, Response, Route}; @@ -9,7 +10,7 @@ use figment::Figment; use rocket::http::Header; use tracing::Level; -pub trait Traceable { +pub trait Trace { fn trace(&self, level: Level); #[inline(always)] fn trace_info(&self) { self.trace(Level::INFO) } @@ -19,7 +20,7 @@ pub trait Traceable { #[inline(always)] fn trace_trace(&self) { self.trace(Level::TRACE) } } -pub trait TraceableCollection: Sized { +pub trait TraceAll: Sized { fn trace_all(self, level: Level); #[inline(always)] fn trace_all_info(self) { self.trace_all(Level::INFO) } @@ -29,20 +30,20 @@ pub trait TraceableCollection: Sized { #[inline(always)] fn trace_all_trace(self) { self.trace_all(Level::TRACE) } } -impl> TraceableCollection for I { +impl> TraceAll for I { fn trace_all(self, level: Level) { self.into_iter().for_each(|i| i.trace(level)) } } -impl Traceable for &T { +impl Trace for &T { #[inline(always)] fn trace(&self, level: Level) { T::trace(self, level) } } -impl Traceable for Figment { +impl Trace for Figment { fn trace(&self, level: Level) { for param in Config::PARAMETERS { if let Some(source) = self.find_metadata(param) { @@ -69,11 +70,12 @@ impl Traceable for Figment { } } -impl Traceable for Config { +impl Trace for Config { fn trace(&self, level: Level) { event! { level, "config", http2 = cfg!(feature = "http2"), log_level = self.log_level.map(|l| l.as_str()), + log_format = ?self.log_format, cli_colors = %self.cli_colors, workers = self.workers, max_blocking = self.max_blocking, @@ -130,7 +132,7 @@ impl Traceable for Config { } } -impl Traceable for Route { +impl Trace for Route { fn trace(&self, level: Level) { event! { level, "route", name = self.name.as_ref().map(|n| &**n), @@ -153,7 +155,7 @@ impl Traceable for Route { } } -impl Traceable for Catcher { +impl Trace for Catcher { fn trace(&self, level: Level) { event! { level, "catcher", name = self.name.as_ref().map(|n| &**n), @@ -167,19 +169,19 @@ impl Traceable for Catcher { } } -impl Traceable for &dyn crate::fairing::Fairing { +impl Trace for &dyn crate::fairing::Fairing { fn trace(&self, level: Level) { self.info().trace(level) } } -impl Traceable for crate::fairing::Info { +impl Trace for crate::fairing::Info { fn trace(&self, level: Level) { event!(level, "fairing", name = self.name, kind = %self.kind) } } -impl Traceable for figment::error::Kind { +impl Trace for figment::error::Kind { fn trace(&self, _: Level) { use figment::error::{OneOf as V, Kind::*}; @@ -200,7 +202,7 @@ impl Traceable for figment::error::Kind { } } -impl Traceable for figment::Error { +impl Trace for figment::Error { fn trace(&self, _: Level) { for e in self.clone() { let span = tracing::error_span! { @@ -218,13 +220,13 @@ impl Traceable for figment::Error { } } -impl Traceable for Header<'_> { +impl Trace for Header<'_> { fn trace(&self, level: Level) { event!(level, "header", name = self.name().as_str(), value = self.value()); } } -impl Traceable for route::Outcome<'_> { +impl Trace for route::Outcome<'_> { fn trace(&self, level: Level) { event!(level, "outcome", outcome = match self { @@ -241,19 +243,19 @@ impl Traceable for route::Outcome<'_> { } } -impl Traceable for Response<'_> { +impl Trace for Response<'_> { fn trace(&self, level: Level) { event!(level, "response", status = self.status().code); } } -impl Traceable for Error { +impl Trace for Error { fn trace(&self, level: Level) { self.kind.trace(level); } } -impl Traceable for Sentry { +impl Trace for Sentry { fn trace(&self, level: Level) { let (file, line, col) = self.location; event!(level, "sentry", @@ -263,13 +265,22 @@ impl Traceable for Sentry { } } -impl Traceable for Request<'_> { +impl Trace for Request<'_> { fn trace(&self, level: Level) { event!(level, "request", method = %self.method(), uri = %self.uri()) } } -impl Traceable for ErrorKind { +impl Trace for ConnectionMeta { + fn trace(&self, level: Level) { + event!(level, "connection", + endpoint = self.peer_endpoint.as_ref().map(display), + certs = self.peer_certs.is_some(), + ) + } +} + +impl Trace for ErrorKind { fn trace(&self, level: Level) { use ErrorKind::*; diff --git a/examples/fairings/src/main.rs b/examples/fairings/src/main.rs index 61208e778b..754a6965f3 100644 --- a/examples/fairings/src/main.rs +++ b/examples/fairings/src/main.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use rocket::{Rocket, Request, State, Data, Build}; use rocket::fairing::{self, AdHoc, Fairing, Info, Kind}; -use rocket::trace::Traceable; +use rocket::trace::Trace; use rocket::http::Method; struct Token(i64); diff --git a/examples/tls/src/redirector.rs b/examples/tls/src/redirector.rs index e38b4969b2..07bc4de814 100644 --- a/examples/tls/src/redirector.rs +++ b/examples/tls/src/redirector.rs @@ -8,7 +8,7 @@ use rocket::{route, Error, Request, Data, Route, Orbit, Rocket, Ignite}; use rocket::fairing::{Fairing, Info, Kind}; use rocket::response::Redirect; use rocket::listener::tcp::TcpListener; -use rocket::trace::Traceable; +use rocket::trace::Trace; #[derive(Debug, Clone, Copy, Default)] pub struct Redirector(u16); diff --git a/testbench/src/server.rs b/testbench/src/server.rs index 15c2119a01..9d014b175d 100644 --- a/testbench/src/server.rs +++ b/testbench/src/server.rs @@ -9,7 +9,7 @@ use rocket::fairing::AdHoc; use rocket::listener::{Bind, DefaultListener}; use rocket::serde::{Deserialize, DeserializeOwned, Serialize}; use rocket::{Build, Ignite, Rocket}; -use rocket::trace::Traceable; +use rocket::trace::Trace; use ipc_channel::ipc::{IpcOneShotServer, IpcReceiver, IpcSender};