mirror of https://github.com/rwf2/Rocket.git
Allow dynamic selection of log format.
This commit is contained in:
parent
cc2b159e85
commit
45264de8c9
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<Level>,
|
||||
/// 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`].
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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<Build> {
|
|||
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(),
|
||||
|
|
|
@ -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<T, E = crate::Error> = std::result::Result<T, E>;
|
||||
|
||||
|
@ -34,6 +34,7 @@ impl Rocket<Orbit> {
|
|||
upgrade: Option<hyper::upgrade::OnUpgrade>,
|
||||
connection: ConnectionMeta,
|
||||
) -> Result<hyper::Response<ReaderStream<ErasedResponse>>, http::Error> {
|
||||
connection.trace_debug();
|
||||
let request = ErasedRequest::new(self, parts, |rocket, parts| {
|
||||
Request::from_hyp(rocket, parts, connection).unwrap_or_else(|e| e)
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ pub fn serialize<S: Serializer>(level: &Option<Level>, s: S) -> Result<S::Ok, S:
|
|||
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<Option<Level>, 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<Level>;
|
||||
|
|
|
@ -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<Option<&'a crate::Config>>>(_config: T) {
|
||||
#[cfg(all(feature = "trace", debug_assertions))]
|
||||
subscriber::RocketFmt::<subscriber::Pretty>::init(_config.into());
|
||||
|
||||
#[cfg(all(feature = "trace", not(debug_assertions)))]
|
||||
subscriber::RocketFmt::<subscriber::Compact>::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_attr(nightly, doc(cfg(feature = "trace")))]
|
||||
pub fn init<'a, T: Into<Option<&'a crate::Config>>>(config: T) {
|
||||
#[cfg(feature = "trace")]
|
||||
crate::trace::subscriber::RocketDynFmt::init(config.into())
|
||||
}
|
||||
|
|
|
@ -1,24 +1,20 @@
|
|||
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 { }
|
||||
|
@ -32,9 +28,7 @@ pub struct RocketFmt<K: private::FmtKind> {
|
|||
pub(crate) style: Style,
|
||||
}
|
||||
|
||||
pub type Handle<K> = reload::Handle<RocketFmt<K>, Layered<RequestIdLayer, Registry>>;
|
||||
|
||||
impl<K: private::FmtKind> RocketFmt<K> {
|
||||
impl<K: private::FmtKind + Default + Copy> RocketFmt<K> {
|
||||
pub(crate) fn state(&self) -> K {
|
||||
self.state.get_or_default().get()
|
||||
}
|
||||
|
@ -45,33 +39,9 @@ impl<K: private::FmtKind> RocketFmt<K> {
|
|||
update(&mut old);
|
||||
cell.set(old);
|
||||
}
|
||||
|
||||
pub(crate) fn init_with(config: Option<&Config>, handle: &OnceLock<Handle<K>>)
|
||||
where Self: Layer<Layered<RequestIdLayer, Registry>>
|
||||
{
|
||||
// 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<K: private::FmtKind> RocketFmt<K> {
|
||||
pub fn new(workers: usize, cli_colors: CliColors, level: Option<Level>) -> Self {
|
||||
Self {
|
||||
state: ThreadLocal::with_capacity(workers),
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
use std::fmt;
|
||||
use std::time::Instant;
|
||||
use std::num::NonZeroU64;
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::OnceLock;
|
||||
use std::time::Instant;
|
||||
|
||||
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<Compact> {
|
||||
pub fn init(config: Option<&crate::Config>) {
|
||||
static HANDLE: OnceLock<Handle<Compact>> = OnceLock::new();
|
||||
|
||||
Self::init_with(config, &HANDLE);
|
||||
}
|
||||
|
||||
fn request_span_id(&self) -> Option<Id> {
|
||||
self.state().request.map(Id::from_non_zero_u64)
|
||||
}
|
||||
|
@ -69,8 +64,9 @@ impl RocketFmt<Compact> {
|
|||
.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<S: Subscriber + for<'a> LookupSpan<'a>> Layer<S> for RocketFmt<Compact> {
|
|||
|
||||
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::<RequestData>().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::<RequestData>().unwrap();
|
||||
data.item = event.find_map_display("name", |v| (name.into(), v.to_string()))
|
||||
}
|
||||
|
||||
if !self.in_debug() {
|
||||
|
@ -175,16 +177,49 @@ impl<S: Subscriber + for<'a> LookupSpan<'a>> Layer<S> for RocketFmt<Compact> {
|
|||
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());
|
||||
let arrow = "→".paint(s.primary().bright());
|
||||
|
||||
println!("{prefix}{chevron} ({} {}ms) {} {} => {}",
|
||||
timestamp.paint(style).primary().dim(),
|
||||
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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Compact>, RocketFmt<Pretty>>,
|
||||
}
|
||||
|
||||
impl From<RocketFmt<Compact>> for RocketDynFmt {
|
||||
fn from(value: RocketFmt<Compact>) -> Self {
|
||||
RocketDynFmt { inner: either::Either::Left(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RocketFmt<Pretty>> for RocketDynFmt {
|
||||
fn from(value: RocketFmt<Pretty>) -> Self {
|
||||
RocketDynFmt { inner: either::Either::Right(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl RocketDynFmt {
|
||||
pub fn init(config: Option<&Config>) {
|
||||
type Handle = reload::Handle<RocketDynFmt, Layered<RequestIdLayer, Registry>>;
|
||||
|
||||
static HANDLE: OnceLock<Handle> = 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::<Pretty>::new(workers, colors, level)),
|
||||
TraceFormat::Compact => Self::from(RocketFmt::<Compact>::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<Level>) {
|
||||
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<S: Subscriber + for<'a> LookupSpan<'a>> Layer<S> 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>));
|
||||
}
|
|
@ -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};
|
||||
|
|
|
@ -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<Pretty> {
|
||||
pub fn init(config: Option<&crate::Config>) {
|
||||
static HANDLE: OnceLock<Handle<Pretty>> = 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(" ")
|
||||
|
|
|
@ -7,6 +7,7 @@ use tracing_subscriber::field::RecordFields;
|
|||
use crate::util::Formatter;
|
||||
|
||||
pub trait RecordDisplay: RecordFields {
|
||||
fn find_map_display<T, F: Fn(&dyn fmt::Display) -> T>(&self, name: &str, f: F) -> Option<T>;
|
||||
fn record_display<F: FnMut(&Field, &dyn fmt::Display)>(&self, f: F);
|
||||
}
|
||||
|
||||
|
@ -53,6 +54,12 @@ impl Visit for Data {
|
|||
}
|
||||
|
||||
impl<T: RecordFields> RecordDisplay for T {
|
||||
fn find_map_display<V, F: Fn(&dyn fmt::Display) -> V>(&self, name: &str, f: F) -> Option<V> {
|
||||
let mut value = None;
|
||||
self.record_display(|field, item| if field.name() == name { value = Some(f(item)); });
|
||||
value
|
||||
}
|
||||
|
||||
fn record_display<F: FnMut(&Field, &dyn fmt::Display)>(&self, f: F) {
|
||||
struct DisplayVisit<F>(F);
|
||||
|
||||
|
|
|
@ -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<T: Traceable, I: IntoIterator<Item = T>> TraceableCollection for I {
|
||||
impl<T: Trace, I: IntoIterator<Item = T>> TraceAll for I {
|
||||
fn trace_all(self, level: Level) {
|
||||
self.into_iter().for_each(|i| i.trace(level))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Traceable> Traceable for &T {
|
||||
impl<T: Trace> 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::*;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
Loading…
Reference in New Issue