]>
Commit | Line | Data |
---|---|---|
f035d41b XL |
1 | //! Callsites represent the source locations from which spans or events |
2 | //! originate. | |
3 | use crate::stdlib::{ | |
4 | fmt, | |
5 | hash::{Hash, Hasher}, | |
f035d41b XL |
6 | sync::Mutex, |
7 | vec::Vec, | |
8 | }; | |
9 | use crate::{ | |
3dfed10e XL |
10 | dispatcher::{self, Dispatch}, |
11 | metadata::{LevelFilter, Metadata}, | |
f035d41b | 12 | subscriber::Interest, |
f035d41b XL |
13 | }; |
14 | ||
5099ac24 | 15 | crate::lazy_static! { |
f035d41b XL |
16 | static ref REGISTRY: Mutex<Registry> = Mutex::new(Registry { |
17 | callsites: Vec::new(), | |
18 | dispatchers: Vec::new(), | |
19 | }); | |
20 | } | |
21 | ||
22 | struct Registry { | |
23 | callsites: Vec<&'static dyn Callsite>, | |
24 | dispatchers: Vec<dispatcher::Registrar>, | |
25 | } | |
26 | ||
27 | impl Registry { | |
28 | fn rebuild_callsite_interest(&self, callsite: &'static dyn Callsite) { | |
29 | let meta = callsite.metadata(); | |
30 | ||
1b1a35ee XL |
31 | // Iterate over the subscribers in the registry, and — if they are |
32 | // active — register the callsite with them. | |
33 | let mut interests = self | |
34 | .dispatchers | |
35 | .iter() | |
36 | .filter_map(|registrar| registrar.try_register(meta)); | |
f035d41b | 37 | |
1b1a35ee XL |
38 | // Use the first subscriber's `Interest` as the base value. |
39 | let interest = if let Some(interest) = interests.next() { | |
40 | // Combine all remaining `Interest`s. | |
41 | interests.fold(interest, Interest::and) | |
42 | } else { | |
43 | // If nobody was interested in this thing, just return `never`. | |
44 | Interest::never() | |
45 | }; | |
f035d41b XL |
46 | |
47 | callsite.set_interest(interest) | |
48 | } | |
49 | ||
50 | fn rebuild_interest(&mut self) { | |
3dfed10e XL |
51 | let mut max_level = LevelFilter::OFF; |
52 | self.dispatchers.retain(|registrar| { | |
53 | if let Some(dispatch) = registrar.upgrade() { | |
54 | // If the subscriber did not provide a max level hint, assume | |
55 | // that it may enable every level. | |
56 | let level_hint = dispatch.max_level_hint().unwrap_or(LevelFilter::TRACE); | |
57 | if level_hint > max_level { | |
58 | max_level = level_hint; | |
59 | } | |
60 | true | |
61 | } else { | |
62 | false | |
63 | } | |
64 | }); | |
f035d41b XL |
65 | |
66 | self.callsites.iter().for_each(|&callsite| { | |
67 | self.rebuild_callsite_interest(callsite); | |
68 | }); | |
3dfed10e | 69 | LevelFilter::set_max(max_level); |
f035d41b XL |
70 | } |
71 | } | |
72 | ||
73 | /// Trait implemented by callsites. | |
74 | /// | |
29967ef6 | 75 | /// These functions are only intended to be called by the callsite registry, which |
f035d41b XL |
76 | /// correctly handles determining the common interest between all subscribers. |
77 | pub trait Callsite: Sync { | |
78 | /// Sets the [`Interest`] for this callsite. | |
79 | /// | |
04454e1e | 80 | /// [`Interest`]: super::subscriber::Interest |
f035d41b XL |
81 | fn set_interest(&self, interest: Interest); |
82 | ||
83 | /// Returns the [metadata] associated with the callsite. | |
84 | /// | |
04454e1e | 85 | /// [metadata]: super::metadata::Metadata |
f035d41b XL |
86 | fn metadata(&self) -> &Metadata<'_>; |
87 | } | |
88 | ||
89 | /// Uniquely identifies a [`Callsite`] | |
90 | /// | |
91 | /// Two `Identifier`s are equal if they both refer to the same callsite. | |
92 | /// | |
04454e1e | 93 | /// [`Callsite`]: super::callsite::Callsite |
f035d41b XL |
94 | #[derive(Clone)] |
95 | pub struct Identifier( | |
96 | /// **Warning**: The fields on this type are currently `pub` because it must | |
97 | /// be able to be constructed statically by macros. However, when `const | |
98 | /// fn`s are available on stable Rust, this will no longer be necessary. | |
99 | /// Thus, these fields are *not* considered stable public API, and they may | |
100 | /// change warning. Do not rely on any fields on `Identifier`. When | |
04454e1e FG |
101 | /// constructing new `Identifier`s, use the `identify_callsite!` macro |
102 | /// instead. | |
f035d41b XL |
103 | #[doc(hidden)] |
104 | pub &'static dyn Callsite, | |
105 | ); | |
106 | ||
107 | /// Clear and reregister interest on every [`Callsite`] | |
108 | /// | |
109 | /// This function is intended for runtime reconfiguration of filters on traces | |
110 | /// when the filter recalculation is much less frequent than trace events are. | |
111 | /// The alternative is to have the [`Subscriber`] that supports runtime | |
112 | /// reconfiguration of filters always return [`Interest::sometimes()`] so that | |
113 | /// [`enabled`] is evaluated for every event. | |
114 | /// | |
3dfed10e | 115 | /// This function will also re-compute the global maximum level as determined by |
29967ef6 | 116 | /// the [`max_level_hint`] method. If a [`Subscriber`] |
3dfed10e XL |
117 | /// implementation changes the value returned by its `max_level_hint` |
118 | /// implementation at runtime, then it **must** call this function after that | |
119 | /// value changes, in order for the change to be reflected. | |
120 | /// | |
04454e1e FG |
121 | /// [`max_level_hint`]: super::subscriber::Subscriber::max_level_hint |
122 | /// [`Callsite`]: super::callsite::Callsite | |
123 | /// [`enabled`]: super::subscriber::Subscriber#tymethod.enabled | |
124 | /// [`Interest::sometimes()`]: super::subscriber::Interest::sometimes | |
125 | /// [`Subscriber`]: super::subscriber::Subscriber | |
f035d41b XL |
126 | pub fn rebuild_interest_cache() { |
127 | let mut registry = REGISTRY.lock().unwrap(); | |
128 | registry.rebuild_interest(); | |
129 | } | |
130 | ||
131 | /// Register a new `Callsite` with the global registry. | |
132 | /// | |
133 | /// This should be called once per callsite after the callsite has been | |
134 | /// constructed. | |
135 | pub fn register(callsite: &'static dyn Callsite) { | |
136 | let mut registry = REGISTRY.lock().unwrap(); | |
137 | registry.rebuild_callsite_interest(callsite); | |
138 | registry.callsites.push(callsite); | |
139 | } | |
140 | ||
141 | pub(crate) fn register_dispatch(dispatch: &Dispatch) { | |
142 | let mut registry = REGISTRY.lock().unwrap(); | |
143 | registry.dispatchers.push(dispatch.registrar()); | |
144 | registry.rebuild_interest(); | |
145 | } | |
146 | ||
147 | // ===== impl Identifier ===== | |
148 | ||
149 | impl PartialEq for Identifier { | |
150 | fn eq(&self, other: &Identifier) -> bool { | |
17df50a5 XL |
151 | core::ptr::eq( |
152 | self.0 as *const _ as *const (), | |
153 | other.0 as *const _ as *const (), | |
154 | ) | |
f035d41b XL |
155 | } |
156 | } | |
157 | ||
158 | impl Eq for Identifier {} | |
159 | ||
160 | impl fmt::Debug for Identifier { | |
161 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
162 | write!(f, "Identifier({:p})", self.0) | |
163 | } | |
164 | } | |
165 | ||
166 | impl Hash for Identifier { | |
167 | fn hash<H>(&self, state: &mut H) | |
168 | where | |
169 | H: Hasher, | |
170 | { | |
171 | (self.0 as *const dyn Callsite).hash(state) | |
172 | } | |
173 | } |