From 7bc2fea0a4c944310c15a8c510ab7563597a978f Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Mon, 20 May 2024 23:50:38 -0500 Subject: [PATCH] wip: fix tracing macro exports --- contrib/dyn_templates/src/engine/tera.rs | 4 +- contrib/dyn_templates/src/fairing.rs | 2 +- contrib/dyn_templates/src/template.rs | 2 +- contrib/sync_db_pools/lib/src/connection.rs | 4 +- core/codegen/src/attribute/route/mod.rs | 21 ++-- core/lib/src/error.rs | 44 ++++---- core/lib/src/fairing/ad_hoc.rs | 2 +- core/lib/src/fairing/fairings.rs | 10 -- core/lib/src/rocket.rs | 10 +- core/lib/src/server.rs | 6 +- core/lib/src/shield/shield.rs | 8 +- core/lib/src/trace/macros.rs | 113 +++++++++++--------- core/lib/src/trace/traceable.rs | 9 +- examples/fairings/src/main.rs | 2 +- examples/tls/src/redirector.rs | 6 +- 15 files changed, 123 insertions(+), 120 deletions(-) diff --git a/contrib/dyn_templates/src/engine/tera.rs b/contrib/dyn_templates/src/engine/tera.rs index 10fb5f42d3..33817c38f4 100644 --- a/contrib/dyn_templates/src/engine/tera.rs +++ b/contrib/dyn_templates/src/engine/tera.rs @@ -21,7 +21,7 @@ impl Engine for Tera { // Finally try to tell Tera about all of the templates. if let Err(e) = tera.add_template_files(files) { - error_span!("Tera templating initialization failed" => { + span_error!("templating", "Tera templating initialization failed" => { let mut error = Some(&e as &dyn Error); while let Some(err) = error { error!("{err}"); @@ -48,7 +48,7 @@ impl Engine for Tera { match Tera::render(self, template, &tera_ctx) { Ok(string) => Some(string), Err(e) => { - error_span!("failed to render Tera template" [template] => { + span_error!("templating", template, "failed to render Tera template" => { let mut error = Some(&e as &dyn Error); while let Some(err) = error { error!("{err}"); diff --git a/contrib/dyn_templates/src/fairing.rs b/contrib/dyn_templates/src/fairing.rs index 4079de8a53..4f5199209e 100644 --- a/contrib/dyn_templates/src/fairing.rs +++ b/contrib/dyn_templates/src/fairing.rs @@ -57,7 +57,7 @@ impl Fairing for TemplateFairing { let cm = rocket.state::() .expect("Template ContextManager registered in on_ignite"); - info_span!("templating" => { + span_info!("templating" => { info!(directory = %Source::from(&*cm.context().root)); info!(engines = ?Engines::ENABLED_EXTENSIONS); }); diff --git a/contrib/dyn_templates/src/template.rs b/contrib/dyn_templates/src/template.rs index 3c92aa93f8..97a73b7b76 100644 --- a/contrib/dyn_templates/src/template.rs +++ b/contrib/dyn_templates/src/template.rs @@ -248,7 +248,7 @@ impl Template { })?; let value = self.value.map_err(|e| { - error_span!("template context failed to serialize" => e.trace_error()); + span_error!("templating", "template context failed to serialize" => e.trace_error()); Status::InternalServerError })?; diff --git a/contrib/sync_db_pools/lib/src/connection.rs b/contrib/sync_db_pools/lib/src/connection.rs index b5f030e54a..bd5c2b4b7c 100644 --- a/contrib/sync_db_pools/lib/src/connection.rs +++ b/contrib/sync_db_pools/lib/src/connection.rs @@ -68,7 +68,7 @@ impl ConnectionPool { let config = match Config::from(database, &rocket) { Ok(config) => config, Err(e) => { - error_span!("database configuration error" [database] => e.trace_error()); + span_error!("database configuration error", database => e.trace_error()); return Err(rocket); } }; @@ -82,7 +82,7 @@ impl ConnectionPool { _marker: PhantomData, })), Err(Error::Config(e)) => { - error_span!("database configuration error" [database] => e.trace_error()); + span_error!("database configuration error", database => e.trace_error()); Err(rocket) } Err(Error::Pool(reason)) => { diff --git a/core/codegen/src/attribute/route/mod.rs b/core/codegen/src/attribute/route/mod.rs index 734574bf55..3e9029e823 100644 --- a/core/codegen/src/attribute/route/mod.rs +++ b/core/codegen/src/attribute/route/mod.rs @@ -105,9 +105,10 @@ fn query_decls(route: &Route) -> Option { )* if !__e.is_empty() { - ::rocket::info_span!("query string failed to match route declaration" => { - for _err in __e { ::rocket::info!("{_err}"); } - }); + ::rocket::trace::span_info!("codegen", + "query string failed to match route declaration" => + { for _err in __e { ::rocket::trace::info!("{_err}"); } } + ); return #Outcome::Forward((#__data, #Status::UnprocessableEntity)); } @@ -127,7 +128,7 @@ fn request_guard_decl(guard: &Guard) -> TokenStream { let #ident: #ty = match <#ty as #FromRequest>::from_request(#__req).await { #Outcome::Success(__v) => __v, #Outcome::Forward(__e) => { - ::rocket::info!(name: "forward", parameter = stringify!(#ident), + ::rocket::trace::info!(name: "forward", parameter = stringify!(#ident), type_name = stringify!(#ty), status = __e.code, "request guard forwarding"); @@ -135,7 +136,7 @@ fn request_guard_decl(guard: &Guard) -> TokenStream { }, #[allow(unreachable_code)] #Outcome::Error((__c, __e)) => { - ::rocket::info!(name: "failure", parameter = stringify!(#ident), + ::rocket::trace::info!(name: "failure", parameter = stringify!(#ident), type_name = stringify!(#ty), reason = %#display_hack!(__e), "request guard failed"); @@ -154,7 +155,7 @@ fn param_guard_decl(guard: &Guard) -> TokenStream { // Returned when a dynamic parameter fails to parse. let parse_error = quote!({ - ::rocket::info!(name: "forward", parameter = #name, + ::rocket::trace::info!(name: "forward", parameter = #name, type_name = stringify!(#ty), reason = %#display_hack!(__error), "path guard forwarding"); @@ -172,7 +173,7 @@ fn param_guard_decl(guard: &Guard) -> TokenStream { #_Err(__error) => return #parse_error, }, #_None => { - ::rocket::error!( + ::rocket::trace::error!( "Internal invariant broken: dyn param {} not found.\n\ Please report this to the Rocket issue tracker.\n\ https://github.com/rwf2/Rocket/issues", #i); @@ -202,7 +203,7 @@ fn data_guard_decl(guard: &Guard) -> TokenStream { let #ident: #ty = match <#ty as #FromData>::from_data(#__req, #__data).await { #Outcome::Success(__d) => __d, #Outcome::Forward((__d, __e)) => { - ::rocket::info!(name: "forward", parameter = stringify!(#ident), + ::rocket::trace::info!(name: "forward", parameter = stringify!(#ident), type_name = stringify!(#ty), status = __e.code, "data guard forwarding"); @@ -210,7 +211,7 @@ fn data_guard_decl(guard: &Guard) -> TokenStream { } #[allow(unreachable_code)] #Outcome::Error((__c, __e)) => { - ::rocket::info!(name: "failure", parameter = stringify!(#ident), + ::rocket::trace::info!(name: "failure", parameter = stringify!(#ident), type_name = stringify!(#ty), reason = %#display_hack!(__e), "data guard failed"); @@ -246,7 +247,7 @@ fn internal_uri_macro_decl(route: &Route) -> TokenStream { /// Rocket generated URI macro. macro_rules! #inner_macro_name { ($($token:tt)*) => {{ - rocket::rocket_internal_uri!(#route_uri, (#(#uri_args),*), $($token)*) + ::rocket::rocket_internal_uri!(#route_uri, (#(#uri_args),*), $($token)*) }}; } diff --git a/core/lib/src/error.rs b/core/lib/src/error.rs index 5d84110f0c..05e955a625 100644 --- a/core/lib/src/error.rs +++ b/core/lib/src/error.rs @@ -7,8 +7,8 @@ use std::sync::Arc; use figment::Profile; use crate::listener::Endpoint; -use crate::trace::Trace; use crate::{Ignite, Orbit, Phase, Rocket}; +use crate::trace::Trace; /// An error that occurs during launch. /// @@ -84,7 +84,7 @@ impl Error { match result { Ok(_) => process::ExitCode::SUCCESS, Err(e) => { - error_span!("aborting launch due to error" => e.trace_error()); + span_error!("error", "aborting launch due to error" => e.trace_error()); process::ExitCode::SUCCESS } } @@ -200,14 +200,14 @@ impl fmt::Display for ServerError<'_> { pub(crate) fn log_server_error(error: &(dyn StdError + 'static)) { let mut error: &(dyn StdError + 'static) = error; if error.downcast_ref::().is_some() { - warn_span!("minor server error" ["{}", ServerError(error)] => { + span_warn!("request error", "{}", ServerError(error) => { while let Some(source) = error.source() { error = source; warn!("{}", ServerError(error)); } }); } else { - error_span!("server error" ["{}", ServerError(error)] => { + span_error!("server error", "{}", ServerError(error) => { while let Some(source) = error.source() { error = source; error!("{}", ServerError(error)); @@ -216,21 +216,6 @@ pub(crate) fn log_server_error(error: &(dyn StdError + 'static)) { } } -#[doc(hidden)] -#[macro_export] -macro_rules! display_hack { - ($v:expr) => ({ - #[allow(unused_imports)] - use $crate::error::display_hack_impl::{DisplayHack, DefaultDisplay as _}; - - #[allow(unreachable_code)] - DisplayHack($v).display() - }) -} - -#[doc(hidden)] -pub use display_hack as display_hack; - #[doc(hidden)] pub mod display_hack_impl { use super::*; @@ -238,9 +223,9 @@ pub mod display_hack_impl { /// The *magic*. /// - /// This type implements a `display()` method for all types that are either - /// `fmt::Display` _or_ `fmt::Debug`, using the former when available. It - /// does so by using a "specialization" hack: it has a blanket + /// This type implements a `display()` method using an internal `T` that is + /// either `fmt::Display` _or_ `fmt::Debug`, using the former when + /// available. It does so by using a "specialization" hack: it has a blanket /// DefaultDisplay trait impl for all types that are `fmt::Debug` and a /// "specialized" inherent impl for all types that are `fmt::Display`. /// @@ -271,3 +256,18 @@ pub mod display_hack_impl { } } } + +#[doc(hidden)] +#[macro_export] +macro_rules! display_hack { + ($v:expr) => ({ + #[allow(unused_imports)] + use $crate::error::display_hack_impl::{DisplayHack, DefaultDisplay as _}; + + #[allow(unreachable_code)] + DisplayHack($v).display() + }) +} + +#[doc(hidden)] +pub use display_hack as display_hack; diff --git a/core/lib/src/fairing/ad_hoc.rs b/core/lib/src/fairing/ad_hoc.rs index 58e985f959..7ce3042e74 100644 --- a/core/lib/src/fairing/ad_hoc.rs +++ b/core/lib/src/fairing/ad_hoc.rs @@ -2,8 +2,8 @@ use futures::future::{Future, BoxFuture, FutureExt}; use parking_lot::Mutex; use crate::route::RouteUri; -use crate::{Rocket, Request, Response, Data, Build, Orbit}; use crate::fairing::{Fairing, Kind, Info, Result}; +use crate::{Rocket, Request, Response, Data, Build, Orbit}; /// A ad-hoc fairing that can be created from a function or closure. /// diff --git a/core/lib/src/fairing/fairings.rs b/core/lib/src/fairing/fairings.rs index 0d50837277..16316c50e5 100644 --- a/core/lib/src/fairing/fairings.rs +++ b/core/lib/src/fairing/fairings.rs @@ -51,16 +51,6 @@ impl Fairings { iter!(self, self.active().collect::>().into_iter()) .map(|v| v.1) .collect() - // .into_iter() - // .map(|i| ) - // if !active_fairings.is_empty() { - // tracing::info_span!("fairings").in_scope(|| { - // for (_, fairing) in iter!(self, active_fairings.into_iter()) { - // let (name, kind) = (fairing.info().name, fairing.info().kind); - // info!(name: "fairing", name, %kind) - // } - // }); - // } } pub fn add(&mut self, fairing: Box) { diff --git a/core/lib/src/rocket.rs b/core/lib/src/rocket.rs index 7ffff42ad0..26d28292d4 100644 --- a/core/lib/src/rocket.rs +++ b/core/lib/src/rocket.rs @@ -234,7 +234,7 @@ impl Rocket { // are visible; we use the final config to set a max log-level in ignite self.figment = Figment::from(provider); crate::trace::init(Config::try_from(&self.figment).ok().as_ref()); - trace_span!("reconfigure" => self.figment().trace_trace()); + span_trace!("reconfigure" => self.figment().trace_trace()); self } @@ -564,14 +564,14 @@ impl Rocket { // Log everything we know: config, routes, catchers, fairings. // TODO: Store/print managed state type names? let fairings = self.fairings.unique_set(); - info_span!("config" [profile = %self.figment().profile()] => { + span_info!("config", profile = %self.figment().profile() => { config.trace_info(); self.figment().trace_debug(); }); - info_span!("routes" [count = self.routes.len()] => self.routes().trace_all_info()); - info_span!("catchers" [count = self.catchers.len()] => self.catchers().trace_all_info()); - info_span!("fairings" [count = fairings.len()] => fairings.trace_all_info()); + span_info!("routes", count = self.routes.len() => self.routes().trace_all_info()); + span_info!("catchers", count = self.catchers.len() => self.catchers().trace_all_info()); + span_info!("fairings", count = fairings.len() => fairings.trace_all_info()); // Ignite the rocket. let rocket: Rocket = Rocket(Igniting { diff --git a/core/lib/src/server.rs b/core/lib/src/server.rs index 7cf265289c..badfb44c95 100644 --- a/core/lib/src/server.rs +++ b/core/lib/src/server.rs @@ -39,7 +39,7 @@ impl Rocket { Request::from_hyp(rocket, parts, connection).unwrap_or_else(|e| e) }); - debug_span!("request headers" => request.inner().headers().iter().trace_all_debug()); + span_debug!("request headers" => request.inner().headers().iter().trace_all_debug()); let mut response = request.into_response( stream, |rocket, request, data| Box::pin(rocket.preprocess(request, data)), @@ -54,7 +54,7 @@ impl Rocket { // TODO: Should upgrades be handled in dispatch? response.inner().trace_info(); - debug_span!("response headers" => response.inner().headers().iter().trace_all_debug()); + span_debug!("response headers" => response.inner().headers().iter().trace_all_debug()); let io_handler = response.make_io_handler(Rocket::extract_io_handler); if let (Some((proto, handler)), Some(upgrade)) = (io_handler, upgrade) { let upgrade = upgrade.map_ok(IoStream::from).map_err(io::Error::other); @@ -92,7 +92,7 @@ async fn io_handler_task(proto: String, stream: S, mut handler: ErasedIoHandl Err(e) => return warn!(error = %e, "i/o upgrade failed"), }; - info!("i/o upgrade succeeded"); + debug!("i/o upgrade succeeded"); if let Err(e) = handler.take().io(stream).await { match e.kind() { io::ErrorKind::BrokenPipe => warn!("i/o handler closed"), diff --git a/core/lib/src/shield/shield.rs b/core/lib/src/shield/shield.rs index 905f37d3b9..9ffbad8666 100644 --- a/core/lib/src/shield/shield.rs +++ b/core/lib/src/shield/shield.rs @@ -4,8 +4,8 @@ use std::sync::atomic::{AtomicBool, Ordering}; use crate::{Rocket, Request, Response, Orbit, Config}; use crate::fairing::{Fairing, Info, Kind}; use crate::http::{Header, uncased::UncasedStr}; -use crate::shield::*; -use crate::trace::*; +use crate::shield::{Frame, Hsts, NoSniff, Permission, Policy}; +use crate::trace::{Trace, TraceAll}; /// A [`Fairing`] that injects browser security and privacy headers into all /// outgoing responses. @@ -195,7 +195,7 @@ impl Fairing for Shield { self.force_hsts.store(true, Ordering::Release); } - info_span!("shield" [policies = self.policies.len()] => { + span_info!("shield", policies = self.policies.len() => { self.policies.values().trace_all_info(); if force_hsts { @@ -211,7 +211,7 @@ impl Fairing for Shield { // the header is not already in the response. for header in self.policies.values() { if response.headers().contains(header.name()) { - warn_span!("shield refusing to overwrite existing response header" => { + span_warn!("shield", "shield refusing to overwrite existing response header" => { header.trace_warn(); }); diff --git a/core/lib/src/trace/macros.rs b/core/lib/src/trace/macros.rs index d1296fea49..eafa7c4164 100644 --- a/core/lib/src/trace/macros.rs +++ b/core/lib/src/trace/macros.rs @@ -1,58 +1,71 @@ macro_rules! declare_span_macro { - ($($name:ident $level:ident),* $(,)?) => ( - $(declare_span_macro!([$] $name $level);)* + ($name:ident $level:ident) => ( + declare_span_macro!([$] $name $level); ); ([$d:tt] $name:ident $level:ident) => ( #[doc(hidden)] #[macro_export] macro_rules! $name { - ($n:literal $d ([ $d ($f:tt)* ])? => $in_scope:expr) => ({ - $crate::tracing::span!($crate::tracing::Level::$level, $n $d (, $d ($f)* )?) + (@[$d ($t:tt)+] => $in_scope:expr) => ({ + $crate::tracing::span!($crate::tracing::Level::$level, $d ($t)+) .in_scope(|| $in_scope); - }) + }); + + (@[$d ($t:tt)+] $token:tt $d ($rest:tt)*) => ({ + $crate::trace::$name!(@[$d ($t)+ $token] $d ($rest)*); + }); + + // base case + ($t:tt $d ($rest:tt)*) => ({ + $crate::trace::$name!(@[$t] $d ($rest)*); + }); } - #[doc(inline)] + #[doc(hidden)] pub use $name as $name; ); } -// FIXME: Maybe we should just use the `tracing` macros directly. Or at least -// make these compatible with the syntax of the `tracing` macros. -declare_span_macro!( - error_span ERROR, - warn_span WARN, - info_span INFO, - trace_span TRACE, - debug_span DEBUG, -); +#[doc(hidden)] +#[macro_export] +macro_rules! event { + ($level:expr, $($args:tt)*) => {{ + match $level { + $crate::tracing::Level::ERROR => event!(@$crate::tracing::Level::ERROR, $($args)*), + $crate::tracing::Level::WARN => event!(@$crate::tracing::Level::WARN, $($args)*), + $crate::tracing::Level::INFO => event!(@$crate::tracing::Level::INFO, $($args)*), + $crate::tracing::Level::DEBUG => event!(@$crate::tracing::Level::DEBUG, $($args)*), + $crate::tracing::Level::TRACE => event!(@$crate::tracing::Level::TRACE, $($args)*), + } + }}; -macro_rules! declare_macro { - ($($name:ident $level:ident),* $(,)?) => ( - $(declare_macro!([$] $name $level);)* + (@$level:expr, $n:expr, $($args:tt)*) => {{ + $crate::tracing::event!(name: $n, target: concat!("rocket::", $n), $level, $($args)*); + }}; +} + +// Re-exports the macro at $path with the name $name. The point is to allow +// a `#[macro_use] extern crate rocket` to also automatically import the +// relevant tracing macros. +macro_rules! reexport { + ($path:ident::$name:ident) => ( + reexport!([$] $path::$name); ); - ([$d:tt] $name:ident $level:ident) => ( + ([ $d:tt ] $path:ident::$name:ident) => { #[doc(hidden)] #[macro_export] macro_rules! $name { - ($d ($t:tt)*) => ($crate::tracing::$level!($d ($t)*)); + ($d ($f:tt)*) => { + $crate::$path::$name!($d ($f)*) + } } - - // pub use $name as $name; - ); + }; } -// FIXME: These are confusing. We should probably just use the `tracing` macros. -declare_macro!( - error error, - info info, - trace trace, - debug debug, - warn warn -); - +#[doc(hidden)] +#[macro_export] macro_rules! span { ($level:expr, $($args:tt)*) => {{ match $level { @@ -70,24 +83,26 @@ macro_rules! span { }}; } -// FIXME: We shouldn't export this. -#[doc(hidden)] -#[macro_export] -macro_rules! event { - ($level:expr, $($args:tt)*) => {{ - match $level { - $crate::tracing::Level::ERROR => event!(@$crate::tracing::Level::ERROR, $($args)*), - $crate::tracing::Level::WARN => event!(@$crate::tracing::Level::WARN, $($args)*), - $crate::tracing::Level::INFO => event!(@$crate::tracing::Level::INFO, $($args)*), - $crate::tracing::Level::DEBUG => event!(@$crate::tracing::Level::DEBUG, $($args)*), - $crate::tracing::Level::TRACE => event!(@$crate::tracing::Level::TRACE, $($args)*), - } - }}; +#[doc(inline)] +pub use span as span; - (@$level:expr, $n:expr, $($args:tt)*) => {{ - $crate::tracing::event!(name: $n, target: concat!("rocket::", $n), $level, $($args)*); - }}; -} +declare_span_macro!(span_error ERROR); +declare_span_macro!(span_warn WARN); +declare_span_macro!(span_info INFO); +declare_span_macro!(span_debug DEBUG); +declare_span_macro!(span_trace TRACE); #[doc(inline)] pub use event as event; + +reexport!(tracing::error); +reexport!(tracing::warn); +reexport!(tracing::info); +reexport!(tracing::debug); +reexport!(tracing::trace); + +#[doc(hidden)] pub use tracing::error; +#[doc(hidden)] pub use tracing::warn; +#[doc(hidden)] pub use tracing::info; +#[doc(hidden)] pub use tracing::debug; +#[doc(hidden)] pub use tracing::trace; diff --git a/core/lib/src/trace/traceable.rs b/core/lib/src/trace/traceable.rs index 572ecb5ba4..bbf11fa01b 100644 --- a/core/lib/src/trace/traceable.rs +++ b/core/lib/src/trace/traceable.rs @@ -216,17 +216,14 @@ impl Trace for figment::error::Kind { impl Trace for figment::Error { fn trace(&self, _: Level) { for e in self.clone() { - let span = tracing::error_span! { - "config", + span_error!("config", key = (!e.path.is_empty()).then_some(&e.path).and_then(|path| { let (profile, metadata) = (e.profile.as_ref()?, e.metadata.as_ref()?); Some(metadata.interpolate(profile, path)) }), source.name = e.metadata.as_ref().map(|m| &*m.name), - source.source = e.metadata.as_ref().and_then(|m| m.source.as_ref()).map(display), - }; - - span.in_scope(|| e.kind.trace_error()); + source.source = e.metadata.as_ref().and_then(|m| m.source.as_ref()).map(display) + => e.kind.trace_error()); } } } diff --git a/examples/fairings/src/main.rs b/examples/fairings/src/main.rs index 754a6965f3..0e826a1c69 100644 --- a/examples/fairings/src/main.rs +++ b/examples/fairings/src/main.rs @@ -76,7 +76,7 @@ fn rocket() -> _ { .attach(AdHoc::on_request("PUT Rewriter", |req, _| { Box::pin(async move { if req.uri().path() == "/" { - info_span!("PUT rewriter" => { + span_info!("PUT rewriter" => { req.trace_info(); info!("changing method to `PUT`"); req.set_method(Method::Put); diff --git a/examples/tls/src/redirector.rs b/examples/tls/src/redirector.rs index 07bc4de814..2e4a5ce320 100644 --- a/examples/tls/src/redirector.rs +++ b/examples/tls/src/redirector.rs @@ -45,7 +45,7 @@ impl Redirector { pub async fn try_launch(self, config: Config) -> Result, Error> { use rocket::http::Method::*; - rocket::info_span!("HTTP -> HTTPS Redirector" => { + rocket::span_info!("HTTP -> HTTPS Redirector" => { info!(from = self.0, to = config.tls_addr.port(), "redirecting"); }); @@ -75,7 +75,7 @@ impl Fairing for Redirector { async fn on_liftoff(&self, rocket: &Rocket) { let Some(tls_addr) = rocket.endpoints().find_map(|e| e.tls()?.tcp()) else { - rocket::warn_span!("HTTP -> HTTPS Redirector" => { + rocket::span_warn!("HTTP -> HTTPS Redirector" => { warn!("Main instance is not being served over TLS/TCP.\n\ Redirector refusing to start."); }); @@ -95,7 +95,7 @@ impl Fairing for Redirector { let shutdown = rocket.shutdown(); rocket::tokio::spawn(async move { if let Err(e) = this.try_launch(config).await { - error_span!("failed to start HTTP -> HTTPS redirector" => { + span_error!("HTTP -> HTTPS Redirector", "failed to start" => { e.trace_error(); info!("shutting down main instance"); });