simple_logger-1.16.0/.cargo_vcs_info.json0000644000000001120000000000100137430ustar { "git": { "sha1": "90db90014e1e1bee30289cf725e7edcf7d307ff2" } } simple_logger-1.16.0/.github/workflows/ci.yml000064400000000000000000000042410072674642500173050ustar 00000000000000--- name: ci on: pull_request: push: branches: - main release: types: - created env: # Just a reassurance to mitigate sudden network connection problems CARGO_NET_RETRY: 10 RUSTUP_MAX_RETRIES: 10 CARGO_INCREMENTAL: 0 RUST_BACKTRACE: full # We don't need any debug symbols on ci, this also speeds up builds a bunch RUSTFLAGS: --deny warnings -Cdebuginfo=0 RUSTDOCFLAGS: --deny warnings jobs: rust-lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable profile: minimal components: rustfmt, clippy - run: cargo clippy --workspace - run: cargo fmt --all -- --check rust-test: runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.toolchain != 'stable' }} strategy: matrix: os: - ubuntu-latest - windows-latest - macos-latest toolchain: - stable features: - "colors" - "threads" - "timestamps" - "stderr" exclude: - os: macos-latest toolchain: stable features: "timestamps" include: - os: ubuntu-latest toolchain: beta features: "colors,threads,timestamps" - os: ubuntu-latest toolchain: nightly features: "colors,threads,timestamps,nightly" steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.toolchain }} profile: minimal - run: cargo +${{ matrix.toolchain }} build --no-default-features --features ${{ matrix.features }} - run: cargo +${{ matrix.toolchain }} test --no-default-features --features ${{ matrix.features }} rust-publish-crates: if: startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest needs: - rust-lint - rust-test steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable profile: minimal - run: cargo publish --token ${{ secrets.CRATES_TOKEN }} simple_logger-1.16.0/.gitignore000064400000000000000000000000220072674642500145530ustar 00000000000000target Cargo.lock simple_logger-1.16.0/Cargo.lock0000644000000057510000000000100117340ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", "winapi", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "colored" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" dependencies = [ "atty", "lazy_static", "winapi", ] [[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "itoa" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" [[package]] name = "log" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", ] [[package]] name = "simple_logger" version = "1.16.0" dependencies = [ "atty", "colored", "log", "time", "winapi", ] [[package]] name = "time" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" dependencies = [ "itoa", "libc", "time-macros", ] [[package]] name = "time-macros" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" simple_logger-1.16.0/Cargo.toml0000644000000027610000000000100117550ustar # 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 are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "simple_logger" version = "1.16.0" authors = ["Sam Clements "] description = "A logger that prints all messages with a readable output format" license = "MIT" repository = "https://github.com/borntyping/rust-simple_logger" [[example]] name = "colors" required-features = ["colors"] [[example]] name = "threads" required-features = ["threads"] [[example]] name = "timestamps_utc" required-features = ["timestamps"] [[example]] name = "timestamps_local" required-features = ["timestamps"] [dependencies.colored] version = "^1.6" optional = true [dependencies.log] version = "^0.4.5" features = ["std"] [dependencies.time] version = "0.3.5" features = ["formatting", "local-offset", "macros"] optional = true [features] colors = ["colored"] default = ["colors", "timestamps"] nightly = [] stderr = [] threads = [] timestamps = ["time"] [target."cfg(windows)".dependencies.atty] version = "0.2.13" [target."cfg(windows)".dependencies.winapi] version = "0.3" features = ["handleapi", "winbase"] simple_logger-1.16.0/Cargo.toml.orig000064400000000000000000000017560072674642500154710ustar 00000000000000[package] name = "simple_logger" version = "1.16.0" license = "MIT" authors = ["Sam Clements "] description = "A logger that prints all messages with a readable output format" repository = "https://github.com/borntyping/rust-simple_logger" edition = "2018" [features] default = ["colors", "timestamps"] colors = ["colored"] threads = [] timestamps = ["time"] nightly = [] stderr = [] [dependencies] log = { version = "^0.4.5", features = ["std"] } time = { version = "0.3.5", features = ["formatting", "local-offset", "macros"], optional = true } colored = { version = "^1.6", optional = true } [target.'cfg(windows)'.dependencies] atty = "0.2.13" winapi = { version = "0.3", features = ["handleapi", "winbase"]} [[example]] name = "colors" required-features = ["colors"] [[example]] name = "threads" required-features = ["threads"] [[example]] name = "timestamps_utc" required-features = ["timestamps"] [[example]] name = "timestamps_local" required-features = ["timestamps"] simple_logger-1.16.0/LICENSE000064400000000000000000000020410072674642500135730ustar 00000000000000Copyright 2015-2021 Sam Clements 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. simple_logger-1.16.0/README.md000064400000000000000000000036750072674642500140630ustar 00000000000000# simple_logger [![](https://img.shields.io/github/tag/borntyping/rust-simple_logger.svg)](https://github.com/borntyping/rust-simple_logger/tags) [![](https://img.shields.io/travis/borntyping/rust-simple_logger.svg)](https://travis-ci.org/borntyping/rust-simple_logger) [![](https://img.shields.io/github/issues/borntyping/rust-simple_logger.svg)](https://github.com/borntyping/rust-simple_logger/issues) A logger that prints all messages with a readable output format. The output format is based on the format used by [Supervisord](http://supervisord.org/). * [Source on GitHub](https://github.com/borntyping/rust-simple_logger) * [Packages on Crates.io](https://crates.io/crates/simple_logger) * [Documentation on Docs.rs](https://docs.rs/simple_logger) Usage ----- ```rust use simple_logger::SimpleLogger; fn main() { SimpleLogger::new().init().unwrap(); log::warn!("This is an example message."); } ``` This outputs: ``` 2015-02-24 01:05:20 WARN [logging_example] This is an example message. ``` You can run the above example with: ```bash cargo run --example init ``` Coloured output and timestamps will be enabled by default. You can remove these features and their respective dependencies by disabling all features in your `Cargo.toml`. ``` [dependencies.simple_logger] default-features = false ``` To include the `timestamps` feature, but not the `colors` feature: ``` [dependencies.simple_logger] default-features = false features = ["timestamps"] ``` To include the `colors` feature, but not the `timestamps` feature: ``` [dependencies.simple_logger] default-features = false features = ["colors"] ``` To direct logging output to `stderr` use the `stderr` feature: ``` [dependencies.simple_logger] features = ["stderr"] ``` This can be combined with any other feature. Licence ------- `simple_logger` is licenced under the [MIT Licence](http://opensource.org/licenses/MIT). Authors ------- Written by [Sam Clements](sam@borntyping.co.uk). simple_logger-1.16.0/examples/colors.rs000064400000000000000000000002330072674642500162540ustar 00000000000000use simple_logger::SimpleLogger; fn main() { SimpleLogger::new().with_colors(true).init().unwrap(); log::warn!("This is an example message."); } simple_logger-1.16.0/examples/init.rs000064400000000000000000000002110072674642500157120ustar 00000000000000use simple_logger::SimpleLogger; fn main() { SimpleLogger::new().init().unwrap(); log::warn!("This is an example message."); } simple_logger-1.16.0/examples/init_with_level.rs000064400000000000000000000003750072674642500201470ustar 00000000000000use log::LevelFilter; use simple_logger::SimpleLogger; fn main() { SimpleLogger::new() .with_level(LevelFilter::Warn) .init() .unwrap(); log::warn!("This will be logged."); log::info!("This will NOT be logged."); } simple_logger-1.16.0/examples/init_with_target_level.rs000064400000000000000000000004560072674642500215150ustar 00000000000000use log::LevelFilter; use simple_logger::SimpleLogger; fn main() { SimpleLogger::new() .with_level(LevelFilter::Info) .with_module_level("init_with_target_level", LevelFilter::Off) .init() .unwrap(); log::info!("This will NOT be logged. (Target disabled)"); } simple_logger-1.16.0/examples/threads.rs000064400000000000000000000011300072674642500164020ustar 00000000000000use simple_logger::SimpleLogger; fn main() { SimpleLogger::new().with_threads(true).init().unwrap(); log::info!("Main thread logs here."); // If the "nightly" feature is enabled, the output will include thread ids. for _ in 1..=5 { std::thread::spawn(|| { log::info!("Unnamed thread logs here."); }) .join() .unwrap(); } std::thread::Builder::new() .name("named_thread".to_string()) .spawn(|| { log::info!("Named thread logs here."); }) .unwrap() .join() .unwrap(); } simple_logger-1.16.0/examples/timestamps_local.rs000064400000000000000000000002410072674642500203120ustar 00000000000000use simple_logger::SimpleLogger; fn main() { SimpleLogger::new().with_local_timestamps().init().unwrap(); log::warn!("This is an example message."); } simple_logger-1.16.0/examples/timestamps_utc.rs000064400000000000000000000002370072674642500200200ustar 00000000000000use simple_logger::SimpleLogger; fn main() { SimpleLogger::new().with_utc_timestamps().init().unwrap(); log::warn!("This is an example message."); } simple_logger-1.16.0/src/lib.rs000064400000000000000000000500000072674642500144670ustar 00000000000000//! A logger that prints all messages with a simple, readable output format. //! //! Optional features include timestamps, colored output and logging to stderr. //! //! ``` //! simple_logger::SimpleLogger::new().env().init().unwrap(); //! //! log::warn!("This is an example message."); //! ``` //! //! Some shortcuts are available for common use cases. //! //! Just initialize logging without any configuration: //! //! ``` //! simple_logger::init().unwrap(); //! ``` //! //! Set the log level from the `RUST_LOG` environment variable: //! //! ``` //! simple_logger::init_with_env().unwrap(); //! ``` //! //! Hardcode a default log level: //! //! ``` //! simple_logger::init_with_level(log::Level::Warn).unwrap(); //! ``` #![cfg_attr(feature = "nightly", feature(thread_id_value))] #[cfg(feature = "colored")] use colored::*; use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError}; use std::collections::HashMap; #[cfg(feature = "timestamps")] use time::{format_description::FormatItem, OffsetDateTime}; #[cfg(feature = "timestamps")] const TIMESTAMP_FORMAT: &[FormatItem] = time::macros::format_description!( "[year]-[month]-[day] [hour]:[minute]:[second],[subsecond digits:3]" ); #[cfg(feature = "timestamps")] #[derive(PartialEq)] enum Timestamps { None, Local, Utc, } /// Implements [`Log`] and a set of simple builder methods for configuration. /// /// Use the various "builder" methods on this struct to configure the logger, /// then call [`init`] to configure the [`log`] crate. pub struct SimpleLogger { /// The default logging level default_level: LevelFilter, /// The specific logging level for each module /// /// This is used to override the default value for some specific modules. /// After initialization, the vector is sorted so that the first (prefix) match /// directly gives us the desired log level. module_levels: Vec<(String, LevelFilter)>, /// Whether to include thread names (and IDs) or not /// /// This field is only available if the `threads` feature is enabled. #[cfg(feature = "threads")] threads: bool, /// Control how timestamps are displayed. /// /// This field is only available if the `timestamps` feature is enabled. #[cfg(feature = "timestamps")] timestamps: Timestamps, /// Whether to use color output or not. /// /// This field is only available if the `color` feature is enabled. #[cfg(feature = "colored")] colors: bool, } impl SimpleLogger { /// Initializes the global logger with a SimpleLogger instance with /// default log level set to `Level::Trace`. /// /// ```no_run /// use simple_logger::SimpleLogger; /// SimpleLogger::new().env().init().unwrap(); /// log::warn!("This is an example message."); /// ``` /// /// [`init`]: #method.init #[must_use = "You must call init() to begin logging"] pub fn new() -> SimpleLogger { SimpleLogger { default_level: LevelFilter::Trace, module_levels: Vec::new(), #[cfg(feature = "threads")] threads: false, #[cfg(feature = "timestamps")] timestamps: Timestamps::Local, #[cfg(feature = "colored")] colors: true, } } /// Simulates env_logger behavior, which enables the user to choose log level by /// setting a `RUST_LOG` environment variable. The `RUST_LOG` is not set or its value is not /// recognized as one of the log levels, this function will use the `Error` level by default. /// /// You may use the various builder-style methods on this type to configure /// the logger, and you must call [`init`] in order to start logging messages. /// /// ```no_run /// use simple_logger::SimpleLogger; /// SimpleLogger::from_env().init().unwrap(); /// log::warn!("This is an example message."); /// ``` /// /// [`init`]: #method.init #[must_use = "You must call init() to begin logging"] #[deprecated( since = "1.12.0", note = "Use [`env`](#method.env) instead. Will be removed in version 2.0.0." )] pub fn from_env() -> SimpleLogger { SimpleLogger::new() .with_level(log::LevelFilter::Error) .env() } /// Simulates env_logger behavior, which enables the user to choose log /// level by setting a `RUST_LOG` environment variable. This will use /// the default level set by [`with_level`] if `RUST_LOG` is not set or /// can't be parsed as a standard log level. /// /// [`with_level`]: #method.with_level #[must_use = "You must call init() to begin logging"] pub fn env(mut self) -> SimpleLogger { if let Ok(level) = std::env::var("RUST_LOG") { match level.to_lowercase().as_str() { "trace" => self.default_level = log::LevelFilter::Trace, "debug" => self.default_level = log::LevelFilter::Debug, "info" => self.default_level = log::LevelFilter::Info, "warn" => self.default_level = log::LevelFilter::Warn, "error" => self.default_level = log::LevelFilter::Error, _ => (), } }; self } /// Set the 'default' log level. /// /// You can override the default level for specific modules and their sub-modules using [`with_module_level`] /// /// [`with_module_level`]: #method.with_module_level #[must_use = "You must call init() to begin logging"] pub fn with_level(mut self, level: LevelFilter) -> SimpleLogger { self.default_level = level; self } /// Override the log level for some specific modules. /// /// This sets the log level of a specific module and all its sub-modules. /// When both the level for a parent module as well as a child module are set, /// the more specific value is taken. If the log level for the same module is /// specified twice, the resulting log level is implementation defined. /// /// # Examples /// /// Silence an overly verbose crate: /// /// ```no_run /// use simple_logger::SimpleLogger; /// use log::LevelFilter; /// /// SimpleLogger::new().with_module_level("chatty_dependency", LevelFilter::Warn).init().unwrap(); /// ``` /// /// Disable logging for all dependencies: /// /// ```no_run /// use simple_logger::SimpleLogger; /// use log::LevelFilter; /// /// SimpleLogger::new() /// .with_level(LevelFilter::Off) /// .with_module_level("my_crate", LevelFilter::Info) /// .init() /// .unwrap(); /// ``` #[must_use = "You must call init() to begin logging"] pub fn with_module_level(mut self, target: &str, level: LevelFilter) -> SimpleLogger { self.module_levels.push((target.to_string(), level)); /* Normally this is only called in `init` to avoid redundancy, but we can't initialize the logger in tests */ #[cfg(test)] self.module_levels .sort_by_key(|(name, _level)| name.len().wrapping_neg()); self } /// Override the log level for specific targets. #[must_use = "You must call init() to begin logging"] #[deprecated( since = "1.11.0", note = "Use [`with_module_level`](#method.with_module_level) instead. Will be removed in version 2.0.0." )] pub fn with_target_levels( mut self, target_levels: HashMap, ) -> SimpleLogger { self.module_levels = target_levels.into_iter().collect(); /* Normally this is only called in `init` to avoid redundancy, but we can't initialize the logger in tests */ #[cfg(test)] self.module_levels .sort_by_key(|(name, _level)| name.len().wrapping_neg()); self } /// Control whether thread names (and IDs) are printed or not. /// /// This method is only available if the `threads` feature is enabled. /// Thread names are disabled by default. #[must_use = "You must call init() to begin logging"] #[cfg(feature = "threads")] pub fn with_threads(mut self, threads: bool) -> SimpleLogger { self.threads = threads; self } /// Control whether timestamps are printed or not. /// /// Timestamps will be displayed in the local timezone. /// /// This method is only available if the `timestamps` feature is enabled. #[must_use = "You must call init() to begin logging"] #[cfg(feature = "timestamps")] #[deprecated( since = "1.16.0", note = "Use [`with_local_timestamps`] or [`with_utc_timestamps`] instead. Will be removed in version 2.0.0." )] pub fn with_timestamps(mut self, timestamps: bool) -> SimpleLogger { if timestamps { self.timestamps = Timestamps::Local } else { self.timestamps = Timestamps::None } self } /// Don't display any timestamps. /// /// This method is only available if the `timestamps` feature is enabled. #[must_use = "You must call init() to begin logging"] #[cfg(feature = "timestamps")] pub fn without_timestamps(mut self) -> SimpleLogger { self.timestamps = Timestamps::None; self } /// Display timestamps using the local timezone. /// /// This method is only available if the `timestamps` feature is enabled. #[must_use = "You must call init() to begin logging"] #[cfg(feature = "timestamps")] pub fn with_local_timestamps(mut self) -> SimpleLogger { self.timestamps = Timestamps::Local; self } /// Display timestamps using UTC. /// /// This method is only available if the `timestamps` feature is enabled. #[must_use = "You must call init() to begin logging"] #[cfg(feature = "timestamps")] pub fn with_utc_timestamps(mut self) -> SimpleLogger { self.timestamps = Timestamps::Utc; self } /// Control whether messages are colored or not. /// /// This method is only available if the `colored` feature is enabled. #[must_use = "You must call init() to begin logging"] #[cfg(feature = "colored")] pub fn with_colors(mut self, colors: bool) -> SimpleLogger { self.colors = colors; self } /// 'Init' the actual logger, instantiate it and configure it, /// this method MUST be called in order for the logger to be effective. pub fn init(mut self) -> Result<(), SetLoggerError> { #[cfg(all(windows, feature = "colored"))] set_up_color_terminal(); /* Sort all module levels from most specific to least specific. The length of the module * name is used instead of its actual depth to avoid module name parsing. */ self.module_levels .sort_by_key(|(name, _level)| name.len().wrapping_neg()); let max_level = self .module_levels .iter() .map(|(_name, level)| level) .copied() .max(); let max_level = max_level .map(|lvl| lvl.max(self.default_level)) .unwrap_or(self.default_level); log::set_max_level(max_level); log::set_boxed_logger(Box::new(self))?; Ok(()) } } impl Default for SimpleLogger { /// See [this](struct.SimpleLogger.html#method.new) fn default() -> Self { SimpleLogger::new() } } impl Log for SimpleLogger { fn enabled(&self, metadata: &Metadata) -> bool { &metadata.level().to_level_filter() <= self .module_levels .iter() /* At this point the Vec is already sorted so that we can simply take * the first match */ .find(|(name, _level)| metadata.target().starts_with(name)) .map(|(_name, level)| level) .unwrap_or(&self.default_level) } fn log(&self, record: &Record) { if self.enabled(record.metadata()) { let level_string = { #[cfg(feature = "colored")] { if self.colors { match record.level() { Level::Error => record.level().to_string().red().to_string(), Level::Warn => record.level().to_string().yellow().to_string(), Level::Info => record.level().to_string().cyan().to_string(), Level::Debug => record.level().to_string().purple().to_string(), Level::Trace => record.level().to_string().normal().to_string(), } } else { record.level().to_string() } } #[cfg(not(feature = "colored"))] { record.level().to_string() } }; let target = if !record.target().is_empty() { record.target() } else { record.module_path().unwrap_or_default() }; let thread = { #[cfg(feature = "threads")] if self.threads { let thread = std::thread::current(); format!("@{}", { #[cfg(feature = "nightly")] { thread.name().unwrap_or(&thread.id().as_u64().to_string()) } #[cfg(not(feature = "nightly"))] { thread.name().unwrap_or("?") } }) } else { "".to_string() } #[cfg(not(feature = "threads"))] "" }; let timestamp = { #[cfg(feature = "timestamps")] match self.timestamps { Timestamps::None => "".to_string(), Timestamps::Local => format!("{} ", OffsetDateTime::now_local().expect(concat!( "Could not determine the UTC offset on this system. ", "Possible causes are that the time crate does not implement \"local_offset_at\" ", "on your system, or that you are running in a multi-threaded environment and ", "the time crate is returning \"None\" from \"local_offset_at\" to avoid unsafe ", "behaviour. See the time crate's documentation for more information. ", "(https://time-rs.github.io/internal-api/time/index.html#feature-flags)" )).format(&TIMESTAMP_FORMAT).unwrap()), Timestamps::Utc => format!("{} ", OffsetDateTime::now_utc().format(&TIMESTAMP_FORMAT).unwrap()), } #[cfg(not(feature = "timestamps"))] "" }; let message = format!( "{}{:<5} [{}{}] {}", timestamp, level_string, target, thread, record.args() ); #[cfg(not(feature = "stderr"))] println!("{}", message); #[cfg(feature = "stderr")] eprintln!("{}", message); } } fn flush(&self) {} } #[cfg(all(windows, feature = "colored"))] fn set_up_color_terminal() { use atty::Stream; if atty::is(Stream::Stdout) { unsafe { use winapi::um::consoleapi::*; use winapi::um::handleapi::*; use winapi::um::processenv::*; use winapi::um::winbase::*; use winapi::um::wincon::*; let stdout = GetStdHandle(STD_OUTPUT_HANDLE); if stdout == INVALID_HANDLE_VALUE { return; } let mut mode: winapi::shared::minwindef::DWORD = 0; if GetConsoleMode(stdout, &mut mode) == 0 { return; } SetConsoleMode(stdout, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); } } } /// Initialise the logger with it's default configuration. /// /// Log messages will not be filtered. /// The `RUST_LOG` environment variable is not used. pub fn init() -> Result<(), SetLoggerError> { SimpleLogger::new().init() } /// Initialise the logger with the `RUST_LOG` environment variable. /// /// Log messages will be filtered based on the `RUST_LOG` environment variable. pub fn init_with_env() -> Result<(), SetLoggerError> { SimpleLogger::new().env().init() } /// Initialise the logger with a specific log level. /// /// Log messages below the given [`Level`] will be filtered. /// The `RUST_LOG` environment variable is not used. pub fn init_with_level(level: Level) -> Result<(), SetLoggerError> { SimpleLogger::new() .with_level(level.to_level_filter()) .init() } /// Use [`init_with_env`] instead. /// /// This does the same as [`init_with_env`] but unwraps the result. #[deprecated( since = "1.12.0", note = "Use [`init_with_env`] instead, which does not unwrap the result. Will be removed in version 2.0.0." )] pub fn init_by_env() { init_with_env().unwrap() } #[cfg(test)] mod test { use super::*; #[test] fn test_module_levels_allowlist() { let logger = SimpleLogger::new() .with_level(LevelFilter::Off) .with_module_level("my_crate", LevelFilter::Info); assert!(logger.enabled(&create_log("my_crate", Level::Info))); assert!(logger.enabled(&create_log("my_crate::module", Level::Info))); assert!(!logger.enabled(&create_log("my_crate::module", Level::Debug))); assert!(!logger.enabled(&create_log("not_my_crate", Level::Debug))); assert!(!logger.enabled(&create_log("not_my_crate::module", Level::Error))); } #[test] fn test_module_levels_denylist() { let logger = SimpleLogger::new() .with_level(LevelFilter::Debug) .with_module_level("my_crate", LevelFilter::Trace) .with_module_level("chatty_dependency", LevelFilter::Info); assert!(logger.enabled(&create_log("my_crate", Level::Info))); assert!(logger.enabled(&create_log("my_crate", Level::Trace))); assert!(logger.enabled(&create_log("my_crate::module", Level::Info))); assert!(logger.enabled(&create_log("my_crate::module", Level::Trace))); assert!(logger.enabled(&create_log("not_my_crate", Level::Debug))); assert!(!logger.enabled(&create_log("not_my_crate::module", Level::Trace))); assert!(logger.enabled(&create_log("chatty_dependency", Level::Info))); assert!(!logger.enabled(&create_log("chatty_dependency", Level::Debug))); assert!(!logger.enabled(&create_log("chatty_dependency::module", Level::Debug))); assert!(logger.enabled(&create_log("chatty_dependency::module", Level::Warn))); } #[test] #[cfg(feature = "timestamps")] fn test_timestamps_defaults() { let builder = SimpleLogger::new(); assert!(builder.timestamps == Timestamps::Local); } #[test] #[cfg(feature = "timestamps")] #[allow(deprecated)] fn test_with_timestamps() { let builder = SimpleLogger::new().with_timestamps(false); assert!(builder.timestamps == Timestamps::None); } #[test] #[cfg(feature = "timestamps")] fn test_with_utc_timestamps() { let builder = SimpleLogger::new().with_utc_timestamps(); assert!(builder.timestamps == Timestamps::Utc); } #[test] #[cfg(feature = "timestamps")] fn test_with_local_timestamps() { let builder = SimpleLogger::new().with_local_timestamps(); assert!(builder.timestamps == Timestamps::Local); } #[test] #[cfg(feature = "colored")] fn test_with_colors() { let mut builder = SimpleLogger::new(); assert!(builder.colors == true); builder = builder.with_colors(false); assert!(builder.colors == false); } fn create_log(name: &str, level: Level) -> Metadata { let mut builder = Metadata::builder(); builder.level(level); builder.target(name); builder.build() } }