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