1use std::cell::RefCell;
33use std::fmt::Display;
34use std::io::prelude::*;
35use std::rc::Rc;
36use std::{fmt, io, mem};
37
38use log::Record;
39
40mod humantime;
41pub(crate) mod writer;
42
43pub use self::humantime::glob::*;
44pub use self::writer::glob::*;
45
46use self::writer::{Buffer, Writer};
47
48pub(crate) mod glob {
49 pub use super::{Target, TimestampPrecision, WriteStyle};
50}
51
52#[derive(Copy, Clone, Debug)]
58pub enum TimestampPrecision {
59 Seconds,
61 Millis,
63 Micros,
65 Nanos,
67}
68
69impl Default for TimestampPrecision {
71 fn default() -> Self {
72 TimestampPrecision::Seconds
73 }
74}
75
76pub struct Formatter {
98 buf: Rc<RefCell<Buffer>>,
99 write_style: WriteStyle,
100}
101
102impl Formatter {
103 pub(crate) fn new(writer: &Writer) -> Self {
104 Formatter {
105 buf: Rc::new(RefCell::new(writer.buffer())),
106 write_style: writer.write_style(),
107 }
108 }
109
110 pub(crate) fn write_style(&self) -> WriteStyle {
111 self.write_style
112 }
113
114 pub(crate) fn print(&self, writer: &Writer) -> io::Result<()> {
115 writer.print(&self.buf.borrow())
116 }
117
118 pub(crate) fn clear(&mut self) {
119 self.buf.borrow_mut().clear()
120 }
121}
122
123impl Write for Formatter {
124 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
125 self.buf.borrow_mut().write(buf)
126 }
127
128 fn flush(&mut self) -> io::Result<()> {
129 self.buf.borrow_mut().flush()
130 }
131}
132
133impl fmt::Debug for Formatter {
134 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135 f.debug_struct("Formatter").finish()
136 }
137}
138
139pub(crate) struct Builder {
140 pub format_timestamp: Option<TimestampPrecision>,
141 pub format_module_path: bool,
142 pub format_level: bool,
143 pub format_indent: Option<usize>,
144 #[allow(unknown_lints, bare_trait_objects)]
145 pub custom_format: Option<Box<Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send>>,
146 built: bool,
147}
148
149impl Default for Builder {
150 fn default() -> Self {
151 Builder {
152 format_timestamp: Some(Default::default()),
153 format_module_path: true,
154 format_level: true,
155 format_indent: Some(4),
156 custom_format: None,
157 built: false,
158 }
159 }
160}
161
162impl Builder {
163 #[allow(unknown_lints, bare_trait_objects)]
169 pub fn build(&mut self) -> Box<Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send> {
170 assert!(!self.built, "attempt to re-use consumed builder");
171
172 let built = mem::replace(
173 self,
174 Builder {
175 built: true,
176 ..Default::default()
177 },
178 );
179
180 if let Some(fmt) = built.custom_format {
181 fmt
182 } else {
183 Box::new(move |buf, record| {
184 let fmt = DefaultFormat {
185 timestamp: built.format_timestamp,
186 module_path: built.format_module_path,
187 level: built.format_level,
188 written_header_value: false,
189 indent: built.format_indent,
190 buf,
191 };
192
193 fmt.write(record)
194 })
195 }
196 }
197}
198
199#[cfg(feature = "termcolor")]
200type SubtleStyle = StyledValue<'static, &'static str>;
201#[cfg(not(feature = "termcolor"))]
202type SubtleStyle = &'static str;
203
204struct DefaultFormat<'a> {
208 timestamp: Option<TimestampPrecision>,
209 module_path: bool,
210 level: bool,
211 written_header_value: bool,
212 indent: Option<usize>,
213 buf: &'a mut Formatter,
214}
215
216impl<'a> DefaultFormat<'a> {
217 fn write(mut self, record: &Record) -> io::Result<()> {
218 self.write_timestamp()?;
219 self.write_level(record)?;
220 self.write_module_path(record)?;
221 self.finish_header()?;
222
223 self.write_args(record)
224 }
225
226 fn subtle_style(&self, text: &'static str) -> SubtleStyle {
227 #[cfg(feature = "termcolor")]
228 {
229 self.buf
230 .style()
231 .set_color(Color::Black)
232 .set_intense(true)
233 .into_value(text)
234 }
235 #[cfg(not(feature = "termcolor"))]
236 {
237 text
238 }
239 }
240
241 fn write_header_value<T>(&mut self, value: T) -> io::Result<()>
242 where
243 T: Display,
244 {
245 if !self.written_header_value {
246 self.written_header_value = true;
247
248 let open_brace = self.subtle_style("[");
249 write!(self.buf, "{}{}", open_brace, value)
250 } else {
251 write!(self.buf, " {}", value)
252 }
253 }
254
255 fn write_level(&mut self, record: &Record) -> io::Result<()> {
256 if !self.level {
257 return Ok(());
258 }
259
260 let level = {
261 #[cfg(feature = "termcolor")]
262 {
263 self.buf.default_styled_level(record.level())
264 }
265 #[cfg(not(feature = "termcolor"))]
266 {
267 record.level()
268 }
269 };
270
271 self.write_header_value(format_args!("{:<5}", level))
272 }
273
274 fn write_timestamp(&mut self) -> io::Result<()> {
275 #[cfg(feature = "humantime")]
276 {
277 use self::TimestampPrecision::*;
278 let ts = match self.timestamp {
279 None => return Ok(()),
280 Some(Seconds) => self.buf.timestamp_seconds(),
281 Some(Millis) => self.buf.timestamp_millis(),
282 Some(Micros) => self.buf.timestamp_micros(),
283 Some(Nanos) => self.buf.timestamp_nanos(),
284 };
285
286 self.write_header_value(ts)
287 }
288 #[cfg(not(feature = "humantime"))]
289 {
290 let _ = self.timestamp;
293 Ok(())
294 }
295 }
296
297 fn write_module_path(&mut self, record: &Record) -> io::Result<()> {
298 if !self.module_path {
299 return Ok(());
300 }
301
302 if let Some(module_path) = record.module_path() {
303 self.write_header_value(module_path)
304 } else {
305 Ok(())
306 }
307 }
308
309 fn finish_header(&mut self) -> io::Result<()> {
310 if self.written_header_value {
311 let close_brace = self.subtle_style("]");
312 write!(self.buf, "{} ", close_brace)
313 } else {
314 Ok(())
315 }
316 }
317
318 fn write_args(&mut self, record: &Record) -> io::Result<()> {
319 match self.indent {
320 None => writeln!(self.buf, "{}", record.args()),
322
323 Some(indent_count) => {
324 struct IndentWrapper<'a, 'b: 'a> {
327 fmt: &'a mut DefaultFormat<'b>,
328 indent_count: usize,
329 }
330
331 impl<'a, 'b> Write for IndentWrapper<'a, 'b> {
332 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
333 let mut first = true;
334 for chunk in buf.split(|&x| x == b'\n') {
335 if !first {
336 write!(self.fmt.buf, "\n{:width$}", "", width = self.indent_count)?;
337 }
338 self.fmt.buf.write_all(chunk)?;
339 first = false;
340 }
341
342 Ok(buf.len())
343 }
344
345 fn flush(&mut self) -> io::Result<()> {
346 self.fmt.buf.flush()
347 }
348 }
349
350 {
352 let mut wrapper = IndentWrapper {
353 fmt: self,
354 indent_count,
355 };
356 write!(wrapper, "{}", record.args())?;
357 }
358
359 writeln!(self.buf)?;
360
361 Ok(())
362 }
363 }
364 }
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370
371 use log::{Level, Record};
372
373 fn write(fmt: DefaultFormat) -> String {
374 let buf = fmt.buf.buf.clone();
375
376 let record = Record::builder()
377 .args(format_args!("log\nmessage"))
378 .level(Level::Info)
379 .file(Some("test.rs"))
380 .line(Some(144))
381 .module_path(Some("test::path"))
382 .build();
383
384 fmt.write(&record).expect("failed to write record");
385
386 let buf = buf.borrow();
387 String::from_utf8(buf.bytes().to_vec()).expect("failed to read record")
388 }
389
390 #[test]
391 fn format_with_header() {
392 let writer = writer::Builder::new()
393 .write_style(WriteStyle::Never)
394 .build();
395
396 let mut f = Formatter::new(&writer);
397
398 let written = write(DefaultFormat {
399 timestamp: None,
400 module_path: true,
401 level: true,
402 written_header_value: false,
403 indent: None,
404 buf: &mut f,
405 });
406
407 assert_eq!("[INFO test::path] log\nmessage\n", written);
408 }
409
410 #[test]
411 fn format_no_header() {
412 let writer = writer::Builder::new()
413 .write_style(WriteStyle::Never)
414 .build();
415
416 let mut f = Formatter::new(&writer);
417
418 let written = write(DefaultFormat {
419 timestamp: None,
420 module_path: false,
421 level: false,
422 written_header_value: false,
423 indent: None,
424 buf: &mut f,
425 });
426
427 assert_eq!("log\nmessage\n", written);
428 }
429
430 #[test]
431 fn format_indent_spaces() {
432 let writer = writer::Builder::new()
433 .write_style(WriteStyle::Never)
434 .build();
435
436 let mut f = Formatter::new(&writer);
437
438 let written = write(DefaultFormat {
439 timestamp: None,
440 module_path: true,
441 level: true,
442 written_header_value: false,
443 indent: Some(4),
444 buf: &mut f,
445 });
446
447 assert_eq!("[INFO test::path] log\n message\n", written);
448 }
449
450 #[test]
451 fn format_indent_zero_spaces() {
452 let writer = writer::Builder::new()
453 .write_style(WriteStyle::Never)
454 .build();
455
456 let mut f = Formatter::new(&writer);
457
458 let written = write(DefaultFormat {
459 timestamp: None,
460 module_path: true,
461 level: true,
462 written_header_value: false,
463 indent: Some(0),
464 buf: &mut f,
465 });
466
467 assert_eq!("[INFO test::path] log\nmessage\n", written);
468 }
469
470 #[test]
471 fn format_indent_spaces_no_header() {
472 let writer = writer::Builder::new()
473 .write_style(WriteStyle::Never)
474 .build();
475
476 let mut f = Formatter::new(&writer);
477
478 let written = write(DefaultFormat {
479 timestamp: None,
480 module_path: false,
481 level: false,
482 written_header_value: false,
483 indent: Some(4),
484 buf: &mut f,
485 });
486
487 assert_eq!("log\n message\n", written);
488 }
489}