1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
//! `MakeVisitor` wrappers for working with `fmt::Display` fields.
use super::{MakeVisitor, VisitFmt, VisitOutput, VisitWrite};
use tracing_core::field::{Field, Visit};

use std::{fmt, io};

/// A visitor wrapper that ensures any strings named "message" are formatted
/// using `fmt::Display`
#[derive(Debug, Clone)]
pub struct Messages<V>(V);

// TODO(eliza): When `error` as a primitive type is stable, add a
// `DisplayErrors` wrapper...

// === impl Messages ===
//
impl<V> Messages<V> {
    /// Returns a new [`MakeVisitor`] implementation that will wrap `inner` so
    /// that any strings named `message` are formatted using `fmt::Display`.
    ///
    /// [`MakeVisitor`]: ../trait.MakeVisitor.html
    pub fn new(inner: V) -> Self {
        Messages(inner)
    }
}

impl<T, V> MakeVisitor<T> for Messages<V>
where
    V: MakeVisitor<T>,
{
    type Visitor = Messages<V::Visitor>;

    #[inline]
    fn make_visitor(&self, target: T) -> Self::Visitor {
        Messages(self.0.make_visitor(target))
    }
}

impl<V> Visit for Messages<V>
where
    V: Visit,
{
    #[inline]
    fn record_i64(&mut self, field: &Field, value: i64) {
        self.0.record_i64(field, value)
    }

    #[inline]
    fn record_u64(&mut self, field: &Field, value: u64) {
        self.0.record_u64(field, value)
    }

    #[inline]
    fn record_bool(&mut self, field: &Field, value: bool) {
        self.0.record_bool(field, value)
    }

    /// Visit a string value.
    fn record_str(&mut self, field: &Field, value: &str) {
        if field.name() == "message" {
            self.0.record_debug(field, &format_args!("{}", value))
        } else {
            self.0.record_str(field, value)
        }
    }

    // TODO(eliza): add RecordError when stable
    // fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
    //     self.record_debug(field, &format_args!("{}", value))
    // }

    #[inline]
    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
        self.0.record_debug(field, value)
    }
}

impl<V, O> VisitOutput<O> for Messages<V>
where
    V: VisitOutput<O>,
{
    #[inline]
    fn finish(self) -> O {
        self.0.finish()
    }
}

impl<V> VisitWrite for Messages<V>
where
    V: VisitWrite,
{
    #[inline]
    fn writer(&mut self) -> &mut dyn io::Write {
        self.0.writer()
    }
}

impl<V> VisitFmt for Messages<V>
where
    V: VisitFmt,
{
    #[inline]
    fn writer(&mut self) -> &mut dyn fmt::Write {
        self.0.writer()
    }
}