cli-log-2.0.0/.cargo_vcs_info.json0000644000000001120000000000000123520ustar { "git": { "sha1": "f2527322dc3b9a569376c413259f5e2070954c74" } } cli-log-2.0.0/.gitignore000064400000000000000000000005000000000000000131110ustar 00000000000000# Generated by Cargo # will have compiled files and executables /target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk cli-log-2.0.0/Cargo.toml0000644000000021770000000000000103650ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "cli-log" version = "2.0.0" authors = ["dystroy "] description = "a simple logging and timing facility configured with an env variable" readme = "README.md" keywords = ["log", "terminal", "file", "benchmark"] categories = [] license = "MIT" repository = "https://github.com/Canop/cli-log" [dependencies.chrono] version = "0.4" [dependencies.file-size] version = "1.0.3" optional = true [dependencies.log] version = "0.4" features = ["std"] [dependencies.proc-status] version = "0.1" optional = true [features] default = ["mem"] mem = ["proc-status", "file-size"] cli-log-2.0.0/Cargo.toml.orig000064400000000000000000000011200000000000000140070ustar 00000000000000[package] name = "cli-log" version = "2.0.0" authors = ["dystroy "] repository = "https://github.com/Canop/cli-log" description = "a simple logging and timing facility configured with an env variable" edition = "2018" keywords = ["log", "terminal", "file", "benchmark"] license = "MIT" categories = [] readme = "README.md" [features] default = ["mem"] mem = ["proc-status", "file-size"] [dependencies] chrono = "0.4" log = { version = "0.4", features = ["std"] } proc-status = { version = "0.1", optional = true } file-size = { version = "1.0.3", optional = true } cli-log-2.0.0/LICENSE000064400000000000000000000020460000000000000121350ustar 00000000000000MIT License Copyright (c) 2020 Canop Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cli-log-2.0.0/README.md000064400000000000000000000054260000000000000124140ustar 00000000000000[![MIT][s2]][l2] [![Latest Version][s1]][l1] [![docs][s3]][l3] [![Chat on Miaou][s4]][l4] [s1]: https://img.shields.io/crates/v/cli-log.svg [l1]: https://crates.io/crates/cli-log [s2]: https://img.shields.io/badge/license-MIT-blue.svg [l2]: LICENSE [s3]: https://docs.rs/cli-log/badge.svg [l3]: https://docs.rs/cli-log/ [s4]: https://miaou.dystroy.org/static/shields/room.svg [l4]: https://miaou.dystroy.org/3 # cli-log The boilerplate to have some file logging with a level given by an environment variable, and a facility to log execution durations according to the relevant log level. It's especially convenient for terminal applications because you don't want to mix log with stdout or stderr. The use of an env variable makes it possible to distribute the application and have users generate some logs without recompilation or configuration. The names of the log file and the env variable are computed from the name of the application. So log initialization is just ``` use cli_log::*; // also import logging macros init_cli_log!(); ``` If you prefer not having to declare cli_log import for all the log and cli-log logging macros, you may use the old `#[macro_use]` import in your main.rs file: ``` #[macro_use] extern crate cli_log; init_cli_log!(); ``` With the `"mem"` feature (enabled by default), when the OS is compatible (unix like), you may dump the current and peak memory usage with the `log_mem` function. Here's a complete application using cli-log (it can be found in examples): ``` use cli_log::*; #[derive(Debug)] struct AppData { count: usize, } impl AppData { fn compute(&mut self) { self.count += 7; } } fn main() { init_cli_log!(); let mut app_data = AppData { count: 35 }; time!(Debug, app_data.compute()); info!("count is {}", app_data.count); debug!("data: {:#?}", &app_data); warn!("this application does nothing"); log_mem(Level::Info); info!("bye"); } ``` If you don't set any `SMALL_APP_LOG` env variable, there won't be any log. A convenient way to set the env variable is to launch the app as ```cli SMALL_APP_LOG=debug small_app ``` or, during development, ```cli SMALL_APP_LOG=debug cargo run ``` This creates a `small_app.log` file containing information like the level, app version, and of course the log operations you did with time precise to the ms and the logging module (target): ```log 21:03:24.081 [INFO] cli_log::init: Starting small-app v1.0.1 with log level DEBUG 21:03:24.081 [DEBUG] small_app: app_data.compute() took 312ns 21:03:24.081 [INFO] small_app: count is 42 21:03:24.081 [DEBUG] small_app: data: AppData { count: 42, } 21:03:24.081 [WARN] small_app: this application does nothing 21:03:24.081 [INFO] cli_log::mem: Physical mem usage: current=938K, peak=3.3M 21:03:24.082 [INFO] small_app: bye ``` cli-log-2.0.0/src/file_logger.rs000064400000000000000000000016540000000000000145470ustar 00000000000000use { log::{ LevelFilter, Log, Metadata, Record, }, std::{ fs::File, io::Write, sync::Mutex, }, }; static TIME_FORMAT: &str = "%T%.3f"; pub(crate) struct FileLogger { pub file: Mutex, pub level: LevelFilter, } impl Log for FileLogger { fn enabled(&self, metadata: &Metadata<'_>) -> bool { metadata.level() <= self.level } fn log(&self, record: &Record<'_>) { if self.enabled(record.metadata()) { let mut w = self.file.lock().unwrap(); let _ = writeln!( w, "{} [{}] {}: {}", chrono::Local::now().format(TIME_FORMAT), record.level(), record.target(), record.args(), ); // we ignore errors here } } fn flush(&self) { let _ = self.file.lock().unwrap().flush(); } } cli-log-2.0.0/src/init.rs000064400000000000000000000036100000000000000132260ustar 00000000000000use { crate::{ file_logger::FileLogger, }, log::{ LevelFilter, }, std::{ env, fs::File, str::FromStr, sync::Mutex, }, }; /// configure the application log according to env variable. pub fn init(app_name: &str, app_version: &str) { let env_var_name = format!( "{}_LOG", app_name.to_ascii_uppercase().replace('-', "_"), ); let level = env::var(&env_var_name).unwrap_or_else(|_| "off".to_string()); if level == "off" { return; } if let Ok(level) = LevelFilter::from_str(&level) { let log_file_name = format!("{}.log", app_name); let file = File::create(&log_file_name) .expect("Log file can't be created"); log::set_max_level(level); let logger = FileLogger { file: Mutex::new(file), level, }; log::set_boxed_logger(Box::new(logger)).unwrap(); log::info!( "Starting {} v{} with log level {}", app_name, app_version, level ); } } /// configure the application log according to env variable /// /// Example: /// /// ``` /// cli_log::init_cli_log!(); /// ``` /// You may specify an altername application name instead /// of your crate name: /// /// ``` /// cli_log::init_cli_log!("my-app"); /// ``` /// /// The application name will also be used to derive the /// env variable name giving the log level, for example /// `MY_APP_LOG=info` for an application named `my-app`. // The point of this macro is to ensure `env!(CARGO_PKG_NAME)` // and `env!(CARGO_PKG_VERSION)` are expanded for the outer // package, not for cli-log #[macro_export] macro_rules! init_cli_log { () => { cli_log::init(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); }; ($app_name: expr) => { cli_log::init($app_name, env!("CARGO_PKG_VERSION")); }; } cli-log-2.0.0/src/lib.rs000064400000000000000000000055430000000000000130400ustar 00000000000000//! The boilerplate to have some file logging with a level given by an environment variable, //! and a facility to log execution durations according to the relevant log level. //! //! It's especially convenient for terminal applications //! because you don't want to mix log with stdout or stderr. //! //! The use of an env variable makes it possible to distribute //! the application and have users generate some logs without //! recompilation or configuration. //! //! The names of the log file and the env variable are //! computed from the name of the application. //! //! So log initialization is just //! //! ``` //! use cli_log::*; // also import logging macros //! init_cli_log!(); //! ``` //! //! If you prefer not having to declare cli_log import for //! all the log and cli-log logging macros, you may use the //! old `#[macro_use]` import in your main.rs file: //! //! ``` //! #[macro_use] extern crate cli_log; //! init_cli_log!(); //! ``` //! //! With the `"mem"` feature (enabled by default), when the OS is compatible //! (unix like), you may dump the current and peak memory usage with //! the `log_mem` function. //! //! //! Here's a complete application using cli-log (it can be found in examples): //! //! ``` //! use cli_log::*; //! //! #[derive(Debug)] //! struct AppData { //! count: usize, //! } //! impl AppData { //! fn compute(&mut self) { //! self.count += 7; //! } //! } //! //! fn main() { //! init_cli_log!(); //! let mut app_data = AppData { count: 35 }; //! time!(Debug, app_data.compute()); //! info!("count is {}", app_data.count); //! debug!("data: {:#?}", &app_data); //! warn!("this application does nothing"); //! log_mem(Level::Info); //! info!("bye"); //! } //! ``` //! //! If you don't set any `SMALL_APP_LOG` env variable, there won't be any log. //! //! A convenient way to set the env variable is to launch the app as //! //! ```cli //! SMALL_APP_LOG=debug small_app //! ``` //! //! or, during development, //! //! ```cli //! SMALL_APP_LOG=debug cargo run //! ``` //! //! This creates a `small_app.log` file containing information like the level, //! app version, and of course the log operations you did with time precise to //! the ms and the logging module (target): //! //! ```log //! 21:03:24.081 [INFO] cli_log::init: Starting small-app v1.0.1 with log level DEBUG //! 21:03:24.081 [DEBUG] small_app: app_data.compute() took 312ns //! 21:03:24.081 [INFO] small_app: count is 42 //! 21:03:24.081 [DEBUG] small_app: data: AppData { //! count: 42, //! } //! 21:03:24.081 [WARN] small_app: this application does nothing //! 21:03:24.081 [INFO] cli_log::mem: Physical mem usage: current=938K, peak=3.3M //! 21:03:24.082 [INFO] small_app: bye //! ``` //! mod file_logger; mod init; mod time; pub use { init::*, log::*, }; #[cfg(feature = "mem")] mod mem; #[cfg(feature = "mem")] pub use mem::log_mem; cli-log-2.0.0/src/mem.rs000064400000000000000000000011430000000000000130400ustar 00000000000000 use log::*; /// log the current and peak physical memory used by /// the current process, if the given log level is /// reached /// /// This function is only available when the feature /// "mem" is enabled and when the OS supports it /// (unix-like systems). pub fn log_mem(level: Level) { if log_enabled!(level) { if let Ok(mem) = proc_status::mem_usage() { log!( level, "Physical mem usage: current={}, peak={}", file_size::fit_4(mem.current as u64), file_size::fit_4(mem.peak as u64), ); } } } cli-log-2.0.0/src/time.rs000064400000000000000000000067520000000000000132330ustar 00000000000000/// print the time that executing some expression took /// but only when relevant according to log level. /// /// The goal of this macro is to avoid doing useless /// `Instant::now`. /// /// Arguments: /// - log level, optional (default is `Debug`) /// - a category, optional (only if name is set) /// - a name, optional (stringified expression is used by default) /// - the expression whose duration we want to log depending on the level /// /// Examples: /// /// ``` /// # use log::*; /// # use cli_log::*; /// # fn do_stuff(arg: usize) -> Result { /// # Ok(arg) /// # } /// # fn main() -> Result<(), String> { /// let result = time!(do_stuff(4)); /// let result = time!(Debug, do_stuff(3))?; /// let result = time!("World creation", do_stuff(7)); /// let sum = time!(Debug, "summing", 2 + 2); /// let sum = time!(Debug, "summing", 2 + 2); /// let mult = time!("operations", "mult 4", 3 * 4); /// let mult = time!(Info, "operations", "mult 4", 3 * 4); /// # Ok(()) /// # } /// ``` #[macro_export] macro_rules! time { ($timed: expr $(,)?) => {{ use cli_log::{*, Level::*}; if log_enabled!(Debug) { let start = std::time::Instant::now(); match $timed { value => { log!(Debug, "{} took {:?}", stringify!($timed), start.elapsed()); value } } } else { $timed } }}; ($level: ident, $timed: expr $(,)?) => {{ use cli_log::{*, Level::*}; if log_enabled!($level) { let start = std::time::Instant::now(); match $timed { value => { log!($level, "{} took {:?}", stringify!($timed), start.elapsed()); value } } } else { $timed } }}; ($name: expr, $timed: expr $(,)?) => {{ use cli_log::{*, Level::*}; if log_enabled!(Debug) { let start = std::time::Instant::now(); match $timed { value => { log!(Debug, "{} took {:?}", $name, start.elapsed()); value } } } else { $timed } }}; ($level: ident, $name: expr, $timed: expr $(,)?) => {{ use cli_log::{*, Level::*}; if log_enabled!($level) { let start = std::time::Instant::now(); match $timed { value => { log!($level, "{} took {:?}", $name, start.elapsed()); value } } } else { $timed } }}; ($cat: expr, $name :expr, $timed: expr $(,)?) => {{ use cli_log::{*, Level::*}; if log_enabled!(Debug) { let start = std::time::Instant::now(); match $timed { value => { log!(Debug, "{} on {:?} took {:?}", $cat, $name, start.elapsed()); value } } } else { $timed } }}; ($level: ident, $cat: expr, $name :expr, $timed: expr $(,)?) => {{ use cli_log::{*, Level::*}; if log_enabled!($level) { let start = std::time::Instant::now(); match $timed { value => { log!($level, "{} on {:?} took {:?}", $cat, $name, start.elapsed()); value } } } else { $timed } }}; }