1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
crate::ix!();
#[derive(Getters, Setters, Debug)]
#[getset(get = "pub", set = "pub")]
pub struct BufferedLayer {
tag: Option<String>,
buffer: Arc<Mutex<Vec<String>>>,
/// The single source of truth for how we print events:
event_printer: EventPrinter,
}
impl BufferedLayer {
pub fn new_with_tag(tag: &str) -> Self {
Self {
tag: Some(tag.to_string()),
buffer: Arc::new(Mutex::new(Vec::new())),
event_printer: EventPrinter::default(),
}
}
}
impl<S: Subscriber> tracing_subscriber::Layer<S> for BufferedLayer {
fn on_event(&self, event: &tracing::Event<'_>, _ctx: Context<'_, S>) {
use tracing::{trace, debug, info, warn, error};
trace!("on_event called for BufferedLayer");
if let Ok(mut buf) = self.buffer.lock() {
trace!("successfully acquired buffer lock, building event log line");
match &self.event_printer {
EventPrinter::FullWithHeader => {
// Original approach: debug-print the entire event
let mut msg = String::new();
let _ = write!(&mut msg, "{:#?}", event);
debug!("pushing fully detailed event log line");
buf.push(msg);
}
EventPrinter::LogLineAndContents {
show_timestamp,
show_loglevel,
show_location,
} => {
// Single-line approach with optional timestamp/level, but
// place the location info after the message with alignment
use chrono::{Local, SecondsFormat};
let now = Local::now().to_rfc3339_opts(SecondsFormat::Millis, true);
let meta = event.metadata();
let mut line = String::new();
if *show_loglevel {
let desired = 6;
let level = meta.level().to_string();
let pad = desired - level.len();
line.push_str(&level);
line.push_str(&" ".repeat(pad));
}
if *show_location {
// we place the location (and level, if requested) at a fixed column
// for consistent right-bracket alignment across lines
let location = format!(" [{}] ", meta.target());
let max_len = 60;
if location.len() > max_len {
let prefix = &location[0..max_len];
line.push_str(&prefix);
} else {
line.push_str(&location);
let pad = max_len - location.len();
line.push_str(&" ".repeat(pad));
}
line.push_str(&" ");
}
// optional timestamp
if *show_timestamp {
line.push_str(&now);
line.push(' ');
}
// collect field data
struct FieldCollector(String);
impl tracing::field::Visit for FieldCollector {
fn record_debug(
&mut self,
f: &tracing::field::Field,
v: &dyn std::fmt::Debug
) {
if f.name() == "message" {
let _ = write!(self.0, "{:?}, ", v);
} else {
let _ = write!(self.0, "{} = {:?}, ", f.name(), v);
}
}
}
let mut visitor = FieldCollector(String::new());
event.record(&mut visitor);
// trim trailing comma, if any
if !visitor.0.is_empty() {
visitor.0.truncate(visitor.0.len().saturating_sub(2));
}
// build the main part of the line (timestamp + message fields)
line.push_str(&visitor.0);
trace!("pushing single-line log event with aligned location bracket");
buf.push(line);
}
EventPrinter::JustTheContents => {
// Minimal approach: only the field values
let mut message = String::new();
struct FieldCollector(String);
impl tracing::field::Visit for FieldCollector {
fn record_debug(
&mut self,
_f: &tracing::field::Field,
v: &dyn std::fmt::Debug
) {
let _ = write!(self.0, "{:?}, ", v);
}
}
let mut visitor = FieldCollector(String::new());
event.record(&mut visitor);
if !visitor.0.is_empty() {
visitor.0.truncate(visitor.0.len().saturating_sub(2));
message.push_str(&visitor.0);
}
debug!("pushing minimal event fields");
buf.push(message);
}
}
} else {
warn!("failed to acquire buffer lock in BufferedLayer::on_event");
}
}
}
// The flush logic remains as-is (unchanged):
impl Flushable for BufferedLayer {
fn flush(&self) {
use colored::Colorize;
if let Ok(mut buf) = self.buffer.lock() {
if let Some(tag) = &self.tag {
let msg = format!("---------------------------------------------------------[trace_events: {}]", tag);
println!("{}", msg.bright_blue());
}
for message in &*buf {
println!("{}", message);
}
buf.clear();
}
}
}
impl Clone for BufferedLayer {
fn clone(&self) -> Self {
Self {
tag: self.tag.clone(),
buffer: Arc::clone(&self.buffer),
event_printer: self.event_printer.clone(),
}
}
}
impl Default for BufferedLayer {
fn default() -> Self {
Self {
tag: None,
buffer: Arc::new(Mutex::new(Vec::new())),
event_printer: EventPrinter::default(),
}
}
}