bee_common/logger/
config.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::logger::LOGGER_STDOUT_NAME;
5
6use log::LevelFilter;
7use serde::Deserialize;
8
9use std::borrow::Cow;
10
11/// Default value for the target width.
12const DEFAULT_TARGET_WIDTH: usize = 42;
13/// Default value for the level width.
14const DEFAULT_LEVEL_WIDTH: usize = 5;
15/// Default name for an output.
16const DEFAULT_OUTPUT_NAME: &str = LOGGER_STDOUT_NAME;
17/// Default log level for an output.
18const DEFAULT_OUTPUT_LEVEL_FILTER: LevelFilter = LevelFilter::Info;
19/// Default value for the color flag.
20const DEFAULT_COLOR_ENABLED: bool = true;
21
22/// Builder for a logger output configuration.
23#[derive(Default, Deserialize)]
24pub struct LoggerOutputConfigBuilder {
25    /// Name of an output file, or `stdout` for standard output.
26    name: Option<String>,
27    /// Log level filter of an output.
28    level_filter: Option<LevelFilter>,
29    /// Log target filters of an output.
30    target_filters: Option<Vec<String>>,
31    /// Log target exclusions of an output.
32    target_exclusions: Option<Vec<String>>,
33    /// Color flag of an output.
34    color_enabled: Option<bool>,
35}
36
37impl LoggerOutputConfigBuilder {
38    /// Creates a new builder for a logger output configuration.
39    pub fn new() -> Self {
40        Self::default()
41    }
42
43    /// Sets the name of a logger output.
44    pub fn name<'a>(mut self, name: impl Into<Cow<'a, str>>) -> Self {
45        self.name.replace(name.into().into_owned());
46        self
47    }
48
49    /// Sets the level of a logger output.
50    pub fn level_filter(mut self, level: LevelFilter) -> Self {
51        self.level_filter.replace(level);
52        self
53    }
54
55    /// Sets a collection of filters of a logger output.
56    /// A message is logged only if one of the filters is part of the log's metadata target.
57    pub fn target_filters(mut self, target_filters: &[&str]) -> Self {
58        self.target_filters = Some(target_filters.iter().map(|f| f.to_string()).collect::<Vec<String>>());
59        self
60    }
61
62    /// Sets the color flag of a logger output.
63    pub fn color_enabled(mut self, color: bool) -> Self {
64        self.color_enabled.replace(color);
65        self
66    }
67
68    /// Builds a logger output configuration.
69    pub fn finish(self) -> LoggerOutputConfig {
70        LoggerOutputConfig {
71            name: self.name.unwrap_or_else(|| DEFAULT_OUTPUT_NAME.to_owned()),
72            level_filter: self.level_filter.unwrap_or(DEFAULT_OUTPUT_LEVEL_FILTER),
73            target_filters: self
74                .target_filters
75                .unwrap_or_else(Vec::new)
76                .iter()
77                .map(|f| f.to_lowercase())
78                .collect(),
79            target_exclusions: self
80                .target_exclusions
81                .unwrap_or_else(Vec::new)
82                .iter()
83                .map(|f| f.to_lowercase())
84                .collect(),
85            color_enabled: self.color_enabled.unwrap_or(DEFAULT_COLOR_ENABLED),
86        }
87    }
88}
89
90/// Logger output configuration.
91#[derive(Clone)]
92pub struct LoggerOutputConfig {
93    /// Name of an output file, or `stdout` for standard output.
94    pub(crate) name: String,
95    /// Log level of an output.
96    pub(crate) level_filter: LevelFilter,
97    /// Log target filters of the output.
98    pub(crate) target_filters: Vec<String>,
99    /// Log target exclusions of the output.
100    pub(crate) target_exclusions: Vec<String>,
101    /// Color flag of the output.
102    pub(crate) color_enabled: bool,
103}
104
105/// Builder for a logger configuration.
106#[derive(Default, Deserialize)]
107pub struct LoggerConfigBuilder {
108    /// Width of the target section of a log.
109    target_width: Option<usize>,
110    /// Width of the level section of a log.
111    level_width: Option<usize>,
112    /// Outputs of the logger.
113    outputs: Option<Vec<LoggerOutputConfigBuilder>>,
114}
115
116impl LoggerConfigBuilder {
117    /// Sets the target width.
118    pub fn with_target_width(mut self, width: usize) -> Self {
119        self.target_width.replace(width);
120        self
121    }
122
123    /// Sets the target width.
124    pub fn with_level_width(mut self, width: usize) -> Self {
125        self.level_width.replace(width);
126        self
127    }
128
129    /// Adds an output builder to the logger builder.
130    pub fn with_output(mut self, output: LoggerOutputConfigBuilder) -> Self {
131        self.outputs.get_or_insert_with(Vec::new).push(output);
132        self
133    }
134
135    /// Sets the level of an output of a logger.
136    pub fn level<'a>(&mut self, name: impl Into<Cow<'a, str>>, level: LevelFilter) {
137        let name = name.into();
138
139        if let Some(outputs) = self.outputs.as_deref_mut() {
140            if let Some(stdout) = outputs.iter_mut().find(|output| match output.name.as_ref() {
141                Some(output_name) => output_name[..] == name,
142                None => false,
143            }) {
144                stdout.level_filter.replace(level);
145            }
146        }
147    }
148
149    /// Builds a logger configuration.
150    pub fn finish(self) -> LoggerConfig {
151        let outputs = self
152            .outputs
153            .map(|os| os.into_iter().map(|o| o.finish()).collect())
154            .unwrap_or_default();
155
156        LoggerConfig {
157            target_width: self.target_width.unwrap_or(DEFAULT_TARGET_WIDTH),
158            level_width: self.level_width.unwrap_or(DEFAULT_LEVEL_WIDTH),
159            outputs,
160        }
161    }
162}
163
164/// Logger configuration.
165#[derive(Clone)]
166pub struct LoggerConfig {
167    /// Width of the target section of a log.
168    pub(crate) target_width: usize,
169    /// Width of the level section of a log.
170    pub(crate) level_width: usize,
171    /// Outputs of the logger.
172    pub(crate) outputs: Vec<LoggerOutputConfig>,
173}
174
175impl LoggerConfig {
176    /// Creates a builder for a logger config.
177    pub fn build() -> LoggerConfigBuilder {
178        LoggerConfigBuilder::default()
179    }
180
181    /// Returns the width of the target section of the `LoggerConfig`.
182    pub fn target_width(&self) -> usize {
183        self.target_width
184    }
185
186    /// Returns the width of the level section of the `LoggerConfig`.
187    pub fn level_width(&self) -> usize {
188        self.level_width
189    }
190
191    /// Returns the outputs of the `LoggerConfig`.
192    pub fn outputs(&self) -> &[LoggerOutputConfig] {
193        &self.outputs
194    }
195}