From de7bc7390b9a37ef566082930a97d55d4f1fd4c8 Mon Sep 17 00:00:00 2001 From: Tao Guo Date: Wed, 18 Oct 2023 15:45:22 +0000 Subject: [PATCH] Use env_logger as default logger. --- Cargo.toml | 1 + README.md | 5 ++--- examples/dd_test.rs | 1 - examples/pipes.rs | 2 -- examples/rust_cookbook.rs | 1 - examples/tetris.rs | 1 - macros/src/lib.rs | 6 ++++++ src/builtins.rs | 7 +++++++ src/child.rs | 7 ++++++- src/lib.rs | 7 +++---- src/logger.rs | 41 +++++++++------------------------------ 11 files changed, 34 insertions(+), 45 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1766370..dd8ac8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ log = "0.4" faccess = "0.2" os_pipe = "0.9" main_error = "0.1.2" +env_logger = "0.10.0" [dev-dependencies] rayon = "1.5" diff --git a/README.md b/README.md index a1e1de6..de92c87 100644 --- a/README.md +++ b/README.md @@ -173,8 +173,6 @@ are printed to stderr will be logged. Since it is returning result type, you can errors if command execution fails. ```rust -// this code snppit is using a builtin simple logger, you can replace it with a real logger -init_builtin_logger(); let dir: &str = "folder with spaces"; assert!(run_cmd!(mkdir /tmp/$dir; ls /tmp/$dir).is_ok()); assert!(run_cmd!(mkdir /tmp/"$dir"; ls /tmp/"$dir"; rmdir /tmp/"$dir").is_err()); @@ -183,7 +181,8 @@ assert!(run_cmd!(mkdir /tmp/"$dir"; ls /tmp/"$dir"; rmdir /tmp/"$dir").is_err()) ``` It is using rust [log crate](https://crates.io/crates/log), and you can use your actual favorite -logging implementation. **Notice that if you don't provide any logger, the stderr from process will be discarded**. +logger implementation. Notice that if you don't provide any logger, it will use env_logger to print +messages from process's stderr. #### Builtin commands ##### cd diff --git a/examples/dd_test.rs b/examples/dd_test.rs index 115caf2..2f4c5dc 100644 --- a/examples/dd_test.rs +++ b/examples/dd_test.rs @@ -33,7 +33,6 @@ struct Opt { } fn main() -> MainResult { - init_builtin_logger(); let Opt { block_size, thread_num, diff --git a/examples/pipes.rs b/examples/pipes.rs index b4061ce..809d9bf 100644 --- a/examples/pipes.rs +++ b/examples/pipes.rs @@ -339,8 +339,6 @@ fn rand() -> i32 { } fn main() -> MainResult { - init_builtin_logger(); - // simple pre-check of TERM, tput's error message should be enough let term = std::env::var("TERM").unwrap(); run_cmd!(tput -T $term sgr0 >/dev/null)?; diff --git a/examples/rust_cookbook.rs b/examples/rust_cookbook.rs index ce9cd0c..2aac829 100644 --- a/examples/rust_cookbook.rs +++ b/examples/rust_cookbook.rs @@ -5,7 +5,6 @@ use cmd_lib::*; use std::io::{BufRead, BufReader}; fn main() -> MainResult { - init_builtin_logger(); cmd_lib::set_pipefail(false); // do not fail due to pipe errors // Run an external command and process stdout diff --git a/examples/tetris.rs b/examples/tetris.rs index 2f1fedb..f1293ed 100644 --- a/examples/tetris.rs +++ b/examples/tetris.rs @@ -557,7 +557,6 @@ fn cmd_exit() { } fn main() -> MainResult { - init_builtin_logger(); #[rustfmt::skip] let old_cfg = run_fun!(stty -g)?; // let's save terminal state ... tls_set!(old_stty_cfg, |cfg| *cfg = old_cfg); diff --git a/macros/src/lib.rs b/macros/src/lib.rs index ff473cd..e64c55d 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -198,6 +198,7 @@ pub fn cmd_error(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let msg = parse_msg(input.into()); quote!({ use ::cmd_lib::AsOsStr; + let _ = ::cmd_lib::try_init_default_logger(); ::cmd_lib::log::error!("{}", #msg) }) .into() @@ -210,6 +211,7 @@ pub fn cmd_warn(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let msg = parse_msg(input.into()); quote!({ use ::cmd_lib::AsOsStr; + let _ = ::cmd_lib::try_init_default_logger(); ::cmd_lib::log::warn!("{}", #msg) }) .into() @@ -243,6 +245,7 @@ pub fn cmd_info(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let msg = parse_msg(input.into()); quote!({ use ::cmd_lib::AsOsStr; + let _ = ::cmd_lib::try_init_default_logger(); ::cmd_lib::log::info!("{}", #msg) }) .into() @@ -255,6 +258,7 @@ pub fn cmd_debug(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let msg = parse_msg(input.into()); quote!({ use ::cmd_lib::AsOsStr; + let _ = ::cmd_lib::try_init_default_logger(); ::cmd_lib::log::debug!("{}", #msg) }) .into() @@ -267,6 +271,7 @@ pub fn cmd_trace(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let msg = parse_msg(input.into()); quote!({ use ::cmd_lib::AsOsStr; + let _ = ::cmd_lib::try_init_default_logger(); ::cmd_lib::log::trace!("{}", #msg) }) .into() @@ -292,6 +297,7 @@ pub fn cmd_die(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let msg = parse_msg(input.into()); quote!({ use ::cmd_lib::AsOsStr; + let _ = ::cmd_lib::try_init_default_logger(); ::cmd_lib::log::error!("FATAL: {}", #msg); std::process::exit(1) }) diff --git a/src/builtins.rs b/src/builtins.rs index cab1a72..c5eb6c9 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -1,4 +1,5 @@ use crate::{CmdEnv, CmdResult}; +use crate::logger::try_init_default_logger; use log::*; use std::io::Write; @@ -8,31 +9,37 @@ pub(crate) fn builtin_echo(env: &mut CmdEnv) -> CmdResult { } pub(crate) fn builtin_die(env: &mut CmdEnv) -> CmdResult { + let _ = try_init_default_logger(); error!("FATAL: {}", env.args()[1..].join(" ")); std::process::exit(1); } pub(crate) fn builtin_error(env: &mut CmdEnv) -> CmdResult { + let _ = try_init_default_logger(); error!("{}", env.args()[1..].join(" ")); Ok(()) } pub(crate) fn builtin_warn(env: &mut CmdEnv) -> CmdResult { + let _ = try_init_default_logger(); warn!("{}", env.args()[1..].join(" ")); Ok(()) } pub(crate) fn builtin_info(env: &mut CmdEnv) -> CmdResult { + let _ = try_init_default_logger(); info!("{}", env.args()[1..].join(" ")); Ok(()) } pub(crate) fn builtin_debug(env: &mut CmdEnv) -> CmdResult { + let _ = try_init_default_logger(); debug!("{}", env.args()[1..].join(" ")); Ok(()) } pub(crate) fn builtin_trace(env: &mut CmdEnv) -> CmdResult { + let _ = try_init_default_logger(); trace!("{}", env.args()[1..].join(" ")); Ok(()) } diff --git a/src/child.rs b/src/child.rs index c64eec0..a98e44b 100644 --- a/src/child.rs +++ b/src/child.rs @@ -1,4 +1,5 @@ use crate::{process, CmdResult, FunResult}; +use crate::logger::try_init_default_logger; use log::{info, warn}; use os_pipe::PipeReader; use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Result}; @@ -284,7 +285,10 @@ impl StderrLogging { BufReader::new(stderr) .lines() .map_while(Result::ok) - .for_each(|line| info!("{}", line)) + .for_each(|line| { + let _ = try_init_default_logger(); + info!("{}", line) + }) }); Self { cmd: cmd.into(), @@ -303,6 +307,7 @@ impl Drop for StderrLogging { fn drop(&mut self) { if let Some(thread) = self.thread.take() { if let Err(e) = thread.join() { + let _ = try_init_default_logger(); warn!("{} logging thread exited with error: {:?}", self.cmd, e); } } diff --git a/src/lib.rs b/src/lib.rs index 20d1b15..5a11b25 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -191,8 +191,6 @@ //! //! ```no_run //! # use cmd_lib::*; -//! // this code snppit is using a builtin simple logger, you can replace it with a real logger -//! init_builtin_logger(); //! let dir: &str = "folder with spaces"; //! assert!(run_cmd!(mkdir /tmp/$dir; ls /tmp/$dir).is_ok()); //! assert!(run_cmd!(mkdir /tmp/"$dir"; ls /tmp/"$dir"; rmdir /tmp/"$dir").is_err()); @@ -201,7 +199,8 @@ //! ``` //! //! It is using rust [log crate](https://crates.io/crates/log), and you can use your actual favorite -//! logging implementation. **Notice that if you don't provide any logger, the stderr from process will be discarded**. +//! logger implementation. Notice that if you don't provide any logger, it will use env_logger to print +//! messages from process's stderr. //! //! ### Builtin commands //! #### cd @@ -364,12 +363,12 @@ pub type CmdResult = std::io::Result<()>; pub use child::{CmdChildren, FunChildren}; #[doc(hidden)] pub use log; -pub use logger::init_builtin_logger; pub use main_error::MainError; pub use main_error::MainResult; pub use process::{ export_cmd, set_debug, set_pipefail, AsOsStr, Cmd, CmdEnv, CmdString, Cmds, GroupCmds, Redirect, }; +pub use logger::try_init_default_logger; mod builtins; mod child; diff --git a/src/logger.rs b/src/logger.rs index 03aeef4..f883f5e 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,34 +1,11 @@ -use log::{Level, LevelFilter, Metadata, Record}; - -static LOGGER: CmdLogger = CmdLogger; - -/// Initializes the builtin cmd_lib logger -/// -/// This is to make examples in this library work, and users should usually use a real logger -/// instead. When being used, it should be called early in the main() function. Default log level -/// is set to `debug`. -/// -/// # Panics -/// -/// This function will panic if it is called more than once, or if another -/// library has already initialized a global logger. -pub fn init_builtin_logger() { - log::set_logger(&LOGGER) - .map(|()| log::set_max_level(LevelFilter::Debug)) - .unwrap(); +use log::SetLoggerError; + +#[doc(hidden)] +pub fn try_init_default_logger() -> Result<(), SetLoggerError> { + env_logger::builder() + .filter_level(log::LevelFilter::Info) + .format_target(false) + .format_timestamp(None) + .try_init() } -struct CmdLogger; -impl log::Log for CmdLogger { - fn enabled(&self, metadata: &Metadata) -> bool { - metadata.level() <= Level::Debug - } - - fn log(&self, record: &Record) { - if self.enabled(record.metadata()) { - eprintln!("{} - {}", record.level(), record.args()); - } - } - - fn flush(&self) {} -}