diff --git a/backend/Cargo.lock b/backend/Cargo.lock index bf50800c..de3839ed 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -459,6 +459,16 @@ dependencies = [ "clap_derive", ] +[[package]] +name = "clap-verbosity-flag" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2678fade3b77aa3a8ff3aae87e9c008d3fb00473a41c71fbf74e91c8c7b37e84" +dependencies = [ + "clap", + "log", +] + [[package]] name = "clap_builder" version = "4.5.32" @@ -2506,6 +2516,7 @@ dependencies = [ "axum_typed_multipart", "chrono", "clap", + "clap-verbosity-flag", "futures", "log", "rand", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 9c346afd..7b0b3307 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -22,6 +22,7 @@ thiserror = { version = "1.0.66", default-features = false } codegen-units = 1 lto = true opt-level = 3 +strip="debuginfo" [workspace.lints.rust] unsafe_code = "forbid" diff --git a/backend/sync_server/Cargo.toml b/backend/sync_server/Cargo.toml index 02ece2a0..9867dede 100644 --- a/backend/sync_server/Cargo.toml +++ b/backend/sync_server/Cargo.toml @@ -36,6 +36,7 @@ regex = "1.11.1" clap = { version = "4.5.32", features = ["derive"] } futures = "0.3.31" serde_json = "1.0.140" +clap-verbosity-flag = "3.0.2" [lints] workspace = true diff --git a/backend/sync_server/src/cli.rs b/backend/sync_server/src/cli.rs index 6e10f4ad..d5c08521 100644 --- a/backend/sync_server/src/cli.rs +++ b/backend/sync_server/src/cli.rs @@ -1 +1,2 @@ pub mod args; +pub mod color_when; diff --git a/backend/sync_server/src/cli/args.rs b/backend/sync_server/src/cli/args.rs index 88c05412..9ffbd892 100644 --- a/backend/sync_server/src/cli/args.rs +++ b/backend/sync_server/src/cli/args.rs @@ -1,6 +1,9 @@ -use std::ffi::OsString; +use std::{ffi::OsString, io::IsTerminal}; use clap::{Parser, ValueEnum}; +use clap_verbosity_flag::{InfoLevel, Verbosity}; + +use crate::cli::color_when::ColorWhen; /// Server for backing the `VaultLink` plugin #[derive(Parser, Debug)] @@ -9,6 +12,9 @@ pub struct Args { #[arg(index = 1)] pub config_path: Option, + #[command(flatten)] + pub verbose: Verbosity, + #[arg( long, require_equals = true, @@ -20,19 +26,3 @@ pub struct Args { )] pub color: ColorWhen, } - -#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)] -pub enum ColorWhen { - Always, - Auto, - Never, -} - -impl std::fmt::Display for ColorWhen { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.to_possible_value() - .expect("no values are skipped") - .get_name() - .fmt(f) - } -} diff --git a/backend/sync_server/src/cli/color_when.rs b/backend/sync_server/src/cli/color_when.rs new file mode 100644 index 00000000..b463d375 --- /dev/null +++ b/backend/sync_server/src/cli/color_when.rs @@ -0,0 +1,31 @@ +use std::{ffi::OsString, io::IsTerminal}; + +use clap::{Parser, ValueEnum}; + +#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)] +pub enum ColorWhen { + Always, + Auto, + Never, +} + +impl ColorWhen { + pub fn use_colors(&self) -> bool { + match self { + ColorWhen::Always => true, + ColorWhen::Auto => { + std::env::var_os("NO_COLOR").is_none() && std::io::stderr().is_terminal() + } + ColorWhen::Never => false, + } + } +} + +impl std::fmt::Display for ColorWhen { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.to_possible_value() + .expect("no values are skipped") + .get_name() + .fmt(f) + } +} diff --git a/backend/sync_server/src/main.rs b/backend/sync_server/src/main.rs index 5ddd45bc..6c31e981 100644 --- a/backend/sync_server/src/main.rs +++ b/backend/sync_server/src/main.rs @@ -6,28 +6,75 @@ mod errors; mod server; mod utils; +use std::process::ExitCode; + use anyhow::{Context as _, Result}; use clap::Parser; use cli::args::Args; use errors::{SyncServerError, init_error}; use log::info; use server::create_server; -use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; +use tracing_subscriber::{EnvFilter, fmt::format, layer::SubscriberExt, util::SubscriberInitExt}; #[tokio::main] -async fn main() -> Result<(), SyncServerError> { +async fn main() -> ExitCode { let args = Args::parse(); - tracing_subscriber::registry() - .with( - tracing_subscriber::EnvFilter::try_from_default_env() - .unwrap_or_else(|_| format!("{}=debug", env!("CARGO_CRATE_NAME")).into()), + let mut result = set_up_logging(&args); + + if result.is_ok() { + result = start_server(args).await; + } + + match result { + Ok(_) => ExitCode::SUCCESS, + Err(e) => { + eprintln!("Failed to set up logging: {}", e); + ExitCode::FAILURE + } + } +} + +fn set_up_logging(args: &Args) -> Result<(), SyncServerError> { + let level_filter = match args.verbose.log_level_filter() { + // We don't want to allow disabling all logging + log::LevelFilter::Off => tracing::Level::ERROR, + + log::LevelFilter::Error => tracing::Level::ERROR, + log::LevelFilter::Warn => tracing::Level::WARN, + log::LevelFilter::Info => tracing::Level::INFO, + log::LevelFilter::Debug => tracing::Level::DEBUG, + log::LevelFilter::Trace => tracing::Level::TRACE, + }; + + let env_filter = EnvFilter::builder() + .with_default_directive(level_filter.into()) + .from_env() + .context("Failed to create logging env filter") + .map_err(init_error)?; + + let use_colors = args.color.use_colors(); + let is_debug_mode = args.verbose.log_level_filter() >= log::LevelFilter::Debug; + + tracing_subscriber::fmt() + .with_ansi(use_colors) + .with_env_filter(env_filter) + .event_format( + format() + .without_time() + .with_target(is_debug_mode) + .with_line_number(is_debug_mode) + .compact(), ) - .with(tracing_subscriber::fmt::layer()) + .finish() .try_init() .context("Failed to initialise tracing") .map_err(init_error)?; + Ok(()) +} + +async fn start_server(args: Args) -> Result<(), SyncServerError> { info!( "Starting VaultLink server version {}", env!("CARGO_PKG_VERSION")