logform/formats/
metadata.rs1use crate::LogInfo;
2use serde_json::json;
3use std::collections::HashMap;
4use std::collections::HashSet;
5
6use super::Format;
7
8pub struct MetadataFormat {
9 key: String,
10 fill_except: HashSet<String>,
11 fill_with: HashSet<String>,
12}
13
14impl MetadataFormat {
15 pub fn new() -> Self {
16 MetadataFormat {
17 key: "metadata".to_string(),
18 fill_except: HashSet::new(),
19 fill_with: HashSet::new(),
20 }
21 }
22
23 pub fn with_key(mut self, key: &str) -> Self {
24 self.key = key.to_string();
25 self
26 }
27
28 pub fn with_fill_except(mut self, keys: Vec<&str>) -> Self {
29 self.fill_except = keys.into_iter().map(String::from).collect();
30 self
31 }
32
33 pub fn with_fill_with(mut self, keys: Vec<&str>) -> Self {
34 self.fill_with = keys.into_iter().map(String::from).collect();
35 self
36 }
37}
38
39impl Format for MetadataFormat {
40 type Input = LogInfo;
41
42 fn transform(&self, mut info: LogInfo) -> Option<Self::Input> {
43 let mut metadata = HashMap::new();
44
45 if !self.fill_with.is_empty() {
46 for key in &self.fill_with {
47 if self.fill_except.contains(key) {
48 continue;
49 }
50 if let Some(value) = info.meta.remove(key) {
51 metadata.insert(key.clone(), value);
52 }
53 }
54 } else {
55 let keys_to_move: Vec<String> = info
57 .meta
58 .keys()
59 .filter(|key| !self.fill_except.contains(*key))
60 .cloned()
61 .collect();
62 for key in keys_to_move {
63 if let Some(value) = info.meta.remove(&key) {
64 metadata.insert(key, value);
65 }
66 }
67 }
68
69 info.meta.insert(self.key.clone(), json!(metadata));
70 Some(info)
71 }
72}
73
74pub fn metadata() -> MetadataFormat {
75 MetadataFormat::new()
76}
77
78#[cfg(test)]
79mod tests {
80 #[test]
81 fn test_metadata_with_fill_with_and_fill_except() {
82 let metadata_format = MetadataFormat::new()
83 .with_key("metadata")
84 .with_fill_with(vec!["key1", "key2", "key3"])
85 .with_fill_except(vec!["key2"]);
86 let mut info = LogInfo::new("info", "Test message");
87 info.meta.insert("key1".to_string(), "value1".into());
88 info.meta.insert("key2".to_string(), "value2".into());
89 info.meta.insert("key3".to_string(), "value3".into());
90
91 let result = metadata_format.transform(info).unwrap();
92 let metadata = result.meta.get("metadata").unwrap();
93
94 assert_eq!(
96 metadata.get("key1"),
97 Some(&Value::String("value1".to_string()))
98 );
99 assert_eq!(
100 metadata.get("key3"),
101 Some(&Value::String("value3".to_string()))
102 );
103 assert!(metadata.get("key2").is_none());
104 }
105
106 #[test]
107 fn test_metadata_with_empty_meta() {
108 let metadata_format = MetadataFormat::new().with_key("metadata");
109 let info = LogInfo::new("info", "Test message");
110 let result = metadata_format.transform(info).unwrap();
111 let metadata = result.meta.get("metadata").unwrap();
112 assert!(metadata.as_object().unwrap().is_empty());
113 }
114
115 #[test]
116 fn test_metadata_with_fill_with_nonexistent_keys() {
117 let metadata_format = MetadataFormat::new()
118 .with_key("metadata")
119 .with_fill_with(vec!["not_present", "also_missing"]);
120 let mut info = LogInfo::new("info", "Test message");
121 info.meta.insert("key1".to_string(), "value1".into());
122 let result = metadata_format.transform(info).unwrap();
123 let metadata = result.meta.get("metadata").unwrap();
124 assert!(metadata.as_object().unwrap().is_empty());
126 assert_eq!(
128 result.meta.get("key1"),
129 Some(&Value::String("value1".to_string()))
130 );
131 }
132
133 #[test]
134 fn test_metadata_format_default_constructor() {
135 let metadata_format = MetadataFormat::new();
136 let mut info = LogInfo::new("info", "Test message");
137 info.meta.insert("key1".to_string(), "value1".into());
138 let result = metadata_format.transform(info).unwrap();
139 let key = &metadata_format.key;
141 let metadata = result.meta.get(key).unwrap();
142 assert_eq!(
143 metadata.get("key1"),
144 Some(&Value::String("value1".to_string()))
145 );
146 assert!(result.meta.get("key1").is_none());
148 }
149 use super::*;
150 use serde_json::Value;
151
152 #[test]
153 fn test_metadata_with_fill_with() {
154 let metadata_format = MetadataFormat::new()
155 .with_key("metadata")
156 .with_fill_with(vec!["key1"]);
157 let mut info = LogInfo::new("info", "Test message");
158 info.meta.insert("key1".to_string(), "value1".into());
159 info.meta.insert("key2".to_string(), "value2".into());
160
161 let result = metadata_format.transform(info).unwrap();
162 let metadata = result.meta.get("metadata").unwrap();
163
164 assert_eq!(
165 metadata.get("key1"),
166 Some(&Value::String("value1".to_string()))
167 );
168 assert!(metadata.get("key2").is_none());
169 assert!(result.meta.get("key1").is_none());
170 assert_eq!(
171 result.meta.get("key2"),
172 Some(&Value::String("value2".to_string()))
173 );
174 }
175
176 #[test]
177 fn test_metadata_with_fill_except() {
178 let metadata_format = MetadataFormat::new()
179 .with_key("metadata")
180 .with_fill_except(vec!["key1", "key3"]);
181 let mut info = LogInfo::new("info", "Test message");
182 info.meta.insert("key1".to_string(), "value1".into());
183 info.meta.insert("key2".to_string(), "value2".into());
184 info.meta.insert("key3".to_string(), "value3".into());
185
186 let result = metadata_format.transform(info).unwrap();
187 let metadata = result.meta.get("metadata").unwrap();
188
189 assert_eq!(
190 metadata.get("key2"),
191 Some(&Value::String("value2".to_string()))
192 );
193 assert!(metadata.get("key1").is_none());
194 assert!(metadata.get("key3").is_none());
195 assert_eq!(
196 result.meta.get("key1"),
197 Some(&Value::String("value1".to_string()))
198 );
199 assert_eq!(
200 result.meta.get("key3"),
201 Some(&Value::String("value3".to_string()))
202 );
203 }
204}