1use crate::error::{ LogResult};
6use std::collections::HashMap;
7use std::path::Path;
8
9#[derive(Debug, Clone)]
11pub struct LogConfig {
12 pub level: String,
14 pub file_path: Option<String>,
16 pub console_output: bool,
18 pub verbose: bool,
20 pub format: LogFormat,
22 pub rotation: Option<RotationConfig>,
24 pub highlight: HighlightConfig,
26 pub filters: Vec<FilterConfig>,
28 pub custom_fields: HashMap<String, String>,
30}
31
32#[derive(Debug, Clone)]
34pub struct LogFormat {
35 pub time_format: String,
37 pub show_file: bool,
39 pub show_line: bool,
41 pub show_module: bool,
43 pub template: Option<String>,
45}
46
47#[derive(Debug, Clone)]
49pub struct RotationConfig {
50 pub max_size: u64,
52 pub max_files: u32,
54 pub compress: bool,
56}
57
58#[derive(Debug, Clone)]
60pub struct HighlightConfig {
61 pub enabled: bool,
63 pub keywords: Vec<String>,
65 pub color_map: HashMap<String, String>,
67}
68
69#[derive(Debug, Clone)]
71pub struct FilterConfig {
72 pub filter_type: FilterType,
74 pub rule: String,
76 pub enabled: bool,
78}
79
80#[derive(Debug, Clone)]
82pub enum FilterType {
83 Regex,
85 Keyword,
87 Level,
89 Module,
91}
92
93impl Default for LogConfig {
94 fn default() -> Self {
95 Self {
96 level: "info".to_string(),
97 file_path: None,
98 console_output: true,
99 verbose: false,
100 format: LogFormat::default(),
101 rotation: None,
102 highlight: HighlightConfig::default(),
103 filters: Vec::new(),
104 custom_fields: HashMap::new(),
105 }
106 }
107}
108
109impl Default for LogFormat {
110 fn default() -> Self {
111 Self {
112 time_format: "%Y-%m-%d %H:%M:%S".to_string(),
113 show_file: true,
114 show_line: true,
115 show_module: false,
116 template: None,
117 }
118 }
119}
120
121impl Default for HighlightConfig {
122 fn default() -> Self {
123 Self {
124 enabled: false,
125 keywords: Vec::new(),
126 color_map: HashMap::new(),
127 }
128 }
129}
130
131pub struct ConfigBuilder {
133 config: LogConfig,
134}
135
136impl ConfigBuilder {
137 pub fn new() -> Self {
139 Self {
140 config: LogConfig::default(),
141 }
142 }
143
144 pub fn level<S: Into<String>>(mut self, level: S) -> Self {
146 self.config.level = level.into();
147 self
148 }
149
150 pub fn file<P: AsRef<Path>>(mut self, path: P) -> Self {
152 self.config.file_path = Some(path.as_ref().to_string_lossy().to_string());
153 self
154 }
155
156 pub fn console(mut self, enabled: bool) -> Self {
158 self.config.console_output = enabled;
159 self
160 }
161
162 pub fn verbose(mut self, enabled: bool) -> Self {
164 self.config.verbose = enabled;
165 self
166 }
167
168 pub fn time_format<S: Into<String>>(mut self, format: S) -> Self {
170 self.config.format.time_format = format.into();
171 self
172 }
173
174 pub fn rotation(mut self, max_size: u64, max_files: u32, compress: bool) -> Self {
176 self.config.rotation = Some(RotationConfig {
177 max_size,
178 max_files,
179 compress,
180 });
181 self
182 }
183
184 pub fn highlight_keywords(mut self, keywords: Vec<String>) -> Self {
186 self.config.highlight.enabled = !keywords.is_empty();
187 self.config.highlight.keywords = keywords;
188 self
189 }
190
191 pub fn add_filter(mut self, filter_type: FilterType, rule: String) -> Self {
193 self.config.filters.push(FilterConfig {
194 filter_type,
195 rule,
196 enabled: true,
197 });
198 self
199 }
200
201 pub fn custom_field<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
203 self.config.custom_fields.insert(key.into(), value.into());
204 self
205 }
206
207 pub fn build(self) -> LogConfig {
209 self.config
210 }
211}
212
213pub struct ConfigLoader;
215
216impl ConfigLoader {
217 pub fn from_file<P: AsRef<Path>>(_path: P) -> LogResult<LogConfig> {
219 Ok(LogConfig::default())
221 }
222
223 pub fn from_env() -> LogResult<LogConfig> {
225 Ok(LogConfig::default())
227 }
228
229 pub fn save_to_file<P: AsRef<Path>>(_config: &LogConfig, _path: P) -> LogResult<()> {
231 Ok(())
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239
240 #[test]
241 fn test_config_builder() {
242 let config = ConfigBuilder::new()
243 .level("debug")
244 .file("/tmp/test.log")
245 .console(true)
246 .verbose(true)
247 .highlight_keywords(vec!["ERROR".to_string(), "WARN".to_string()])
248 .build();
249
250 assert_eq!(config.level, "debug");
251 assert_eq!(config.file_path, Some("/tmp/test.log".to_string()));
252 assert!(config.console_output);
253 assert!(config.verbose);
254 assert!(config.highlight.enabled);
255 assert_eq!(config.highlight.keywords.len(), 2);
256 }
257}