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 (k, 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<'a> {
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
1094fn local_timestamp_from_chrono(
1096 local_time: chrono::DateTime<chrono::Local>,
1097) -> result::Result<time::OffsetDateTime, TimestampError> {
1098 use chrono::Utc;
1099 let offset: chrono::FixedOffset = local_time.fixed_offset().timezone();
1100 let utc_time: chrono::DateTime<Utc> = local_time.to_utc();
1101 #[cfg(test)]
1102 {
1103 if offset.local_minus_utc() == 0 {
1104 assert_eq!(utc_time.to_rfc3339(), local_time.to_rfc3339());
1105 } else {
1106 assert_ne!(utc_time.to_rfc3339(), local_time.to_rfc3339());
1107 }
1108 }
1109 let utc_time: time::OffsetDateTime =
1110 time::OffsetDateTime::from_unix_timestamp(utc_time.timestamp())
1111 .map_err(TimestampError::LocalTimeConversion)?
1112 + time::Duration::nanoseconds(i64::from(
1113 utc_time.timestamp_subsec_nanos(),
1114 ));
1115 Ok(utc_time.to_offset(
1116 time::UtcOffset::from_whole_seconds(offset.local_minus_utc())
1117 .map_err(TimestampError::LocalTimeConversion)?,
1118 ))
1119}
1120
1121pub fn timestamp_local(io: &mut dyn io::Write) -> io::Result<()> {
1129 let now = local_timestamp_from_chrono(chrono::Local::now())?;
1130 write!(
1131 io,
1132 "{}",
1133 now.format(TIMESTAMP_FORMAT)
1134 .map_err(TimestampError::Format)?
1135 )
1136}
1137
1138pub fn timestamp_utc(io: &mut dyn io::Write) -> io::Result<()> {
1142 let now = time::OffsetDateTime::now_utc();
1143 write!(
1144 io,
1145 "{}",
1146 now.format(TIMESTAMP_FORMAT)
1147 .map_err(TimestampError::Format)?
1148 )
1149}
1150
1151#[derive(Debug)]
1153#[non_exhaustive]
1154enum TimestampError {
1155 Format(time::error::Format),
1157 LocalTimeConversion(time::error::ComponentRange),
1160}
1161impl fmt::Display for TimestampError {
1166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1167 match self {
1168 TimestampError::Format(cause) => {
1169 write!(f, "Failed to format timestamp: {cause}")
1170 }
1171 TimestampError::LocalTimeConversion(cause) => {
1172 write!(f, "Failed to convert local time: {cause}")
1173 }
1174 }
1175 }
1176}
1177impl From<TimestampError> for io::Error {
1178 fn from(cause: TimestampError) -> Self {
1179 io::Error::new(io::ErrorKind::Other, cause)
1180 }
1181}
1182impl std::error::Error for TimestampError {
1183 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1184 match self {
1185 TimestampError::Format(cause) => Some(cause),
1186 TimestampError::LocalTimeConversion(cause) => Some(cause),
1187 }
1188 }
1189}
1190
1191pub struct PlainDecorator<W>(RefCell<W>)
1214where
1215 W: io::Write;
1216
1217impl<W> PlainDecorator<W>
1218where
1219 W: io::Write,
1220{
1221 pub fn new(io: W) -> Self {
1223 PlainDecorator(RefCell::new(io))
1224 }
1225}
1226
1227impl<W> Decorator for PlainDecorator<W>
1228where
1229 W: io::Write,
1230{
1231 fn with_record<F>(
1232 &self,
1233 _record: &Record,
1234 _logger_values: &OwnedKVList,
1235 f: F,
1236 ) -> io::Result<()>
1237 where
1238 F: FnOnce(&mut dyn RecordDecorator) -> io::Result<()>,
1239 {
1240 f(&mut PlainRecordDecorator(&self.0))
1241 }
1242}
1243
1244pub struct PlainRecordDecorator<'a, W: 'a>(&'a RefCell<W>)
1246where
1247 W: io::Write;
1248
1249impl<'a, W> io::Write for PlainRecordDecorator<'a, W>
1250where
1251 W: io::Write,
1252{
1253 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1254 self.0.borrow_mut().write(buf)
1255 }
1256
1257 fn flush(&mut self) -> io::Result<()> {
1258 self.0.borrow_mut().flush()
1259 }
1260}
1261
1262impl<'a, W> Drop for PlainRecordDecorator<'a, W>
1263where
1264 W: io::Write,
1265{
1266 fn drop(&mut self) {
1267 let _ = self.flush();
1268 }
1269}
1270
1271impl<'a, W> RecordDecorator for PlainRecordDecorator<'a, W>
1272where
1273 W: io::Write,
1274{
1275 fn reset(&mut self) -> io::Result<()> {
1276 Ok(())
1277 }
1278}
1279
1280pub struct PlainSyncDecorator<W>(sync::Arc<sync::Mutex<W>>)
1297where
1298 W: io::Write;
1299
1300impl<W> PlainSyncDecorator<W>
1301where
1302 W: io::Write,
1303{
1304 pub fn new(io: W) -> Self {
1306 PlainSyncDecorator(sync::Arc::new(sync::Mutex::new(io)))
1307 }
1308}
1309
1310impl<W> Decorator for PlainSyncDecorator<W>
1311where
1312 W: io::Write,
1313{
1314 fn with_record<F>(
1315 &self,
1316 _record: &Record,
1317 _logger_values: &OwnedKVList,
1318 f: F,
1319 ) -> io::Result<()>
1320 where
1321 F: FnOnce(&mut dyn RecordDecorator) -> io::Result<()>,
1322 {
1323 f(&mut PlainSyncRecordDecorator {
1324 io: self.0.clone(),
1325 buf: vec![],
1326 })
1327 }
1328}
1329
1330pub struct PlainSyncRecordDecorator<W>
1332where
1333 W: io::Write,
1334{
1335 io: sync::Arc<sync::Mutex<W>>,
1336 buf: Vec<u8>,
1337}
1338
1339impl<W> io::Write for PlainSyncRecordDecorator<W>
1340where
1341 W: io::Write,
1342{
1343 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1344 self.buf.write(buf)
1345 }
1346
1347 fn flush(&mut self) -> io::Result<()> {
1348 if self.buf.is_empty() {
1349 return Ok(());
1350 }
1351
1352 let mut io = self.io.lock().map_err(|_| {
1353 io::Error::new(io::ErrorKind::Other, "mutex locking error")
1354 })?;
1355
1356 io.write_all(&self.buf)?;
1357 self.buf.clear();
1358 io.flush()
1359 }
1360}
1361
1362impl<W> Drop for PlainSyncRecordDecorator<W>
1363where
1364 W: io::Write,
1365{
1366 fn drop(&mut self) {
1367 let _ = self.flush();
1368 }
1369}
1370
1371impl<W> RecordDecorator for PlainSyncRecordDecorator<W>
1372where
1373 W: io::Write,
1374{
1375 fn reset(&mut self) -> io::Result<()> {
1376 Ok(())
1377 }
1378}
1379
1380enum AnyTerminal {
1387 Stdout {
1389 term: Box<term::StdoutTerminal>,
1390 supports_reset: bool,
1391 supports_color: bool,
1392 supports_bold: bool,
1393 },
1394 Stderr {
1396 term: Box<term::StderrTerminal>,
1397 supports_reset: bool,
1398 supports_color: bool,
1399 supports_bold: bool,
1400 },
1401 FallbackStdout,
1402 FallbackStderr,
1403}
1404
1405impl AnyTerminal {
1406 fn should_use_color(&self) -> bool {
1407 if std::env::var_os("NO_COLOR").map_or(false, |x| !x.is_empty()) {
1409 return false;
1410 }
1411 match *self {
1412 AnyTerminal::Stdout { .. } => std::io::stdout().is_terminal(),
1413 AnyTerminal::Stderr { .. } => std::io::stderr().is_terminal(),
1414 AnyTerminal::FallbackStdout => false,
1415 AnyTerminal::FallbackStderr => false,
1416 }
1417 }
1418}
1419
1420pub struct TermDecoratorBuilder {
1422 use_stderr: bool,
1423 color: Option<bool>,
1424}
1425
1426impl TermDecoratorBuilder {
1427 fn new() -> Self {
1428 TermDecoratorBuilder {
1429 use_stderr: true,
1430 color: None,
1431 }
1432 }
1433
1434 pub fn stderr(mut self) -> Self {
1436 self.use_stderr = true;
1437 self
1438 }
1439
1440 pub fn stdout(mut self) -> Self {
1442 self.use_stderr = false;
1443 self
1444 }
1445
1446 pub fn force_color(mut self) -> Self {
1448 self.color = Some(true);
1449 self
1450 }
1451
1452 pub fn force_plain(mut self) -> Self {
1454 self.color = Some(false);
1455 self
1456 }
1457
1458 pub fn try_build(self) -> Option<TermDecorator> {
1464 let io = if self.use_stderr {
1465 term::stderr().map(|t| {
1466 let supports_reset = t.supports_reset();
1467 let supports_color = t.supports_color();
1468 let supports_bold = t.supports_attr(term::Attr::Bold);
1469 AnyTerminal::Stderr {
1470 term: t,
1471 supports_reset,
1472 supports_color,
1473 supports_bold,
1474 }
1475 })
1476 } else {
1477 term::stdout().map(|t| {
1478 let supports_reset = t.supports_reset();
1479 let supports_color = t.supports_color();
1480 let supports_bold = t.supports_attr(term::Attr::Bold);
1481 AnyTerminal::Stdout {
1482 term: t,
1483 supports_reset,
1484 supports_color,
1485 supports_bold,
1486 }
1487 })
1488 };
1489
1490 io.map(|io| {
1491 let use_color = self.color.unwrap_or_else(|| io.should_use_color());
1492 TermDecorator {
1493 use_color,
1494 term: RefCell::new(io),
1495 }
1496 })
1497 }
1498
1499 pub fn build(self) -> TermDecorator {
1504 let io = if self.use_stderr {
1505 term::stderr()
1506 .map(|t| {
1507 let supports_reset = t.supports_reset();
1508 let supports_color = t.supports_color();
1509 let supports_bold = t.supports_attr(term::Attr::Bold);
1510 AnyTerminal::Stderr {
1511 term: t,
1512 supports_reset,
1513 supports_color,
1514 supports_bold,
1515 }
1516 })
1517 .unwrap_or(AnyTerminal::FallbackStderr)
1518 } else {
1519 term::stdout()
1520 .map(|t| {
1521 let supports_reset = t.supports_reset();
1522 let supports_color = t.supports_color();
1523 let supports_bold = t.supports_attr(term::Attr::Bold);
1524 AnyTerminal::Stdout {
1525 term: t,
1526 supports_reset,
1527 supports_color,
1528 supports_bold,
1529 }
1530 })
1531 .unwrap_or(AnyTerminal::FallbackStdout)
1532 };
1533
1534 let use_color = self.color.unwrap_or_else(|| io.should_use_color());
1535 TermDecorator {
1536 term: RefCell::new(io),
1537 use_color,
1538 }
1539 }
1540}
1541
1542pub struct TermDecorator {
1550 term: RefCell<AnyTerminal>,
1551 use_color: bool,
1552}
1553
1554impl TermDecorator {
1555 #[allow(clippy::new_ret_no_self)]
1557 pub fn new() -> TermDecoratorBuilder {
1558 TermDecoratorBuilder::new()
1559 }
1560
1561 pub fn level_to_color(level: slog::Level) -> u16 {
1565 match level {
1566 Level::Critical => 5,
1567 Level::Error => 1,
1568 Level::Warning => 3,
1569 Level::Info => 2,
1570 Level::Debug => 6,
1571 Level::Trace => 4,
1572 }
1573 }
1574}
1575
1576impl Decorator for TermDecorator {
1577 fn with_record<F>(
1578 &self,
1579 record: &Record,
1580 _logger_values: &OwnedKVList,
1581 f: F,
1582 ) -> io::Result<()>
1583 where
1584 F: FnOnce(&mut dyn RecordDecorator) -> io::Result<()>,
1585 {
1586 let mut term = self.term.borrow_mut();
1587 let mut deco = TermRecordDecorator {
1588 term: &mut term,
1589 level: record.level(),
1590 use_color: self.use_color,
1591 };
1592 {
1593 f(&mut deco)
1594 }
1595 }
1596}
1597
1598pub struct TermRecordDecorator<'a> {
1600 term: &'a mut AnyTerminal,
1601 level: slog::Level,
1602 use_color: bool,
1603}
1604
1605impl<'a> io::Write for TermRecordDecorator<'a> {
1606 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1607 match *self.term {
1608 AnyTerminal::Stdout { ref mut term, .. } => term.write(buf),
1609 AnyTerminal::Stderr { ref mut term, .. } => term.write(buf),
1610 AnyTerminal::FallbackStdout => std::io::stdout().write(buf),
1611 AnyTerminal::FallbackStderr => std::io::stderr().write(buf),
1612 }
1613 }
1614
1615 fn flush(&mut self) -> io::Result<()> {
1616 match *self.term {
1617 AnyTerminal::Stdout { ref mut term, .. } => term.flush(),
1618 AnyTerminal::Stderr { ref mut term, .. } => term.flush(),
1619 AnyTerminal::FallbackStdout => std::io::stdout().flush(),
1620 AnyTerminal::FallbackStderr => std::io::stderr().flush(),
1621 }
1622 }
1623}
1624
1625impl<'a> Drop for TermRecordDecorator<'a> {
1626 fn drop(&mut self) {
1627 let _ = self.flush();
1628 }
1629}
1630
1631fn term_error_to_io_error(e: term::Error) -> io::Error {
1632 match e {
1633 term::Error::Io(e) => e,
1634 e => io::Error::new(io::ErrorKind::Other, format!("term error: {}", e)),
1635 }
1636}
1637
1638impl<'a> RecordDecorator for TermRecordDecorator<'a> {
1639 fn reset(&mut self) -> io::Result<()> {
1640 if !self.use_color {
1641 return Ok(());
1642 }
1643 match *self.term {
1644 AnyTerminal::Stdout {
1645 ref mut term,
1646 supports_reset,
1647 ..
1648 } if supports_reset => term.reset(),
1649 AnyTerminal::Stderr {
1650 ref mut term,
1651 supports_reset,
1652 ..
1653 } if supports_reset => term.reset(),
1654 _ => Ok(()),
1655 }
1656 .map_err(term_error_to_io_error)
1657 }
1658
1659 fn start_level(&mut self) -> io::Result<()> {
1660 if !self.use_color {
1661 return Ok(());
1662 }
1663 let color = TermDecorator::level_to_color(self.level);
1664 match *self.term {
1665 AnyTerminal::Stdout {
1666 ref mut term,
1667 supports_color,
1668 ..
1669 } if supports_color => term.fg(color as term::color::Color),
1670 AnyTerminal::Stderr {
1671 ref mut term,
1672 supports_color,
1673 ..
1674 } if supports_color => term.fg(color as term::color::Color),
1675 _ => Ok(()),
1676 }
1677 .map_err(term_error_to_io_error)
1678 }
1679
1680 fn start_key(&mut self) -> io::Result<()> {
1681 if !self.use_color {
1682 return Ok(());
1683 }
1684 match self.term {
1685 &mut AnyTerminal::Stdout {
1686 ref mut term,
1687 supports_color,
1688 supports_bold,
1689 ..
1690 } => {
1691 if supports_bold {
1692 term.attr(term::Attr::Bold)
1693 } else if supports_color {
1694 term.fg(term::color::BRIGHT_WHITE)
1695 } else {
1696 Ok(())
1697 }
1698 }
1699 &mut AnyTerminal::Stderr {
1700 ref mut term,
1701 supports_color,
1702 supports_bold,
1703 ..
1704 } => {
1705 if supports_bold {
1706 term.attr(term::Attr::Bold)
1707 } else if supports_color {
1708 term.fg(term::color::BRIGHT_WHITE)
1709 } else {
1710 Ok(())
1711 }
1712 }
1713 &mut AnyTerminal::FallbackStdout
1714 | &mut AnyTerminal::FallbackStderr => Ok(()),
1715 }
1716 .map_err(term_error_to_io_error)
1717 }
1718
1719 fn start_msg(&mut self) -> io::Result<()> {
1720 self.start_key()
1722 }
1723}
1724
1725pub struct TestStdoutWriter;
1756
1757impl io::Write for TestStdoutWriter {
1758 fn write(&mut self, data: &[u8]) -> io::Result<usize> {
1759 print!(
1760 "{}",
1761 std::str::from_utf8(data)
1762 .map_err(|x| io::Error::new(io::ErrorKind::InvalidData, x))?
1763 );
1764 Ok(data.len())
1765 }
1766 fn flush(&mut self) -> io::Result<()> {
1767 io::stdout().flush()
1768 }
1769}
1770pub fn term_compact() -> CompactFormat<TermDecorator> {
1775 let decorator = TermDecorator::new().build();
1776 CompactFormat::new(decorator).build()
1777}
1778
1779pub fn term_full() -> FullFormat<TermDecorator> {
1781 let decorator = TermDecorator::new().build();
1782 FullFormat::new(decorator).build()
1783}
1784
1785#[cfg(test)]
1788mod tests {
1789 use super::*;
1790 #[test]
1791 fn test_logger() {
1792 let logger = {
1793 let decorator = PlainSyncDecorator::new(TestStdoutWriter);
1794 let drain = FullFormat::new(decorator).build().fuse();
1795
1796 slog::Logger::root_typed(drain, o!())
1797 };
1798 info!(logger, "Hi from logger test");
1799 }
1800}
1801