1use id_arena::Arena;
4use tracing_core::{
5 span::{Attributes, Id, Record},
6 Event, Metadata, Subscriber,
7};
8use tracing_subscriber::{
9 layer::{Context, Filter},
10 registry::LookupSpan,
11 Layer,
12};
13
14use std::{
15 fmt, ops,
16 sync::{Arc, RwLock},
17};
18
19use crate::{
20 CapturedEvent, CapturedEventId, CapturedEventInner, CapturedEvents, CapturedSpan,
21 CapturedSpanId, CapturedSpanInner, CapturedSpans, SpanStats,
22};
23use tracing_tunnel::TracedValues;
24
25#[derive(Debug)]
30pub struct Storage {
31 pub(crate) spans: Arena<CapturedSpanInner>,
32 pub(crate) events: Arena<CapturedEventInner>,
33 root_span_ids: Vec<CapturedSpanId>,
34 root_event_ids: Vec<CapturedEventId>,
35}
36
37impl Storage {
38 pub(crate) fn new() -> Self {
39 Self {
40 spans: Arena::new(),
41 events: Arena::new(),
42 root_span_ids: vec![],
43 root_event_ids: vec![],
44 }
45 }
46
47 pub(crate) fn span(&self, id: CapturedSpanId) -> CapturedSpan<'_> {
48 CapturedSpan {
49 inner: &self.spans[id],
50 storage: self,
51 }
52 }
53
54 pub(crate) fn event(&self, id: CapturedEventId) -> CapturedEvent<'_> {
55 CapturedEvent {
56 inner: &self.events[id],
57 storage: self,
58 }
59 }
60
61 pub fn all_spans(&self) -> CapturedSpans<'_> {
63 CapturedSpans::from_arena(self)
64 }
65
66 pub fn root_spans(&self) -> CapturedSpans<'_> {
69 CapturedSpans::from_slice(self, &self.root_span_ids)
70 }
71
72 pub fn all_events(&self) -> CapturedEvents<'_> {
74 CapturedEvents::from_arena(self)
75 }
76
77 pub fn root_events(&self) -> CapturedEvents<'_> {
80 CapturedEvents::from_slice(self, &self.root_event_ids)
81 }
82
83 pub(crate) fn push_span(
84 &mut self,
85 metadata: &'static Metadata<'static>,
86 values: TracedValues<&'static str>,
87 parent_id: Option<CapturedSpanId>,
88 ) -> CapturedSpanId {
89 let span_id = self.spans.alloc_with_id(|id| CapturedSpanInner {
90 metadata,
91 values,
92 stats: SpanStats::default(),
93 id,
94 parent_id,
95 child_ids: vec![],
96 event_ids: vec![],
97 });
98 if let Some(parent_id) = parent_id {
99 let span = self.spans.get_mut(parent_id).unwrap();
100 span.child_ids.push(span_id);
101 } else {
102 self.root_span_ids.push(span_id);
103 }
104 span_id
105 }
106
107 fn on_span_enter(&mut self, id: CapturedSpanId) {
108 let span = self.spans.get_mut(id).unwrap();
109 span.stats.entered += 1;
110 }
111
112 fn on_span_exit(&mut self, id: CapturedSpanId) {
113 let span = self.spans.get_mut(id).unwrap();
114 span.stats.exited += 1;
115 }
116
117 fn on_span_closed(&mut self, id: CapturedSpanId) {
118 let span = self.spans.get_mut(id).unwrap();
119 span.stats.is_closed = true;
120 }
121
122 fn on_record(&mut self, id: CapturedSpanId, values: TracedValues<&'static str>) {
123 let span = self.spans.get_mut(id).unwrap();
124 span.values.extend(values);
125 }
126
127 pub(crate) fn push_event(
128 &mut self,
129 metadata: &'static Metadata<'static>,
130 values: TracedValues<&'static str>,
131 parent_id: Option<CapturedSpanId>,
132 ) -> CapturedEventId {
133 let event_id = self.events.alloc_with_id(|id| CapturedEventInner {
134 metadata,
135 values,
136 id,
137 parent_id,
138 });
139 if let Some(parent_id) = parent_id {
140 let span = self.spans.get_mut(parent_id).unwrap();
141 span.event_ids.push(event_id);
142 } else {
143 self.root_event_ids.push(event_id);
144 }
145 event_id
146 }
147}
148
149#[derive(Debug, Clone)]
151pub struct SharedStorage {
152 inner: Arc<RwLock<Storage>>,
153}
154
155impl Default for SharedStorage {
156 fn default() -> Self {
157 Self {
158 inner: Arc::new(RwLock::new(Storage::new())),
159 }
160 }
161}
162
163#[allow(clippy::missing_panics_doc)] impl SharedStorage {
165 pub fn lock(&self) -> impl ops::Deref<Target = Storage> + '_ {
168 self.inner
169 .read()
170 .expect("failed accessing shared tracing data storage")
171 }
172}
173
174pub struct CaptureLayer<S> {
189 filter: Option<Box<dyn Filter<S> + Send + Sync>>,
190 storage: Arc<RwLock<Storage>>,
191}
192
193impl<S> fmt::Debug for CaptureLayer<S> {
194 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
195 formatter
196 .debug_struct("CaptureLayer")
197 .field("filter", &self.filter.as_ref().map(|_| "Filter"))
198 .field("storage", &self.storage)
199 .finish()
200 }
201}
202
203impl<S> CaptureLayer<S>
204where
205 S: Subscriber + for<'a> LookupSpan<'a>,
206{
207 pub fn new(storage: &SharedStorage) -> Self {
211 Self {
212 filter: None,
213 storage: Arc::clone(&storage.inner),
214 }
215 }
216
217 #[must_use]
222 pub fn with_filter<F>(mut self, filter: F) -> Self
223 where
224 F: Filter<S> + Send + Sync + 'static,
225 {
226 self.filter = Some(Box::new(filter));
227 self
228 }
229
230 fn enabled(&self, metadata: &Metadata<'_>, ctx: &Context<'_, S>) -> bool {
231 self.filter
232 .as_deref()
233 .map_or(true, |filter| filter.enabled(metadata, ctx))
234 }
235
236 fn lock(&self) -> impl ops::DerefMut<Target = Storage> + '_ {
237 self.storage
238 .write()
239 .expect("failed locking shared tracing data storage for write")
240 }
241}
242
243impl<S> Layer<S> for CaptureLayer<S>
244where
245 S: Subscriber + for<'a> LookupSpan<'a>,
246{
247 fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
248 if !self.enabled(attrs.metadata(), &ctx) {
249 return;
250 }
251
252 let parent_id = if let Some(mut scope) = ctx.span_scope(id) {
253 scope.find_map(|span| span.extensions().get::<CapturedSpanId>().copied())
254 } else {
255 None
256 };
257 let values = TracedValues::from_values(attrs.values());
258 let arena_id = self.lock().push_span(attrs.metadata(), values, parent_id);
259 ctx.span(id).unwrap().extensions_mut().insert(arena_id);
260 }
261
262 fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
263 let span = ctx.span(id).unwrap();
264 if let Some(id) = span.extensions().get::<CapturedSpanId>().copied() {
265 self.lock().on_record(id, TracedValues::from_record(values));
266 };
267 }
268
269 fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
270 if !self.enabled(event.metadata(), &ctx) {
271 return;
272 }
273
274 let parent_id = if let Some(mut scope) = ctx.event_scope(event) {
275 scope.find_map(|span| span.extensions().get::<CapturedSpanId>().copied())
276 } else {
277 None
278 };
279 self.lock()
280 .push_event(event.metadata(), TracedValues::from_event(event), parent_id);
281 }
282
283 fn on_enter(&self, id: &Id, ctx: Context<'_, S>) {
284 let span = ctx.span(id).unwrap();
285 if let Some(id) = span.extensions().get::<CapturedSpanId>().copied() {
286 self.lock().on_span_enter(id);
287 };
288 }
289
290 fn on_exit(&self, id: &Id, ctx: Context<'_, S>) {
291 let span = ctx.span(id).unwrap();
292 if let Some(id) = span.extensions().get::<CapturedSpanId>().copied() {
293 self.lock().on_span_exit(id);
294 };
295 }
296
297 fn on_close(&self, id: Id, ctx: Context<'_, S>) {
298 let span = ctx.span(&id).unwrap();
299 if let Some(id) = span.extensions().get::<CapturedSpanId>().copied() {
300 self.lock().on_span_closed(id);
301 };
302 }
303}