/rust/registry/src/index.crates.io-6f17d22bba15001f/syslog-6.0.1/src/format.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use std::collections::HashMap; |
2 | | use std::fmt::Display; |
3 | | use std::io::Write; |
4 | | use time; |
5 | | |
6 | | use errors::*; |
7 | | use facility::Facility; |
8 | | use get_hostname; |
9 | | use get_process_info; |
10 | | use Priority; |
11 | | |
12 | | #[allow(non_camel_case_types)] |
13 | | #[derive(Copy, Clone)] |
14 | | pub enum Severity { |
15 | | LOG_EMERG, |
16 | | LOG_ALERT, |
17 | | LOG_CRIT, |
18 | | LOG_ERR, |
19 | | LOG_WARNING, |
20 | | LOG_NOTICE, |
21 | | LOG_INFO, |
22 | | LOG_DEBUG, |
23 | | } |
24 | | |
25 | | pub trait LogFormat<T> { |
26 | | fn format<W: Write>(&self, w: &mut W, severity: Severity, message: T) -> Result<()>; |
27 | | |
28 | 0 | fn emerg<W: Write>(&mut self, w: &mut W, message: T) -> Result<()> { |
29 | 0 | self.format(w, Severity::LOG_EMERG, message) |
30 | 0 | } |
31 | | |
32 | 0 | fn alert<W: Write>(&mut self, w: &mut W, message: T) -> Result<()> { |
33 | 0 | self.format(w, Severity::LOG_ALERT, message) |
34 | 0 | } |
35 | | |
36 | 0 | fn crit<W: Write>(&mut self, w: &mut W, message: T) -> Result<()> { |
37 | 0 | self.format(w, Severity::LOG_CRIT, message) |
38 | 0 | } |
39 | | |
40 | 0 | fn err<W: Write>(&mut self, w: &mut W, message: T) -> Result<()> { |
41 | 0 | self.format(w, Severity::LOG_ERR, message) |
42 | 0 | } |
43 | | |
44 | 0 | fn warning<W: Write>(&mut self, w: &mut W, message: T) -> Result<()> { |
45 | 0 | self.format(w, Severity::LOG_WARNING, message) |
46 | 0 | } |
47 | | |
48 | 0 | fn notice<W: Write>(&mut self, w: &mut W, message: T) -> Result<()> { |
49 | 0 | self.format(w, Severity::LOG_NOTICE, message) |
50 | 0 | } |
51 | | |
52 | 0 | fn info<W: Write>(&mut self, w: &mut W, message: T) -> Result<()> { |
53 | 0 | self.format(w, Severity::LOG_INFO, message) |
54 | 0 | } |
55 | | |
56 | 0 | fn debug<W: Write>(&mut self, w: &mut W, message: T) -> Result<()> { |
57 | 0 | self.format(w, Severity::LOG_DEBUG, message) |
58 | 0 | } |
59 | | } |
60 | | |
61 | | #[derive(Clone, Debug)] |
62 | | pub struct Formatter3164 { |
63 | | pub facility: Facility, |
64 | | pub hostname: Option<String>, |
65 | | pub process: String, |
66 | | pub pid: u32, |
67 | | } |
68 | | |
69 | | impl<T: Display> LogFormat<T> for Formatter3164 { |
70 | 0 | fn format<W: Write>(&self, w: &mut W, severity: Severity, message: T) -> Result<()> { |
71 | 0 | let format = |
72 | 0 | time::format_description::parse("[month repr:short] [day] [hour]:[minute]:[second]") |
73 | 0 | .unwrap(); |
74 | | |
75 | 0 | if let Some(ref hostname) = self.hostname { |
76 | 0 | write!( |
77 | 0 | w, |
78 | 0 | "<{}>{} {} {}[{}]: {}", |
79 | 0 | encode_priority(severity, self.facility), |
80 | 0 | now_local() |
81 | 0 | .map(|timestamp| timestamp.format(&format).unwrap()) Unexecuted instantiation: <syslog::format::Formatter3164 as syslog::format::LogFormat<alloc::string::String>>::format::<std::io::stdio::StderrLock>::{closure#2} Unexecuted instantiation: <syslog::format::Formatter3164 as syslog::format::LogFormat<alloc::string::String>>::format::<syslog::LoggerBackend>::{closure#2} |
82 | 0 | .unwrap(), |
83 | 0 | hostname, |
84 | 0 | self.process, |
85 | 0 | self.pid, |
86 | 0 | message |
87 | 0 | ) |
88 | 0 | .chain_err(|| ErrorKind::Format) Unexecuted instantiation: <syslog::format::Formatter3164 as syslog::format::LogFormat<alloc::string::String>>::format::<std::io::stdio::StderrLock>::{closure#0} Unexecuted instantiation: <syslog::format::Formatter3164 as syslog::format::LogFormat<alloc::string::String>>::format::<syslog::LoggerBackend>::{closure#0} |
89 | | } else { |
90 | 0 | write!( |
91 | 0 | w, |
92 | 0 | "<{}>{} {}[{}]: {}", |
93 | 0 | encode_priority(severity, self.facility), |
94 | 0 | now_local() |
95 | 0 | .map(|timestamp| timestamp.format(&format).unwrap()) Unexecuted instantiation: <syslog::format::Formatter3164 as syslog::format::LogFormat<alloc::string::String>>::format::<std::io::stdio::StderrLock>::{closure#3} Unexecuted instantiation: <syslog::format::Formatter3164 as syslog::format::LogFormat<alloc::string::String>>::format::<syslog::LoggerBackend>::{closure#3} |
96 | 0 | .unwrap(), |
97 | 0 | self.process, |
98 | 0 | self.pid, |
99 | 0 | message |
100 | 0 | ) |
101 | 0 | .chain_err(|| ErrorKind::Format) Unexecuted instantiation: <syslog::format::Formatter3164 as syslog::format::LogFormat<alloc::string::String>>::format::<std::io::stdio::StderrLock>::{closure#1} Unexecuted instantiation: <syslog::format::Formatter3164 as syslog::format::LogFormat<alloc::string::String>>::format::<syslog::LoggerBackend>::{closure#1} |
102 | | } |
103 | 0 | } Unexecuted instantiation: <syslog::format::Formatter3164 as syslog::format::LogFormat<alloc::string::String>>::format::<std::io::stdio::StderrLock> Unexecuted instantiation: <syslog::format::Formatter3164 as syslog::format::LogFormat<alloc::string::String>>::format::<syslog::LoggerBackend> |
104 | | } |
105 | | |
106 | | impl Default for Formatter3164 { |
107 | | /// Returns a `Formatter3164` with default settings. |
108 | | /// |
109 | | /// The default settings are as follows: |
110 | | /// |
111 | | /// * `facility`: `LOG_USER`, as [specified by POSIX]. |
112 | | /// * `hostname`: Automatically detected using [the `hostname` crate], if possible. |
113 | | /// * `process`: Automatically detected using [`std::env::current_exe`], or if that fails, an empty string. |
114 | | /// * `pid`: Automatically detected using [`libc::getpid`]. |
115 | | /// |
116 | | /// [`libc::getpid`]: https://docs.rs/libc/0.2/libc/fn.getpid.html |
117 | | /// [specified by POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/closelog.html |
118 | | /// [`std::env::current_exe`]: https://doc.rust-lang.org/std/env/fn.current_exe.html |
119 | | /// [the `hostname` crate]: https://crates.io/crates/hostname |
120 | 0 | fn default() -> Self { |
121 | 0 | let (process, pid) = get_process_info().unwrap_or((String::new(), std::process::id())); |
122 | 0 | let hostname = get_hostname().ok(); |
123 | 0 |
|
124 | 0 | Self { |
125 | 0 | facility: Default::default(), |
126 | 0 | hostname, |
127 | 0 | process, |
128 | 0 | pid, |
129 | 0 | } |
130 | 0 | } |
131 | | } |
132 | | |
133 | | /// RFC 5424 structured data |
134 | | pub type StructuredData = HashMap<String, HashMap<String, String>>; |
135 | | |
136 | | #[derive(Clone, Debug)] |
137 | | pub struct Formatter5424 { |
138 | | pub facility: Facility, |
139 | | pub hostname: Option<String>, |
140 | | pub process: String, |
141 | | pub pid: u32, |
142 | | } |
143 | | |
144 | | impl Formatter5424 { |
145 | 0 | pub fn format_5424_structured_data(&self, data: StructuredData) -> String { |
146 | 0 | if data.is_empty() { |
147 | 0 | "-".to_string() |
148 | | } else { |
149 | 0 | let mut res = String::new(); |
150 | 0 | for (id, params) in &data { |
151 | 0 | res = res + "[" + id; |
152 | 0 | for (name, value) in params { |
153 | 0 | res = res + " " + name + "=\"" + value + "\""; |
154 | 0 | } |
155 | 0 | res += "]"; |
156 | | } |
157 | | |
158 | 0 | res |
159 | | } |
160 | 0 | } |
161 | | } |
162 | | |
163 | | impl<T: Display> LogFormat<(u32, StructuredData, T)> for Formatter5424 { |
164 | 0 | fn format<W: Write>( |
165 | 0 | &self, |
166 | 0 | w: &mut W, |
167 | 0 | severity: Severity, |
168 | 0 | log_message: (u32, StructuredData, T), |
169 | 0 | ) -> Result<()> { |
170 | 0 | let (message_id, data, message) = log_message; |
171 | 0 |
|
172 | 0 | write!( |
173 | 0 | w, |
174 | 0 | "<{}>1 {} {} {} {} {} {} {}", // v1 |
175 | 0 | encode_priority(severity, self.facility), |
176 | 0 | time::OffsetDateTime::now_utc() |
177 | 0 | .format(&time::format_description::well_known::Rfc3339) |
178 | 0 | .unwrap(), |
179 | 0 | self.hostname |
180 | 0 | .as_ref() |
181 | 0 | .map(|x| &x[..]) |
182 | 0 | .unwrap_or("localhost"), |
183 | 0 | self.process, |
184 | 0 | self.pid, |
185 | 0 | message_id, |
186 | 0 | self.format_5424_structured_data(data), |
187 | 0 | message |
188 | 0 | ) |
189 | 0 | .chain_err(|| ErrorKind::Format) |
190 | 0 | } |
191 | | } |
192 | | |
193 | | impl Default for Formatter5424 { |
194 | | /// Returns a `Formatter5424` with default settings. |
195 | | /// |
196 | | /// The default settings are as follows: |
197 | | /// |
198 | | /// * `facility`: `LOG_USER`, as [specified by POSIX]. |
199 | | /// * `hostname`: Automatically detected using [the `hostname` crate], if possible. |
200 | | /// * `process`: Automatically detected using [`std::env::current_exe`], or if that fails, an empty string. |
201 | | /// * `pid`: Automatically detected using [`libc::getpid`]. |
202 | | /// |
203 | | /// [`libc::getpid`]: https://docs.rs/libc/0.2/libc/fn.getpid.html |
204 | | /// [specified by POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/closelog.html |
205 | | /// [`std::env::current_exe`]: https://doc.rust-lang.org/std/env/fn.current_exe.html |
206 | | /// [the `hostname` crate]: https://crates.io/crates/hostname |
207 | 0 | fn default() -> Self { |
208 | 0 | // Get the defaults from `Formatter3164` and move them over. |
209 | 0 | let Formatter3164 { |
210 | 0 | facility, |
211 | 0 | hostname, |
212 | 0 | process, |
213 | 0 | pid, |
214 | 0 | } = Default::default(); |
215 | 0 | Self { |
216 | 0 | facility, |
217 | 0 | hostname, |
218 | 0 | process, |
219 | 0 | pid, |
220 | 0 | } |
221 | 0 | } |
222 | | } |
223 | | |
224 | 0 | fn encode_priority(severity: Severity, facility: Facility) -> Priority { |
225 | 0 | facility as u8 | severity as u8 |
226 | 0 | } |
227 | | |
228 | | #[cfg(unix)] |
229 | | // On unix platforms, time::OffsetDateTime::now_local always returns an error so use UTC instead |
230 | | // https://github.com/time-rs/time/issues/380 |
231 | 0 | fn now_local() -> std::result::Result<time::OffsetDateTime, time::error::IndeterminateOffset> { |
232 | 0 | Ok(time::OffsetDateTime::now_utc()) |
233 | 0 | } |
234 | | |
235 | | #[cfg(not(unix))] |
236 | | fn now_local() -> std::result::Result<time::OffsetDateTime, time::error::IndeterminateOffset> { |
237 | | time::OffsetDateTime::now_local() |
238 | | } |
239 | | |
240 | | #[test] |
241 | | fn test_formatter3164_defaults() { |
242 | | let d = Formatter3164::default(); |
243 | | |
244 | | // `Facility` doesn't implement `PartialEq`, so we use a `match` instead. |
245 | | assert!(match d.facility { |
246 | | Facility::LOG_USER => true, |
247 | | _ => false, |
248 | | }); |
249 | | |
250 | | assert!(match &d.hostname { |
251 | | Some(hostname) => !hostname.is_empty(), |
252 | | None => false, |
253 | | }); |
254 | | |
255 | | assert!(!d.process.is_empty()); |
256 | | |
257 | | // Can't really make any assertions about the pid. |
258 | | } |
259 | | |
260 | | #[test] |
261 | | fn test_formatter5424_defaults() { |
262 | | let d = Formatter5424::default(); |
263 | | |
264 | | // `Facility` doesn't implement `PartialEq`, so we use a `match` instead. |
265 | | assert!(match d.facility { |
266 | | Facility::LOG_USER => true, |
267 | | _ => false, |
268 | | }); |
269 | | |
270 | | assert!(match &d.hostname { |
271 | | Some(hostname) => !hostname.is_empty(), |
272 | | None => false, |
273 | | }); |
274 | | |
275 | | assert!(!d.process.is_empty()); |
276 | | |
277 | | // Can't really make any assertions about the pid. |
278 | | } |