options.rs (3014B)
1 use chrono::Local; 2 use std::path::PathBuf; 3 4 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 5 pub enum LogFileLayout { 6 PrefixedDate, 7 DatedFileName, 8 } 9 10 #[derive(Debug, Clone)] 11 pub struct LoggingOptions { 12 pub dir: Option<PathBuf>, 13 pub file_name: String, 14 pub stdout: bool, 15 pub default_level: Option<String>, 16 pub file_layout: LogFileLayout, 17 } 18 19 impl LoggingOptions { 20 pub fn also_stdout(&self) -> bool { 21 self.stdout 22 } 23 24 pub fn resolved_log_file_name_for_date(&self, date: &str) -> String { 25 match self.file_layout { 26 LogFileLayout::PrefixedDate => format!("{}.{}", self.file_name, date), 27 LogFileLayout::DatedFileName => format!("{}.{}", date, self.file_name), 28 } 29 } 30 31 pub fn resolved_current_log_file_path(&self) -> Option<PathBuf> { 32 let dir = self.dir.as_ref()?; 33 let date = Local::now().format("%Y-%m-%d").to_string(); 34 Some(dir.join(self.resolved_log_file_name_for_date(date.as_str()))) 35 } 36 } 37 38 impl Default for LoggingOptions { 39 fn default() -> Self { 40 Self { 41 dir: None, 42 file_name: "radroots.log".into(), 43 stdout: true, 44 default_level: None, 45 file_layout: LogFileLayout::PrefixedDate, 46 } 47 } 48 } 49 50 #[cfg(test)] 51 mod tests { 52 use super::{LogFileLayout, LoggingOptions}; 53 use std::path::PathBuf; 54 55 #[test] 56 fn prefixed_date_layout_resolves_expected_file_name() { 57 let options = LoggingOptions { 58 dir: Some(PathBuf::from("/tmp/logs")), 59 file_name: "myc.log".to_owned(), 60 stdout: false, 61 default_level: None, 62 file_layout: LogFileLayout::PrefixedDate, 63 }; 64 65 assert_eq!( 66 options.resolved_log_file_name_for_date("2026-03-23"), 67 "myc.log.2026-03-23" 68 ); 69 } 70 71 #[test] 72 fn dated_file_name_layout_resolves_expected_file_name() { 73 let options = LoggingOptions { 74 dir: Some(PathBuf::from("/tmp/logs")), 75 file_name: "log".to_owned(), 76 stdout: false, 77 default_level: None, 78 file_layout: LogFileLayout::DatedFileName, 79 }; 80 81 assert_eq!( 82 options.resolved_log_file_name_for_date("2026-03-23"), 83 "2026-03-23.log" 84 ); 85 } 86 87 #[test] 88 fn current_log_file_path_joins_dir_and_layout_shape() { 89 let options = LoggingOptions { 90 dir: Some(PathBuf::from("/tmp/logs")), 91 file_name: "log".to_owned(), 92 stdout: false, 93 default_level: None, 94 file_layout: LogFileLayout::DatedFileName, 95 }; 96 97 let path = options 98 .resolved_current_log_file_path() 99 .expect("resolved path"); 100 101 assert_eq!(path.parent(), Some(PathBuf::from("/tmp/logs").as_path())); 102 assert!( 103 path.file_name() 104 .and_then(|value| value.to_str()) 105 .is_some_and(|value| value.ends_with(".log")) 106 ); 107 } 108 }