opentracingrust/span/
log.rs1use std::collections::HashMap;
2use std::collections::hash_map::Iter;
3
4use std::time::SystemTime;
5
6
7#[derive(Debug, Default)]
44pub struct Log {
45 fields: LogFileds,
46 timestamp: Option<SystemTime>,
47}
48
49impl Log {
50 pub fn new() -> Log {
52 Log {
53 fields: LogFileds::new(),
54 timestamp: None,
55 }
56 }
57}
58
59impl Log {
60 pub fn at(mut self, timestamp: SystemTime) -> Log {
62 self.timestamp = Some(timestamp);
63 self
64 }
65
66 pub fn at_or_now(&mut self) {
68 if self.timestamp.is_none() {
69 self.timestamp = Some(SystemTime::now())
70 }
71 }
72
73 pub fn log<LV: Into<LogValue>>(mut self, key: &str, value: LV) -> Log {
77 self.fields.log(key.into(), value.into());
78 self
79 }
80
81 pub fn iter(&self) -> Iter<String, LogValue> {
83 self.fields.iter()
84 }
85
86 pub fn timestamp(&self) -> Option<&SystemTime> {
88 self.timestamp.as_ref()
89 }
90}
91
92
93#[derive(Debug, Default)]
95struct LogFileds(HashMap<String, LogValue>);
96
97impl LogFileds {
98 pub fn new() -> LogFileds {
100 LogFileds(HashMap::new())
101 }
102
103 pub fn log(&mut self, key: String, value: LogValue) {
105 self.0.insert(key, value);
106 }
107
108 pub fn iter(&self) -> Iter<String, LogValue> {
110 self.0.iter()
111 }
112}
113
114
115#[derive(Debug, PartialEq)]
117pub enum LogValue {
118 Boolean(bool),
119 Float(f64),
120 Integer(i64),
121 String(String),
122}
123
124impl From<bool> for LogValue {
125 fn from(value: bool) -> LogValue {
126 LogValue::Boolean(value)
127 }
128}
129
130impl From<f64> for LogValue {
131 fn from(value: f64) -> LogValue {
132 LogValue::Float(value)
133 }
134}
135
136impl From<i64> for LogValue {
137 fn from(value: i64) -> LogValue {
138 LogValue::Integer(value)
139 }
140}
141
142impl<'a> From<&'a str> for LogValue {
143 fn from(value: &'a str) -> LogValue {
144 LogValue::String(String::from(value))
145 }
146}
147
148impl From<String> for LogValue {
149 fn from(value: String) -> LogValue {
150 LogValue::String(value)
151 }
152}
153
154
155#[cfg(test)]
156mod tests {
157 use std::time::Duration;
158 use std::time::SystemTime;
159
160 use super::Log;
161 use super::LogValue;
162
163 #[test]
164 fn add_field() {
165 let log = Log::new().log("key", "value");
166 let entries: Vec<(&String, &LogValue)> = log.iter().collect();
167 assert_eq!(entries, [
168 (&String::from("key"), &LogValue::String(String::from("value")))
169 ]);
170 }
171
172 #[test]
173 fn defults_to_no_time() {
174 match Log::new().timestamp() {
175 None => (),
176 _ => panic!("Time should not be set")
177 }
178 }
179
180 #[test]
181 fn set_default_timestamp() {
182 let start = SystemTime::now();
183 let mut log = Log::new();
184 log.at_or_now();
185 let time = log.timestamp().unwrap();
186 let duration = time.duration_since(start).unwrap();
187 if duration > Duration::from_millis(100) {
188 panic!("Log timestamp too far from expected time");
189 }
190 }
191
192 #[test]
193 fn set_log_timestamp() {
194 let time = SystemTime::now();
195 let log = Log::new().at(time.clone());
196 assert_eq!(&time, log.timestamp().unwrap());
197 }
198}