Skip to content

Commit 15ba14c

Browse files
committed
1
1 parent 514408d commit 15ba14c

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"]
@@ -57,7 +57,7 @@ spdlog-internal = { version = "=0.1.0", path = "../spdlog-internal", optional =
5757
spdlog-macros = { version = "0.1.0", path = "../spdlog-macros" }
5858
spin = "0.9.8"
5959
thiserror = "1.0.37"
60-
toml = "0.8.8"
60+
toml = { version = "0.8.8", optional = true }
6161

6262
[target.'cfg(windows)'.dependencies]
6363
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
use std::mem::{align_of, size_of};
@@ -276,6 +302,35 @@ impl LevelFilter {
276302
None
277303
}
278304
}
305+
306+
// TODO: cfg
307+
fn from_config_str(v: &str) -> Option<Self> {
308+
let value =
309+
if v.ends_with(')') && v.matches('(').count() == 1 && v.matches(')').count() == 1 {
310+
let (lpa, rpa) = (v.find('(').unwrap(), v.find(')').unwrap());
311+
assert!(lpa < rpa);
312+
313+
let condition = &v[..lpa];
314+
let level = v[lpa + 1..rpa].parse::<Level>().ok()?;
315+
316+
match condition {
317+
"Equal" => Self::Equal(level),
318+
"NotEqual" => Self::NotEqual(level),
319+
"MoreSevere" => Self::MoreSevere(level),
320+
"MoreSevereEqual" => Self::MoreSevereEqual(level),
321+
"MoreVerbose" => Self::MoreVerbose(level),
322+
"MoreVerboseEqual" => Self::MoreVerboseEqual(level),
323+
_ => return None,
324+
}
325+
} else {
326+
match v {
327+
"Off" => Self::Off,
328+
"All" => Self::All,
329+
_ => return None,
330+
}
331+
};
332+
Some(value)
333+
}
279334
}
280335

281336
#[cfg(feature = "log")]
@@ -373,6 +428,53 @@ mod tests {
373428
);
374429
}
375430

431+
#[test]
432+
fn level_filter_from_str_for_config() {
433+
assert_eq!(
434+
LevelFilter::Off,
435+
LevelFilter::from_config_str("Off").unwrap()
436+
);
437+
assert_eq!(
438+
LevelFilter::Equal(Level::Trace),
439+
LevelFilter::from_config_str("Equal(trace)").unwrap()
440+
);
441+
assert_eq!(
442+
LevelFilter::NotEqual(Level::Debug),
443+
LevelFilter::from_config_str("NotEqual(debug)").unwrap()
444+
);
445+
assert_eq!(
446+
LevelFilter::MoreSevere(Level::Info),
447+
LevelFilter::from_config_str("MoreSevere(info)").unwrap()
448+
);
449+
assert_eq!(
450+
LevelFilter::MoreSevereEqual(Level::Warn),
451+
LevelFilter::from_config_str("MoreSevereEqual(warn)").unwrap()
452+
);
453+
assert_eq!(
454+
LevelFilter::MoreVerbose(Level::Error),
455+
LevelFilter::from_config_str("MoreVerbose(Error)").unwrap()
456+
);
457+
assert_eq!(
458+
LevelFilter::MoreVerboseEqual(Level::Critical),
459+
LevelFilter::from_config_str("MoreVerboseEqual(Critical)").unwrap()
460+
);
461+
assert_eq!(
462+
LevelFilter::All,
463+
LevelFilter::from_config_str("All").unwrap()
464+
);
465+
466+
assert!(LevelFilter::from_config_str("Unknown").is_none());
467+
assert!(LevelFilter::from_config_str("Equal(info").is_none());
468+
assert!(LevelFilter::from_config_str("Equal)info(").is_none());
469+
assert!(LevelFilter::from_config_str("Equal)info").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+
}
477+
376478
#[test]
377479
fn iter() {
378480
let mut iter = Level::iter();

0 commit comments

Comments
 (0)