p2p_chat/logging/
collector.rs1use super::LogBuffer;
4use crate::ui::LogEntry;
5use chrono::Utc;
6use std::sync::Arc;
7use tracing::{Event, Subscriber};
8use tracing_subscriber::{
9 layer::{Context, SubscriberExt},
10 registry::LookupSpan,
11 Layer,
12};
13
14pub struct TUILogCollector {
16 buffer: Arc<LogBuffer>,
17}
18
19impl TUILogCollector {
20 pub fn new(buffer: Arc<LogBuffer>) -> Self {
26 Self { buffer }
27 }
28
29 pub fn init_subscriber(
42 buffer: Arc<LogBuffer>,
43 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
44 let collector = TUILogCollector::new(buffer);
45
46 let subscriber = tracing_subscriber::registry().with(collector);
48
49 tracing::subscriber::set_global_default(subscriber)?;
50 Ok(())
51 }
52}
53
54impl<S> Layer<S> for TUILogCollector
55where
56 S: Subscriber + for<'a> LookupSpan<'a>,
57{
58 fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
64 let metadata = event.metadata();
65
66 let mut message = String::new();
68 let mut visitor = MessageVisitor(&mut message);
69 event.record(&mut visitor);
70
71 let target = metadata.target();
73 let module = if let Some(module_path) = metadata.module_path() {
74 module_path
76 .split("::")
77 .last()
78 .unwrap_or(module_path)
79 .to_string()
80 } else {
81 target.to_string()
82 };
83
84 let entry = LogEntry {
86 timestamp: Utc::now(),
87 level: *metadata.level(),
88 module,
89 message,
90 };
91
92 self.buffer.add_entry(entry);
94 }
95}
96
97struct MessageVisitor<'a>(&'a mut String);
99
100impl<'a> tracing::field::Visit for MessageVisitor<'a> {
101 fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
103 if field.name() == "message" {
104 *self.0 = format!("{:?}", value);
105 } else {
106 if !self.0.is_empty() {
107 self.0.push(' ');
108 }
109 self.0.push_str(&format!("{}={:?}", field.name(), value));
110 }
111 }
112
113 fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
115 if field.name() == "message" {
116 *self.0 = value.to_string();
117 } else {
118 if !self.0.is_empty() {
119 self.0.push(' ');
120 }
121 self.0.push_str(&format!("{}={}", field.name(), value));
122 }
123 }
124
125 fn record_i64(&mut self, field: &tracing::field::Field, value: i64) {
127 if !self.0.is_empty() {
128 self.0.push(' ');
129 }
130 self.0.push_str(&format!("{}={}", field.name(), value));
131 }
132
133 fn record_u64(&mut self, field: &tracing::field::Field, value: u64) {
135 if !self.0.is_empty() {
136 self.0.push(' ');
137 }
138 self.0.push_str(&format!("{}={}", field.name(), value));
139 }
140
141 fn record_bool(&mut self, field: &tracing::field::Field, value: bool) {
143 if !self.0.is_empty() {
144 self.0.push(' ');
145 }
146 self.0.push_str(&format!("{}={}", field.name(), value));
147 }
148}