      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
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171

    //! Callsites represent the source locations from which spans or events
    //! originate.
    use crate::stdlib::{
        fmt,
        hash::{Hash, Hasher},
        sync::Mutex,
        vec::Vec,
    };
    use crate::{
        dispatcher::{self, Dispatch},
        metadata::{LevelFilter, Metadata},
        subscriber::Interest,
    };

    lazy_static! {
        static ref REGISTRY: Mutex<Registry> = Mutex::new(Registry {
            callsites: Vec::new(),
            dispatchers: Vec::new(),
        });
    }

    struct Registry {
        callsites: Vec<&'static dyn Callsite>,
        dispatchers: Vec<dispatcher::Registrar>,
    }

    impl Registry {
        fn rebuild_callsite_interest(&self, callsite: &'static dyn Callsite) {
            let meta = callsite.metadata();

            // Iterate over the subscribers in the registry, and — if they are
            // active — register the callsite with them.
            let mut interests = self
                .dispatchers
                .iter()
                .filter_map(|registrar| registrar.try_register(meta));

            // Use the first subscriber's `Interest` as the base value.
            let interest = if let Some(interest) = interests.next() {
                // Combine all remaining `Interest`s.
                interests.fold(interest, Interest::and)
            } else {
                // If nobody was interested in this thing, just return `never`.
                Interest::never()
            };

            callsite.set_interest(interest)
        }

        fn rebuild_interest(&mut self) {
            let mut max_level = LevelFilter::OFF;
            self.dispatchers.retain(|registrar| {
                if let Some(dispatch) = registrar.upgrade() {
                    // If the subscriber did not provide a max level hint, assume
                    // that it may enable every level.
                    let level_hint = dispatch.max_level_hint().unwrap_or(LevelFilter::TRACE);
                    if level_hint > max_level {
                        max_level = level_hint;
                    }
                    true
                } else {
                    false
                }
            });

            self.callsites.iter().for_each(|&callsite| {
                self.rebuild_callsite_interest(callsite);
            });
            LevelFilter::set_max(max_level);
        }
    }

    /// Trait implemented by callsites.
    ///
    /// These functions are only intended to be called by the callsite registry, which
    /// correctly handles determining the common interest between all subscribers.
    pub trait Callsite: Sync {
        /// Sets the [`Interest`] for this callsite.
        ///
        /// [`Interest`]: ../subscriber/struct.Interest.html
        fn set_interest(&self, interest: Interest);

        /// Returns the [metadata] associated with the callsite.
        ///
        /// [metadata]: ../metadata/struct.Metadata.html
        fn metadata(&self) -> &Metadata<'_>;
    }

    /// Uniquely identifies a [`Callsite`]
    ///
    /// Two `Identifier`s are equal if they both refer to the same callsite.
    ///
    /// [`Callsite`]: ../callsite/trait.Callsite.html
    #[derive(Clone)]
    pub struct Identifier(
        /// **Warning**: The fields on this type are currently `pub` because it must
        /// be able to be constructed statically by macros. However, when `const
        /// fn`s are available on stable Rust, this will no longer be necessary.
        /// Thus, these fields are *not* considered stable public API, and they may
        /// change warning. Do not rely on any fields on `Identifier`. When
        /// constructing new `Identifier`s, use the `identify_callsite!` macro or
        /// the `Callsite::id` function instead.
        // TODO: When `Callsite::id` is a const fn, this need no longer be `pub`.
        #[doc(hidden)]
        pub &'static dyn Callsite,
    );

    /// Clear and reregister interest on every [`Callsite`]
    ///
    /// This function is intended for runtime reconfiguration of filters on traces
    /// when the filter recalculation is much less frequent than trace events are.
    /// The alternative is to have the [`Subscriber`] that supports runtime
    /// reconfiguration of filters always return [`Interest::sometimes()`] so that
    /// [`enabled`] is evaluated for every event.
    ///
    /// This function will also re-compute the global maximum level as determined by
    /// the [`max_level_hint`] method. If a [`Subscriber`]
    /// implementation changes the value returned by its `max_level_hint`
    /// implementation at runtime, then it **must** call this function after that
    /// value changes, in order for the change to be reflected.
    ///
    /// [`max_level_hint`]: ../subscriber/trait.Subscriber.html#method.max_level_hint
    /// [`Callsite`]: ../callsite/trait.Callsite.html
    /// [`enabled`]: ../subscriber/trait.Subscriber.html#tymethod.enabled
    /// [`Interest::sometimes()`]: ../subscriber/struct.Interest.html#method.sometimes
    /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
    pub fn rebuild_interest_cache() {
        let mut registry = REGISTRY.lock().unwrap();
        registry.rebuild_interest();
    }

    /// Register a new `Callsite` with the global registry.
    ///
    /// This should be called once per callsite after the callsite has been
    /// constructed.
    pub fn register(callsite: &'static dyn Callsite) {
        let mut registry = REGISTRY.lock().unwrap();
        registry.rebuild_callsite_interest(callsite);
        registry.callsites.push(callsite);
    }

    pub(crate) fn register_dispatch(dispatch: &Dispatch) {
        let mut registry = REGISTRY.lock().unwrap();
        registry.dispatchers.push(dispatch.registrar());
        registry.rebuild_interest();
    }

    // ===== impl Identifier =====

    impl PartialEq for Identifier {
        fn eq(&self, other: &Identifier) -> bool {
            self.0 as *const _ as *const () == other.0 as *const _ as *const ()
        }
    }

    impl Eq for Identifier {}

    impl fmt::Debug for Identifier {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "Identifier({:p})", self.0)
        }
    }

    impl Hash for Identifier {
        fn hash<H>(&self, state: &mut H)
        where
            H: Hasher,
        {
            (self.0 as *const dyn Callsite).hash(state)
        }
    }