freeswitch_log_parser/
level.rs1use std::fmt;
2use std::str::FromStr;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub enum LogLevel {
12 Debug,
13 Info,
14 Notice,
15 Warning,
16 Err,
18 Crit,
19 Alert,
20 Console,
22}
23
24impl LogLevel {
25 pub const ALL_LABELS: &[&str] = &[
27 "debug", "info", "notice", "warning", "err", "crit", "alert", "console",
28 ];
29}
30
31impl fmt::Display for LogLevel {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 let s = match self {
34 LogLevel::Debug => "debug",
35 LogLevel::Info => "info",
36 LogLevel::Notice => "notice",
37 LogLevel::Warning => "warning",
38 LogLevel::Err => "err",
39 LogLevel::Crit => "crit",
40 LogLevel::Alert => "alert",
41 LogLevel::Console => "console",
42 };
43 f.write_str(s)
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq)]
49pub struct ParseLevelError;
50
51impl fmt::Display for ParseLevelError {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 f.write_str("invalid log level")
54 }
55}
56
57impl std::error::Error for ParseLevelError {}
58
59impl FromStr for LogLevel {
60 type Err = ParseLevelError;
61
62 fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
63 if s.eq_ignore_ascii_case("debug") {
64 Ok(LogLevel::Debug)
65 } else if s.eq_ignore_ascii_case("info") {
66 Ok(LogLevel::Info)
67 } else if s.eq_ignore_ascii_case("notice") {
68 Ok(LogLevel::Notice)
69 } else if s.eq_ignore_ascii_case("warning") {
70 Ok(LogLevel::Warning)
71 } else if s.eq_ignore_ascii_case("err") {
72 Ok(LogLevel::Err)
73 } else if s.eq_ignore_ascii_case("crit") {
74 Ok(LogLevel::Crit)
75 } else if s.eq_ignore_ascii_case("alert") {
76 Ok(LogLevel::Alert)
77 } else if s.eq_ignore_ascii_case("console") {
78 Ok(LogLevel::Console)
79 } else {
80 Result::Err(ParseLevelError)
81 }
82 }
83}
84
85impl LogLevel {
86 pub fn from_bracketed(s: &str) -> Option<LogLevel> {
90 let bytes = s.as_bytes();
91 if bytes.len() < 3 || bytes[0] != b'[' || bytes[bytes.len() - 1] != b']' {
92 return None;
93 }
94 s[1..s.len() - 1].parse().ok()
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn from_str_round_trip() {
104 let variants = [
105 LogLevel::Debug,
106 LogLevel::Info,
107 LogLevel::Notice,
108 LogLevel::Warning,
109 LogLevel::Err,
110 LogLevel::Crit,
111 LogLevel::Alert,
112 LogLevel::Console,
113 ];
114 for v in variants {
115 let s = v.to_string();
116 let parsed: LogLevel = s.parse().unwrap();
117 assert_eq!(parsed, v, "round-trip failed for {v}");
118 }
119 }
120
121 #[test]
122 fn from_str_case_insensitive() {
123 assert_eq!("DEBUG".parse::<LogLevel>().unwrap(), LogLevel::Debug);
124 assert_eq!("Info".parse::<LogLevel>().unwrap(), LogLevel::Info);
125 assert_eq!("WARNING".parse::<LogLevel>().unwrap(), LogLevel::Warning);
126 assert_eq!("err".parse::<LogLevel>().unwrap(), LogLevel::Err);
127 }
128
129 #[test]
130 fn from_str_invalid() {
131 assert!("FAKE".parse::<LogLevel>().is_err());
132 assert!("".parse::<LogLevel>().is_err());
133 assert!("ERROR".parse::<LogLevel>().is_err());
134 }
135
136 #[test]
137 fn from_bracketed_all_variants() {
138 assert_eq!(LogLevel::from_bracketed("[DEBUG]"), Some(LogLevel::Debug));
139 assert_eq!(LogLevel::from_bracketed("[INFO]"), Some(LogLevel::Info));
140 assert_eq!(LogLevel::from_bracketed("[NOTICE]"), Some(LogLevel::Notice));
141 assert_eq!(
142 LogLevel::from_bracketed("[WARNING]"),
143 Some(LogLevel::Warning)
144 );
145 assert_eq!(LogLevel::from_bracketed("[ERR]"), Some(LogLevel::Err));
146 assert_eq!(LogLevel::from_bracketed("[CRIT]"), Some(LogLevel::Crit));
147 assert_eq!(LogLevel::from_bracketed("[ALERT]"), Some(LogLevel::Alert));
148 assert_eq!(
149 LogLevel::from_bracketed("[CONSOLE]"),
150 Some(LogLevel::Console)
151 );
152 }
153
154 #[test]
155 fn from_bracketed_rejects_malformed() {
156 assert_eq!(LogLevel::from_bracketed("[FAKE]"), None);
157 assert_eq!(LogLevel::from_bracketed("DEBUG"), None);
158 assert_eq!(LogLevel::from_bracketed("[]"), None);
159 assert_eq!(LogLevel::from_bracketed("["), None);
160 assert_eq!(LogLevel::from_bracketed(""), None);
161 }
162
163 #[test]
164 fn ord_severity_order() {
165 assert!(LogLevel::Debug < LogLevel::Info);
166 assert!(LogLevel::Info < LogLevel::Notice);
167 assert!(LogLevel::Notice < LogLevel::Warning);
168 assert!(LogLevel::Warning < LogLevel::Err);
169 assert!(LogLevel::Err < LogLevel::Crit);
170 assert!(LogLevel::Crit < LogLevel::Alert);
171 assert!(LogLevel::Alert < LogLevel::Console);
172 }
173}