fern_logger/
config.rs

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