1use std::cell::RefCell;
59use std::fmt::Display;
60use std::io::prelude::Write;
61use std::rc::Rc;
62use std::{fmt, io, mem};
63
64#[cfg(feature = "color")]
65use log::Level;
66use log::Record;
67
68#[cfg(feature = "humantime")]
69mod humantime;
70#[cfg(feature = "unstable-kv")]
71mod kv;
72pub(crate) mod writer;
73
74#[cfg(feature = "color")]
75pub use anstyle as style;
76
77#[cfg(feature = "humantime")]
78pub use self::humantime::Timestamp;
79#[cfg(feature = "unstable-kv")]
80pub use self::kv::*;
81pub use self::writer::Target;
82pub use self::writer::WriteStyle;
83
84use self::writer::{Buffer, Writer};
85
86#[allow(clippy::exhaustive_enums)] #[derive(Copy, Clone, Debug)]
93pub enum TimestampPrecision {
94 Seconds,
96 Millis,
98 Micros,
100 Nanos,
102}
103
104impl Default for TimestampPrecision {
106 fn default() -> Self {
107 TimestampPrecision::Seconds
108 }
109}
110
111pub struct Formatter {
132 buf: Rc<RefCell<Buffer>>,
133 write_style: WriteStyle,
134}
135
136impl Formatter {
137 pub(crate) fn new(writer: &Writer) -> Self {
138 Formatter {
139 buf: Rc::new(RefCell::new(writer.buffer())),
140 write_style: writer.write_style(),
141 }
142 }
143
144 pub(crate) fn write_style(&self) -> WriteStyle {
145 self.write_style
146 }
147
148 pub(crate) fn print(&self, writer: &Writer) -> io::Result<()> {
149 writer.print(&self.buf.borrow())
150 }
151
152 pub(crate) fn clear(&mut self) {
153 self.buf.borrow_mut().clear();
154 }
155}
156
157#[cfg(feature = "color")]
158impl Formatter {
159 pub fn default_level_style(&self, level: Level) -> style::Style {
165 if self.write_style == WriteStyle::Never {
166 style::Style::new()
167 } else {
168 match level {
169 Level::Trace => style::AnsiColor::Cyan.on_default(),
170 Level::Debug => style::AnsiColor::Blue.on_default(),
171 Level::Info => style::AnsiColor::Green.on_default(),
172 Level::Warn => style::AnsiColor::Yellow.on_default(),
173 Level::Error => style::AnsiColor::Red
174 .on_default()
175 .effects(style::Effects::BOLD),
176 }
177 }
178 }
179}
180
181impl Write for Formatter {
182 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
183 self.buf.borrow_mut().write(buf)
184 }
185
186 fn flush(&mut self) -> io::Result<()> {
187 self.buf.borrow_mut().flush()
188 }
189}
190
191impl fmt::Debug for Formatter {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 let buf = self.buf.borrow();
194 f.debug_struct("Formatter")
195 .field("buf", &buf)
196 .field("write_style", &self.write_style)
197 .finish()
198 }
199}
200
201pub(crate) type FormatFn = Box<dyn Fn(&mut Formatter, &Record<'_>) -> io::Result<()> + Sync + Send>;
202
203pub(crate) struct Builder {
204 pub(crate) format_timestamp: Option<TimestampPrecision>,
205 pub(crate) format_module_path: bool,
206 pub(crate) format_target: bool,
207 pub(crate) format_level: bool,
208 pub(crate) format_indent: Option<usize>,
209 pub(crate) custom_format: Option<FormatFn>,
210 pub(crate) format_suffix: &'static str,
211 #[cfg(feature = "unstable-kv")]
212 pub(crate) kv_format: Option<Box<KvFormatFn>>,
213 built: bool,
214}
215
216impl Builder {
217 pub(crate) fn build(&mut self) -> FormatFn {
223 assert!(!self.built, "attempt to re-use consumed builder");
224
225 let built = mem::replace(
226 self,
227 Builder {
228 built: true,
229 ..Default::default()
230 },
231 );
232
233 if let Some(fmt) = built.custom_format {
234 fmt
235 } else {
236 Box::new(move |buf, record| {
237 let fmt = DefaultFormat {
238 timestamp: built.format_timestamp,
239 module_path: built.format_module_path,
240 target: built.format_target,
241 level: built.format_level,
242 written_header_value: false,
243 indent: built.format_indent,
244 suffix: built.format_suffix,
245 #[cfg(feature = "unstable-kv")]
246 kv_format: built.kv_format.as_deref().unwrap_or(&default_kv_format),
247 buf,
248 };
249
250 fmt.write(record)
251 })
252 }
253 }
254}
255
256impl Default for Builder {
257 fn default() -> Self {
258 Builder {
259 format_timestamp: Some(Default::default()),
260 format_module_path: false,
261 format_target: true,
262 format_level: true,
263 format_indent: Some(4),
264 custom_format: None,
265 format_suffix: "\n",
266 #[cfg(feature = "unstable-kv")]
267 kv_format: None,
268 built: false,
269 }
270 }
271}
272
273#[cfg(feature = "color")]
274type SubtleStyle = StyledValue<&'static str>;
275#[cfg(not(feature = "color"))]
276type SubtleStyle = &'static str;
277
278#[cfg(feature = "color")]
280struct StyledValue<T> {
281 style: style::Style,
282 value: T,
283}
284
285#[cfg(feature = "color")]
286impl<T: Display> Display for StyledValue<T> {
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 let style = self.style;
289
290 write!(f, "{style}")?;
293 self.value.fmt(f)?;
294 write!(f, "{style:#}")?;
295 Ok(())
296 }
297}
298
299#[cfg(not(feature = "color"))]
300type StyledValue<T> = T;
301
302struct DefaultFormat<'a> {
306 timestamp: Option<TimestampPrecision>,
307 module_path: bool,
308 target: bool,
309 level: bool,
310 written_header_value: bool,
311 indent: Option<usize>,
312 buf: &'a mut Formatter,
313 suffix: &'a str,
314 #[cfg(feature = "unstable-kv")]
315 kv_format: &'a KvFormatFn,
316}
317
318impl<'a> DefaultFormat<'a> {
319 fn write(mut self, record: &Record<'_>) -> io::Result<()> {
320 self.write_timestamp()?;
321 self.write_level(record)?;
322 self.write_module_path(record)?;
323 self.write_target(record)?;
324 self.finish_header()?;
325
326 self.write_args(record)?;
327 #[cfg(feature = "unstable-kv")]
328 self.write_kv(record)?;
329 write!(self.buf, "{}", self.suffix)
330 }
331
332 fn subtle_style(&self, text: &'static str) -> SubtleStyle {
333 #[cfg(feature = "color")]
334 {
335 StyledValue {
336 style: if self.buf.write_style == WriteStyle::Never {
337 style::Style::new()
338 } else {
339 style::AnsiColor::BrightBlack.on_default()
340 },
341 value: text,
342 }
343 }
344 #[cfg(not(feature = "color"))]
345 {
346 text
347 }
348 }
349
350 fn write_header_value<T>(&mut self, value: T) -> io::Result<()>
351 where
352 T: Display,
353 {
354 if !self.written_header_value {
355 self.written_header_value = true;
356
357 let open_brace = self.subtle_style("[");
358 write!(self.buf, "{}{}", open_brace, value)
359 } else {
360 write!(self.buf, " {}", value)
361 }
362 }
363
364 fn write_level(&mut self, record: &Record<'_>) -> io::Result<()> {
365 if !self.level {
366 return Ok(());
367 }
368
369 let level = {
370 let level = record.level();
371 #[cfg(feature = "color")]
372 {
373 StyledValue {
374 style: self.buf.default_level_style(level),
375 value: level,
376 }
377 }
378 #[cfg(not(feature = "color"))]
379 {
380 level
381 }
382 };
383
384 self.write_header_value(format_args!("{:<5}", level))
385 }
386
387 fn write_timestamp(&mut self) -> io::Result<()> {
388 #[cfg(feature = "humantime")]
389 {
390 use self::TimestampPrecision::{Micros, Millis, Nanos, Seconds};
391 let ts = match self.timestamp {
392 None => return Ok(()),
393 Some(Seconds) => self.buf.timestamp_seconds(),
394 Some(Millis) => self.buf.timestamp_millis(),
395 Some(Micros) => self.buf.timestamp_micros(),
396 Some(Nanos) => self.buf.timestamp_nanos(),
397 };
398
399 self.write_header_value(ts)
400 }
401 #[cfg(not(feature = "humantime"))]
402 {
403 let _ = self.timestamp;
406 Ok(())
407 }
408 }
409
410 fn write_module_path(&mut self, record: &Record<'_>) -> io::Result<()> {
411 if !self.module_path {
412 return Ok(());
413 }
414
415 if let Some(module_path) = record.module_path() {
416 self.write_header_value(module_path)
417 } else {
418 Ok(())
419 }
420 }
421
422 fn write_target(&mut self, record: &Record<'_>) -> io::Result<()> {
423 if !self.target {
424 return Ok(());
425 }
426
427 match record.target() {
428 "" => Ok(()),
429 target => self.write_header_value(target),
430 }
431 }
432
433 fn finish_header(&mut self) -> io::Result<()> {
434 if self.written_header_value {
435 let close_brace = self.subtle_style("]");
436 write!(self.buf, "{} ", close_brace)
437 } else {
438 Ok(())
439 }
440 }
441
442 fn write_args(&mut self, record: &Record<'_>) -> io::Result<()> {
443 match self.indent {
444 None => write!(self.buf, "{}", record.args()),
446
447 Some(indent_count) => {
448 struct IndentWrapper<'a, 'b> {
451 fmt: &'a mut DefaultFormat<'b>,
452 indent_count: usize,
453 }
454
455 impl<'a, 'b> Write for IndentWrapper<'a, 'b> {
456 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
457 let mut first = true;
458 for chunk in buf.split(|&x| x == b'\n') {
459 if !first {
460 write!(
461 self.fmt.buf,
462 "{}{:width$}",
463 self.fmt.suffix,
464 "",
465 width = self.indent_count
466 )?;
467 }
468 self.fmt.buf.write_all(chunk)?;
469 first = false;
470 }
471
472 Ok(buf.len())
473 }
474
475 fn flush(&mut self) -> io::Result<()> {
476 self.fmt.buf.flush()
477 }
478 }
479
480 {
482 let mut wrapper = IndentWrapper {
483 fmt: self,
484 indent_count,
485 };
486 write!(wrapper, "{}", record.args())?;
487 }
488
489 Ok(())
490 }
491 }
492 }
493
494 #[cfg(feature = "unstable-kv")]
495 fn write_kv(&mut self, record: &Record<'_>) -> io::Result<()> {
496 let format = self.kv_format;
497 format(self.buf, record.key_values())
498 }
499}
500
501#[cfg(test)]
502mod tests {
503 use super::*;
504
505 use log::{Level, Record};
506
507 fn write_record(record: Record<'_>, fmt: DefaultFormat<'_>) -> String {
508 let buf = fmt.buf.buf.clone();
509
510 fmt.write(&record).expect("failed to write record");
511
512 let buf = buf.borrow();
513 String::from_utf8(buf.as_bytes().to_vec()).expect("failed to read record")
514 }
515
516 fn write_target(target: &str, fmt: DefaultFormat<'_>) -> String {
517 write_record(
518 Record::builder()
519 .args(format_args!("log\nmessage"))
520 .level(Level::Info)
521 .file(Some("test.rs"))
522 .line(Some(144))
523 .module_path(Some("test::path"))
524 .target(target)
525 .build(),
526 fmt,
527 )
528 }
529
530 fn write(fmt: DefaultFormat<'_>) -> String {
531 write_target("", fmt)
532 }
533
534 fn formatter() -> Formatter {
535 let writer = writer::Builder::new()
536 .write_style(WriteStyle::Never)
537 .build();
538
539 Formatter::new(&writer)
540 }
541
542 #[test]
543 fn format_with_header() {
544 let mut f = formatter();
545
546 let written = write(DefaultFormat {
547 timestamp: None,
548 module_path: true,
549 target: false,
550 level: true,
551 #[cfg(feature = "unstable-kv")]
552 kv_format: &hidden_kv_format,
553 written_header_value: false,
554 indent: None,
555 suffix: "\n",
556 buf: &mut f,
557 });
558
559 assert_eq!("[INFO test::path] log\nmessage\n", written);
560 }
561
562 #[test]
563 fn format_no_header() {
564 let mut f = formatter();
565
566 let written = write(DefaultFormat {
567 timestamp: None,
568 module_path: false,
569 target: false,
570 level: false,
571 #[cfg(feature = "unstable-kv")]
572 kv_format: &hidden_kv_format,
573 written_header_value: false,
574 indent: None,
575 suffix: "\n",
576 buf: &mut f,
577 });
578
579 assert_eq!("log\nmessage\n", written);
580 }
581
582 #[test]
583 fn format_indent_spaces() {
584 let mut f = formatter();
585
586 let written = write(DefaultFormat {
587 timestamp: None,
588 module_path: true,
589 target: false,
590 level: true,
591 #[cfg(feature = "unstable-kv")]
592 kv_format: &hidden_kv_format,
593 written_header_value: false,
594 indent: Some(4),
595 suffix: "\n",
596 buf: &mut f,
597 });
598
599 assert_eq!("[INFO test::path] log\n message\n", written);
600 }
601
602 #[test]
603 fn format_indent_zero_spaces() {
604 let mut f = formatter();
605
606 let written = write(DefaultFormat {
607 timestamp: None,
608 module_path: true,
609 target: false,
610 level: true,
611 #[cfg(feature = "unstable-kv")]
612 kv_format: &hidden_kv_format,
613 written_header_value: false,
614 indent: Some(0),
615 suffix: "\n",
616 buf: &mut f,
617 });
618
619 assert_eq!("[INFO test::path] log\nmessage\n", written);
620 }
621
622 #[test]
623 fn format_indent_spaces_no_header() {
624 let mut f = formatter();
625
626 let written = write(DefaultFormat {
627 timestamp: None,
628 module_path: false,
629 target: false,
630 level: false,
631 #[cfg(feature = "unstable-kv")]
632 kv_format: &hidden_kv_format,
633 written_header_value: false,
634 indent: Some(4),
635 suffix: "\n",
636 buf: &mut f,
637 });
638
639 assert_eq!("log\n message\n", written);
640 }
641
642 #[test]
643 fn format_suffix() {
644 let mut f = formatter();
645
646 let written = write(DefaultFormat {
647 timestamp: None,
648 module_path: false,
649 target: false,
650 level: false,
651 #[cfg(feature = "unstable-kv")]
652 kv_format: &hidden_kv_format,
653 written_header_value: false,
654 indent: None,
655 suffix: "\n\n",
656 buf: &mut f,
657 });
658
659 assert_eq!("log\nmessage\n\n", written);
660 }
661
662 #[test]
663 fn format_suffix_with_indent() {
664 let mut f = formatter();
665
666 let written = write(DefaultFormat {
667 timestamp: None,
668 module_path: false,
669 target: false,
670 level: false,
671 #[cfg(feature = "unstable-kv")]
672 kv_format: &hidden_kv_format,
673 written_header_value: false,
674 indent: Some(4),
675 suffix: "\n\n",
676 buf: &mut f,
677 });
678
679 assert_eq!("log\n\n message\n\n", written);
680 }
681
682 #[test]
683 fn format_target() {
684 let mut f = formatter();
685
686 let written = write_target(
687 "target",
688 DefaultFormat {
689 timestamp: None,
690 module_path: true,
691 target: true,
692 level: true,
693 #[cfg(feature = "unstable-kv")]
694 kv_format: &hidden_kv_format,
695 written_header_value: false,
696 indent: None,
697 suffix: "\n",
698 buf: &mut f,
699 },
700 );
701
702 assert_eq!("[INFO test::path target] log\nmessage\n", written);
703 }
704
705 #[test]
706 fn format_empty_target() {
707 let mut f = formatter();
708
709 let written = write(DefaultFormat {
710 timestamp: None,
711 module_path: true,
712 target: true,
713 level: true,
714 #[cfg(feature = "unstable-kv")]
715 kv_format: &hidden_kv_format,
716 written_header_value: false,
717 indent: None,
718 suffix: "\n",
719 buf: &mut f,
720 });
721
722 assert_eq!("[INFO test::path] log\nmessage\n", written);
723 }
724
725 #[test]
726 fn format_no_target() {
727 let mut f = formatter();
728
729 let written = write_target(
730 "target",
731 DefaultFormat {
732 timestamp: None,
733 module_path: true,
734 target: false,
735 level: true,
736 #[cfg(feature = "unstable-kv")]
737 kv_format: &hidden_kv_format,
738 written_header_value: false,
739 indent: None,
740 suffix: "\n",
741 buf: &mut f,
742 },
743 );
744
745 assert_eq!("[INFO test::path] log\nmessage\n", written);
746 }
747
748 #[cfg(feature = "unstable-kv")]
749 #[test]
750 fn format_kv_default() {
751 let kvs = &[("a", 1u32), ("b", 2u32)][..];
752 let mut f = formatter();
753 let record = Record::builder()
754 .args(format_args!("log message"))
755 .level(Level::Info)
756 .module_path(Some("test::path"))
757 .key_values(&kvs)
758 .build();
759
760 let written = write_record(
761 record,
762 DefaultFormat {
763 timestamp: None,
764 module_path: false,
765 target: false,
766 level: true,
767 kv_format: &default_kv_format,
768 written_header_value: false,
769 indent: None,
770 suffix: "\n",
771 buf: &mut f,
772 },
773 );
774
775 assert_eq!("[INFO ] log message a=1 b=2\n", written);
776 }
777
778 #[cfg(feature = "unstable-kv")]
779 #[test]
780 fn format_kv_default_full() {
781 let kvs = &[("a", 1u32), ("b", 2u32)][..];
782 let mut f = formatter();
783 let record = Record::builder()
784 .args(format_args!("log\nmessage"))
785 .level(Level::Info)
786 .module_path(Some("test::path"))
787 .target("target")
788 .file(Some("test.rs"))
789 .line(Some(42))
790 .key_values(&kvs)
791 .build();
792
793 let written = write_record(
794 record,
795 DefaultFormat {
796 timestamp: None,
797 module_path: true,
798 target: true,
799 level: true,
800 kv_format: &default_kv_format,
801 written_header_value: false,
802 indent: None,
803 suffix: "\n",
804 buf: &mut f,
805 },
806 );
807
808 assert_eq!("[INFO test::path target] log\nmessage a=1 b=2\n", written);
809 }
810}