Skip to content

Commit bbf5f52

Browse files
committed
1
1 parent 398788f commit bbf5f52

File tree

3 files changed

+212
-27
lines changed

3 files changed

+212
-27
lines changed

spdlog/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ release-level-info = []
3232
release-level-debug = []
3333
release-level-trace = []
3434

35-
config = ["serde", "erased-serde"]
35+
config = ["serde", "erased-serde", "toml"]
3636
source-location = []
3737
native = []
3838
libsystemd = ["libsystemd-sys"]
@@ -58,7 +58,7 @@ spdlog-macros = { version = "0.1.0", path = "../spdlog-macros" }
5858
spin = "0.9.8"
5959
static_assertions = "1.1.0"
6060
thiserror = "1.0.37"
61-
toml = "0.8.8"
61+
toml = { version = "0.8.8", optional = true }
6262

6363
[target.'cfg(windows)'.dependencies]
6464
winapi = { version = "0.3.9", features = ["consoleapi", "debugapi", "handleapi", "processenv", "processthreadsapi", "winbase", "wincon"] }

spdlog/src/config/mod.rs

Lines changed: 106 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,31 +55,27 @@ pub trait Configurable: Sized {
5555
fn build(params: Self::Params) -> Result<Self>;
5656
}
5757

58-
mod storage {
59-
use serde::Deserialize;
60-
61-
use super::*;
62-
63-
#[derive(Deserialize)]
64-
#[serde(deny_unknown_fields)]
65-
pub(super) struct Logger(
66-
#[serde(deserialize_with = "crate::config::deser::logger")] crate::Logger,
67-
);
68-
69-
#[derive(Deserialize)]
70-
#[serde(deny_unknown_fields)]
71-
pub(super) struct Config {
72-
loggers: HashMap<String, Logger>,
73-
}
58+
// #[derive(Deserialize)]
59+
// #[serde(deny_unknown_fields)]
60+
// pub(super) struct Logger(#[serde(deserialize_with =
61+
// "crate::config::deser::logger")] crate::Logger);
62+
63+
#[derive(PartialEq, Debug, Deserialize)]
64+
#[serde(deny_unknown_fields)]
65+
pub(super) struct ConfigView {
66+
loggers: HashMap<String, toml::Value>,
7467
}
7568

76-
pub struct Config(storage::Config);
69+
#[derive(PartialEq, Debug)]
70+
pub struct Config {
71+
view: ConfigView, // Stores the config values only, build lazily
72+
}
7773

7874
impl Config {
7975
// TODO: Remember to remove me
8076
pub fn new_for_test(inputs: &str) -> Result<Self> {
81-
let config = toml::from_str(inputs).unwrap();
82-
Ok(Self(config))
77+
let view = toml::from_str(inputs).unwrap();
78+
Ok(Self { view })
8379
}
8480
}
8581

@@ -90,24 +86,111 @@ mod tests {
9086

9187
#[test]
9288
fn full() {
89+
let path = TEST_LOGS_PATH.join("unit_test_config_full.log");
9390
let inputs = format!(
9491
r#"
9592
[loggers.default]
9693
sinks = [
9794
{{ name = "$ConfigMockSink1", arg = 114 }},
9895
{{ name = "$ConfigMockSink2", arg = 514 }},
9996
{{ name = "$ConfigMockSink3", arg = 1919 }},
100-
{{ name = "FileSink", path = "{}", formatter = {{ name = "PatternFormatter", template = "114514 {{payload}}{{eol}}" }} }}
97+
{{ name = "FileSink", path = "{}", formatter = {{ name = "PatternFormatter", template = "Meow! {{payload}}{{eol}}" }} }}
10198
]
102-
# flush_level_filter = "all" # TODO: design the syntax
99+
flush_level_filter = "Equal(Info)" # TODO: reconsider the syntax
100+
101+
[loggers.network]
102+
sinks = [ {{ name = "$ConfigMockSink2", arg = 810 }} ]
103103
# TODO: flush_period = "10s"
104104
"#,
105-
TEST_LOGS_PATH.join("unit_test_config_full.log").display()
105+
path.display()
106106
);
107107

108108
register_global();
109109

110-
Config::new_for_test(&inputs).unwrap();
110+
let config = Config::new_for_test(&inputs).unwrap();
111+
112+
assert_eq!(
113+
config.view,
114+
ConfigView {
115+
loggers: HashMap::from([
116+
(
117+
"default".to_string(),
118+
toml::Value::Table(toml::Table::from_iter([
119+
(
120+
"sinks".to_string(),
121+
toml::Value::Array(vec![
122+
toml::Value::Table(toml::Table::from_iter([
123+
(
124+
"name".to_string(),
125+
toml::Value::String("$ConfigMockSink1".to_string())
126+
),
127+
("arg".to_string(), toml::Value::Integer(114))
128+
])),
129+
toml::Value::Table(toml::Table::from_iter([
130+
(
131+
"name".to_string(),
132+
toml::Value::String("$ConfigMockSink2".to_string())
133+
),
134+
("arg".to_string(), toml::Value::Integer(514))
135+
])),
136+
toml::Value::Table(toml::Table::from_iter([
137+
(
138+
"name".to_string(),
139+
toml::Value::String("$ConfigMockSink3".to_string())
140+
),
141+
("arg".to_string(), toml::Value::Integer(1919))
142+
])),
143+
toml::Value::Table(toml::Table::from_iter([
144+
(
145+
"name".to_string(),
146+
toml::Value::String("FileSink".to_string())
147+
),
148+
(
149+
"path".to_string(),
150+
toml::Value::String(path.display().to_string())
151+
),
152+
(
153+
"formatter".to_string(),
154+
toml::Value::Table(toml::Table::from_iter([
155+
(
156+
"name".to_string(),
157+
toml::Value::String(
158+
"PatternFormatter".to_string()
159+
),
160+
),
161+
(
162+
"template".to_string(),
163+
toml::Value::String(
164+
"Meow! {payload}{eol}".to_string()
165+
),
166+
)
167+
]))
168+
)
169+
]))
170+
])
171+
),
172+
(
173+
"flush_level_filter".to_string(),
174+
toml::Value::String("Equal(Info)".to_string())
175+
)
176+
]))
177+
),
178+
(
179+
"network".to_string(),
180+
toml::Value::Table(toml::Table::from_iter([(
181+
"sinks".to_string(),
182+
toml::Value::Array(vec![toml::Value::Table(toml::Table::from_iter([
183+
(
184+
"name".to_string(),
185+
toml::Value::String("$ConfigMockSink2".to_string())
186+
),
187+
("arg".to_string(), toml::Value::Integer(810))
188+
]))])
189+
)]))
190+
)
191+
])
192+
}
193+
);
111194

112195
// TODO
113196
}

spdlog/src/level.rs

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const LOG_LEVEL_SHORT_NAMES: [&str; Level::count()] = ["C", "E", "W", "I", "D",
5555
/// [`log!`]: crate::log!
5656
#[repr(u16)]
5757
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
58-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
58+
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
5959
pub enum Level {
6060
/// Designates critical errors.
6161
Critical = 0,
@@ -202,7 +202,6 @@ impl FromStr for Level {
202202
/// ```
203203
#[repr(align(4))]
204204
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
205-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
206205
pub enum LevelFilter {
207206
/// Disables all levels.
208207
Off,
@@ -224,6 +223,33 @@ pub enum LevelFilter {
224223
All,
225224
}
226225

226+
impl<'de> serde::Deserialize<'de> for LevelFilter {
227+
fn deserialize<D>(de: D) -> Result<Self, D::Error>
228+
where
229+
D: serde::Deserializer<'de>,
230+
{
231+
struct LevelFilterExprVisitor;
232+
233+
impl<'de> serde::de::Visitor<'de> for LevelFilterExprVisitor {
234+
type Value = LevelFilter;
235+
236+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
237+
formatter.write_str("a spdlog-rs level filter expression")
238+
}
239+
240+
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
241+
where
242+
E: serde::de::Error,
243+
{
244+
LevelFilter::from_config_str(v)
245+
.ok_or_else(|| E::custom(format!("unknown level filter expression '{}'", v)))
246+
}
247+
}
248+
249+
de.deserialize_str(LevelFilterExprVisitor)
250+
}
251+
}
252+
227253
cfg_if! {
228254
if #[cfg(test)] {
229255
static_assertions::const_assert!(atomic::Atomic::<LevelFilter>::is_lock_free());
@@ -279,6 +305,35 @@ impl LevelFilter {
279305
None
280306
}
281307
}
308+
309+
// TODO: cfg
310+
fn from_config_str(v: &str) -> Option<Self> {
311+
let value =
312+
if v.ends_with(')') && v.matches('(').count() == 1 && v.matches(')').count() == 1 {
313+
let (lpa, rpa) = (v.find('(').unwrap(), v.find(')').unwrap());
314+
assert!(lpa < rpa);
315+
316+
let condition = &v[..lpa];
317+
let level = v[lpa + 1..rpa].parse::<Level>().ok()?;
318+
319+
match condition {
320+
"Equal" => Self::Equal(level),
321+
"NotEqual" => Self::NotEqual(level),
322+
"MoreSevere" => Self::MoreSevere(level),
323+
"MoreSevereEqual" => Self::MoreSevereEqual(level),
324+
"MoreVerbose" => Self::MoreVerbose(level),
325+
"MoreVerboseEqual" => Self::MoreVerboseEqual(level),
326+
_ => return None,
327+
}
328+
} else {
329+
match v {
330+
"Off" => Self::Off,
331+
"All" => Self::All,
332+
_ => return None,
333+
}
334+
};
335+
Some(value)
336+
}
282337
}
283338

284339
#[cfg(feature = "log")]
@@ -376,6 +431,53 @@ mod tests {
376431
);
377432
}
378433

434+
#[test]
435+
fn level_filter_from_str_for_config() {
436+
assert_eq!(
437+
LevelFilter::Off,
438+
LevelFilter::from_config_str("Off").unwrap()
439+
);
440+
assert_eq!(
441+
LevelFilter::Equal(Level::Trace),
442+
LevelFilter::from_config_str("Equal(trace)").unwrap()
443+
);
444+
assert_eq!(
445+
LevelFilter::NotEqual(Level::Debug),
446+
LevelFilter::from_config_str("NotEqual(debug)").unwrap()
447+
);
448+
assert_eq!(
449+
LevelFilter::MoreSevere(Level::Info),
450+
LevelFilter::from_config_str("MoreSevere(info)").unwrap()
451+
);
452+
assert_eq!(
453+
LevelFilter::MoreSevereEqual(Level::Warn),
454+
LevelFilter::from_config_str("MoreSevereEqual(warn)").unwrap()
455+
);
456+
assert_eq!(
457+
LevelFilter::MoreVerbose(Level::Error),
458+
LevelFilter::from_config_str("MoreVerbose(Error)").unwrap()
459+
);
460+
assert_eq!(
461+
LevelFilter::MoreVerboseEqual(Level::Critical),
462+
LevelFilter::from_config_str("MoreVerboseEqual(Critical)").unwrap()
463+
);
464+
assert_eq!(
465+
LevelFilter::All,
466+
LevelFilter::from_config_str("All").unwrap()
467+
);
468+
469+
assert!(LevelFilter::from_config_str("Unknown").is_none());
470+
assert!(LevelFilter::from_config_str("Equal(info").is_none());
471+
assert!(LevelFilter::from_config_str("Equal)info(").is_none());
472+
assert!(LevelFilter::from_config_str("Equal)info").is_none());
473+
assert!(LevelFilter::from_config_str("(Equal)info").is_none());
474+
assert!(LevelFilter::from_config_str("Equal(info) ").is_none());
475+
assert!(LevelFilter::from_config_str(" Equal(info)").is_none());
476+
assert!(LevelFilter::from_config_str("Equal (info)").is_none());
477+
assert!(LevelFilter::from_config_str("Equal( info)").is_none());
478+
assert!(LevelFilter::from_config_str("Equal(info )").is_none());
479+
}
480+
379481
#[test]
380482
fn iter() {
381483
let mut iter = Level::iter();

0 commit comments

Comments
 (0)