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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::{group, EventGroup, Histogram, SpanGroup, TimingSubscriber};
use std::hash::Hash;

/// Builder for [`TimingSubscriber`] instances.
///
/// This type implements the [builder pattern]. It lets you easily configure and construct a new
/// [`TimingSubscriber`] subscriber. See the individual methods for details. To start, use
/// [`Builder::from`]:
///
/// ```rust
/// use tracing_timing::{Builder, Histogram};
/// let builder = Builder::default();
/// let subscriber = builder.build(|| Histogram::new(3).unwrap());
/// ```
///
/// See the various `new_*` methods on [`Histogram`] for how to construct an appropriate histogram
/// in the first place. All samples recorded by the subscriber returned from [`Builder::build`]
/// will be recorded into histograms as returned by the provided constructor. You can also
/// construct the histograms based on the span and event group it will be tracking by using
/// [`Builder::build_informed`].
///
///   [builder pattern]: https://rust-lang-nursery.github.io/api-guidelines/type-safety.html#c-builder
pub struct Builder<S = group::ByName, E = group::ByMessage> {
    span_group: S,
    event_group: E,
    time: quanta::Clock,
}

impl Default for Builder<group::ByName, group::ByMessage> {
    fn default() -> Self {
        Builder {
            span_group: group::ByName,
            event_group: group::ByMessage,
            time: quanta::Clock::new(),
        }
    }
}

impl<S, E> Builder<S, E> {
    /// Set the mechanism used to divide spans into groups.
    ///
    /// See [`SpanGroup`] and the [`group`] module for details.
    pub fn spans<S2>(self, span_group: S2) -> Builder<S2, E> {
        Builder {
            span_group,
            event_group: self.event_group,
            time: self.time,
        }
    }

    /// Set the mechanism used to divide events into per-span groups.
    ///
    /// See [`EventGroup`] and the [`group`] module for details.
    pub fn events<E2>(self, event_group: E2) -> Builder<S, E2> {
        Builder {
            span_group: self.span_group,
            event_group,
            time: self.time,
        }
    }

    /// Set the time source to use for time measurements.
    pub fn time(mut self, time: quanta::Clock) -> Builder<S, E> {
        self.time = time;
        self
    }

    /// Construct a [`TimingSubscriber`] that uses the given function to construct new histograms.
    ///
    /// This is equivalent to [`build`], except that the passed function is also told which
    /// span/event group the histogram is for.
    ///
    /// Note that you _may_ run into weird lifetime errors from the compiler when using this method
    /// with a closure. This is a [known compiler issue]. You can work around it by adding a slight
    /// type hint to the arguments passed to the closure as follows (note the `: &_`):
    ///
    /// ```rust
    /// use tracing_timing::{Builder, Histogram};
    /// let builder = Builder::default();
    /// let subscriber = builder.build_informed(|s: &_, e: &_| Histogram::new(3).unwrap());
    /// ```
    ///
    ///   [known compiler issue]: https://github.com/rust-lang/rust/issues/41078
    pub fn build_informed<F>(self, new_histogram: F) -> TimingSubscriber<S, E>
    where
        S: SpanGroup,
        E: EventGroup,
        S::Id: Hash + Eq,
        E::Id: Hash + Eq,
        F: FnMut(&S::Id, &E::Id) -> Histogram<u64> + Send + Sync + 'static,
    {
        let (tx, rx) = crossbeam::channel::unbounded();
        TimingSubscriber {
            span_group: self.span_group,
            event_group: self.event_group,
            time: self.time,
            reader: super::ReaderState {
                created: rx,
                histograms: Default::default(),
            }
            .into(),
            writers: super::WriterState {
                last_event: Default::default(),
                refcount: Default::default(),
                spans: Default::default(),
                tls: Default::default(),
                idle_recorders: Default::default(),
                new_histogram: Box::new(new_histogram),
                created: tx,
            }
            .into(),
        }
    }

    /// Construct a [`TimingSubscriber`] that uses the given function to construct new histograms.
    pub fn build<F>(self, mut new_histogram: F) -> TimingSubscriber<S, E>
    where
        S: SpanGroup,
        E: EventGroup,
        S::Id: Hash + Eq,
        E::Id: Hash + Eq,
        F: FnMut() -> Histogram<u64> + Send + Sync + 'static,
    {
        self.build_informed(move |_: &_, _: &_| (new_histogram)())
    }
}