tuwunel_core/log/capture/
layer.rs1use std::{fmt, sync::Arc};
2
3use arrayvec::ArrayVec;
4use tracing::field::{Field, Visit};
5use tracing_core::{Event, Subscriber};
6use tracing_subscriber::{layer::Context, registry::LookupSpan};
7
8use super::{Capture, Data, State};
9
10pub struct Layer {
11 state: Arc<State>,
12}
13
14struct Visitor {
15 values: Values,
16}
17
18type Values = ArrayVec<Value, 32>;
19pub type Value = (&'static str, String);
20
21type ScopeNames = ArrayVec<&'static str, 32>;
22
23impl Layer {
24 #[inline]
25 pub fn new(state: &Arc<State>) -> Self { Self { state: state.clone() } }
26}
27
28impl fmt::Debug for Layer {
29 #[inline]
30 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
31 formatter.debug_struct("capture::Layer").finish()
32 }
33}
34
35impl<S> tracing_subscriber::Layer<S> for Layer
36where
37 S: Subscriber + for<'a> LookupSpan<'a>,
38{
39 fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
40 self.state
41 .active
42 .read()
43 .expect("shared lock")
44 .iter()
45 .filter(|capture| filter(self, capture, event, &ctx))
46 .for_each(|capture| handle(self, capture, event, &ctx));
47 }
48}
49
50fn handle<S>(layer: &Layer, capture: &Capture, event: &Event<'_>, ctx: &Context<'_, S>)
51where
52 S: Subscriber + for<'a> LookupSpan<'a>,
53{
54 let names = ScopeNames::new();
55 let mut visitor = Visitor { values: Values::new() };
56 event.record(&mut visitor);
57
58 let mut closure = capture.closure.lock().expect("exclusive lock");
59 closure(Data {
60 layer,
61 event,
62 current: &ctx.current_span(),
63 values: &visitor.values,
64 scope: &names,
65 });
66}
67
68fn filter<S>(layer: &Layer, capture: &Capture, event: &Event<'_>, ctx: &Context<'_, S>) -> bool
69where
70 S: Subscriber + for<'a> LookupSpan<'a>,
71{
72 let values = Values::new();
73 let mut names = ScopeNames::new();
74 if let Some(scope) = ctx.event_scope(event) {
75 for span in scope {
76 names.push(span.name());
77 }
78 }
79
80 capture.filter.as_ref().is_none_or(|filter| {
81 filter(Data {
82 layer,
83 event,
84 current: &ctx.current_span(),
85 values: &values,
86 scope: &names,
87 })
88 })
89}
90
91impl Visit for Visitor {
92 fn record_debug(&mut self, f: &Field, v: &dyn fmt::Debug) {
93 self.values.push((f.name(), format!("{v:?}")));
94 }
95
96 fn record_str(&mut self, f: &Field, v: &str) { self.values.push((f.name(), v.to_owned())); }
97}