The Logger system can now be expanded with external logging libraries.
While external loggers can be used, if you are compiling with --features use_std, then it will default to just printing everything to the stdout unless a logger is created. This library can be used without the STD library, however, you will have to write an external logger.
This commit is contained in:
208
src/lib.rs
208
src/lib.rs
@ -1,12 +1,210 @@
|
||||
///
|
||||
///
|
||||
///
|
||||
//! This is the logging system used by different CyberMages projects.
|
||||
//! This is meant to work with both std and non std Rust programs.
|
||||
|
||||
|
||||
// Handle using the core or the std of Rust depending on the chosen feature.
|
||||
#![cfg_attr(not(feature="use_std"), no_std)]
|
||||
|
||||
// This crate can only use parts of Rust that are in both the core
|
||||
// and the standard library. This way the logging system will work for
|
||||
// libraries that use either.
|
||||
//
|
||||
// This is handled by coding using the std library and referencing the core
|
||||
// library as the std library if the core library is desired.
|
||||
#[cfg(not(feature="use_std"))]
|
||||
extern crate core as std;
|
||||
|
||||
|
||||
|
||||
// Define the modules that are a
|
||||
// part of this library.
|
||||
mod log_level;
|
||||
mod guard;
|
||||
mod levels;
|
||||
mod location;
|
||||
mod logger;
|
||||
mod logger_states;
|
||||
mod macros;
|
||||
mod faux_logger;
|
||||
mod record;
|
||||
|
||||
|
||||
pub use self::log_level::LogLevel;
|
||||
|
||||
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||
|
||||
use self::faux_logger::FauxLogger;
|
||||
use self::guard::Guard;
|
||||
use self::logger_states::LoggerStates;
|
||||
|
||||
pub use self::levels::Levels;
|
||||
pub use self::location::Location;
|
||||
pub use self::logger::Logger;
|
||||
pub use self::record::Record;
|
||||
|
||||
|
||||
|
||||
/// This is the currently set global Logger.
|
||||
/// It will default to a fake Logger that does nothing.
|
||||
static mut GLOBAL_LOGGER: *const Logger = &FauxLogger;
|
||||
|
||||
/// The STATE of the GLOBAL_LOGGER.
|
||||
static STATE: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
|
||||
|
||||
/// Handles setting the GLOBAL_LOGGER and getting
|
||||
/// it ready to log new Records.
|
||||
fn set_logger_base<F>(create_logger: F)
|
||||
-> Result<(), u8>
|
||||
where F: FnOnce() -> *const Logger
|
||||
{
|
||||
if STATE.compare_and_swap(LoggerStates::Uninitialized.into(),
|
||||
LoggerStates::Initializing.into(),
|
||||
Ordering::SeqCst) !=
|
||||
LoggerStates::Uninitialized.into()
|
||||
{
|
||||
return Err(1);
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
GLOBAL_LOGGER = create_logger();
|
||||
}
|
||||
STATE.store(LoggerStates::Initialized.into(), Ordering::SeqCst);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handles clearing the GLOBAL_LOGGER.
|
||||
/// This will return a pointer to the Logger that
|
||||
/// was previously set.
|
||||
fn clear_logger_base() -> Result<*const Logger, u8>
|
||||
{
|
||||
let logger: *const Logger;
|
||||
|
||||
// Set to INITIALIZING to prevent re-initialization after
|
||||
if STATE.compare_and_swap(LoggerStates::Initialized.into(),
|
||||
LoggerStates::Initializing.into(),
|
||||
Ordering::SeqCst) !=
|
||||
LoggerStates::Initialized.into()
|
||||
{
|
||||
return Err(2);
|
||||
}
|
||||
|
||||
// Wait until there are no references alive to the
|
||||
// current GLOBAL_LOGGER.
|
||||
Guard::spin_until(0);
|
||||
|
||||
// Change the GLOBAL_LOGGER to the fake one to unset it.
|
||||
unsafe
|
||||
{
|
||||
logger = GLOBAL_LOGGER;
|
||||
GLOBAL_LOGGER = &FauxLogger;
|
||||
Ok(logger)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current logger.
|
||||
///
|
||||
/// This should be the FauxLogger if no logger has been set,
|
||||
/// or whatever logger has been set. If a logger has been
|
||||
/// cleared then this will return None.
|
||||
fn get_logger() -> Option<Guard>
|
||||
{
|
||||
let guard: Guard;
|
||||
|
||||
if STATE.load(Ordering::SeqCst) != LoggerStates::Initializing.into()
|
||||
{
|
||||
None
|
||||
}
|
||||
else
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
guard = Guard::new(GLOBAL_LOGGER);
|
||||
}
|
||||
|
||||
Some(guard)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Logger to use for logging.
|
||||
#[cfg(not(feature="use_std"))]
|
||||
pub fn set_logger<F>(create_logger: F)
|
||||
-> Result<(), u8>
|
||||
where F: FnOnce() -> *const Logger
|
||||
{
|
||||
set_logger_base(create_logger)
|
||||
}
|
||||
|
||||
/// Clear the logger currently being used.
|
||||
///
|
||||
/// This will return a pointer to the Logger that
|
||||
/// was previously set.
|
||||
#[cfg(not(feature="use_std"))]
|
||||
pub fn clear_logger() -> Result<*const Logger, u8>
|
||||
{
|
||||
clear_logger_base()
|
||||
}
|
||||
|
||||
/// Set the Logger to use for logging.
|
||||
#[cfg(feature="use_std")]
|
||||
pub fn set_logger<F>(create_logger: F)
|
||||
-> Result<(), u8>
|
||||
where F: FnOnce() -> Box<Logger>
|
||||
{
|
||||
// I hate using closures, but it is the only way I
|
||||
// can think of to handle this right now.
|
||||
unsafe
|
||||
{
|
||||
set_logger_base(|| ::std::mem::transmute(create_logger()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the logger currently being used.
|
||||
///
|
||||
/// This will return a pointer to the Logger that
|
||||
/// was previously set.
|
||||
#[cfg(feature="use_std")]
|
||||
pub fn clear_logger() -> Result<Box<Logger>, u8>
|
||||
{
|
||||
match clear_logger_base()
|
||||
{
|
||||
Ok(logger) =>
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
Ok(::std::mem::transmute(logger))
|
||||
}
|
||||
}
|
||||
|
||||
Err(error) =>
|
||||
{
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Do NOT use outside of this crate.
|
||||
///
|
||||
/// This records a log message.
|
||||
#[doc(hidden)]
|
||||
pub fn log_record(domain: &str, lvl: Levels, module_path: &str,
|
||||
file_name: &str, line_num: u32,
|
||||
message: ::std::fmt::Arguments)
|
||||
{
|
||||
let mut record: Record;
|
||||
|
||||
match get_logger()
|
||||
{
|
||||
Some(logger) =>
|
||||
{
|
||||
record = Record::new(domain, lvl, message);
|
||||
record.set_location(module_path, file_name, line_num);
|
||||
|
||||
logger.log(&record)
|
||||
}
|
||||
|
||||
None =>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user