Skip to content

Commit

Permalink
wip: formatting subscriber
Browse files Browse the repository at this point in the history
  • Loading branch information
SergioBenitez committed May 7, 2024
1 parent 75f8b12 commit 282139d
Show file tree
Hide file tree
Showing 14 changed files with 447 additions and 270 deletions.
4 changes: 2 additions & 2 deletions core/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ uuid = ["uuid_", "rocket_http/uuid"]
tls = ["rustls", "tokio-rustls", "rustls-pemfile"]
mtls = ["tls", "x509-parser"]
tokio-macros = ["tokio/macros"]
trace = ["tracing-subscriber", "rustls?/logging", "tokio-rustls?/logging", "multer/log"]
trace = ["tracing-subscriber", "tinyvec", "rustls?/logging", "tokio-rustls?/logging", "multer/log"]

[dependencies]
# Optional serialization dependencies.
Expand Down Expand Up @@ -86,7 +86,7 @@ state = "0.6"

# tracing
tracing = { version = "0.1.40", default-features = false, features = ["std", "attributes"] }
# tracing-futures = { version = "0.2", default-features = false, features = ["std-future"] }
tinyvec = { version = "1.6", optional = true, features = ["std", "rustc_1_57"] }

[dependencies.tracing-subscriber]
version = "0.3.18"
Expand Down
240 changes: 97 additions & 143 deletions core/lib/src/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@ use figment::{Figment, Profile, Provider, Metadata, error::Result};
use figment::providers::{Serialized, Env, Toml, Format};
use figment::value::{Map, Dict, magic::RelativePathBuf};
use serde::{Deserialize, Serialize};
use yansi::{Paint, Style, Color::Primary};
use tracing::{level_filters::LevelFilter, Level};
use tracing::Level;

// use crate::log::PaintExt;
// use crate::config::{LogLevel, ShutdownConfig, Ident, CliColors};
#[cfg(feature = "secrets")]
use crate::config::SecretKey;
use crate::config::{ShutdownConfig, Ident, CliColors};
use crate::request::{self, Request, FromRequest};
use crate::http::uncased::Uncased;
use crate::data::Limits;

#[cfg(feature = "secrets")]
use crate::config::SecretKey;
use crate::util::Formatter;

/// Rocket server configuration.
///
Expand Down Expand Up @@ -166,15 +163,6 @@ impl Default for Config {
}

impl Config {
const DEPRECATED_KEYS: &'static [(&'static str, Option<&'static str>)] = &[
("env", Some(Self::PROFILE)), ("log", Some(Self::LOG_LEVEL)),
("read_timeout", None), ("write_timeout", None),
];

const DEPRECATED_PROFILES: &'static [(&'static str, Option<&'static str>)] = &[
("dev", Some("debug")), ("prod", Some("release")), ("stag", None)
];

/// Returns the default configuration for the `debug` profile, _irrespective
/// of the Rust compilation profile_ and `ROCKET_PROFILE`.
///
Expand Down Expand Up @@ -317,7 +305,7 @@ impl Config {
}

#[cfg(feature = "secrets")]
pub(crate) fn known_secret_key_used(&self) -> bool {
fn known_secret_key_used(&self) -> bool {
const KNOWN_SECRET_KEYS: &[&str] = &[
"hPRYyVRiMyxpw5sBB1XeCMN1kFsDCqKvBi2QJxBVHQk="
];
Expand All @@ -328,93 +316,82 @@ impl Config {
})
}

