From fc7edb2f2fe9cbca79282c8c141d64fc9509d253 Mon Sep 17 00:00:00 2001 From: theMackabu <theMackabu@gmail.com> Date: Wed, 20 Nov 2024 13:14:13 -0800 Subject: [PATCH] migrate to tracing --- Cargo.lock | 14 +--- Cargo.toml | 4 +- maid/client/cli/mod.rs | 9 +-- maid/client/cli/tasks.rs | 4 +- maid/client/cli/verbose.rs | 116 ++++++++++++++++++++++++++++++++++ maid/client/helpers/string.rs | 29 +++++++-- maid/client/main.rs | 16 +++-- maid/client/parse/file.rs | 16 ++--- maid/client/table.rs | 23 +++---- 9 files changed, 174 insertions(+), 57 deletions(-) create mode 100644 maid/client/cli/verbose.rs diff --git a/Cargo.lock b/Cargo.lock index e133e4e..09f1c77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -351,16 +351,6 @@ dependencies = [ "clap_derive", ] -[[package]] -name = "clap-verbosity-flag" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34c77f67047557f62582784fd7482884697731b2932c7d37ced54bce2312e1e2" -dependencies = [ - "clap", - "log", -] - [[package]] name = "clap_builder" version = "4.5.21" @@ -1452,7 +1442,6 @@ dependencies = [ "bytes", "chrono", "clap", - "clap-verbosity-flag", "colored", "data-encoding", "env_logger", @@ -1469,7 +1458,6 @@ dependencies = [ "json5", "lazy_static", "libc", - "log", "macros-rs", "merge-struct", "merkle_hash", @@ -1492,6 +1480,8 @@ dependencies = [ "tokio", "tokio-util", "toml", + "tracing", + "tracing-subscriber", "tungstenite 0.20.1", "url", "uuid", diff --git a/Cargo.toml b/Cargo.toml index 0c4f818..03696a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,6 @@ opt-level = 3 codegen-units = 1 [dependencies] -log = "0.4.22" tar = "0.4.43" home = "0.5.9" colored = "2.1.0" @@ -78,11 +77,12 @@ indicatif = "0.17.9" serde_json = "1.0.133" text_placeholder = "0.5.1" global_placeholders = "0.1.0" -clap-verbosity-flag = "2.2.3" +log = { version = "0.1.40", package = "tracing" } clap = { version = "4.5.21", features = ["derive"] } serde = { version = "1.0.215", features = ["derive"] } uuid = { version = "1.11.0", features = ["v4", "fast-rng"] } +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } tungstenite = { version = "0.20.1", features = ["rustls-tls-webpki-roots"] } # enable-feature = client diff --git a/maid/client/cli/mod.rs b/maid/client/cli/mod.rs index 8c788e0..84d8a82 100644 --- a/maid/client/cli/mod.rs +++ b/maid/client/cli/mod.rs @@ -1,3 +1,8 @@ +pub(crate) mod verbose; +pub(crate) mod butler; +pub(crate) mod run; +pub(crate) mod tasks; + use crate::helpers; use crate::parse; use crate::server; @@ -230,7 +235,3 @@ pub fn exec(task: &str, args: &Vec<String>, path: &String, silent: bool, is_dep: } } } - -pub mod butler; -pub mod run; -pub mod tasks; diff --git a/maid/client/cli/tasks.rs b/maid/client/cli/tasks.rs index ebd170d..798a875 100644 --- a/maid/client/cli/tasks.rs +++ b/maid/client/cli/tasks.rs @@ -33,7 +33,7 @@ impl List { }; let verbose = match log_level.unwrap() { - log::Level::Error => string!(), + log::Level::ERROR => string!(), _ => string!(task.script), }; @@ -79,7 +79,7 @@ impl List { }; let verbose = match log_level.unwrap() { - log::Level::Error => string!(), + log::Level::ERROR => string!(), _ => string!(task.script), }; diff --git a/maid/client/cli/verbose.rs b/maid/client/cli/verbose.rs new file mode 100644 index 0000000..3cbd6ff --- /dev/null +++ b/maid/client/cli/verbose.rs @@ -0,0 +1,116 @@ +use log::{level_filters::LevelFilter, Level}; +use std::fmt; + +#[derive(clap::Args, Debug, Clone, Default)] +pub struct Verbosity<L: LogLevel = ErrorLevel> { + #[arg( + long, + short = 'v', + action = clap::ArgAction::Count, + global = true, + help = L::verbose_help(), + long_help = L::verbose_long_help(), + )] + verbose: u8, + + #[arg( + long, + short = 'q', + action = clap::ArgAction::Count, + global = true, + help = L::quiet_help(), + long_help = L::quiet_long_help(), + conflicts_with = "verbose", + )] + quiet: u8, + + #[arg(skip)] + phantom: std::marker::PhantomData<L>, +} + +#[allow(dead_code)] +impl<L: LogLevel> Verbosity<L> { + pub fn new(verbose: u8, quiet: u8) -> Self { + Verbosity { + verbose, + quiet, + phantom: std::marker::PhantomData, + } + } + + pub fn is_present(&self) -> bool { self.verbose != 0 || self.quiet != 0 } + + pub fn log_level(&self) -> Option<Level> { level_enum(self.verbosity()) } + + pub fn log_level_filter(&self) -> LevelFilter { return level_enum(self.verbosity()).map(LevelFilter::from_level).unwrap_or(LevelFilter::OFF); } + + pub fn is_silent(&self) -> bool { self.log_level().is_none() } + + fn verbosity(&self) -> i8 { level_value(L::default()) - (self.quiet as i8) + (self.verbose as i8) } +} + +fn level_value(level: Option<Level>) -> i8 { + match level { + None => -1, + Some(Level::ERROR) => 0, + Some(Level::WARN) => 1, + Some(Level::INFO) => 2, + Some(Level::DEBUG) => 3, + Some(Level::TRACE) => 4, + } +} + +fn level_enum(verbosity: i8) -> Option<Level> { + match verbosity { + i8::MIN..=-1 => None, + 0 => Some(Level::ERROR), + 1 => Some(Level::WARN), + 2 => Some(Level::INFO), + 3 => Some(Level::DEBUG), + 4..=i8::MAX => Some(Level::TRACE), + } +} + +impl<L: LogLevel> fmt::Display for Verbosity<L> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.verbosity()) } +} + +pub trait LogLevel { + fn default() -> Option<Level>; + + fn verbose_help() -> Option<&'static str> { Some("Increase logging verbosity") } + + fn verbose_long_help() -> Option<&'static str> { None } + + fn quiet_help() -> Option<&'static str> { Some("Decrease logging verbosity") } + + fn quiet_long_help() -> Option<&'static str> { None } +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct ErrorLevel; + +impl LogLevel for ErrorLevel { + fn default() -> Option<Level> { return Some(Level::ERROR); } +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct WarnLevel; + +impl LogLevel for WarnLevel { + fn default() -> Option<Level> { return Some(Level::WARN); } +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct InfoLevel; + +impl LogLevel for InfoLevel { + fn default() -> Option<Level> { return Some(Level::INFO); } +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct NoneLevel; + +impl LogLevel for NoneLevel { + fn default() -> Option<Level> { None } +} diff --git a/maid/client/helpers/string.rs b/maid/client/helpers/string.rs index b02f4af..e99f525 100644 --- a/maid/client/helpers/string.rs +++ b/maid/client/helpers/string.rs @@ -1,17 +1,32 @@ use colored::{ColoredString, Colorize}; use std::path::Path; -pub fn seperator() -> ColoredString { ":".white() } -pub fn arrow_icon() -> ColoredString { "»".white() } -pub fn add_icon() -> ColoredString { "+".green() } -pub fn cross_icon() -> ColoredString { "✖".red() } -pub fn check_icon() -> ColoredString { "✔".green() } +// cache +use std::collections::HashMap; +use std::sync::{Mutex, LazyLock}; -pub fn path_to_str(path: &Path) -> &'static str { Box::leak(String::from(path.to_string_lossy()).into_boxed_str()) } +static STRING_CACHE: LazyLock<Mutex<HashMap<String, &'static str>>> = LazyLock::new(|| Mutex::new(HashMap::new())); -pub fn trim_start_end(value: &str) -> &str { +pub(crate) fn path_to_str(path: &Path) -> &'static str { + let string = path.to_string_lossy().into_owned(); + if let Some(cached) = STRING_CACHE.lock().unwrap().get(&string) { + return cached; + } + + let leaked = Box::leak(string.clone().into_boxed_str()); + STRING_CACHE.lock().unwrap().insert(string, leaked); + leaked +} + +pub(crate) fn trim_start_end(value: &str) -> &str { let mut chars = value.chars(); chars.next(); chars.next_back(); chars.as_str() } + +pub(crate) fn seperator() -> ColoredString { ":".white() } +pub(crate) fn arrow_icon() -> ColoredString { "»".white() } +pub(crate) fn add_icon() -> ColoredString { "+".green() } +pub(crate) fn cross_icon() -> ColoredString { "✖".red() } +pub(crate) fn check_icon() -> ColoredString { "✔".green() } \ No newline at end of file diff --git a/maid/client/main.rs b/maid/client/main.rs index f7b66a2..d9dcf91 100644 --- a/maid/client/main.rs +++ b/maid/client/main.rs @@ -9,7 +9,8 @@ mod table; mod task; use clap::{Parser, ValueEnum}; -use clap_verbosity_flag::Verbosity; +use cli::verbose::{NoneLevel, Verbosity}; +use tracing_subscriber::{fmt, prelude::*}; use macros_rs::str; use std::path::Path; @@ -70,7 +71,7 @@ struct Cli { system: Option<System>, #[clap(flatten)] - verbose: Verbosity, + verbose: Verbosity<NoneLevel>, /// Shows this quick reference #[clap(short, long, action = clap::ArgAction::HelpLong)] @@ -97,10 +98,15 @@ enum Project { fn main() { let cli = Cli::parse(); - + let fmt_layer = fmt::layer().without_time(); + + tracing_subscriber::registry() + .with(cli.verbose.log_level_filter()) + .with(fmt_layer) + .init(); + globals::init(); - env_logger::Builder::new().filter_level(cli.verbose.log_level_filter()).init(); - + dispatch!(cli, { init => cli::butler::init(), health => server::cli::connect(&cli.path), diff --git a/maid/client/parse/file.rs b/maid/client/parse/file.rs index b60ce6b..18d6f83 100644 --- a/maid/client/parse/file.rs +++ b/maid/client/parse/file.rs @@ -1,7 +1,6 @@ use crate::structs::Maidfile; use colored::Colorize; use macros_rs::{crashln, string, then}; -use serde_json::json; use std::{env, fs, io::Result, path::Path, path::PathBuf}; macro_rules! create_path { @@ -49,7 +48,7 @@ fn find_path(path: &Path, file_name: &str, kind: &str) -> Result<Option<fs::DirE } } -fn find_file(starting_directory: &Path, file_name: &String, trace: bool) -> Option<PathBuf> { +fn find_file(starting_directory: &Path, file_name: &String) -> Option<PathBuf> { let mut path: PathBuf = starting_directory.into(); let find_kind = |kind: &str, mut inner: PathBuf| -> Filesystem { let file_path = create_path!(file_name, kind); @@ -60,10 +59,6 @@ fn find_file(starting_directory: &Path, file_name: &String, trace: bool) -> Opti None => inner.push(file_path), } - if trace { - log::trace!("{}", json!({"kind": kind, "path": inner})) - }; - Filesystem { path: Some(inner.clone()), is_file: inner.is_file(), @@ -82,7 +77,6 @@ fn find_file(starting_directory: &Path, file_name: &String, trace: bool) -> Opti } fn read_file(path: PathBuf, kind: &str) -> Maidfile { - log::debug!("Maidfile is {kind}"); let contents = match fs::read_to_string(&path) { Ok(contents) => contents, Err(err) => { @@ -112,11 +106,11 @@ fn read_file(path: PathBuf, kind: &str) -> Maidfile { pub fn read_maidfile_with_error(filename: &String, error: &str) -> Maidfile { match env::current_dir() { - Ok(path) => match find_file(&path, &filename, true) { + Ok(path) => match find_file(&path, &filename) { Some(path) => { - log::info!("Found maidfile path: {}", path.display()); - let extension = path.extension().and_then(|s| s.to_str()); + log::debug!(path = path.display().to_string(), kind = extension, "Found tasks"); + match extension { Some("yaml") | Some("yml") | Some("json") | Some("json5") => read_file(path.clone(), extension.unwrap()), _ => read_file(path, "toml"), @@ -136,7 +130,7 @@ pub fn read_maidfile_with_error(filename: &String, error: &str) -> Maidfile { pub fn find_maidfile_root(filename: &String) -> PathBuf { match env::current_dir() { - Ok(path) => match find_file(&path, &filename, false) { + Ok(path) => match find_file(&path, &filename) { Some(mut path) => { path.pop(); log::info!("Found project path: {}", path.display()); diff --git a/maid/client/table.rs b/maid/client/table.rs index ef7ab18..70c05f8 100644 --- a/maid/client/table.rs +++ b/maid/client/table.rs @@ -1,9 +1,7 @@ use crate::helpers; use crate::structs::Maidfile; -use colored::Colorize; use macros_rs::{errorln, str, ternary}; -use serde_json::json; use std::path::PathBuf; use std::{collections::BTreeMap, collections::HashMap, env}; use text_placeholder::Template; @@ -16,13 +14,13 @@ pub fn create(values: Maidfile, args: &Vec<String>, project: PathBuf) -> HashMap table.insert("os.platform", env::consts::OS); table.insert("os.arch", env::consts::ARCH); - log::info!("{} os.platform: '{}'", helpers::string::add_icon(), env::consts::OS.yellow()); - log::info!("{} os.arch: '{}'", helpers::string::add_icon(), env::consts::ARCH.yellow()); + log::trace!(os_platform = env::consts::OS); + log::trace!(os_arch = env::consts::ARCH); match env::current_dir() { Ok(path) => { table.insert("dir.current", helpers::string::path_to_str(&path)); - log::info!("{} dir.current: '{}'", helpers::string::add_icon(), helpers::string::path_to_str(&path).yellow()); + log::trace!(dir_current = path.display().to_string()); } Err(err) => { log::warn!("{err}"); @@ -33,19 +31,18 @@ pub fn create(values: Maidfile, args: &Vec<String>, project: PathBuf) -> HashMap match home::home_dir() { Some(path) => { table.insert("dir.home", helpers::string::path_to_str(&path)); - log::info!("{} dir.home: '{}'", helpers::string::add_icon(), helpers::string::path_to_str(&path).yellow()); + log::trace!(dir_home = path.display().to_string()); } None => { errorln!("Home directory could not be added as script variable."); } } - let project_root = helpers::string::path_to_str(&project); - table.insert("dir.project", project_root); - log::info!("{} dir.project: '{}'", helpers::string::add_icon(), project_root.yellow()); + table.insert("dir.project", helpers::string::path_to_str(&project)); + log::trace!(dir_project = project.display().to_string()); for (pos, arg) in args.iter().enumerate() { - log::info!("{} arg.{pos}: '{}'", helpers::string::add_icon(), arg.yellow()); + log::trace!("arg_{pos} = \"{arg}\""); table.insert(str!(format!("arg.{pos}")), arg); } @@ -62,11 +59,9 @@ pub fn create(values: Maidfile, args: &Vec<String>, project: PathBuf) -> HashMap ); env::set_var(key, value_formatted.clone()); - log::info!("{} env.{key}: '{}'", helpers::string::add_icon(), value_formatted.yellow()); + log::trace!("env_{key} = \"{value_formatted}\""); table.insert(str!(format!("env.{}", key.clone())), str!(value_formatted)); } - - log::trace!("{}", json!({ "env": table })); - + return table; } -- GitLab