From 44bbdbd93becbda82fd8adf5d17151310b08aa67 Mon Sep 17 00:00:00 2001 From: dan pittman Date: Tue, 20 Jun 2017 10:30:49 -0700 Subject: [PATCH] removes shutdown and adds `flush` to Log trait. Signed-off-by: dan pittman --- env/src/lib.rs | 2 + src/lib.rs | 148 +++++-------------------------- tests/filters.rs | 1 + tests/max_level_features/main.rs | 2 + 4 files changed, 25 insertions(+), 128 deletions(-) diff --git a/env/src/lib.rs b/env/src/lib.rs index cc39833..4c6ca69 100644 --- a/env/src/lib.rs +++ b/env/src/lib.rs @@ -375,6 +375,8 @@ impl Log for Logger { }, }; } + + fn flush(&self) {} } struct Directive { diff --git a/src/lib.rs b/src/lib.rs index f485c1b..9f3bfcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -150,6 +150,7 @@ //! println!("{} - {}", record.level(), record.args()); //! } //! } +//! fn flush(&self) {} //! } //! //! # fn main() {} @@ -173,6 +174,7 @@ //! # impl log::Log for SimpleLogger { //! # fn enabled(&self, _: &Metadata) -> bool { false } //! # fn log(&self, _: &log::Record) {} +//! # fn flush(&self) {} //! # } //! # fn main() {} //! # #[cfg(feature = "use_std")] @@ -189,19 +191,15 @@ //! `default-features = false` when specifying the dependency in `Cargo.toml`. //! This makes no difference to libraries using `log` since the logging API //! remains the same. However executables will need to use the [`set_logger_raw`] -//! function to initialize a logger and the [`shutdown_logger_raw`] function to -//! shut down the global logger before exiting: +//! function to initialize a logger. //! //! ```rust //! # extern crate log; -//! # use log::{Level, LevelFilter, SetLoggerError, ShutdownLoggerError, -//! # Metadata}; +//! # use log::{Level, LevelFilter, Log, SetLoggerError, Metadata}; //! # struct SimpleLogger; //! # impl log::Log for SimpleLogger { //! # fn enabled(&self, _: &Metadata) -> bool { false } //! # fn log(&self, _: &log::Record) {} -//! # } -//! # impl SimpleLogger { //! # fn flush(&self) {} //! # } //! # fn main() {} @@ -214,12 +212,6 @@ //! }) //! } //! } -//! pub fn shutdown() -> Result<(), ShutdownLoggerError> { -//! log::shutdown_logger_raw().map(|logger| { -//! let logger = unsafe { &*(logger as *const SimpleLogger) }; -//! logger.flush(); -//! }) -//! } //! ``` //! //! # Features @@ -241,7 +233,6 @@ //! [`set_logger`]: fn.set_logger.html //! [`MaxLevelFilter`]: struct.MaxLevelFilter.html //! [`set_logger_raw`]: fn.set_logger_raw.html -//! [`shutdown_logger_raw`]: fn.shutdown_logger_raw.html //! [env_logger]: https://docs.rs/env_logger/*/env_logger/ //! [simple_logger]: https://github.com/borntyping/rust-simple_logger //! [simplelog]: https://github.com/drakulix/simplelog.rs @@ -275,7 +266,6 @@ use std::cmp; use std::error; use std::fmt; use std::mem; -use std::ops::Deref; use std::str::FromStr; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; @@ -283,29 +273,15 @@ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; mod macros; mod serde; -// The setup here is a bit weird to make shutdown_logger_raw work. -// -// There are four different states that we care about: the logger's +// There are three different states that we care about: the logger's // uninitialized, the logger's initializing (set_logger's been called but -// LOGGER hasn't actually been set yet), the logger's active, or the logger is -// shut down after calling shutdown_logger_raw. +// LOGGER hasn't actually been set yet), or the logger's active. // // The LOGGER static holds a pointer to the global logger. It is protected by // the STATE static which determines whether LOGGER has been initialized yet. -// -// The shutdown_logger_raw routine needs to make sure that no threads are -// actively logging before it returns. The number of actively logging threads is -// tracked in the REFCOUNT static. The routine first sets STATE back to -// INITIALIZING. All logging calls past that point will immediately return -// without accessing the logger. At that point, the at_exit routine just waits -// for the refcount to reach 0 before deallocating the logger. Note that the -// refcount does not necessarily monotonically decrease at this point, as new -// log calls still increment and decrement it, but the interval in between is -// small enough that the wait is really just for the active log calls to finish. static mut LOGGER: *const Log = &NopLogger; static STATE: AtomicUsize = ATOMIC_USIZE_INIT; -static REFCOUNT: AtomicUsize = ATOMIC_USIZE_INIT; const UNINITIALIZED: usize = 0; const INITIALIZING: usize = 1; @@ -317,7 +293,6 @@ static LOG_LEVEL_NAMES: [&'static str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DE static SET_LOGGER_ERROR: &'static str = "attempted to set a logger after the logging system \ was already initialized"; -static SHUTDOWN_LOGGER_ERROR: &'static str = "attempted to shut down the logger without an active logger"; static LEVEL_PARSE_ERROR: &'static str = "attempted to convert a string that doesn't match an existing log level"; /// An enum representing the available verbosity levels of the logger. @@ -613,6 +588,7 @@ impl LevelFilter { /// record.location().module_path(), /// record.args()); /// } +/// fn flush(&self) {} /// } /// ``` /// @@ -691,6 +667,7 @@ impl<'a> Record<'a> { /// println!("{} - {}", record.level(), record.args()); /// } /// } +/// fn flush(&self) {} /// } /// /// # fn main(){} @@ -729,6 +706,9 @@ pub trait Log: Sync + Send { /// Implementations of `log` should perform all necessary filtering /// internally. fn log(&self, record: &Record); + + /// Flushes any buffered records. + fn flush(&self); } // Just used as a dummy initial value for LOGGER @@ -740,6 +720,7 @@ impl Log for NopLogger { } fn log(&self, _: &Record) {} + fn flush(&self) {} } /// The location of a log message. @@ -776,6 +757,7 @@ impl Log for NopLogger { /// location.line(), /// record.args()); /// } +/// fn flush(&self) {} /// } /// ``` /// @@ -906,6 +888,7 @@ pub fn max_level() -> LevelFilter { /// println!("Rust says: {} - {}", record.level(), record.args()); /// } /// } +/// fn flush(&self) {} /// } /// /// fn try_init() -> Result<(), SetLoggerError> { @@ -981,8 +964,7 @@ pub fn set_logger(logger: Box, filter: LevelFilter) { /// # Safety /// /// The pointer returned by `make_logger` must remain valid for the entire -/// duration of the program or until [`shutdown_logger_raw`] is called. In -/// addition, [`shutdown_logger`] *must not* be called after this function. +/// duration of the program. /// /// # Examples /// @@ -1006,14 +988,15 @@ pub fn set_logger(logger: Box, filter: LevelFilter) { /// println!("{} - {}", record.level(), record.args()); /// } /// } +/// fn flush(&self) {} /// } /// /// # fn main(){ /// unsafe { -/// log::set_logger_raw(|max_log_level| { +/// log::set_logger_raw(|max_log_level| { /// max_log_level.set(LevelFilter::Info); /// &MY_LOGGER as *const MyLogger -/// }) +/// }) /// }; /// /// info!("hello log"); @@ -1023,8 +1006,6 @@ pub fn set_logger(logger: Box, filter: LevelFilter) { /// ``` /// /// [`set_logger`]: fn.set_logger.html -/// [`shutdown_logger`]: fn.shutdown_logger.html -/// [`shutdown_logger_raw`]: fn.shutdown_logger_raw.html pub unsafe fn set_logger_raw(make_logger: M) -> Result<(), SetLoggerError> where M: FnOnce(MaxLevelFilter) -> *const Log { @@ -1037,55 +1018,6 @@ pub unsafe fn set_logger_raw(make_logger: M) -> Result<(), SetLoggerError> Ok(()) } -/// Shuts down the global logger. -/// -/// This function may only be called once in the lifetime of a program, and may -/// not be called before `set_logger`. Once the global logger has been shut -/// down, it can no longer be re-initialized by `set_logger`. Any log events -/// that occur after the call to `shutdown_logger` completes will be ignored. -/// -/// The logger that was originally created by the call to to `set_logger` is -/// returned on success. At that point it is guaranteed that no other threads -/// are concurrently accessing the logger object. -#[cfg(feature = "use_std")] -pub fn shutdown_logger() -> Result, ShutdownLoggerError> { - shutdown_logger_raw().map(|l| unsafe { mem::transmute(l) }) -} - -/// Shuts down the global logger. -/// -/// This function is similar to `shutdown_logger` except that it is usable in -/// `no_std` code. -/// -/// This function may only be called once in the lifetime of a program, and may -/// not be called before `set_logger_raw`. Once the global logger has been shut -/// down, it can no longer be re-initialized by `set_logger_raw`. Any log -/// events that occur after the call to `shutdown_logger_raw` completes will be -/// ignored. -/// -/// The pointer that was originally passed to `set_logger_raw` is returned on -/// success. At that point it is guaranteed that no other threads are -/// concurrently accessing the logger object. -pub fn shutdown_logger_raw() -> Result<*const Log, ShutdownLoggerError> { - // Set the global log level to stop other thread from logging - MAX_LOG_LEVEL_FILTER.store(0, Ordering::SeqCst); - - // Set to INITIALIZING to prevent re-initialization after - if STATE.compare_and_swap(INITIALIZED, INITIALIZING, Ordering::SeqCst) != INITIALIZED { - return Err(ShutdownLoggerError(())); - } - - while REFCOUNT.load(Ordering::SeqCst) != 0 { - // FIXME add a sleep here when it doesn't involve timers - } - - unsafe { - let logger = LOGGER; - LOGGER = &NopLogger; - Ok(logger) - } -} - /// The type returned by [`set_logger`] if [`set_logger`] has already been called. /// [`set_logger`]: fn.set_logger.html #[allow(missing_copy_implementations)] @@ -1106,28 +1038,6 @@ impl error::Error for SetLoggerError { } } -/// The type returned by [`shutdown_logger_raw`] if [`shutdown_logger_raw`] has -/// already been called or if [`set_logger_raw`] has not been called yet. -/// [`set_logger_raw`]: fn.set_logger_raw.html -/// [`shutdown_logger_raw`]: fn.shutdown_logger_raw.html -#[allow(missing_copy_implementations)] -#[derive(Debug)] -pub struct ShutdownLoggerError(()); - -impl fmt::Display for ShutdownLoggerError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str(SHUTDOWN_LOGGER_ERROR) - } -} - -// The Error trait is not available in libcore -#[cfg(feature = "use_std")] -impl error::Error for ShutdownLoggerError { - fn description(&self) -> &str { - SHUTDOWN_LOGGER_ERROR - } -} - /// The type returned by [`from_str`] when the string doesn't match any of the log levels. /// [`from_str`]: https://doc.rust-lang.org/std/str/trait.FromStr.html#tymethod.from_str #[allow(missing_copy_implementations)] @@ -1190,29 +1100,11 @@ mod panic { } } -struct LoggerGuard(&'static Log); - -impl Drop for LoggerGuard { - fn drop(&mut self) { - REFCOUNT.fetch_sub(1, Ordering::SeqCst); - } -} - -impl Deref for LoggerGuard { - type Target = Log; - - fn deref(&self) -> &(Log + 'static) { - self.0 - } -} - -fn logger() -> Option { - REFCOUNT.fetch_add(1, Ordering::SeqCst); +fn logger() -> Option<&'static Log> { if STATE.load(Ordering::SeqCst) != INITIALIZED { - REFCOUNT.fetch_sub(1, Ordering::SeqCst); None } else { - Some(LoggerGuard(unsafe { &*LOGGER })) + Some(unsafe { &*LOGGER }) } } diff --git a/tests/filters.rs b/tests/filters.rs index f40af72..5fc55b2 100644 --- a/tests/filters.rs +++ b/tests/filters.rs @@ -29,6 +29,7 @@ impl Log for Logger { fn log(&self, record: &Record) { *self.0.last_log.lock().unwrap() = Some(record.level()); } + fn flush(&self) {} } fn main() { diff --git a/tests/max_level_features/main.rs b/tests/max_level_features/main.rs index 49f607d..168f024 100644 --- a/tests/max_level_features/main.rs +++ b/tests/max_level_features/main.rs @@ -30,6 +30,8 @@ impl Log for Logger { fn log(&self, record: &Record) { *self.0.last_log.lock().unwrap() = Some(record.level()); } + + fn flush(&self) {} } fn main() {