1use std::cell::RefCell;
33use std::fmt::Display;
34use std::io::prelude::*;
35use std::rc::Rc;
36use std::{fmt, io, mem};
37
38#[cfg(feature = "color")]
39use log::Level;
40use log::Record;
41
42#[cfg(feature = "humantime")]
43mod humantime;
44pub(crate) mod writer;
45
46#[cfg(feature = "color")]
47mod style;
48#[cfg(feature = "color")]
49pub use style::{Color, Style, StyledValue};
50
51#[cfg(feature = "humantime")]
52pub use self::humantime::Timestamp;
53pub use self::writer::glob::*;
54
55use self::writer::{Buffer, Writer};
56
57pub(crate) mod glob {
58 pub use super::{Target, TimestampPrecision, WriteStyle};
59}
60
61#[derive(Copy, Clone, Debug)]
67pub enum TimestampPrecision {
68 Seconds,
70 Millis,
72 Micros,
74 Nanos,
76}
77
78impl Default for TimestampPrecision {
80 fn default() -> Self {
81 TimestampPrecision::Seconds
82 }
83}
84
85pub struct Formatter {
107 buf: Rc<RefCell<Buffer>>,
108 write_style: WriteStyle,
109}
110
111impl Formatter {
112 pub(crate) fn new(writer: &Writer) -> Self {
113 Formatter {
114 buf: Rc::new(RefCell::new(writer.buffer())),
115 write_style: writer.write_style(),
116 }
117 }
118
119 pub(crate) fn write_style(&self) -> WriteStyle {
120 self.write_style
121 }
122
123 pub(crate) fn print(&self, writer: &Writer) -> io::Result<()> {
124 writer.print(&self.buf.borrow())
125 }
126
127 pub(crate) fn clear(&mut self) {
128 self.buf.borrow_mut().clear()
129 }
130}
131
132#[cfg(feature = "color")]
133impl Formatter {
134 pub fn style(&self) -> Style {
159 Style {
160 buf: self.buf.clone(),
161 spec: termcolor::ColorSpec::new(),
162 }
163 }
164
165 pub fn default_level_style(&self, level: Level) -> Style {
169 let mut level_style = self.style();
170 match level {
171 Level::Trace => level_style.set_color(Color::Cyan),
172 Level::Debug => level_style.set_color(Color::Blue),
173 Level::Info => level_style.set_color(Color::Green),
174 Level::Warn => level_style.set_color(Color::Yellow),
175 Level::Error => level_style.set_color(Color::Red).set_bold(true),
176 };
177 level_style
178 }
179
180 pub fn default_styled_level(&self, level: Level) -> StyledValue<'static, Level> {
184 self.default_level_style(level).into_value(level)
185 }
186}
187
188impl Write for Formatter {
189 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
190 self.buf.borrow_mut().write(buf)
191 }
192
193 fn flush(&mut self) -> io::Result<()> {
194 self.buf.borrow_mut().flush()
195 }
196}
197
198impl fmt::Debug for Formatter {
199 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200 f.debug_struct("Formatter").finish()
201 }
202}
203
204pub(crate) type FormatFn = Box<dyn Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send>;
205
206pub(crate) struct Builder {
207 pub format_timestamp: Option<TimestampPrecision>,
208 pub format_module_path: bool,
209 pub format_target: bool,
210 pub format_level: bool,
211 pub format_indent: Option<usize>,
212 pub custom_format: Option<FormatFn>,
213 pub format_suffix: &'static str,
214 built: bool,
215}
216
217impl Builder {
218 pub fn build(&mut self) -> FormatFn {
224 assert!(!self.built, "attempt to re-use consumed builder");
225
226 let built = mem::replace(
227 self,
228 Builder {
229 built: true,
230 ..Default::default()
231 },
232 );
233
234 if let Some(fmt) = built.custom_format {
235 fmt
236 } else {
237 Box::new(move |buf, record| {
238 let fmt = DefaultFormat {
239 timestamp: built.format_timestamp,
240 module_path: built.format_module_path,
241 target: built.format_target,
242 level: built.format_level,
243 written_header_value: false,
244 indent: built.format_indent,
245 suffix: built.format_suffix,
246 buf,
247 };
248
249 fmt.write(record)
250 })
251 }
252 }
253}
254
255impl Default for Builder {
256 fn default() -> Self {
257 Builder {
258 format_timestamp: Some(Default::default()),
259 format_module_path: false,
260 format_target: true,
261 format_level: true,
262 format_indent: Some(4),
263 custom_format: None,
264 format_suffix: "\n",
265 built: false,
266 }
267 }
268}
269
270#[cfg(feature = "color")]
271type SubtleStyle = StyledValue<'static, &'static str>;
272#[cfg(not(feature = "color"))]
273type SubtleStyle = &'static str;
274
275struct DefaultFormat<'a> {
279 timestamp: Option<TimestampPrecision>,
280 module_path: bool,
281 target: bool,
282 level: bool,
283 written_header_value: bool,
284 indent: Option<usize>,
285 buf: &'a mut Formatter,
286 suffix: &'a str,
287}
288
289impl<'a> DefaultFormat<'a> {
290 fn write(mut self, record: &Record) -> io::Result<()> {
291 self.write_timestamp()?;
292 self.write_level(record)?;
293 self.write_module_path(record)?;
294 self.write_target(record)?;
295 self.finish_header()?;
296
297 self.write_args(record)
298 }
299
300 fn subtle_style(&self, text: &'static str) -> SubtleStyle {
301 #[cfg(feature = "color")]
302 {
303 self.buf
304 .style()
305 .set_color(Color::Black)
306 .set_intense(true)
307 .clone()
308 .into_value(text)
309 }
310 #[cfg(not(feature = "color"))]
311 {
312 text
313 }
314 }
315
316 fn write_header_value<T>(&mut self, value: T) -> io::Result<()>
317 where
318 T: Display,
319 {
320 if !self.written_header_value {
321 self.written_header_value = true;
322
323 let open_brace = self.subtle_style("[");
324 write!(self.buf, "{}{}", open_brace, value)
325 } else {
326 write!(self.buf, " {}", value)
327 }
328 }
329
330 fn write_level(&mut self, record: &Record) -> io::Result<()> {
331 if !self.level {
332 return Ok(());
333 }
334
335 let level = {
336 #[cfg(feature = "color")]
337 {
338 self.buf.default_styled_level(record.level())
339 }
340 #[cfg(not(feature = "color"))]
341 {
342 record.level()
343 }
344 };
345
346 self.write_header_value(format_args!("{:<5}", level))
347 }
348
349 fn write_timestamp(&mut self) -> io::Result<()> {
350 #[cfg(feature = "humantime")]
351 {
352 use self::TimestampPrecision::*;
353 let ts = match self.timestamp {
354 None => return Ok(()),
355 Some(Seconds) => self.buf.timestamp_seconds(),
356 Some(Millis) => self.buf.timestamp_millis(),
357 Some(Micros) => self.buf.timestamp_micros(),
358 Some(Nanos) => self.buf.timestamp_nanos(),
359 };
360
361 self.write_header_value(ts)
362 }
363 #[cfg(not(feature = "humantime"))]
364 {
365 let _ = self.timestamp;
368 Ok(())
369 }
370 }
371
372 fn write_module_path(&mut self, record: &Record) -> io::Result<()> {
373 if !self.module_path {
374 return Ok(());
375 }
376
377 if let Some(module_path) = record.module_path() {
378 self.write_header_value(module_path)
379 } else {
380 Ok(())
381 }
382 }
383
384 fn write_target(&mut self, record: &Record) -> io::Result<()> {
385 if !self.target {
386 return Ok(());
387 }
388
389 match record.target() {
390 "" => Ok(()),
391 target => self.write_header_value(target),
392 }
393 }
394
395 fn finish_header(&mut self) -> io::Result<()> {
396 if self.written_header_value {
397 let close_brace = self.subtle_style("]");
398 write!(self.buf, "{} ", close_brace)
399 } else {
400 Ok(())
401 }
402 }
403
404 fn write_args(&mut self, record: &Record) -> io::Result<()> {
405 match self.indent {
406 None => write!(self.buf, "{}{}", record.args(), self.suffix),
408
409 Some(indent_count) => {
410 struct IndentWrapper<'a, 'b: 'a> {
413 fmt: &'a mut DefaultFormat<'b>,
414 indent_count: usize,
415 }
416
417 impl<'a, 'b> Write for IndentWrapper<'a, 'b> {
418 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
419 let mut first = true;
420 for chunk in buf.split(|&x| x == b'\n') {
421 if !first {
422 write!(
423 self.fmt.buf,
424 "{}{:width$}",
425 self.fmt.suffix,
426 "",
427 width = self.indent_count
428 )?;
429 }
430 self.fmt.buf.write_all(chunk)?;
431 first = false;
432 }
433
434 Ok(buf.len())
435 }
436
437 fn flush(&mut self) -> io::Result<()> {
438 self.fmt.buf.flush()
439 }
440 }
441
442 {
444 let mut wrapper = IndentWrapper {
445 fmt: self,
446 indent_count,
447 };
448 write!(wrapper, "{}", record.args())?;
449 }
450
451 write!(self.buf, "{}", self.suffix)?;
452
453 Ok(())
454 }
455 }
456 }
457}
458
459#[cfg(test)]
460mod tests {
461 use super::*;
462
463 use log::{Level, Record};
464
465 fn write_record(record: Record, fmt: DefaultFormat) -> String {
466 let buf = fmt.buf.buf.clone();
467
468 fmt.write(&record).expect("failed to write record");
469
470 let buf = buf.borrow();
471 String::from_utf8(buf.as_bytes().to_vec()).expect("failed to read record")
472 }
473
474 fn write_target(target: &str, fmt: DefaultFormat) -> String {
475 write_record(
476 Record::builder()
477 .args(format_args!("log\nmessage"))
478 .level(Level::Info)
479 .file(Some("test.rs"))
480 .line(Some(144))
481 .module_path(Some("test::path"))
482 .target(target)
483 .build(),
484 fmt,
485 )
486 }
487
488 fn write(fmt: DefaultFormat) -> String {
489 write_target("", fmt)
490 }
491
492 #[test]
493 fn format_with_header() {
494 let writer = writer::Builder::new()
495 .write_style(WriteStyle::Never)
496 .build();
497
498 let mut f = Formatter::new(&writer);
499
500 let written = write(DefaultFormat {
501 timestamp: None,
502 module_path: true,
503 target: false,
504 level: true,
505 written_header_value: false,
506 indent: None,
507 suffix: "\n",
508 buf: &mut f,
509 });
510
511 assert_eq!("[INFO test::path] log\nmessage\n", written);
512 }
513
514 #[test]
515 fn format_no_header() {
516 let writer = writer::Builder::new()
517 .write_style(WriteStyle::Never)
518 .build();
519
520 let mut f = Formatter::new(&writer);
521
522 let written = write(DefaultFormat {
523 timestamp: None,
524 module_path: false,
525 target: false,
526 level: false,
527 written_header_value: false,
528 indent: None,
529 suffix: "\n",
530 buf: &mut f,
531 });
532
533 assert_eq!("log\nmessage\n", written);
534 }
535
536 #[test]
537 fn format_indent_spaces() {
538 let writer = writer::Builder::new()
539 .write_style(WriteStyle::Never)
540 .build();
541
542 let mut f = Formatter::new(&writer);
543
544 let written = write(DefaultFormat {
545 timestamp: None,
546 module_path: true,
547 target: false,
548 level: true,
549 written_header_value: false,
550 indent: Some(4),
551 suffix: "\n",
552 buf: &mut f,
553 });
554
555 assert_eq!("[INFO test::path] log\n message\n", written);
556 }
557
558 #[test]
559 fn format_indent_zero_spaces() {
560 let writer = writer::Builder::new()
561 .write_style(WriteStyle::Never)
562 .build();
563
564 let mut f = Formatter::new(&writer);
565
566 let written = write(DefaultFormat {
567 timestamp: None,
568 module_path: true,
569 target: false,
570 level: true,
571 written_header_value: false,
572 indent: Some(0),
573 suffix: "\n",
574 buf: &mut f,
575 });
576
577 assert_eq!("[INFO test::path] log\nmessage\n", written);
578 }
579
580 #[test]
581 fn format_indent_spaces_no_header() {
582 let writer = writer::Builder::new()
583 .write_style(WriteStyle::Never)
584 .build();
585
586 let mut f = Formatter::new(&writer);
587
588 let written = write(DefaultFormat {
589 timestamp: None,
590 module_path: false,
591 target: false,
592 level: false,
593 written_header_value: false,
594 indent: Some(4),
595 suffix: "\n",
596 buf: &mut f,
597 });
598
599 assert_eq!("log\n message\n", written);
600 }
601
602 #[test]
603 fn format_suffix() {
604 let writer = writer::Builder::new()
605 .write_style(WriteStyle::Never)
606 .build();
607
608 let mut f = Formatter::new(&writer);
609
610 let written = write(DefaultFormat {
611 timestamp: None,
612 module_path: false,
613 target: false,
614 level: false,
615 written_header_value: false,
616 indent: None,
617 suffix: "\n\n",
618 buf: &mut f,
619 });
620
621 assert_eq!("log\nmessage\n\n", written);
622 }
623
624 #[test]
625 fn format_suffix_with_indent() {
626 let writer = writer::Builder::new()
627 .write_style(WriteStyle::Never)
628 .build();
629
630 let mut f = Formatter::new(&writer);
631
632 let written = write(DefaultFormat {
633 timestamp: None,
634 module_path: false,
635 target: false,
636 level: false,
637 written_header_value: false,
638 indent: Some(4),
639 suffix: "\n\n",
640 buf: &mut f,
641 });
642
643 assert_eq!("log\n\n message\n\n", written);
644 }
645
646 #[test]
647 fn format_target() {
648 let writer = writer::Builder::new()
649 .write_style(WriteStyle::Never)
650 .build();
651
652 let mut f = Formatter::new(&writer);
653
654 let written = write_target(
655 "target",
656 DefaultFormat {
657 timestamp: None,
658 module_path: true,
659 target: true,
660 level: true,
661 written_header_value: false,
662 indent: None,
663 suffix: "\n",
664 buf: &mut f,
665 },
666 );
667
668 assert_eq!("[INFO test::path target] log\nmessage\n", written);
669 }
670
671 #[test]
672 fn format_empty_target() {
673 let writer = writer::Builder::new()
674 .write_style(WriteStyle::Never)
675 .build();
676
677 let mut f = Formatter::new(&writer);
678
679 let written = write(DefaultFormat {
680 timestamp: None,
681 module_path: true,
682 target: true,
683 level: true,
684 written_header_value: false,
685 indent: None,
686 suffix: "\n",
687 buf: &mut f,
688 });
689
690 assert_eq!("[INFO test::path] log\nmessage\n", written);
691 }
692
693 #[test]
694 fn format_no_target() {
695 let writer = writer::Builder::new()
696 .write_style(WriteStyle::Never)
697 .build();
698
699 let mut f = Formatter::new(&writer);
700
701 let written = write_target(
702 "target",
703 DefaultFormat {
704 timestamp: None,
705 module_path: true,
706 target: false,
707 level: true,
708 written_header_value: false,
709 indent: None,
710 suffix: "\n",
711 buf: &mut f,
712 },
713 );
714
715 assert_eq!("[INFO test::path] log\nmessage\n", written);
716 }
717}