1use log::LevelFilter;
5use serde::Deserialize;
6
7use std::borrow::Cow;
8
9const DEFAULT_TARGET_WIDTH: usize = 42;
11const DEFAULT_LEVEL_WIDTH: usize = 5;
13const DEFAULT_OUTPUT_NAME: &str = crate::LOGGER_STDOUT_NAME;
15const DEFAULT_OUTPUT_LEVEL_FILTER: LevelFilter = LevelFilter::Info;
17const DEFAULT_COLOR_ENABLED: bool = false;
19
20#[derive(Default, Deserialize, PartialEq)]
22#[must_use]
23pub struct LoggerOutputConfigBuilder {
24 name: Option<String>,
26 #[serde(alias = "levelFilter")]
28 level_filter: Option<LevelFilter>,
29 #[serde(alias = "targetFilters")]
31 target_filters: Option<Vec<String>>,
32 #[serde(alias = "targetExclusions")]
34 target_exclusions: Option<Vec<String>>,
35 #[serde(alias = "colorEnabled")]
37 color_enabled: Option<bool>,
38}
39
40impl LoggerOutputConfigBuilder {
41 pub fn new() -> Self {
43 Self::default()
44 }
45
46 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 pub fn level_filter(mut self, level: LevelFilter) -> Self {
54 self.level_filter.replace(level);
55 self
56 }
57
58 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 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 pub fn color_enabled(mut self, color: bool) -> Self {
74 self.color_enabled.replace(color);
75 self
76 }
77
78 #[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#[derive(Clone, PartialEq)]
103pub struct LoggerOutputConfig {
104 pub(crate) name: String,
106 pub(crate) level_filter: LevelFilter,
108 pub(crate) target_filters: Vec<String>,
110 pub(crate) target_exclusions: Vec<String>,
112 pub(crate) color_enabled: bool,
114}
115
116impl LoggerOutputConfig {
117 pub fn name(&self) -> &str {
119 &self.name
120 }
121
122 pub fn level_filter(&self) -> LevelFilter {
124 self.level_filter
125 }
126
127 pub fn target_filters(&self) -> &[String] {
129 &self.target_filters
130 }
131
132 pub fn target_exclusions(&self) -> &[String] {
134 &self.target_exclusions
135 }
136
137 pub fn color_enabled(&self) -> bool {
139 self.color_enabled
140 }
141}
142
143#[derive(Default, Deserialize, PartialEq)]
145#[must_use]
146pub struct LoggerConfigBuilder {
147 #[serde(alias = "targetWidth")]
149 target_width: Option<usize>,
150 #[serde(alias = "levelWidth")]
152 level_width: Option<usize>,
153 outputs: Option<Vec<LoggerOutputConfigBuilder>>,
155}
156
157impl LoggerConfigBuilder {
158 pub fn with_target_width(mut self, width: usize) -> Self {
160 self.target_width.replace(width);
161 self
162 }
163
164 pub fn with_level_width(mut self, width: usize) -> Self {
166 self.level_width.replace(width);
167 self
168 }
169
170 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 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 #[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#[derive(Clone, PartialEq)]
208pub struct LoggerConfig {
209 pub(crate) target_width: usize,
211 pub(crate) level_width: usize,
213 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 pub fn build() -> LoggerConfigBuilder {
226 LoggerConfigBuilder::default()
227 }
228
229 pub fn target_width(&self) -> usize {
231 self.target_width
232 }
233
234 pub fn level_width(&self) -> usize {
236 self.level_width
237 }
238
239 pub fn outputs(&self) -> &[LoggerOutputConfig] {
241 &self.outputs
242 }
243}