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
use crate::trace::{Event, Span};
use std::marker::PhantomData;

/// Represents the ability to publish events and spans to some arbitrary backend.
pub trait Telemetry {
    /// Type used to record tracing fields.
    type Visitor: tracing::field::Visit;
    /// Globally unique identifier, uniquely identifies a trace.
    type TraceId: Send + Sync + Clone;
    /// Identifies spans within a trace.
    type SpanId: Send + Sync + Clone;

    /// Initialize a visitor, used to record values from spans and events as they are observed
    fn mk_visitor(&self) -> Self::Visitor;

    /// Report a `Span` to this Telemetry instance's backend.
    fn report_span(&self, span: Span<Self::Visitor, Self::SpanId, Self::TraceId>);

    /// Report an `Event` to this Telemetry instance's backend.
    fn report_event(&self, event: Event<Self::Visitor, Self::SpanId, Self::TraceId>);
}

/// Visitor that records no information when visiting tracing fields.
#[derive(Default, Debug)]
pub struct BlackholeVisitor;

impl tracing::field::Visit for BlackholeVisitor {
    fn record_debug(&mut self, _: &tracing::field::Field, _: &dyn std::fmt::Debug) {}
}

/// Telemetry implementation that does not publish information to any backend.
/// For use in tests.
pub struct BlackholeTelemetry<S, T>(PhantomData<S>, PhantomData<T>);

impl<S, T> Default for BlackholeTelemetry<S, T> {
    fn default() -> Self {
        BlackholeTelemetry(PhantomData, PhantomData)
    }
}

impl<SpanId, TraceId> Telemetry for BlackholeTelemetry<SpanId, TraceId>
where
    SpanId: 'static + Clone + Send + Sync,
    TraceId: 'static + Clone + Send + Sync,
{
    type Visitor = BlackholeVisitor;
    type TraceId = TraceId;
    type SpanId = SpanId;

    fn mk_visitor(&self) -> Self::Visitor {
        Default::default()
    }

    fn report_span(&self, _: Span<Self::Visitor, Self::SpanId, Self::TraceId>) {}

    fn report_event(&self, _: Event<Self::Visitor, Self::SpanId, Self::TraceId>) {}
}

#[cfg(test)]
pub(crate) mod test {
    use super::*;
    use std::sync::Arc;
    use std::sync::Mutex;

    // simplified ID types
    pub(crate) type TraceId = u64;
    pub(crate) type SpanId = tracing::Id;

    /// Mock telemetry capability
    pub struct TestTelemetry {
        spans: Arc<Mutex<Vec<Span<BlackholeVisitor, SpanId, TraceId>>>>,
        events: Arc<Mutex<Vec<Event<BlackholeVisitor, SpanId, TraceId>>>>,
    }

    impl TestTelemetry {
        pub fn new(
            spans: Arc<Mutex<Vec<Span<BlackholeVisitor, SpanId, TraceId>>>>,
            events: Arc<Mutex<Vec<Event<BlackholeVisitor, SpanId, TraceId>>>>,
        ) -> Self {
            TestTelemetry { spans, events }
        }
    }

    impl Telemetry for TestTelemetry {
        type Visitor = BlackholeVisitor;
        type SpanId = SpanId;
        type TraceId = TraceId;

        fn mk_visitor(&self) -> Self::Visitor {
            BlackholeVisitor
        }

        fn report_span(&self, span: Span<BlackholeVisitor, SpanId, TraceId>) {
            // succeed or die. failure is unrecoverable (mutex poisoned)
            let mut spans = self.spans.lock().unwrap();
            spans.push(span);
        }

        fn report_event(&self, event: Event<BlackholeVisitor, SpanId, TraceId>) {
            // succeed or die. failure is unrecoverable (mutex poisoned)
            let mut events = self.events.lock().unwrap();
            events.push(event);
        }
    }
}