tui_logger/
tracing_subscriber.rs1use super::TUI_LOGGER;
4use log::{self, Log, Record};
5use std::collections::BTreeMap;
6use std::fmt;
7use tracing_subscriber::Layer;
8
9#[derive(Default)]
10struct ToStringVisitor<'a>(BTreeMap<&'a str, String>);
11
12impl fmt::Display for ToStringVisitor<'_> {
13 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14 self.0.iter().try_for_each(|(k, v)| -> fmt::Result {
15 if *k == "message" {
16 write!(f, " {}", v)
17 } else {
18 write!(f, " {}: {}", k, v)
19 }
20 })
21 }
22}
23
24impl<'a> tracing::field::Visit for ToStringVisitor<'a> {
25 fn record_f64(&mut self, field: &tracing::field::Field, value: f64) {
26 self.0
27 .insert(field.name(), format_args!("{}", value).to_string());
28 }
29
30 fn record_i64(&mut self, field: &tracing::field::Field, value: i64) {
31 self.0
32 .insert(field.name(), format_args!("{}", value).to_string());
33 }
34
35 fn record_u64(&mut self, field: &tracing::field::Field, value: u64) {
36 self.0
37 .insert(field.name(), format_args!("{}", value).to_string());
38 }
39
40 fn record_bool(&mut self, field: &tracing::field::Field, value: bool) {
41 self.0
42 .insert(field.name(), format_args!("{}", value).to_string());
43 }
44
45 fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
46 self.0
47 .insert(field.name(), format_args!("{}", value).to_string());
48 }
49
50 fn record_error(
51 &mut self,
52 field: &tracing::field::Field,
53 value: &(dyn std::error::Error + 'static),
54 ) {
55 self.0
56 .insert(field.name(), format_args!("{}", value).to_string());
57 }
58
59 fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
60 self.0
61 .insert(field.name(), format_args!("{:?}", value).to_string());
62 }
63}
64
65#[allow(clippy::needless_doctest_main)]
66pub struct TuiTracingSubscriberLayer;
89
90impl<S> Layer<S> for TuiTracingSubscriberLayer
91where
92 S: tracing::Subscriber,
93{
94 fn on_event(
95 &self,
96 event: &tracing::Event<'_>,
97 _ctx: tracing_subscriber::layer::Context<'_, S>,
98 ) {
99 let mut visitor = ToStringVisitor::default();
100 event.record(&mut visitor);
101
102 let level = match *event.metadata().level() {
103 tracing::Level::ERROR => log::Level::Error,
104 tracing::Level::WARN => log::Level::Warn,
105 tracing::Level::INFO => log::Level::Info,
106 tracing::Level::DEBUG => log::Level::Debug,
107 tracing::Level::TRACE => log::Level::Trace,
108 };
109
110 TUI_LOGGER.log(
111 &Record::builder()
112 .args(format_args!("{}", visitor))
113 .level(level)
114 .target(event.metadata().target())
115 .file(event.metadata().file())
116 .line(event.metadata().line())
117 .module_path(event.metadata().module_path())
118 .build(),
119 );
120 }
121}