1use {
2 crate::{
3 draw::{DrawEvent, MAX_LINES, draw_thread},
4 inputs::inputs_thread,
5 },
6 std::{
7 collections::VecDeque,
8 io::{self, Write},
9 marker::PhantomData,
10 sync::{Arc, Mutex, Once, mpsc},
11 thread,
12 },
13 tracing::Subscriber,
14 tracing_subscriber::{
15 Layer, Registry,
16 fmt::{
17 Layer as FmtLayer, MakeWriter,
18 format::{DefaultFields, Format},
19 },
20 layer::{Layered, SubscriberExt},
21 },
22};
23
24static TRACING: Once = Once::new();
25
26const NAME_NOT_FOUND: &str = "undefined";
27
28pub struct LogTerminal<N, E, V, S> {
29 rl: RedirectLayer<V, S>,
30 fmt_layer: FmtLayer<Layered<RedirectLayer<V, S>, Registry>, N, E, ChannelWriter>,
31}
32
33impl<V, S> LogTerminal<DefaultFields, Format, V, S>
34where
35 S: PartialEq<String>,
36 V: AsRef<[S]>,
37{
38 pub fn new(split_by: SplitBy<V, S>) -> LogTerminal<DefaultFields, Format, V, S> {
39 let (rl, cw) = RedirectLayer::new(split_by);
40 let fmt_layer = FmtLayer::new().with_writer(cw);
41 LogTerminal { rl, fmt_layer }
42 }
43}
44
45impl<N, E, V, S> LogTerminal<N, E, V, S>
46where
47 N: Send + Sync + 'static,
48 E: Send + Sync + 'static,
49 S: PartialEq<String>,
50 V: AsRef<[S]>,
51 RedirectLayer<V, S>: Send + Sync + 'static,
52 FmtLayer<Layered<RedirectLayer<V, S>, Registry>, N, E, ChannelWriter>:
53 Layer<Layered<RedirectLayer<V, S>, Registry>>,
54{
55 pub fn customize_fmt_layer<N1, E1>(
56 self,
57 closure: impl FnOnce(
58 FmtLayer<Layered<RedirectLayer<V, S>, Registry>, N, E, ChannelWriter>,
59 )
60 -> FmtLayer<Layered<RedirectLayer<V, S>, Registry>, N1, E1, ChannelWriter>,
61 ) -> LogTerminal<N1, E1, V, S> {
62 LogTerminal {
63 rl: self.rl,
64 fmt_layer: closure(self.fmt_layer),
65 }
66 }
67
68 pub fn with_max_level(mut self, level: tracing::Level) -> LogTerminal<N, E, V, S> {
69 self.rl.max_level = level;
70 self
71 }
72
73 pub fn with_max_lines(self, lines: usize) -> LogTerminal<N, E, V, S> {
74 *MAX_LINES.lock().unwrap() = lines;
75 self
76 }
77
78 pub fn finish(self) {
79 TRACING.call_once(|| {
80 let subscriber = tracing_subscriber::registry()
81 .with(self.rl)
82 .with(self.fmt_layer);
83
84 tracing::subscriber::set_global_default(subscriber)
85 .expect("global subscriber already set");
86 });
87 }
88}
89
90pub enum SplitBy<V, S> {
91 Target(SplitFilter<V, S>),
93 TargetPrefix(SplitFilter<V, S>),
95 SpanPrefix(SplitFilter<V, S>),
97}
98
99#[non_exhaustive]
100pub enum SplitFilter<V, S> {
101 WhiteList(V, PhantomData<S>),
103 BlackList(V, PhantomData<S>),
105 None,
107}
108
109impl<V, S> SplitFilter<V, S>
110where
111 S: PartialEq<String>,
112 V: AsRef<[S]>,
113{
114 pub fn whitelist(items: V) -> Self {
116 Self::WhiteList(items, PhantomData)
117 }
118
119 pub fn blacklist(items: V) -> Self {
121 Self::BlackList(items, PhantomData)
122 }
123}
124
125impl SplitFilter<Vec<String>, String> {
126 pub fn none() -> Self {
128 Self::None
129 }
130}
131
132impl<V, S> SplitFilter<V, S>
133where
134 S: PartialEq<String>,
135 V: AsRef<[S]>,
136{
137 pub fn filter<'a>(&self, target: String) -> Option<String> {
138 match self {
139 SplitFilter::WhiteList(items, _) => {
140 if items.as_ref().iter().any(|item| item == &target) {
141 Some(target)
142 } else {
143 None
144 }
145 },
146 SplitFilter::BlackList(items, _) => {
147 if items.as_ref().iter().any(|item| item == &target) {
148 None
149 } else {
150 Some(target)
151 }
152 },
153 SplitFilter::None => Some(target),
154 }
155 }
156}
157
158pub struct RedirectLayer<V, S> {
159 max_level: tracing::Level,
160 split_by: SplitBy<V, S>,
161 events: Arc<Mutex<VecDeque<Option<String>>>>,
162}
163
164impl<V, S> RedirectLayer<V, S>
165where
166 S: PartialEq<String>,
167 V: AsRef<[S]>,
168{
169 pub fn new(split_by: SplitBy<V, S>) -> (Self, ChannelWriter) {
170 let (tx, rx) = mpsc::channel();
171
172 let events: Arc<Mutex<VecDeque<Option<String>>>> = Default::default();
173
174 let _events = events.clone();
175 let _tx = tx.clone();
176
177 thread::spawn(move || inputs_thread(_tx));
178 thread::spawn(move || draw_thread(_events, rx));
179
180 (
181 Self {
182 max_level: tracing::Level::DEBUG,
183 events,
184 split_by,
185 },
186 ChannelWriter { tx },
187 )
188 }
189
190 fn filter<Sub>(
191 &self,
192 event: &tracing::Event<'_>,
193 _ctx: tracing_subscriber::layer::Context<'_, Sub>,
194 ) -> Option<String>
195 where
196 Sub: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
197 {
198 match &self.split_by {
199 SplitBy::Target(filter) => filter.filter(event.metadata().target().to_string()),
200 SplitBy::TargetPrefix(filter) => {
201 let full_target = event.metadata().target();
202
203 let target = full_target
204 .split("::")
205 .next()
206 .unwrap_or(full_target)
207 .to_string();
208 filter.filter(target)
209 },
210 SplitBy::SpanPrefix(filter) => {
211 let str = if let Some(scope) = _ctx.event_scope(event) {
212 if let Some(span) = scope.from_root().next() {
213 span.name().to_string()
214 } else {
215 NAME_NOT_FOUND.to_string()
216 }
217 } else {
218 NAME_NOT_FOUND.to_string()
219 };
220 filter.filter(str)
221 },
222 }
223 }
224}
225
226impl<S, V, Sub> Layer<Sub> for RedirectLayer<V, S>
227where
228 Self: 'static,
229 S: PartialEq<String>,
230 V: AsRef<[S]>,
231 Sub: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
232{
233 fn enabled(
234 &self,
235 metadata: &tracing::Metadata<'_>,
236 _ctx: tracing_subscriber::layer::Context<'_, Sub>,
237 ) -> bool {
238 metadata.level() <= &self.max_level
239 }
240
241 fn on_event(
242 &self,
243 event: &tracing::Event<'_>,
244 _ctx: tracing_subscriber::layer::Context<'_, Sub>,
245 ) {
246 let name = self.filter(event, _ctx);
247
248 self.events.lock().unwrap().push_back(name);
249 }
250}
251
252pub struct ChannelWriter {
253 tx: mpsc::Sender<DrawEvent>,
254}
255
256impl<'a> MakeWriter<'a> for ChannelWriter {
257 type Writer = &'a Self;
258
259 fn make_writer(&'a self) -> Self::Writer {
260 self
261 }
262}
263
264impl<'a> Write for &'a ChannelWriter {
265 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
266 self.tx.send(DrawEvent::Trace(buf.to_vec())).unwrap();
267 Ok(buf.len())
268 }
269
270 fn flush(&mut self) -> io::Result<()> {
271 Ok(())
272 }
273}