Skip to content

Commit 8eff3dd

Browse files
feat: properly serialize filters & appenders in RawConfig
1 parent 9fdfbc6 commit 8eff3dd

File tree

3 files changed

+93
-14
lines changed

3 files changed

+93
-14
lines changed

src/append/mod.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use log::{Log, Record};
44
#[cfg(feature = "config_parsing")]
55
use serde::{de, Deserialize, Deserializer};
6+
use serde::{Serialize, Serializer};
67
#[cfg(feature = "config_parsing")]
78
use serde_value::Value;
89
#[cfg(feature = "config_parsing")]
@@ -115,7 +116,7 @@ impl<T: Log + fmt::Debug + 'static> Append for T {
115116

116117
/// Configuration for an appender.
117118
#[cfg(feature = "config_parsing")]
118-
#[derive(Clone, Eq, PartialEq, Hash, Debug, serde::Serialize)]
119+
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
119120
pub struct AppenderConfig {
120121
/// The appender kind.
121122
pub kind: String,
@@ -151,6 +152,46 @@ impl<'de> Deserialize<'de> for AppenderConfig {
151152
}
152153
}
153154

155+
#[cfg(feature = "config_parsing")]
156+
impl Serialize for AppenderConfig {
157+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
158+
where
159+
S: Serializer,
160+
{
161+
let mut map: BTreeMap<Value, Value> = BTreeMap::new();
162+
163+
map.insert(
164+
Value::String("kind".to_string()),
165+
Value::String(self.kind.clone()),
166+
);
167+
168+
// Insert the `filters` field into the map if it's not empty
169+
if !self.filters.is_empty() {
170+
let filters: Vec<Value> = self
171+
.filters
172+
.iter()
173+
.map(|f| serde_value::to_value(f).unwrap())
174+
.collect();
175+
176+
map.insert(Value::String("filters".to_string()), Value::Seq(filters));
177+
} else {
178+
map.insert(
179+
Value::String("filters".to_string()),
180+
Value::String("[]".to_string()),
181+
);
182+
}
183+
184+
if let Value::Map(ref config_map) = self.config {
185+
for (key, value) in config_map {
186+
map.insert(key.clone(), value.clone());
187+
}
188+
}
189+
190+
// Serialize the map
191+
map.serialize(serializer)
192+
}
193+
}
194+
154195
#[cfg(test)]
155196
mod test {
156197
#[cfg(any(feature = "file_appender", feature = "rolling_file_appender"))]

src/config/raw.rs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,12 @@ use std::{collections::HashMap, fmt, marker::PhantomData, sync::Arc, time::Durat
9494
use anyhow::anyhow;
9595
use derive_more::Debug;
9696
use log::LevelFilter;
97-
use serde::de::{self, Deserialize as SerdeDeserialize, DeserializeOwned};
97+
use serde::{
98+
de::{self, Deserialize as SerdeDeserialize, DeserializeOwned},
99+
ser,
100+
};
98101
use serde_value::Value;
102+
99103
use thiserror::Error;
100104
use typemap_ors::{Key, ShareCloneMap};
101105

@@ -322,6 +326,7 @@ pub enum DeserializingConfigError {
322326
#[serde(deny_unknown_fields)]
323327
pub struct RawConfig {
324328
#[serde(deserialize_with = "de_duration", default)]
329+
#[serde(serialize_with = "ser_duration")]
325330
refresh_rate: Option<Duration>,
326331

327332
#[serde(default)]
@@ -403,6 +408,19 @@ impl RawConfig {
403408
}
404409
}
405410

411+
fn ser_duration<S>(duration: &Option<Duration>, s: S) -> Result<S::Ok, S::Error>
412+
where
413+
S: ser::Serializer,
414+
{
415+
match duration {
416+
Some(duration) => {
417+
let duration_str: String = humantime::format_duration(*duration).to_string();
418+
s.serialize_some(&duration_str)
419+
}
420+
None => s.serialize_none(),
421+
}
422+
}
423+
406424
fn de_duration<'de, D>(d: D) -> Result<Option<Duration>, D::Error>
407425
where
408426
D: de::Deserializer<'de>,
@@ -481,9 +499,11 @@ mod test {
481499
use super::*;
482500
use std::fs;
483501

484-
const CFG: &'static str = r#"
485-
refresh_rate: 60 seconds
486-
502+
const CFG: &'static str = r#"refresh_rate: 1m
503+
root:
504+
level: info
505+
appenders:
506+
- console
487507
appenders:
488508
console:
489509
kind: console
@@ -495,12 +515,6 @@ appenders:
495515
path: /tmp/baz.log
496516
encoder:
497517
pattern: "%m"
498-
499-
root:
500-
appenders:
501-
- console
502-
level: info
503-
504518
loggers:
505519
foo::bar::baz:
506520
level: warn
@@ -524,10 +538,11 @@ loggers:
524538
let config = ::serde_yaml::from_str::<RawConfig>(CFG).unwrap();
525539
let errors = config.appenders_lossy(&Deserializers::new()).1;
526540
println!("{:?}", errors);
541+
assert!(errors.is_empty());
527542

528543
let config = ::serde_yaml::to_string::<RawConfig>(&config);
529544

530-
assert!(config.is_ok())
545+
assert_eq!(config.unwrap(), CFG)
531546
}
532547

533548
#[test]

src/filter/mod.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use log::Record;
44
#[cfg(feature = "config_parsing")]
5-
use serde::de;
5+
use serde::{de, Serialize, Serializer};
66
#[cfg(feature = "config_parsing")]
77
use serde_value::Value;
88
#[cfg(feature = "config_parsing")]
@@ -52,7 +52,7 @@ pub enum Response {
5252

5353
/// Configuration for a filter.
5454
#[cfg(feature = "config_parsing")]
55-
#[derive(Clone, Eq, PartialEq, Hash, Debug, serde::Serialize)]
55+
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
5656
pub struct FilterConfig {
5757
/// The filter kind.
5858
pub kind: String,
@@ -80,6 +80,29 @@ impl<'de> de::Deserialize<'de> for FilterConfig {
8080
}
8181
}
8282

83+
#[cfg(feature = "config_parsing")]
84+
impl Serialize for FilterConfig {
85+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
86+
where
87+
S: Serializer,
88+
{
89+
let mut map = BTreeMap::new();
90+
91+
map.insert(
92+
Value::String("kind".to_owned()),
93+
Value::String(self.kind.clone()),
94+
);
95+
96+
if let Value::Map(ref config_map) = self.config {
97+
for (key, value) in config_map {
98+
map.insert(key.clone(), value.clone());
99+
}
100+
}
101+
102+
map.serialize(serializer)
103+
}
104+
}
105+
83106
#[cfg(test)]
84107
mod test {
85108
#[cfg(feature = "config_parsing")]

0 commit comments

Comments
 (0)