#[inline]
pub(crate) fn trace_print(&self, figment: &Figment) {
// if self.log_level != LogLevel::Debug {
// return;
// }
#[tracing::instrument(name = "config", skip_all, fields(profile = %figment.profile()))]
pub(crate) fn pretty_print(&self, figment: &Figment) {
info! {
name: "values",
http2 = cfg!(feature = "http2"),
log_level = self.log_level.map(|l| l.as_str()),
cli_colors = %self.cli_colors,
workers = self.workers,
max_blocking = self.max_blocking,
ident = %self.ident,
ip_header = self.ip_header.as_ref().map(|s| s.as_str()),
proxy_proto_header = self.proxy_proto_header.as_ref().map(|s| s.as_str()),
limits = %Formatter(|f| f.debug_map()
.entries(self.limits.limits.iter().map(|(k, v)| (k.as_str(), v.to_string())))
.finish()),
temp_dir = %self.temp_dir.relative().display(),
keep_alive = (self.keep_alive != 0).then_some(self.keep_alive),
shutdown.ctrlc = self.shutdown.ctrlc,
shutdown.signals = %{
#[cfg(not(unix))] {
"disabled (not unix)"
}

#[cfg(unix)] {
Formatter(|f| f.debug_set()
.entries(self.shutdown.signals.iter().map(|s| s.as_str()))
.finish())
}
},
shutdown.grace = self.shutdown.grace,
shutdown.mercy = self.shutdown.mercy,
shutdown.force = self.shutdown.force,
};

