simple_log/
level.rs

1use crate::InnerLevel;
2use core::fmt;
3use log::{Level, LevelFilter};
4pub use parser::*;
5use serde::de::DeserializeSeed;
6use serde::{de, Deserializer};
7
8pub(crate) mod parser {
9    use crate::{InnerLevel, TargetLevel};
10    use log::LevelFilter;
11    use std::str::FromStr;
12    use winnow::ascii::{alpha1, multispace0};
13    use winnow::combinator::{opt, repeat};
14    use winnow::token::take_while;
15    use winnow::{Parser, Result as WResult};
16
17    ///
18    /// ```rust
19    /// use log::LevelFilter;
20    /// use simple_log::level::parse_level;
21    /// let input = "off";
22    /// assert_eq!(parse_level(input).unwrap(), (LevelFilter::Off, vec![]));
23    ///
24    /// let input = "debug";
25    /// assert_eq!(parse_level(input).unwrap(), (LevelFilter::Debug, vec![]));
26    ///
27    /// let input = "info";
28    /// assert_eq!(parse_level(input).unwrap(), (LevelFilter::Info, vec![]));
29    ///
30    /// let input = "warn";
31    /// assert_eq!(parse_level(input).unwrap(), (LevelFilter::Warn, vec![]));
32    ///
33    /// let input = "error";
34    /// assert_eq!(parse_level(input).unwrap(), (LevelFilter::Error, vec![]));
35    ///
36    /// let input = "off !!!";
37    /// assert_eq!(parse_level(input).err().unwrap(),
38    /// r###"Failed to parse level:
39    /// off !!!
40    ///    ^
41    /// "###);
42    ///
43    /// let input = "warning";
44    /// assert_eq!(parse_level(input).err().unwrap(),
45    /// r#"Failed to parse level:
46    /// warning
47    /// ^
48    /// attempted to convert a string that doesn't match an existing log level"#);
49    ///
50    ///
51    /// let input = "info,";
52    /// assert_eq!(parse_level(input).err().unwrap(),
53    /// r#"Failed to parse level:
54    /// info,
55    ///     ^
56    /// "#);
57    ///
58    /// let input = "error,app=off";
59    /// assert_eq!(parse_level(input).unwrap(), (LevelFilter::Error, vec![("app", LevelFilter::Off).into()]));
60    ///
61    /// let input = "debug,app=error,";
62    /// assert_eq!(parse_level(input).unwrap(), (LevelFilter::Debug, vec![("app", LevelFilter::Error).into()]));
63    ///
64    /// let input = "debug,app=error,filter_module::app::ctrl=error,app::launch::c123onf=info";
65    /// assert_eq!(
66    /// parse_level(input).unwrap(),
67    ///  (LevelFilter::Debug, vec![
68    ///   ("app", LevelFilter::Error).into(),
69    ///   ("filter_module::app::ctrl", LevelFilter::Error).into(),
70    ///   ("app::launch::c123onf", LevelFilter::Info).into(),
71    ///  ]));
72    ///
73    ///```
74    ///
75    pub fn parse_level(input: &str) -> Result<InnerLevel, String> {
76        match (
77            level,
78            opt((multispace0, ',', repeat(1.., target_level)))
79                .map(|c| c.map(|(_, _, t)| t).unwrap_or_default()),
80        )
81            .parse(input)
82        {
83            Ok((level, targets)) => Ok((level, targets)),
84            Err(err) => Err(format!("Failed to parse level:\n{}", err)),
85        }
86    }
87
88    fn level(input: &mut &str) -> WResult<LevelFilter> {
89        alpha1.try_map(LevelFilter::from_str).parse_next(input)
90    }
91
92    fn target_level(input: &mut &str) -> WResult<TargetLevel> {
93        (multispace0, target_name, '=', level, multispace0, opt(','))
94            .map(|(_, name, _, level, _, _)| (name, level).into())
95            .parse_next(input)
96    }
97
98    fn target_name<'a>(input: &mut &'a str) -> WResult<&'a str> {
99        take_while(1.., ('0'..='9', 'A'..='Z', 'a'..='z', ':', '_')).parse_next(input)
100    }
101}
102
103#[allow(clippy::wrong_self_convention)]
104pub trait LevelInto {
105    fn into_level(&self) -> &str;
106}
107
108impl LevelInto for &str {
109    fn into_level(&self) -> &str {
110        self
111    }
112}
113
114impl LevelInto for String {
115    fn into_level(&self) -> &str {
116        self.as_str()
117    }
118}
119
120impl LevelInto for &String {
121    fn into_level(&self) -> &str {
122        self.as_str()
123    }
124}
125
126impl LevelInto for LevelFilter {
127    fn into_level(&self) -> &str {
128        self.as_str()
129    }
130}
131
132impl LevelInto for Level {
133    fn into_level(&self) -> &str {
134        self.as_str()
135    }
136}
137
138macro_rules! de_from {
139    ($err:expr) => {
140        LevelSerde::deserialize($err).map_err(de::Error::custom)
141    };
142}
143
144struct LevelSerde;
145
146impl LevelSerde {
147    fn deserialize<S>(s: S) -> Result<InnerLevel, String>
148    where
149        S: Into<String>,
150    {
151        let s = s.into();
152        parse_level(&s)
153    }
154}
155
156impl<'de> DeserializeSeed<'de> for LevelSerde {
157    type Value = InnerLevel;
158
159    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
160    where
161        D: Deserializer<'de>,
162    {
163        deserializer.deserialize_any(self)
164    }
165}
166
167impl serde::de::Visitor<'_> for LevelSerde {
168    type Value = InnerLevel;
169
170    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
171        formatter.write_str("inner level")
172    }
173
174    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
175    where
176        E: serde::de::Error,
177    {
178        de_from!(s)
179    }
180}
181
182pub fn deserialize_level<'de, D>(deserializer: D) -> Result<InnerLevel, D::Error>
183where
184    D: serde::Deserializer<'de>,
185{
186    deserializer.deserialize_any(LevelSerde)
187}
188
189#[cfg(test)]
190mod tests {
191    use super::*;
192
193    #[test]
194    fn quick_log_level1() {
195        fn quick_log_level<S: LevelInto>(level: S) {
196            level.into_level();
197        }
198
199        quick_log_level("debug");
200        quick_log_level("debug".to_string());
201        quick_log_level(LevelFilter::Debug);
202        quick_log_level(Level::Debug);
203    }
204}