.
//
//!
//! # Logger
//!
//! `Logger` is the work-horse of the crate.
//!
//! It contains the primary methods to both create a logger instance, and has
//! the methods to add log messages at various log levels.
//!
#![allow()]
mod builder;
mod level;
mod log_entry;
use ::{,, Result};
use ::::{,};
use ::::::IterMut;
use ::::{,};
use ::::consts;
use ::::{,};
use ::::Write;
use ::::PhantomData;
use ::module_path;
use ::::DerefMut;
use ::::Path;
use ::::::Sender;
use ::::{,,,};
use ::thread;
use ::{,};
pub use ::*;
pub use ::Level;
pub use ::LogEntry;
use crate::*;
///
/// This is the work-horse, providing the primary methods of the crate.
///
pub struct Logger {
///
/// Identify the source of log messages passed to this logger.
///
/// This would ideally be the **mod** path.
///
mod_path:
///
/// The name of the function/method inside which the log message
/// is generated.
///
fn_name:
///
/// Default level used by `log(msg)`.
///
level:
///
/// Holds the handlers associated with this logger.
///
handlers: <<<>>>
}
impl Logger {
///
/// Create a new Logger instance.
///
/// Logging level is set to it's default setting (INFO).
///
/// No `handlers` are set. Use the various methods of
/// [`LoggerBuilder`] to configure the new `Logger`.
///
/// ## Parameters
/// - `mod_path` - The module path. Can be set with: [`module_path!()`]
///
/// Returns a `LoggerBuilder` for further configuring.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::builder(module_path!())
/// .add_console_handler()
/// .build();
/// ```
///
pub fn builder(mod_path: &str) -> {
::(to_string())
}
///
/// Log a CONFIG message.
///
/// If the logger is currently enabled for the CONFIG message level
/// then the given message is forwarded to all the registered output
/// Handler objects.
///
/// ## Parameters
/// - `msg` - The string message.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::console_logger(module_path!());
/// log.set_level(Level::CONFIG);
/// log.config("Some text to store.");
/// ```
///
pub fn config(&mut selfmsg: &str) {
selflog(::CONFIG, &selffn_name(),);
}
///
/// Create new Logger instance, with a `ConsoleHandler`, output
/// set to: [`std::io::stdout`].
///
/// Logging level is set to it's default setting (INFO).
///
/// ## Parameters
/// - `mod_path`- The module path. Suggest using [`module_path!()`].
///
/// Returns a configured `Logger`.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::console_logger(module_path!());
/// log.set_fn_name("main");
///
/// log.warning("Don't over do it.");
/// ```
/// Output to stdout:
/// ```text
/// flogging->main [WARNING] Don't over do it.
/// ```
///
pub fn console_logger(mod_path: &str) -> {
::()add_console_handler()build()
}
///
/// Create new Logger instance, with a custom handler.
///
/// ## Parameters
/// - `mod_path`- The module path. Suggest using [`module_path!()`].
/// - `label` - Unique label for this custom handler.
/// - `custom` - The boxed custom handler.
///
/// Returns a configured `Logger`.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::custom_logger(
/// module_path!(),
/// "MockHandler",
/// Box::new(MockHandler::create("Some text").unwrap()),
/// );
/// log.set_fn_name("main");
///
/// log.warning("Don't over do it.");
/// ```
/// [`MockHandler`] doesn't publish anything, as [`publish()`][MockHandler::publish()] is a **NoOp** method.
/// It is used here to make the example work.
///
/// However, it is expected that _your_ custom handler will do a little more.
///
pub fn custom_logger(mod_path: &strlabel: &strcustom: <>) -> {
::()
add_custom_handler(,)
build()
}
///
/// Create new Logger instance, with a `ConsoleHandler`, output
/// set to: [`std::io::stderr`].
///
/// Logging level is set to it's default setting (INFO).
///
/// ## Parameters
/// - `mod_path`- The module path. Suggest using [`module_path!()`].
///
/// Returns a configured `Logger`.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::econsole_logger(module_path!());
/// log.set_fn_name("main");
///
/// log.warning("Don't over do it.");
/// ```
/// Output to stderr:
/// ```text
/// flogging->main [WARNING] Don't over do it.
/// ```
///
pub fn econsole_logger(mod_path: &str) -> {
::()add_econsole_handler()build()
}
///
/// Log a method entry.
///
/// This is a convenience method that can be used to log entry to a method.
/// A `LogEntry` with message "Entry" and log level FINER, is logged.
///
/// ## Examples
/// ```
/// mod my_mod {
/// extern crate flogging;
/// use flogging::*;
/// use std::cell::{LazyCell, RefCell};
///
/// // Setting up the module level logger.
/// const LOGGER: LazyCell<RefCell<Logger>> = LazyCell::new(|| {
/// RefCell::new({
/// Logger::builder(module_path!())
/// .add_console_handler()
/// .set_level(Level::FINEST)
/// .build()
/// })
/// });
///
/// pub fn my_func(data: &str) {
/// let binding = LOGGER;
/// let mut log = binding.borrow_mut();
/// log.set_fn_name("my_func");
///
/// log.entering();
/// }
/// }
///
/// fn main() {
/// let data = "Some data";
/// my_mod::my_func(data);
/// }
/// ```
/// Output:
/// ```text
/// flogging::my_mod->my_func [FINER ] Entry
/// ```
///
pub fn entering(&mut self) {
selflog(::FINER, &selffn_name(), "Entry");
}
///
/// Log a method entry.
///
/// This is a convenience method that can be used to log entry to a method.
/// A `LogEntry` with message "Entry" and log level FINER, is logged.
///
/// ## Parameters
/// - `msg` - The string message.
///
/// ## Examples
/// ```
/// mod my_mod {
/// extern crate flogging;
/// use flogging::*;
/// use std::cell::{LazyCell, RefCell};
///
/// // Setting up the module level logger.
/// const LOGGER: LazyCell<RefCell<Logger>> = LazyCell::new(|| {
/// RefCell::new({
/// Logger::builder(module_path!())
/// .add_console_handler()
/// .set_level(Level::FINEST)
/// .build()
/// })
/// });
///
/// pub fn my_func(data: &str) {
/// let binding = LOGGER;
/// let mut log = binding.borrow_mut();
/// log.set_fn_name("my_func");
///
/// log.entering_with(&format!("data: \"{data}\""));
/// }
/// }
///
/// fn main() {
/// let data = "Some data";
/// my_mod::my_func(data);
/// }
/// ```
/// Output:
/// ```text
/// flogging::my_mod->my_func [FINER ] Entry: (data: "Some data")
/// ```
///
pub fn entering_with(&mut selfmsg: &str) {
selflog(
::FINER,
&selffn_name(),
&("Entry: ("to_string() ++ ")"),
);
}
///
/// Log a method return.
///
/// This is a convenience method that can be used to log returning from a method.
/// A `LogEntry` with message "Return" and log level FINER, is logged.
///
/// ## Examples
/// ```
/// mod my_mod {
/// extern crate flogging;
/// use flogging::*;
/// use std::cell::{LazyCell, RefCell};
///
/// // Setting up the module level logger.
/// const LOGGER: LazyCell<RefCell<Logger>> = LazyCell::new(|| {
/// RefCell::new({
/// Logger::builder(module_path!())
/// .add_console_handler()
/// .set_level(Level::FINEST)
/// .build()
/// })
/// });
///
/// pub fn my_func(data: &str) {
/// let binding = LOGGER;
/// let mut log = binding.borrow_mut();
/// log.set_fn_name("my_func");
///
/// log.exiting();
/// }
/// }
///
/// fn main() {
/// let data = "Some data";
/// my_mod::my_func(data);
/// }
/// ```
/// Output:
/// ```text
/// flogging::my_mod->my_func [FINER ] Return
/// ```
///
pub fn exiting(&mut self) {
selflog(::FINER, &selffn_name(), "Return");
}
///
/// Log a method return.
///
/// This is a convenience method that can be used to log returning from a method.
/// A `LogEntry` with message "Return" and log level FINER, is logged.
///
/// ## Parameters
/// - `msg` - The string message.
///
/// ## Examples
/// ```
/// mod my_mod {
/// extern crate flogging;
/// use flogging::*;
/// use std::cell::{LazyCell, RefCell};
///
/// // Setting up the module level logger.
/// const LOGGER: LazyCell<RefCell<Logger>> = LazyCell::new(|| {
/// RefCell::new({
/// Logger::builder(module_path!())
/// .add_console_handler()
/// .set_level(Level::FINEST)
/// .build()
/// })
/// });
///
/// pub fn my_func(data: &str) -> bool {
/// let binding = LOGGER;
/// let mut log = binding.borrow_mut();
/// log.set_fn_name("my_func");
///
/// let rtn = true;
/// log.exiting_with(&format!("rtn: {rtn}"));
/// rtn
/// }
/// }
///
/// fn main() {
/// let data = "Some data";
/// my_mod::my_func(data);
/// }
/// ```
/// Output:
/// ```text
/// flogging::my_mod->my_func [FINER ] Return: (rtn: true)
/// ```
///
pub fn exiting_with(&mut selfmsg: &str) {
selflog(
::FINER,
&selffn_name(),
&("Return: ("to_string() ++ ")"),
);
}
///
/// Create new Logger instance, with a `FileHandler`.
///
/// Logging level is set to it's default setting (INFO).
///
/// ## Parameters
/// - `mod_path`- The module path. Suggest using [`std::module_path`][mp].
/// - `filename` - The name of the log file to use. Will be created
/// if it doesn't exist.
///
/// Returns a configured `Logger`.
///
/// ## Examples
/// ```
/// use flogging::Logger;
///
/// let mut log = Logger::file_logger(module_path!(), "test_logs/logger.log");
/// log.set_fn_name("main");
///
/// log.info("Some text to store.");
/// ```
/// Output:
/// ```text
/// 2025-07-18T12:14:47.322720683+08:00 flogging->main [INFO ] Some text to store.
/// ```
///
/// [mp]: https://doc.rust-lang.org/std/macro.module_path.html
pub fn file_logger(mod_path: &strfilename: &str) -> {
::()add_file_handler()build()
}
///
/// Log a FINE message.
///
/// If the logger is currently enabled for the FINE message level
/// then the given message is forwarded to all the registered output
/// Handler objects.
///
/// ## Parameters
/// - `msg` - The string message.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::console_logger(module_path!());
/// log.set_level(Level::FINEST);
/// log.set_fn_name("main");
///
/// log.fine("Some text to store.");
/// ```
/// Output:
/// ```text
/// flogging->main [FINE ] Some text to store.
/// ```
///
pub fn fine(&mut selfmsg: &str) {
selflog(::FINE, &selffn_name(),);
}
///
/// Log a FINER message.
///
/// If the logger is currently enabled for the FINER message level
/// then the given message is forwarded to all the registered output
/// Handler objects.
///
/// ## Parameters
/// - `msg` - The string message.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::console_logger(module_path!());
/// log.set_level(Level::FINEST);
/// log.set_fn_name("main");
///
/// log.finer("Some text to store.");
/// ```
/// Output:
/// ```text
/// flogging->main [FINER ] Some text to store.
/// ```
///
pub fn finer(&mut selfmsg: &str) {
selflog(::FINER, &selffn_name(),);
}
///
/// Log a FINEST message.
///
/// If the logger is currently enabled for the FINEST message level
/// then the given message is forwarded to all the registered output
/// Handler objects.
///
/// ## Parameters
/// - `msg` - The string message.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::console_logger(module_path!());
/// log.set_level(Level::FINEST);
/// log.set_fn_name("main");
///
/// log.finest("Some text to store.");
/// ```
/// Output:
/// ```text
/// flogging->main [FINEST ] Some text to store.
/// ```
///
pub fn finest(&mut selfmsg: &str) {
selflog(::FINEST, &selffn_name(),);
}
///
/// Get the current function/method name.
///
pub fn fn_name(&self) -> {
selfclone()
}
///
/// Get required `Handler`.
///
/// ## Parameters
/// - `handler` - The enum of the required handler.
///
/// Returns Some boxed handler, or None.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::string_logger(module_path!());
/// log.set_fn_name("get_handler");
///
/// log.info("Some text to store.");
///
/// let h = log.get_handler(Handler::String).unwrap();
/// println!("{h}");
/// ```
pub fn get_handler(&mut selfhandler:) -> <<&mut>> {
match selfget_mut()get_mut(&) {
Some() => Some(Box::(&mut **)),
None => None,
}
}
///
/// Check if the required `Handler` has been added to this `Logger`.
///
/// ## Parameters
/// - `handler` - The enum of the required handler.
///
/// Returns `true` if it exists, `false` otherwise.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::string_logger(module_path!());
/// log.info("Some text to store.");
///
/// println!("This logger has a 'StringHandler': {}", log.has_handler(Handler::String));
/// ```
pub fn has_handler(&selfhandler:) -> bool {
selfborrow()contains_key(&)
}
///
/// Log a INFO message.
///
/// If the logger is currently enabled for the INFO message level
/// then the given message is forwarded to all the registered output
/// Handler objects.
///
/// ## Parameters
/// - `msg` - The string message.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::console_logger(module_path!());
/// log.set_level(Level::FINEST);
/// log.set_fn_name("main");
///
/// log.info("Some text to store.");
/// ```
/// Output:
/// ```text
/// flogging->main [INFO ] Some text to store.
/// ```
///
pub fn info(&mut selfmsg: &str) {
selflog(::INFO, &selffn_name(),);
}
///
/// Check if a message of the given level would actually be logged by this logger.
///
/// ## Parameters
/// - `level` - The level to compare with.
///
/// Returns `true` if it is loggable, `false` if not.
///
fn is_loggable(&selflevel: &) -> bool {
*>= self
}
///
/// Checks whether or not this logger is processing log requests.
///
/// Returns `true` if it is, `false` if not.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::console_logger(module_path!());
/// log.set_level(Level::OFF);
/// log.set_fn_name("main");
///
/// let msg = "The program might become unstable.";
/// log.warning(msg);
///
/// if !log.is_logging() {
/// eprintln!{"{msg}"};
/// }
/// ```
/// Output to [`std::io::stderr`]:
/// ```text
/// The program might become unstable.
/// ```
///
pub fn is_logging(&self) -> bool {
selflevel() != &::OFF
}
///
/// Obtain the current logging level for this Log instance.
///
pub fn level(&self) -> & {
&self
}
///
/// Log a `LogEntry`.
///
/// All the other logging methods in this class call through this method to actually
/// perform any logging.
///
/// ## Parameters
/// - `entry` - The `LogEntry` to be published.
///
fn _log(&mut selfentry: &mut) {
set_mod_path(selfclone());
forin selfget_mut() {
1.publish();
}
}
///
/// Log a message, with no arguments.
///
/// If the logger is currently enabled for the given message level then the given
/// message is forwarded to all the registered output `Handler` objects.
///
/// ## Parameters
/// - `level` - One of the message level identifiers, e.g., SEVERE.
/// - `fn_name` - The name of the function/method from-which this method
/// was called.
/// - `msg` - The string message.
///
fn log(&mut selflevel:fn_name: &strmsg: &str) {
if !selfis_loggable(&) {
return;
}
// build LogEntry
let mut= ::(,to_string(),to_string());
// Send LogEntry
self_log(&mut);
}
///
/// Create new Logger instance, with a `ConsoleHandler`, output
/// set to: [`std::io::stdout`].
///
/// Logging level is set to it's default setting (INFO).
///
/// All `INFO` level log entries are output without any formatting.
/// All other levels are processed through the formatter, first.
///
/// ## Parameters
/// - `mod_path`- The module path. Suggest using [`module_path!()`].
///
/// Returns a configured `Logger`.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::pconsole_logger(module_path!());
/// log.set_fn_name("main");
///
/// log.warning("Don't over do it.");
/// ```
/// Output to stderr:
/// ```text
/// flogging->main [WARNING] Don't over do it.
/// ```
///
pub fn pconsole_logger(mod_path: &str) -> {
::()add_pconsole_handler()build()
}
///
/// Remove an existing log file.
///
/// The purpose of this, is to allow resetting of the log file, each time
/// a test run is done.
///
/// ## Note
///
/// This **must** be called _before_ adding the corresponding file handler
/// that is going to open this file.
///
/// ## Parameters
///
/// - `filename` - The name of the output log file. Must include any relevant
/// path (relative or absolute).
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// Logger::remove_file("test_logs/logger.log");
/// let mut log = Logger::file_logger(module_path!(), "test_logs/logger.log");
/// log.set_fn_name("main");
/// log.info("Something to log.");
/// ```
///
pub fn remove_file(filename: &str) {
let _ = ::()is_err();
}
///
/// Set the current function/method name.
///
/// ## Parameters
/// - `fn_name` - The name of the function/method in which you are
/// logging.
///
/// Returns itself for chaining purposes.
///
pub fn set_fn_name(&mut selffn_name: &str) -> &mut Self {
self=to_string();
self
}
///
/// Set logging level for this Log instance.
///
/// ## Parameters
/// - `level` - The new logging level to set.
///
/// Returns itself for chaining purposes.
///
pub fn set_level(&mut selflevel:) -> &mut Self {
self=;
self
}
///
/// Log a SEVERE message.
///
/// If the logger is currently enabled for the SEVERE message level
/// then the given message is forwarded to all the registered output
/// Handler objects.
///
/// ## Parameters
/// - `msg` - The string message.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::console_logger(module_path!());
/// log.set_level(Level::FINEST);
/// log.set_fn_name("main");
///
/// log.severe("Some text to store.");
/// ```
/// Output:
/// ```text
/// flogging->main [SEVERE ] Some text to store.
/// ```
///
pub fn severe(&mut selfmsg: &str) {
selflog(::SEVERE, &selffn_name(),);
}
///
/// Create new Logger instance, with a `ConsoleHandler`.
///
/// Logging level is set to it's default setting (INFO).
///
/// I expect this will be primarily used during unit testing of
/// the logging output. Though, any requirement to pass-on the log entry,
/// perhaps for further processing, would also be a valid use case.
///
/// ## Parameters
/// - `mod_path`- The module path. Suggest using [`module_path!()`].
///
/// Returns a configured `Logger`.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::string_logger(module_path!());
/// log.set_fn_name("main");
///
/// log.warning("Don't over do it.");
///
/// let log_str = log.get_handler(Handler::String).unwrap().get_log();
///
/// println!("{log_str}");
/// ```
/// Output:
/// ```text
/// flogging->main [WARNING] Don't over do it.
/// ```
///
pub fn string_logger(mod_path: &str) -> {
::()add_string_handler()build()
}
///
/// Log a WARNING message.
///
/// If the logger is currently enabled for the WARNING message level
/// then the given message is forwarded to all the registered output
/// Handler objects.
///
/// ## Parameters
/// - `msg` - The string message.
///
/// ## Examples
/// ```
/// use flogging::*;
///
/// let mut log = Logger::console_logger(module_path!());
/// log.set_level(Level::FINEST);
/// log.set_fn_name("main");
///
/// log.warning("Some text to store.");
/// ```
/// Output:
/// ```text
/// flogging->main [WARNING] Some text to store.
/// ```
///
pub fn warning(&mut selfmsg: &str) {
selflog(::WARNING, &selffn_name(),);
}
}
impl ::for Logger {
fn fmt(&selff: &mut ::<_>) -> :: {
let mut= String::();
forin selfborrow()iter() {
let= format!("{}: {}\n",0,1);
push_str(&);
}
writeln!(
"{}::{} - [{}]\n\n{}",
self, self, self,
)
}
}
#[cfg()]
mod tests;