blob: 9e1c390acdc8696f15e884a4ac5146386dccbe4c [file] [log] [blame]
use log::LevelFilter;
pub use chrono::offset::{FixedOffset, Local, Offset, TimeZone, Utc};
use std::borrow::Cow;
#[derive(Debug, Clone, Copy)]
/// Padding to be used for logging the level
pub enum LevelPadding {
/// Add spaces on the left side
Left,
/// Add spaces on the right side
Right,
/// Do not pad the level
Off,
}
#[derive(Debug, Clone, Copy)]
/// Padding to be used for logging the thread id/name
pub enum ThreadPadding {
/// Add spaces on the left side, up to usize many
Left(usize),
/// Add spaces on the right side, up to usize many
Right(usize),
/// Do not pad the thread id/name
Off,
}
#[derive(Debug, Clone, Copy, PartialEq)]
/// Mode for logging the thread name or id or both.
pub enum ThreadLogMode {
/// Log thread ids only
IDs,
/// Log the thread names only
Names,
/// If this thread is named, log the name. Otherwise, log the thread id.
Both,
}
/// Configuration for the Loggers
///
/// All loggers print the message in the following form:
/// `00:00:00 [LEVEL] crate::module: [lib.rs::100] your_message`
/// Every space delimited part except the actual message is optional.
///
/// Pass this struct to your logger to change when these information shall
/// be logged.
///
/// Construct using `Default` or using `ConfigBuilder`
#[derive(Debug, Clone)]
pub struct Config {
pub(crate) time: LevelFilter,
pub(crate) level: LevelFilter,
pub(crate) level_padding: LevelPadding,
pub(crate) thread: LevelFilter,
pub(crate) thread_log_mode: ThreadLogMode,
pub(crate) thread_padding: ThreadPadding,
pub(crate) target: LevelFilter,
pub(crate) location: LevelFilter,
pub(crate) time_format: Cow<'static, str>,
pub(crate) time_offset: FixedOffset,
pub(crate) time_local: bool,
pub(crate) filter_allow: Cow<'static, [Cow<'static, str>]>,
pub(crate) filter_ignore: Cow<'static, [Cow<'static, str>]>,
}
/// Builder for the Logger Configurations (`Config`)
///
/// All loggers print the message in the following form:
/// `00:00:00 [LEVEL] crate::module: [lib.rs::100] your_message`
/// Every space delimited part except the actual message is optional.
///
/// Use this struct to create a custom `Config` changing when these information shall
/// be logged. Every part can be enabled for a specific Level and is then
/// automatically enable for all lower levels as well.
///
/// The Result is that the logging gets more detailed the more verbose it gets.
/// E.g. to have one part shown always use `Level::Error`. But if you
/// want to show the source line only on `Trace` use that.
#[derive(Debug, Clone)]
pub struct ConfigBuilder(Config);
impl ConfigBuilder {
/// Create a new default ConfigBuilder
pub fn new() -> ConfigBuilder {
ConfigBuilder(Config::default())
}
/// Set at which level and below the level itself shall be logged (default is Error)
pub fn set_max_level<'a>(&'a mut self, level: LevelFilter) -> &'a mut ConfigBuilder {
self.0.level = level;
self
}
/// Set at which level and below the current time shall be logged (default is Error)
pub fn set_time_level<'a>(&'a mut self, time: LevelFilter) -> &'a mut ConfigBuilder {
self.0.time = time;
self
}
/// Set at which level and below the thread id shall be logged. (default is Debug)
pub fn set_thread_level<'a>(&'a mut self, thread: LevelFilter) -> &'a mut ConfigBuilder {
self.0.thread = thread;
self
}
/// Set at which level and below the target shall be logged. (default is Debug)
pub fn set_target_level<'a>(&'a mut self, target: LevelFilter) -> &'a mut ConfigBuilder {
self.0.target = target;
self
}
/// Set at which level and below a source code reference shall be logged (default is Trace)
pub fn set_location_level<'a>(&'a mut self, location: LevelFilter) -> &'a mut ConfigBuilder {
self.0.location = location;
self
}
/// Set how the levels should be padded, when logging (default is Left)
pub fn set_level_padding<'a>(&'a mut self, padding: LevelPadding) -> &'a mut ConfigBuilder {
self.0.level_padding = padding;
self
}
/// Set how the thread should be padded
pub fn set_thread_padding<'a>(&'a mut self, padding: ThreadPadding) -> &'a mut ConfigBuilder {
self.0.thread_padding = padding;
self
}
/// Set the mode for logging the thread
pub fn set_thread_mode<'a>(&'a mut self, mode: ThreadLogMode) -> &'a mut ConfigBuilder {
self.0.thread_log_mode = mode;
self
}
/// Set time chrono [strftime] format string.
///
/// [strftime]: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers
pub fn set_time_format_str<'a>(
&'a mut self,
time_format: &'static str,
) -> &'a mut ConfigBuilder {
self.0.time_format = Cow::Borrowed(time_format);
self
}
/// Set time chrono [strftime] format string.
///
/// [strftime]: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers
pub fn set_time_format<'a>(&'a mut self, time_format: String) -> &'a mut ConfigBuilder {
self.0.time_format = Cow::Owned(time_format);
self
}
/// Set offset used for logging time (default is 0)
pub fn set_time_offset<'a>(&'a mut self, time_offset: FixedOffset) -> &'a mut ConfigBuilder {
self.0.time_offset = time_offset;
self
}
/// set if you log in local timezone or UTC (default is UTC)
pub fn set_time_to_local<'a>(&'a mut self, local: bool) -> &'a mut ConfigBuilder {
self.0.time_local = local;
self
}
/// Add allowed module filters.
/// If any are specified, only records from modules starting with one of these entries will be printed
///
/// For example, `add_filter_allow_str("tokio::uds")` would allow only logging from the `tokio` crates `uds` module.
pub fn add_filter_allow_str<'a>(
&'a mut self,
time_format: &'static str,
) -> &'a mut ConfigBuilder {
let mut list = Vec::from(&*self.0.filter_allow);
list.push(Cow::Borrowed(time_format));
self.0.filter_allow = Cow::Owned(list);
self
}
/// Add allowed module filters.
/// If any are specified, only records from modules starting with one of these entries will be printed
///
/// For example, `add_filter_allow(format!("{}{}","tokio", "uds"))` would allow only logging from the `tokio` crates `uds` module.
pub fn add_filter_allow<'a>(&'a mut self, time_format: String) -> &'a mut ConfigBuilder {
let mut list = Vec::from(&*self.0.filter_allow);
list.push(Cow::Owned(time_format));
self.0.filter_allow = Cow::Owned(list);
self
}
/// Clear allowed module filters.
/// If none are specified, nothing is filtered out
pub fn clear_filter_allow<'a>(&'a mut self) -> &'a mut ConfigBuilder {
self.0.filter_allow = Cow::Borrowed(&[]);
self
}
/// Add denied module filters.
/// If any are specified, records from modules starting with one of these entries will be ignored
///
/// For example, `add_filter_ignore_str("tokio::uds")` would deny logging from the `tokio` crates `uds` module.
pub fn add_filter_ignore_str<'a>(
&'a mut self,
time_format: &'static str,
) -> &'a mut ConfigBuilder {
let mut list = Vec::from(&*self.0.filter_ignore);
list.push(Cow::Borrowed(time_format));
self.0.filter_ignore = Cow::Owned(list);
self
}
/// Add denied module filters.
/// If any are specified, records from modules starting with one of these entries will be ignored
///
/// For example, `add_filter_ignore(format!("{}{}","tokio", "uds"))` would deny logging from the `tokio` crates `uds` module.
pub fn add_filter_ignore<'a>(&'a mut self, time_format: String) -> &'a mut ConfigBuilder {
let mut list = Vec::from(&*self.0.filter_ignore);
list.push(Cow::Owned(time_format));
self.0.filter_ignore = Cow::Owned(list);
self
}
/// Clear ignore module filters.
/// If none are specified, nothing is filtered
pub fn clear_filter_ignore<'a>(&'a mut self) -> &'a mut ConfigBuilder {
self.0.filter_ignore = Cow::Borrowed(&[]);
self
}
/// Build new `Config`
pub fn build(&mut self) -> Config {
self.0.clone()
}
}
impl Default for Config {
fn default() -> Config {
Config {
time: LevelFilter::Error,
level: LevelFilter::Error,
level_padding: LevelPadding::Off,
thread: LevelFilter::Debug,
thread_log_mode: ThreadLogMode::IDs,
thread_padding: ThreadPadding::Off,
target: LevelFilter::Debug,
location: LevelFilter::Trace,
time_format: Cow::Borrowed("%H:%M:%S"),
time_offset: FixedOffset::east(0),
time_local: false,
filter_allow: Cow::Borrowed(&[]),
filter_ignore: Cow::Borrowed(&[]),
}
}
}