trace!("-- configuration trace information --");
for param in Self::PARAMETERS {
if let Some(meta) = figment.find_metadata(param) {
let (param, name) = (param.blue(), meta.name.primary());
if let Some(ref source) = meta.source {
trace_!("{:?} parameter source: {} ({})", param, name, source);
} else {
trace_!("{:?} parameter source: {}", param, name);
if let Some(source) = figment.find_metadata(param) {
trace! {
param,
%source.name,
source.source = source.source.as_ref().map(|s| s.to_string()),
}
}
}
}

pub(crate) fn pretty_print(&self, figment: &Figment) {
static VAL: Style = Primary.bold();

self.trace_print(figment);
launch_meta!("{}Configured for {}.", "🔧 ".emoji(), self.profile.underline());
launch_meta_!("workers: {}", self.workers.paint(VAL));
launch_meta_!("max blocking threads: {}", self.max_blocking.paint(VAL));
launch_meta_!("ident: {}", self.ident.paint(VAL));

match self.ip_header {
Some(ref name) => launch_meta_!("IP header: {}", name.paint(VAL)),
None => launch_meta_!("IP header: {}", "disabled".paint(VAL))
}

match self.proxy_proto_header.as_ref() {
Some(name) => launch_meta_!("Proxy-Proto header: {}", name.paint(VAL)),
None => launch_meta_!("Proxy-Proto header: {}", "disabled".paint(VAL))
}

launch_meta_!("limits: {}", self.limits.paint(VAL));
launch_meta_!("temp dir: {}", self.temp_dir.relative().display().paint(VAL));
launch_meta_!("http/2: {}", (cfg!(feature = "http2").paint(VAL)));

match self.keep_alive {
0 => launch_meta_!("keep-alive: {}", "disabled".paint(VAL)),
ka => launch_meta_!("keep-alive: {}{}", ka.paint(VAL), "s".paint(VAL)),
}

launch_meta_!("shutdown: {}", self.shutdown.paint(VAL));
launch_meta_!("log level: {}", LevelFilter::from(self.log_level).paint(VAL));
launch_meta_!("cli colors: {}", self.cli_colors.paint(VAL));

// Check for now deprecated config values.
for (key, replacement) in Self::DEPRECATED_KEYS {
if let Some(md) = figment.find_metadata(key) {
warn!("found value for deprecated config key `{}`", key.paint(VAL));
if let Some(ref source) = md.source {
launch_meta_!("in {} {}", source.paint(VAL), md.name);
}

if let Some(new_key) = replacement {
launch_meta_!("key has been by replaced by `{}`", new_key.paint(VAL));
} else {
launch_meta_!("key has no special meaning");
if let Some(source) = figment.find_metadata(key) {
warn! {
name: "deprecated",
key,
replacement,
%source.name,
source.source = source.source.as_ref().map(|s| s.to_string()),
"config key `{key}` is deprecated and has no meaning"
}
}
}

// Check for now removed config values.
for (prefix, replacement) in Self::DEPRECATED_PROFILES {
if let Some(profile) = figment.profiles().find(|p| p.starts_with(prefix)) {
warn!("found set deprecated profile `{}`", profile.paint(VAL));

if let Some(new_profile) = replacement {
launch_meta_!("profile was replaced by `{}`", new_profile.paint(VAL));
} else {
launch_meta_!("profile `{}` has no special meaning", profile);
#[cfg(feature = "secrets")] {
if !self.secret_key.is_provided() {
warn! {
name: "volatile_secret_key",
"secrets enabled without configuring a stable `secret_key`; \
private/signed cookies will become unreadable after restarting; \
disable the `secrets` feature or configure a `secret_key`; \
this becomes a hard error in non-debug profiles",
}
}
}

#[cfg(feature = "secrets")] {
launch_meta_!("secret key: {}", self.secret_key.paint(VAL));
if !self.secret_key.is_provided() {
warn!("secrets enabled without configuring a stable `secret_key`");
warn_!("private/signed cookies will become unreadable after restarting");
launch_meta_!("disable the `secrets` feature or configure a `secret_key`");
launch_meta_!("this becomes a {} in non-debug profiles", "hard error".red());
if self.known_secret_key_used() {
warn! {
name: "insecure_secret_key",
"The configured `secret_key` is exposed and insecure. \
The configured key is publicly published and thus insecure. \
Try generating a new key with `head -c64 /dev/urandom | base64`."
}
}
}
}
Expand Down Expand Up @@ -487,6 +464,13 @@ impl Config {
Self::SECRET_KEY, Self::TEMP_DIR, Self::LOG_LEVEL, Self::SHUTDOWN,
Self::CLI_COLORS,
];

/// An array of deprecated stringy parameter names.
const DEPRECATED_KEYS: &'static [(&'static str, Option<&'static str>)] = &[
("env", Some(Self::PROFILE)), ("log", Some(Self::LOG_LEVEL)),
("read_timeout", None), ("write_timeout", None),
];

}

impl Provider for Config {
Expand Down Expand Up @@ -537,63 +521,33 @@ pub fn bail_with_config_error<T>(error: figment::Error) -> T {

#[doc(hidden)]
pub fn pretty_print_error(error: figment::Error) {
use figment::error::{Kind, OneOf};
use figment::error::{OneOf as V, Kind::*};

// crate::log::init_default();
error!("Failed to extract valid configuration.");
for e in error {
fn w<T>(v: T) -> yansi::Painted<T> { Paint::new(v).primary() }

let span = tracing::error_span! {
"error: configuration",
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| Some(m.source.as_ref()?.to_string())),
};

let _scope = span.enter();
match e.kind {
Kind::Message(msg) => error_!("{}", msg),
Kind::InvalidType(v, exp) => {
error_!("invalid type: found {}, expected {}", w(v), w(exp));
}
Kind::InvalidValue(v, exp) => {
error_!("invalid value {}, expected {}", w(v), w(exp));
},
Kind::InvalidLength(v, exp) => {
error_!("invalid length {}, expected {}", w(v), w(exp))
},
Kind::UnknownVariant(v, exp) => {
error_!("unknown variant: found `{}`, expected `{}`", w(v), w(OneOf(exp)))
}
Kind::UnknownField(v, exp) => {
error_!("unknown field: found `{}`, expected `{}`", w(v), w(OneOf(exp)))
}
Kind::MissingField(v) => {
error_!("missing field `{}`", w(v))
}
Kind::DuplicateField(v) => {
error_!("duplicate field `{}`", w(v))
}
Kind::ISizeOutOfRange(v) => {
error_!("signed integer `{}` is out of range", w(v))
}
Kind::USizeOutOfRange(v) => {
error_!("unsigned integer `{}` is out of range", w(v))
}
Kind::Unsupported(v) => {
error_!("unsupported type `{}`", w(v))
}
Kind::UnsupportedKey(a, e) => {
error_!("unsupported type `{}` for key: must be `{}`", w(a), w(e))
}
}

if let (Some(ref profile), Some(ref md)) = (&e.profile, &e.metadata) {
if !e.path.is_empty() {
let key = md.interpolate(profile, &e.path);
info_!("for key {}", w(key));
}
}

if let Some(md) = e.metadata {
if let Some(source) = md.source {
info_!("in {} {}", w(source), md.name);
} else {
info_!("in {}", w(md.name));
}
Message(message) => error!(message),
InvalidType(actual, expected) => error!(name: "invalid type", %actual, expected),
InvalidValue(actual, expected) => error!(name: "invalid value", %actual, expected),
InvalidLength(actual, expected) => error!(name: "invalid length", %actual, expected),
UnknownVariant(actual, v) => error!(name: "unknown variant", actual, expected = %V(v)),
UnknownField(actual, v) => error!(name: "unknown field", actual, expected = %V(v)),
UnsupportedKey(actual, v) => error!(name: "unsupported key", %actual, expected = &*v),
MissingField(value) => error!(name: "missing field", value = &*value),
DuplicateField(value) => error!(name: "duplicate field", value),
ISizeOutOfRange(value) => error!(name: "out of range signed integer", value),
USizeOutOfRange(value) => error!(name: "out of range unsigned integer", value),
Unsupported(value) => error!(name: "unsupported type", %value),
}
}
}
15 changes: 1 addition & 14 deletions core/lib/src/data/limits.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::fmt;

use serde::{Serialize, Deserialize};
use crate::request::{Request, FromRequest, Outcome};

Expand Down Expand Up @@ -126,7 +124,7 @@ use crate::http::uncased::Uncased;
pub struct Limits {
#[serde(deserialize_with = "Limits::deserialize")]
#[serde(serialize_with = "figment::util::vec_tuple_map::serialize")]
limits: Vec<(Uncased<'static>, ByteUnit)>,
pub(crate) limits: Vec<(Uncased<'static>, ByteUnit)>,
}

impl Default for Limits {
Expand Down Expand Up @@ -314,17 +312,6 @@ impl Limits {
}
}

impl fmt::Display for Limits {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, (k, v)) in self.limits.iter().enumerate() {
if i != 0 { f.write_str(", ")? }
write!(f, "{} = {}", k, v)?;
}

Ok(())
}
}

#[crate::async_trait]
impl<'r> FromRequest<'r> for &'r Limits {
type Error = std::convert::Infallible;
Expand Down
1 change: 1 addition & 0 deletions core/lib/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ impl Error {
/// }
/// # };
/// ```
// FIXME: Remove `Error` panicking behavior. Make display/debug better.
pub fn pretty_print(&self) -> &'static str {
self.mark_handled();
match self.kind() {
Expand Down
15 changes: 6 additions & 9 deletions core/lib/src/fairing/fairings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ use std::collections::HashSet;

use crate::{Rocket, Request, Response, Data, Build, Orbit};
use crate::fairing::{Fairing, Info, Kind};
// use crate::log::PaintExt;

use yansi::Paint;

#[derive(Default)]
pub struct Fairings {
Expand Down Expand Up @@ -173,12 +170,12 @@ impl Fairings {
pub fn pretty_print(&self) {
let active_fairings = self.active().collect::<HashSet<_>>();
if !active_fairings.is_empty() {
launch_meta!("{}{}:", "📡 ".emoji(), "Fairings".magenta());

for (_, fairing) in iter!(self, active_fairings.into_iter()) {
let (name, kind) = (fairing.info().name, fairing.info().kind);
launch_meta_!("{} ({})", name.primary().bold(), kind.blue().bold());
}
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)
}
});
}
}
}
Expand Down
Loading

0 comments on commit 282139d

Please sign in to comment.