1#![warn(missing_docs)]
87
88use slog::Drain;
89use slog::Key;
90use slog::*;
91use std::cell::RefCell;
92use std::io::Write as IoWrite;
93use std::panic::{RefUnwindSafe, UnwindSafe};
94use std::result;
95use std::{fmt, io, mem, sync};
96
97use is_terminal::IsTerminal;
102pub trait Decorator {
110 fn with_record<F>(
115 &self,
116 _record: &Record,
117 _logger_values: &OwnedKVList,
118 f: F,
119 ) -> io::Result<()>
120 where
121 F: FnOnce(&mut dyn RecordDecorator) -> io::Result<()>;
122}
123
124impl<T: ?Sized> Decorator for Box<T>
125where
126 T: Decorator,
127{
128 fn with_record<F>(
129 &self,
130 record: &Record,
131 logger_kv: &OwnedKVList,
132 f: F,
133 ) -> io::Result<()>
134 where
135 F: FnOnce(&mut dyn RecordDecorator) -> io::Result<()>,
136 {
137 (**self).with_record(record, logger_kv, f)
138 }
139}
140
141pub trait RecordDecorator: io::Write {
143 fn reset(&mut self) -> io::Result<()>;
145
146 fn start_whitespace(&mut self) -> io::Result<()> {
148 self.reset()
149 }
150
151 fn start_msg(&mut self) -> io::Result<()> {
153 self.reset()
154 }
155
156 fn start_timestamp(&mut self) -> io::Result<()> {
158 self.reset()
159 }
160
161 fn start_level(&mut self) -> io::Result<()> {
163 self.reset()
164 }
165
166 fn start_comma(&mut self) -> io::Result<()> {
168 self.reset()
169 }
170
171 fn start_key(&mut self) -> io::Result<()> {
173 self.reset()
174 }
175
176 fn start_value(&mut self) -> io::Result<()> {
178 self.reset()
179 }
180
181 fn start_location(&mut self) -> io::Result<()> {
183 self.reset()
184 }
185
186 fn start_separator(&mut self) -> io::Result<()> {
188 self.reset()
189 }
190}
191
192impl RecordDecorator for Box<dyn RecordDecorator> {
193 fn reset(&mut self) -> io::Result<()> {
194 (**self).reset()
195 }
196 fn start_whitespace(&mut self) -> io::Result<()> {
197 (**self).start_whitespace()
198 }
199
200 fn start_msg(&mut self) -> io::Result<()> {
202 (**self).start_msg()
203 }
204
205 fn start_timestamp(&mut self) -> io::Result<()> {
207 (**self).start_timestamp()
208 }
209
210 fn start_level(&mut self) -> io::Result<()> {
212 (**self).start_level()
213 }
214
215 fn start_comma(&mut self) -> io::Result<()> {
217 (**self).start_comma()
218 }
219
220 fn start_key(&mut self) -> io::Result<()> {
222 (**self).start_key()
223 }
224
225 fn start_value(&mut self) -> io::Result<()> {
227 (**self).start_value()
228 }
229
230 fn start_location(&mut self) -> io::Result<()> {
232 (**self).start_location()
233 }
234
235 fn start_separator(&mut self) -> io::Result<()> {
237 (**self).start_separator()
238 }
239}
240pub fn print_msg_header(
245 fn_timestamp: &dyn ThreadSafeTimestampFn<Output = io::Result<()>>,
246 mut rd: &mut dyn RecordDecorator,
247 record: &Record,
248 use_file_location: bool,
249) -> io::Result<bool> {
250 rd.start_timestamp()?;
251 fn_timestamp(&mut rd)?;
252
253 rd.start_whitespace()?;
254 write!(rd, " ")?;
255
256 rd.start_level()?;
257 write!(rd, "{}", record.level().as_short_str())?;
258
259 if use_file_location {
260 rd.start_location()?;
261 write!(
262 rd,
263 "[{}:{}:{}]",
264 record.location().file,
265 record.location().line,
266 record.location().column
267 )?;
268 }
269
270 rd.start_whitespace()?;
271 write!(rd, " ")?;
272
273 rd.start_msg()?;
274 let mut count_rd = CountingWriter::new(&mut rd);
275 write!(count_rd, "{}", record.msg())?;
276 Ok(count_rd.count() != 0)
277}
278
279pub trait ThreadSafeHeaderFn:
288 Fn(
289 &dyn ThreadSafeTimestampFn<Output = io::Result<()>>,
290 &mut dyn RecordDecorator,
291 &Record,
292 bool,
293 ) -> io::Result<bool>
294 + Send
295 + Sync
296 + UnwindSafe
297 + RefUnwindSafe
298 + 'static
299{
300}
301
302impl<F> ThreadSafeHeaderFn for F
303where
304 F: Fn(
305 &dyn ThreadSafeTimestampFn<Output = io::Result<()>>,
306 &mut dyn RecordDecorator,
307 &Record,
308 bool,
309 ) -> io::Result<bool>
310 + Send
311 + Sync,
312 F: UnwindSafe + RefUnwindSafe + 'static,
313 F: ?Sized,
314{
315}
316
317pub struct FullFormat<D>
326where
327 D: Decorator,
328{
329 decorator: D,
330 fn_timestamp: Box<dyn ThreadSafeTimestampFn<Output = io::Result<()>>>,
331 use_original_order: bool,
332 use_file_location: bool,
333 header_printer: Box<dyn ThreadSafeHeaderFn>,
334}
335
336pub struct FullFormatBuilder<D>
338where
339 D: Decorator,
340{
341 decorator: D,
342 fn_timestamp: Box<dyn ThreadSafeTimestampFn<Output = io::Result<()>>>,
343 original_order: bool,
344 file_location: bool,
345 header_printer: Box<dyn ThreadSafeHeaderFn>,
346}
347
348impl<D> FullFormatBuilder<D>
349where
350 D: Decorator,
351{
352 pub fn use_utc_timestamp(mut self) -> Self {
354 self.fn_timestamp = Box::new(timestamp_utc);
355 self
356 }
357
358 pub fn use_local_timestamp(mut self) -> Self {
360 self.fn_timestamp = Box::new(timestamp_local);
361 self
362 }
363
364 pub fn use_custom_timestamp<F>(mut self, f: F) -> Self
366 where
367 F: ThreadSafeTimestampFn,
368 {
369 self.fn_timestamp = Box::new(f);
370 self
371 }
372
373 pub fn use_file_location(mut self) -> Self {
375 self.file_location = true;
376 self
377 }
378
379 pub fn use_original_order(mut self) -> Self {
384 self.original_order = true;
385 self
386 }
387
388 pub fn use_custom_header_print<F>(mut self, f: F) -> Self
440 where
441 F: ThreadSafeHeaderFn,
442 {
443 self.header_printer = Box::new(f);
444 self
445 }
446
447 pub fn build(self) -> FullFormat<D> {
449 FullFormat {
450 decorator: self.decorator,
451 fn_timestamp: self.fn_timestamp,
452 use_original_order: self.original_order,
453 use_file_location: self.file_location,
454 header_printer: self.header_printer,
455 }
456 }
457}
458
459impl<D> Drain for FullFormat<D>
460where
461 D: Decorator,
462{
463 type Ok = ();
464 type Err = io::Error;
465
466 fn log(
467 &self,
468 record: &Record,
469 values: &OwnedKVList,
470 ) -> result::Result<Self::Ok, Self::Err> {
471 self.format_full(record, values)
472 }
473}
474
475impl<D> FullFormat<D>
476where
477 D: Decorator,
478{
479 #[allow(clippy::new_ret_no_self)]
481 pub fn new(d: D) -> FullFormatBuilder<D> {
482 FullFormatBuilder {
483 fn_timestamp: Box::new(timestamp_local),
484 decorator: d,
485 original_order: false,
486 file_location: false,
487 header_printer: Box::new(print_msg_header),
488 }
489 }
490
491 fn format_full(
492 &self,
493 record: &Record,
494 values: &OwnedKVList,
495 ) -> io::Result<()> {
496 self.decorator.with_record(record, values, |decorator| {
497 let header_printer = &self.header_printer;
498 let comma_needed = header_printer(
499 &*self.fn_timestamp,
500 decorator,
501 record,
502 self.use_file_location,
503 )?;
504
505 {
506 let mut serializer = Serializer::new(
507 decorator,
508 comma_needed,
509 self.use_original_order,
510 );
511
512 record.kv().serialize(record, &mut serializer)?;
513
514 values.serialize(record, &mut serializer)?;
515
516 serializer.finish()?;
517 }
518
519 decorator.start_whitespace()?;
520 writeln!(decorator)?;
521
522 decorator.flush()?;
523
524 Ok(())
525 })
526 }
527}
528pub struct CompactFormat<D>
539where
540 D: Decorator,
541{
542 decorator: D,
543 history: RefCell<Vec<(Vec<u8>, Vec<u8>)>>,
544 fn_timestamp: Box<dyn ThreadSafeTimestampFn<Output = io::Result<()>>>,
545 header_printer: Box<dyn ThreadSafeHeaderFn>,
546}
547
548pub struct CompactFormatBuilder<D>
550where
551 D: Decorator,
552{
553 decorator: D,
554 fn_timestamp: Box<dyn ThreadSafeTimestampFn<Output = io::Result<()>>>,
555 header_printer: Box<dyn ThreadSafeHeaderFn>,
556}
557
558impl<D> CompactFormatBuilder<D>
559where
560 D: Decorator,
561{
562 pub fn use_utc_timestamp(mut self) -> Self {
564 self.fn_timestamp = Box::new(timestamp_utc);
565 self
566 }
567
568 pub fn use_local_timestamp(mut self) -> Self {
570 self.fn_timestamp = Box::new(timestamp_local);
571 self
572 }
573
574 pub fn use_custom_timestamp<F>(mut self, f: F) -> Self
576 where
577 F: ThreadSafeTimestampFn,
578 {
579 self.fn_timestamp = Box::new(f);
580 self
581 }
582
583 pub fn use_custom_header_print<F>(mut self, f: F) -> Self
587 where
588 F: ThreadSafeHeaderFn,
589 {
590 self.header_printer = Box::new(f);
591 self
592 }
593
594 pub fn build(self) -> CompactFormat<D> {
596 CompactFormat {
597 decorator: self.decorator,
598 fn_timestamp: self.fn_timestamp,
599 history: RefCell::new(vec![]),
600 header_printer: self.header_printer,
601 }
602 }
603}
604
605impl<D> Drain for CompactFormat<D>
606where
607 D: Decorator,
608{
609 type Ok = ();
610 type Err = io::Error;
611
612 fn log(
613 &self,
614 record: &Record,
615 values: &OwnedKVList,
616 ) -> result::Result<Self::Ok, Self::Err> {
617 self.format_compact(record, values)
618 }
619}
620
621impl<D> CompactFormat<D>
622where
623 D: Decorator,
624{
625 #[allow(clippy::new_ret_no_self)]
627 pub fn new(d: D) -> CompactFormatBuilder<D> {
628 CompactFormatBuilder {
629 fn_timestamp: Box::new(timestamp_local),
630 decorator: d,
631 header_printer: Box::new(print_msg_header),
632 }
633 }
634
635 fn format_compact(
636 &self,
637 record: &Record,
638 values: &OwnedKVList,
639 ) -> io::Result<()> {
640 self.decorator.with_record(record, values, |decorator| {
641 let indent = {
642 let mut history_ref = self.history.borrow_mut();
643 let mut serializer =
644 CompactFormatSerializer::new(decorator, &mut *history_ref);
645
646 values.serialize(record, &mut serializer)?;
647
648 serializer.finish()?
649 };
650
651 decorator.start_whitespace()?;
652
653 for _ in 0..indent {
654 write!(decorator, " ")?;
655 }
656
657 let header_printer = &self.header_printer;
658 let comma_needed =
659 header_printer(&*self.fn_timestamp, decorator, record, false)?;
660
661 {
662 let mut serializer =
663 Serializer::new(decorator, comma_needed, false);
664
665 record.kv().serialize(record, &mut serializer)?;
666
667 serializer.finish()?;
668 }
669
670 decorator.start_whitespace()?;
671 writeln!(decorator)?;
672
673 decorator.flush()?;
674
675 Ok(())
676 })
677 }
678}
679pub struct Serializer<'a> {
684 comma_needed: bool,
685 decorator: &'a mut dyn RecordDecorator,
686 reverse: bool,
687 stack: Vec<(String, String)>,
688}
689
690impl<'a> Serializer<'a> {
691 pub fn new(
693 d: &'a mut dyn RecordDecorator,
694 comma_needed: bool,
695 reverse: bool,
696 ) -> Self {
697 Serializer {
698 comma_needed,
699 decorator: d,
700 reverse,
701 stack: vec![],
702 }
703 }
704
705 fn maybe_print_comma(&mut self) -> io::Result<()> {
706 if self.comma_needed {
707 self.decorator.start_comma()?;
708 write!(self.decorator, ", ")?;
709 }
710 self.comma_needed |= true;
711 Ok(())
712 }
713
714 pub fn finish(mut self) -> io::Result<()> {
716 loop {
717 if let Some((k, v)) = self.stack.pop() {
718 self.maybe_print_comma()?;
719 self.decorator.start_key()?;
720 write!(self.decorator, "{}", k)?;
721 write!(self.decorator, ":")?;
722 self.decorator.start_whitespace()?;
723 write!(self.decorator, " ")?;
724 self.decorator.start_value()?;
725 write!(self.decorator, "{}", v)?;
726 } else {
727 return Ok(());
728 }
729 }
730 }
731}
732
733impl<'a> Drop for Serializer<'a> {
734 fn drop(&mut self) {
735 if !self.stack.is_empty() {
736 panic!("stack not empty");
737 }
738 }
739}
740
741macro_rules! s(
742 ($s:expr, $k:expr, $v:expr) => {
743
744 if $s.reverse {
745 $s.stack.push(($k.into(), format!("{}", $v)));
746 } else {
747 $s.maybe_print_comma()?;
748 $s.decorator.start_key()?;
749 write!($s.decorator, "{}", $k)?;
750 $s.decorator.start_separator()?;
751 write!($s.decorator, ":")?;
752 $s.decorator.start_whitespace()?;
753 write!($s.decorator, " ")?;
754 $s.decorator.start_value()?;
755 write!($s.decorator, "{}", $v)?;
756 }
757 };
758);
759
760impl<'a> slog::ser::Serializer for Serializer<'a> {
761 fn emit_none(&mut self, key: Key) -> slog::Result {
762 s!(self, key, "None");
763 Ok(())
764 }
765 fn emit_unit(&mut self, key: Key) -> slog::Result {
766 s!(self, key, "()");
767 Ok(())
768 }
769
770 fn emit_bool(&mut self, key: Key, val: bool) -> slog::Result {
771 s!(self, key, val);
772 Ok(())
773 }
774
775 fn emit_char(&mut self, key: Key, val: char) -> slog::Result {
776 s!(self, key, val);
777 Ok(())
778 }
779
780 fn emit_usize(&mut self, key: Key, val: usize) -> slog::Result {
781 s!(self, key, val);
782 Ok(())
783 }
784 fn emit_isize(&mut self, key: Key, val: isize) -> slog::Result {
785 s!(self, key, val);
786 Ok(())
787 }
788
789 fn emit_u8(&mut self, key: Key, val: u8) -> slog::Result {
790 s!(self, key, val);
791 Ok(())
792 }
793 fn emit_i8(&mut self, key: Key, val: i8) -> slog::Result {
794 s!(self, key, val);
795 Ok(())
796 }
797 fn emit_u16(&mut self, key: Key, val: u16) -> slog::Result {
798 s!(self, key, val);
799 Ok(())
800 }
801 fn emit_i16(&mut self, key: Key, val: i16) -> slog::Result {
802 s!(self, key, val);
803 Ok(())
804 }
805 fn emit_u32(&mut self, key: Key, val: u32) -> slog::Result {
806 s!(self, key, val);
807 Ok(())
808 }
809 fn emit_i32(&mut self, key: Key, val: i32) -> slog::Result {
810 s!(self, key, val);
811 Ok(())
812 }
813 fn emit_f32(&mut self, key: Key, val: f32) -> slog::Result {
814 s!(self, key, val);
815 Ok(())
816 }
817 fn emit_u64(&mut self, key: Key, val: u64) -> slog::Result {
818 s!(self, key, val);
819 Ok(())
820 }
821 fn emit_i64(&mut self, key: Key, val: i64) -> slog::Result {
822 s!(self, key, val);
823 Ok(())
824 }
825 fn emit_f64(&mut self, key: Key, val: f64) -> slog::Result {
826 s!(self, key, val);
827 Ok(())
828 }
829 fn emit_str(&mut self, key: Key, val: &str) -> slog::Result {
830 s!(self, key, val);
831 Ok(())
832 }
833 fn emit_arguments(
834 &mut self,
835 key: Key,
836 val: &fmt::Arguments,
837 ) -> slog::Result {
838 s!(self, key, val);
839 Ok(())
840 }
841 #[cfg(feature = "nested-values")]
842 fn emit_serde(
843 &mut self,
844 key: Key,
845 val: &dyn slog::SerdeValue,
846 ) -> slog::Result {
847 let mut writer = Vec::new();
848 serde::ser::Serialize::serialize(
849 val.as_serde(),
850 &mut serde_json::Serializer::new(&mut writer),
851 )
852 .map_err(std::io::Error::from)?;
853 let val =
854 std::str::from_utf8(&writer).expect("serde JSON is always UTF-8");
855 s!(self, key, val);
856 Ok(())
857 }
858}
859pub struct CompactFormatSerializer<'a> {
864 decorator: &'a mut dyn RecordDecorator,
865 history: &'a mut Vec<(Vec<u8>, Vec<u8>)>,
866 buf: Vec<(Vec<u8>, Vec<u8>)>,
867}
868
869impl<'a> CompactFormatSerializer<'a> {
870 pub fn new(
872 d: &'a mut dyn RecordDecorator,
873 history: &'a mut Vec<(Vec<u8>, Vec<u8>)>,
874 ) -> Self {
875 CompactFormatSerializer {
876 decorator: d,
877 history,
878 buf: vec![],
879 }
880 }
881
882 pub fn finish(&mut self) -> io::Result<usize> {
884 let mut indent = 0;
885
886 for mut buf in self.buf.drain(..).rev() {
887 let (print, trunc, push) =
888 if let Some(prev) = self.history.get_mut(indent) {
889 if *prev != buf {
890 *prev = mem::take(&mut buf);
891 (true, true, false)
892 } else {
893 (false, false, false)
894 }
895 } else {
896 (true, false, true)
897 };
898
899 if push {
900 self.history.push(mem::take(&mut buf));
901 }
902
903 if trunc {
904 self.history.truncate(indent + 1);
905 }
906
907 if print {
908 let &(ref k, ref v) =
909 self.history.get(indent).expect("assertion failed");
910 self.decorator.start_whitespace()?;
911 for _ in 0..indent {
912 write!(self.decorator, " ")?;
913 }
914 self.decorator.start_key()?;
915 self.decorator.write_all(k)?;
916 self.decorator.start_separator()?;
917 write!(self.decorator, ":")?;
918 self.decorator.start_whitespace()?;
919 write!(self.decorator, " ")?;
920 self.decorator.start_value()?;
921 self.decorator.write_all(v)?;
922
923 self.decorator.start_whitespace()?;
924 writeln!(self.decorator)?;
925 }
926
927 indent += 1;
928 }
929
930 Ok(indent)
931 }
932}
933
934macro_rules! cs(
935 ($s:expr, $k:expr, $v:expr) => {
936
937 let mut k = vec!();
938 let mut v = vec!();
939 write!(&mut k, "{}", $k)?;
940 write!(&mut v, "{}", $v)?;
941 $s.buf.push((k, v));
942 };
943);
944
945impl<'a> slog::ser::Serializer for CompactFormatSerializer<'a> {
946 fn emit_none(&mut self, key: Key) -> slog::Result {
947 cs!(self, key, "None");
948 Ok(())
949 }
950 fn emit_unit(&mut self, key: Key) -> slog::Result {
951 cs!(self, key, "()");
952 Ok(())
953 }
954
955 fn emit_bool(&mut self, key: Key, val: bool) -> slog::Result {
956 cs!(self, key, val);
957 Ok(())
958 }
959
960 fn emit_char(&mut self, key: Key, val: char) -> slog::Result {
961 cs!(self, key, val);
962 Ok(())
963 }
964
965 fn emit_usize(&mut self, key: Key, val: usize) -> slog::Result {
966 cs!(self, key, val);
967 Ok(())
968 }
969 fn emit_isize(&mut self, key: Key, val: isize) -> slog::Result {
970 cs!(self, key, val);
971 Ok(())
972 }
973
974 fn emit_u8(&mut self, key: Key, val: u8) -> slog::Result {
975 cs!(self, key, val);
976 Ok(())
977 }
978 fn emit_i8(&mut self, key: Key, val: i8) -> slog::Result {
979 cs!(self, key, val);
980 Ok(())
981 }
982 fn emit_u16(&mut self, key: Key, val: u16) -> slog::Result {
983 cs!(self, key, val);
984 Ok(())
985 }
986 fn emit_i16(&mut self, key: Key, val: i16) -> slog::Result {
987 cs!(self, key, val);
988 Ok(())
989 }
990 fn emit_u32(&mut self, key: Key, val: u32) -> slog::Result {
991 cs!(self, key, val);
992 Ok(())
993 }
994 fn emit_i32(&mut self, key: Key, val: i32) -> slog::Result {
995 cs!(self, key, val);
996 Ok(())
997 }
998 fn emit_f32(&mut self, key: Key, val: f32) -> slog::Result {
999 cs!(self, key, val);
1000 Ok(())
1001 }
1002 fn emit_u64(&mut self, key: Key, val: u64) -> slog::Result {
1003 cs!(self, key, val);
1004 Ok(())
1005 }
1006 fn emit_i64(&mut self, key: Key, val: i64) -> slog::Result {
1007 cs!(self, key, val);
1008 Ok(())
1009 }
1010 fn emit_f64(&mut self, key: Key, val: f64) -> slog::Result {
1011 cs!(self, key, val);
1012 Ok(())
1013 }
1014 fn emit_str(&mut self, key: Key, val: &str) -> slog::Result {
1015 cs!(self, key, val);
1016 Ok(())
1017 }
1018 fn emit_arguments(
1019 &mut self,
1020 key: Key,
1021 val: &fmt::Arguments,
1022 ) -> slog::Result {
1023 cs!(self, key, val);
1024 Ok(())
1025 }
1026}
1027pub struct CountingWriter<'a> {
1032 wrapped: &'a mut dyn io::Write,
1033 count: usize,
1034}
1035
1036impl<'a> CountingWriter<'a> {
1037 pub fn new(wrapped: &'a mut dyn io::Write) -> CountingWriter {
1039 CountingWriter { wrapped, count: 0 }
1040 }
1041
1042 pub fn count(&self) -> usize {
1044 self.count
1045 }
1046}
1047
1048impl<'a> io::Write for CountingWriter<'a> {
1049 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1050 self.wrapped.write(buf).map(|n| {
1051 self.count += n;
1052 n
1053 })
1054 }
1055
1056 fn flush(&mut self) -> io::Result<()> {
1057 self.wrapped.flush()
1058 }
1059
1060 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1061 self.wrapped.write_all(buf).map(|_| {
1062 self.count += buf.len();
1063 })
1064 }
1065}
1066pub trait ThreadSafeTimestampFn:
1075 Fn(&mut dyn io::Write) -> io::Result<()>
1076 + Send
1077 + Sync
1078 + UnwindSafe
1079 + RefUnwindSafe
1080 + 'static
1081{
1082}
1083
1084impl<F> ThreadSafeTimestampFn for F
1085where
1086 F: Fn(&mut dyn io::Write) -> io::Result<()> + Send + Sync,
1087 F: UnwindSafe + RefUnwindSafe + 'static,
1088 F: ?Sized,
1089{
1090}
1091
1092const TIMESTAMP_FORMAT: &[time::format_description::FormatItem] = time::macros::format_description!("[month repr:short] [day] [hour repr:24]:[minute]:[second].[subsecond digits:3]");
1093
1094pub fn timestamp_local(io: &mut dyn io::Write) -> io::Result<()> {
1098 let now: time::OffsetDateTime = std::time::SystemTime::now().into();
1099 write!(
1100 io,
1101 "{}",
1102 now.format(TIMESTAMP_FORMAT)
1103 .map_err(convert_time_fmt_error)?
1104 )
1105}
1106
1107pub fn timestamp_utc(io: &mut dyn io::Write) -> io::Result<()> {
1111 let now = time::OffsetDateTime::now_utc();
1112 write!(
1113 io,
1114 "{}",
1115 now.format(TIMESTAMP_FORMAT)
1116 .map_err(convert_time_fmt_error)?
1117 )
1118}
1119fn convert_time_fmt_error(cause: time::error::Format) -> io::Error {
1120 io::Error::new(io::ErrorKind::Other, cause)
1121}
1122
1123pub struct PlainDecorator<W>(RefCell<W>)
1147where
1148 W: io::Write;
1149
1150impl<W> PlainDecorator<W>
1151where
1152 W: io::Write,
1153{
1154 pub fn new(io: W) -> Self {
1156 PlainDecorator(RefCell::new(io))
1157 }
1158}
1159
1160impl<W> Decorator for PlainDecorator<W>
1161where
1162 W: io::Write,
1163{
1164 fn with_record<F>(
1165 &self,
1166 _record: &Record,
1167 _logger_values: &OwnedKVList,
1168 f: F,
1169 ) -> io::Result<()>
1170 where
1171 F: FnOnce(&mut dyn RecordDecorator) -> io::Result<()>,
1172 {
1173 f(&mut PlainRecordDecorator(&self.0))
1174 }
1175}
1176
1177pub struct PlainRecordDecorator<'a, W: 'a>(&'a RefCell<W>)
1179where
1180 W: io::Write;
1181
1182impl<'a, W> io::Write for PlainRecordDecorator<'a, W>
1183where
1184 W: io::Write,
1185{
1186 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1187 self.0.borrow_mut().write(buf)
1188 }
1189
1190 fn flush(&mut self) -> io::Result<()> {
1191 self.0.borrow_mut().flush()
1192 }
1193}
1194
1195impl<'a, W> Drop for PlainRecordDecorator<'a, W>
1196where
1197 W: io::Write,
1198{
1199 fn drop(&mut self) {
1200 let _ = self.flush();
1201 }
1202}
1203
1204impl<'a, W> RecordDecorator for PlainRecordDecorator<'a, W>
1205where
1206 W: io::Write,
1207{
1208 fn reset(&mut self) -> io::Result<()> {
1209 Ok(())
1210 }
1211}
1212
1213pub struct PlainSyncDecorator<W>(sync::Arc<sync::Mutex<W>>)
1230where
1231 W: io::Write;
1232
1233impl<W> PlainSyncDecorator<W>
1234where
1235 W: io::Write,
1236{
1237 pub fn new(io: W) -> Self {
1239 PlainSyncDecorator(sync::Arc::new(sync::Mutex::new(io)))
1240 }
1241}
1242
1243impl<W> Decorator for PlainSyncDecorator<W>
1244where
1245 W: io::Write,
1246{
1247 fn with_record<F>(
1248 &self,
1249 _record: &Record,
1250 _logger_values: &OwnedKVList,
1251 f: F,
1252 ) -> io::Result<()>
1253 where
1254 F: FnOnce(&mut dyn RecordDecorator) -> io::Result<()>,
1255 {
1256 f(&mut PlainSyncRecordDecorator {
1257 io: self.0.clone(),
1258 buf: vec![],
1259 })
1260 }
1261}
1262
1263pub struct PlainSyncRecordDecorator<W>
1265where
1266 W: io::Write,
1267{
1268 io: sync::Arc<sync::Mutex<W>>,
1269 buf: Vec<u8>,
1270}
1271
1272impl<W> io::Write for PlainSyncRecordDecorator<W>
1273where
1274 W: io::Write,
1275{
1276 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1277 self.buf.write(buf)
1278 }
1279
1280 fn flush(&mut self) -> io::Result<()> {
1281 if self.buf.is_empty() {
1282 return Ok(());
1283 }
1284
1285 let mut io = self.io.lock().map_err(|_| {
1286 io::Error::new(io::ErrorKind::Other, "mutex locking error")
1287 })?;
1288
1289 io.write_all(&self.buf)?;
1290 self.buf.clear();
1291 io.flush()
1292 }
1293}
1294
1295impl<W> Drop for PlainSyncRecordDecorator<W>
1296where
1297 W: io::Write,
1298{
1299 fn drop(&mut self) {
1300 let _ = self.flush();
1301 }
1302}
1303
1304impl<W> RecordDecorator for PlainSyncRecordDecorator<W>
1305where
1306 W: io::Write,
1307{
1308 fn reset(&mut self) -> io::Result<()> {
1309 Ok(())
1310 }
1311}
1312
1313enum AnyTerminal {
1320 Stdout {
1322 term: Box<term::StdoutTerminal>,
1323 supports_reset: bool,
1324 supports_color: bool,
1325 supports_bold: bool,
1326 },
1327 Stderr {
1329 term: Box<term::StderrTerminal>,
1330 supports_reset: bool,
1331 supports_color: bool,
1332 supports_bold: bool,
1333 },
1334 FallbackStdout,
1335 FallbackStderr,
1336}
1337
1338impl AnyTerminal {
1339 fn should_use_color(&self) -> bool {
1340 match *self {
1341 AnyTerminal::Stdout { .. } => std::io::stdout().is_terminal(),
1342 AnyTerminal::Stderr { .. } => std::io::stderr().is_terminal(),
1343 AnyTerminal::FallbackStdout => false,
1344 AnyTerminal::FallbackStderr => false,
1345 }
1346 }
1347}
1348
1349pub struct TermDecoratorBuilder {
1351 use_stderr: bool,
1352 color: Option<bool>,
1353}
1354
1355impl TermDecoratorBuilder {
1356 fn new() -> Self {
1357 TermDecoratorBuilder {
1358 use_stderr: true,
1359 color: None,
1360 }
1361 }
1362
1363 pub fn stderr(mut self) -> Self {
1365 self.use_stderr = true;
1366 self
1367 }
1368
1369 pub fn stdout(mut self) -> Self {
1371 self.use_stderr = false;
1372 self
1373 }
1374
1375 pub fn force_color(mut self) -> Self {
1377 self.color = Some(true);
1378 self
1379 }
1380
1381 pub fn force_plain(mut self) -> Self {
1383 self.color = Some(false);
1384 self
1385 }
1386
1387 pub fn try_build(self) -> Option<TermDecorator> {
1393 let io = if self.use_stderr {
1394 term::stderr().map(|t| {
1395 let supports_reset = t.supports_reset();
1396 let supports_color = t.supports_color();
1397 let supports_bold = t.supports_attr(term::Attr::Bold);
1398 AnyTerminal::Stderr {
1399 term: t,
1400 supports_reset,
1401 supports_color,
1402 supports_bold,
1403 }
1404 })
1405 } else {
1406 term::stdout().map(|t| {
1407 let supports_reset = t.supports_reset();
1408 let supports_color = t.supports_color();
1409 let supports_bold = t.supports_attr(term::Attr::Bold);
1410 AnyTerminal::Stdout {
1411 term: t,
1412 supports_reset,
1413 supports_color,
1414 supports_bold,
1415 }
1416 })
1417 };
1418
1419 io.map(|io| {
1420 let use_color = self.color.unwrap_or_else(|| io.should_use_color());
1421 TermDecorator {
1422 use_color,
1423 term: RefCell::new(io),
1424 }
1425 })
1426 }
1427
1428 pub fn build(self) -> TermDecorator {
1433 let io = if self.use_stderr {
1434 term::stderr()
1435 .map(|t| {
1436 let supports_reset = t.supports_reset();
1437 let supports_color = t.supports_color();
1438 let supports_bold = t.supports_attr(term::Attr::Bold);
1439 AnyTerminal::Stderr {
1440 term: t,
1441 supports_reset,
1442 supports_color,
1443 supports_bold,
1444 }
1445 })
1446 .unwrap_or(AnyTerminal::FallbackStderr)
1447 } else {
1448 term::stdout()
1449 .map(|t| {
1450 let supports_reset = t.supports_reset();
1451 let supports_color = t.supports_color();
1452 let supports_bold = t.supports_attr(term::Attr::Bold);
1453 AnyTerminal::Stdout {
1454 term: t,
1455 supports_reset,
1456 supports_color,
1457 supports_bold,
1458 }
1459 })
1460 .unwrap_or(AnyTerminal::FallbackStdout)
1461 };
1462
1463 let use_color = self.color.unwrap_or_else(|| io.should_use_color());
1464 TermDecorator {
1465 term: RefCell::new(io),
1466 use_color,
1467 }
1468 }
1469}
1470
1471pub struct TermDecorator {
1479 term: RefCell<AnyTerminal>,
1480 use_color: bool,
1481}
1482
1483impl TermDecorator {
1484 #[allow(clippy::new_ret_no_self)]
1486 pub fn new() -> TermDecoratorBuilder {
1487 TermDecoratorBuilder::new()
1488 }
1489
1490 pub fn level_to_color(level: slog::Level) -> u16 {
1494 match level {
1495 Level::Critical => 5,
1496 Level::Error => 1,
1497 Level::Warning => 3,
1498 Level::Info => 2,
1499 Level::Debug => 6,
1500 Level::Trace => 4,
1501 }
1502 }
1503}
1504
1505impl Decorator for TermDecorator {
1506 fn with_record<F>(
1507 &self,
1508 record: &Record,
1509 _logger_values: &OwnedKVList,
1510 f: F,
1511 ) -> io::Result<()>
1512 where
1513 F: FnOnce(&mut dyn RecordDecorator) -> io::Result<()>,
1514 {
1515 let mut term = self.term.borrow_mut();
1516 let mut deco = TermRecordDecorator {
1517 term: &mut *term,
1518 level: record.level(),
1519 use_color: self.use_color,
1520 };
1521 {
1522 f(&mut deco)
1523 }
1524 }
1525}
1526
1527pub struct TermRecordDecorator<'a> {
1529 term: &'a mut AnyTerminal,
1530 level: slog::Level,
1531 use_color: bool,
1532}
1533
1534impl<'a> io::Write for TermRecordDecorator<'a> {
1535 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1536 match *self.term {
1537 AnyTerminal::Stdout { ref mut term, .. } => term.write(buf),
1538 AnyTerminal::Stderr { ref mut term, .. } => term.write(buf),
1539 AnyTerminal::FallbackStdout => std::io::stdout().write(buf),
1540 AnyTerminal::FallbackStderr => std::io::stderr().write(buf),
1541 }
1542 }
1543
1544 fn flush(&mut self) -> io::Result<()> {
1545 match *self.term {
1546 AnyTerminal::Stdout { ref mut term, .. } => term.flush(),
1547 AnyTerminal::Stderr { ref mut term, .. } => term.flush(),
1548 AnyTerminal::FallbackStdout => std::io::stdout().flush(),
1549 AnyTerminal::FallbackStderr => std::io::stderr().flush(),
1550 }
1551 }
1552}
1553
1554impl<'a> Drop for TermRecordDecorator<'a> {
1555 fn drop(&mut self) {
1556 let _ = self.flush();
1557 }
1558}
1559
1560fn term_error_to_io_error(e: term::Error) -> io::Error {
1561 match e {
1562 term::Error::Io(e) => e,
1563 e => io::Error::new(io::ErrorKind::Other, format!("term error: {}", e)),
1564 }
1565}
1566
1567impl<'a> RecordDecorator for TermRecordDecorator<'a> {
1568 fn reset(&mut self) -> io::Result<()> {
1569 if !self.use_color {
1570 return Ok(());
1571 }
1572 match *self.term {
1573 AnyTerminal::Stdout {
1574 ref mut term,
1575 supports_reset,
1576 ..
1577 } if supports_reset => term.reset(),
1578 AnyTerminal::Stderr {
1579 ref mut term,
1580 supports_reset,
1581 ..
1582 } if supports_reset => term.reset(),
1583 _ => Ok(()),
1584 }
1585 .map_err(term_error_to_io_error)
1586 }
1587
1588 fn start_level(&mut self) -> io::Result<()> {
1589 if !self.use_color {
1590 return Ok(());
1591 }
1592 let color = TermDecorator::level_to_color(self.level);
1593 match *self.term {
1594 AnyTerminal::Stdout {
1595 ref mut term,
1596 supports_color,
1597 ..
1598 } if supports_color => term.fg(color as term::color::Color),
1599 AnyTerminal::Stderr {
1600 ref mut term,
1601 supports_color,
1602 ..
1603 } if supports_color => term.fg(color as term::color::Color),
1604 _ => Ok(()),
1605 }
1606 .map_err(term_error_to_io_error)
1607 }
1608
1609 fn start_key(&mut self) -> io::Result<()> {
1610 if !self.use_color {
1611 return Ok(());
1612 }
1613 match self.term {
1614 &mut AnyTerminal::Stdout {
1615 ref mut term,
1616 supports_color,
1617 supports_bold,
1618 ..
1619 } => {
1620 if supports_bold {
1621 term.attr(term::Attr::Bold)
1622 } else if supports_color {
1623 term.fg(term::color::BRIGHT_WHITE)
1624 } else {
1625 Ok(())
1626 }
1627 }
1628 &mut AnyTerminal::Stderr {
1629 ref mut term,
1630 supports_color,
1631 supports_bold,
1632 ..
1633 } => {
1634 if supports_bold {
1635 term.attr(term::Attr::Bold)
1636 } else if supports_color {
1637 term.fg(term::color::BRIGHT_WHITE)
1638 } else {
1639 Ok(())
1640 }
1641 }
1642 &mut AnyTerminal::FallbackStdout
1643 | &mut AnyTerminal::FallbackStderr => Ok(()),
1644 }
1645 .map_err(term_error_to_io_error)
1646 }
1647
1648 fn start_msg(&mut self) -> io::Result<()> {
1649 self.start_key()
1651 }
1652}
1653
1654pub struct TestStdoutWriter;
1685
1686impl io::Write for TestStdoutWriter {
1687 fn write(&mut self, data: &[u8]) -> io::Result<usize> {
1688 print!(
1689 "{}",
1690 std::str::from_utf8(data)
1691 .map_err(|x| io::Error::new(io::ErrorKind::InvalidData, x))?
1692 );
1693 Ok(data.len())
1694 }
1695 fn flush(&mut self) -> io::Result<()> {
1696 io::stdout().flush()
1697 }
1698}
1699pub fn term_compact() -> CompactFormat<TermDecorator> {
1704 let decorator = TermDecorator::new().build();
1705 CompactFormat::new(decorator).build()
1706}
1707
1708pub fn term_full() -> FullFormat<TermDecorator> {
1710 let decorator = TermDecorator::new().build();
1711 FullFormat::new(decorator).build()
1712}
1713
1714#[cfg(test)]
1717mod tests {
1718 use super::*;
1719 #[test]
1720 fn test_logger() {
1721 let logger = {
1722 let decorator = PlainSyncDecorator::new(TestStdoutWriter);
1723 let drain = FullFormat::new(decorator).build().fuse();
1724
1725 slog::Logger::root_typed(drain, o!())
1726 };
1727 info!(logger, "Hi from logger test");
1728 }
1729}
1730