use log::LevelFilter;
use serde::Deserialize;
use std::borrow::Cow;
const DEFAULT_TARGET_WIDTH: usize = 42;
const DEFAULT_LEVEL_WIDTH: usize = 5;
const DEFAULT_OUTPUT_NAME: &str = crate::LOGGER_STDOUT_NAME;
const DEFAULT_OUTPUT_LEVEL_FILTER: LevelFilter = LevelFilter::Info;
const DEFAULT_COLOR_ENABLED: bool = false;
#[derive(Default, Deserialize, PartialEq)]
#[must_use]
pub struct LoggerOutputConfigBuilder {
name: Option<String>,
#[serde(alias = "levelFilter")]
level_filter: Option<LevelFilter>,
#[serde(alias = "targetFilters")]
target_filters: Option<Vec<String>>,
#[serde(alias = "targetExclusions")]
target_exclusions: Option<Vec<String>>,
#[serde(alias = "colorEnabled")]
color_enabled: Option<bool>,
}
impl LoggerOutputConfigBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn name<'a>(mut self, name: impl Into<Cow<'a, str>>) -> Self {
self.name.replace(name.into().into_owned());
self
}
pub fn level_filter(mut self, level: LevelFilter) -> Self {
self.level_filter.replace(level);
self
}
pub fn target_filters(mut self, target_filters: &[&str]) -> Self {
self.target_filters = Some(target_filters.iter().map(ToString::to_string).collect::<Vec<_>>());
self
}
pub fn target_exclusions(mut self, target_exclusions: &[&str]) -> Self {
self.target_exclusions = Some(target_exclusions.iter().map(ToString::to_string).collect::<Vec<_>>());
self
}
pub fn color_enabled(mut self, color: bool) -> Self {
self.color_enabled.replace(color);
self
}
#[must_use]
pub fn finish(self) -> LoggerOutputConfig {
LoggerOutputConfig {
name: self.name.unwrap_or_else(|| DEFAULT_OUTPUT_NAME.to_owned()),
level_filter: self.level_filter.unwrap_or(DEFAULT_OUTPUT_LEVEL_FILTER),
target_filters: self
.target_filters
.unwrap_or_default()
.iter()
.map(|f| f.to_lowercase())
.collect(),
target_exclusions: self
.target_exclusions
.unwrap_or_default()
.iter()
.map(|f| f.to_lowercase())
.collect(),
color_enabled: self.color_enabled.unwrap_or(DEFAULT_COLOR_ENABLED),
}
}
}
#[derive(Clone, PartialEq)]
pub struct LoggerOutputConfig {
pub(crate) name: String,
pub(crate) level_filter: LevelFilter,
pub(crate) target_filters: Vec<String>,
pub(crate) target_exclusions: Vec<String>,
pub(crate) color_enabled: bool,
}
impl LoggerOutputConfig {
pub fn name(&self) -> &str {
&self.name
}
pub fn level_filter(&self) -> LevelFilter {
self.level_filter
}
pub fn target_filters(&self) -> &[String] {
&self.target_filters
}
pub fn target_exclusions(&self) -> &[String] {
&self.target_exclusions
}
pub fn color_enabled(&self) -> bool {
self.color_enabled
}
}
#[derive(Default, Deserialize, PartialEq)]
#[must_use]
pub struct LoggerConfigBuilder {
#[serde(alias = "targetWidth")]
target_width: Option<usize>,
#[serde(alias = "levelWidth")]
level_width: Option<usize>,
outputs: Option<Vec<LoggerOutputConfigBuilder>>,
}
impl LoggerConfigBuilder {
pub fn with_target_width(mut self, width: usize) -> Self {
self.target_width.replace(width);
self
}
pub fn with_level_width(mut self, width: usize) -> Self {
self.level_width.replace(width);
self
}
pub fn with_output(mut self, output: LoggerOutputConfigBuilder) -> Self {
self.outputs.get_or_insert_with(Vec::new).push(output);
self
}
pub fn level<'a>(&mut self, name: impl Into<Cow<'a, str>>, level: LevelFilter) {
let name = name.into();
if let Some(outputs) = self.outputs.as_deref_mut() {
if let Some(stdout) = outputs.iter_mut().find(|output| match output.name.as_ref() {
Some(output_name) => output_name[..] == name,
None => false,
}) {
stdout.level_filter.replace(level);
}
}
}
#[must_use]
pub fn finish(self) -> LoggerConfig {
let outputs = self
.outputs
.map(|os| os.into_iter().map(|o| o.finish()).collect())
.unwrap_or_default();
LoggerConfig {
target_width: self.target_width.unwrap_or(DEFAULT_TARGET_WIDTH),
level_width: self.level_width.unwrap_or(DEFAULT_LEVEL_WIDTH),
outputs,
}
}
}
#[derive(Clone, PartialEq)]
pub struct LoggerConfig {
pub(crate) target_width: usize,
pub(crate) level_width: usize,
pub(crate) outputs: Vec<LoggerOutputConfig>,
}
impl Default for LoggerConfig {
fn default() -> Self {
LoggerConfigBuilder::default().finish()
}
}
impl LoggerConfig {
pub fn build() -> LoggerConfigBuilder {
LoggerConfigBuilder::default()
}
pub fn target_width(&self) -> usize {
self.target_width
}
pub fn level_width(&self) -> usize {
self.level_width
}
pub fn outputs(&self) -> &[LoggerOutputConfig] {
&self.outputs
}
}