Skip to content

Commit f4a5b28

Browse files
authored
Indent multiline output properly (#7)
1 parent 218ff0b commit f4a5b28

File tree

1 file changed

+108
-63
lines changed

1 file changed

+108
-63
lines changed

src/lib.rs

Lines changed: 108 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
use ansi_term::{Color, Style};
22
use chrono::{DateTime, Local};
3-
use std::{fmt, io, io::Write as _};
3+
use std::sync::Mutex;
4+
use std::{
5+
fmt::{self, Write as _},
6+
io,
7+
};
8+
49
use tracing::{
510
field::{Field, Visit},
611
span::{Attributes, Id},
@@ -16,6 +21,42 @@ pub struct HierarchicalLayer {
1621
stdout: io::Stdout,
1722
indent_amount: usize,
1823
ansi: bool,
24+
bufs: Mutex<Buffers>,
25+
}
26+
27+
#[derive(Debug)]
28+
struct Buffers {
29+
pub current_buf: String,
30+
pub indent_buf: String,
31+
}
32+
33+
impl Buffers {
34+
fn new() -> Self {
35+
Self {
36+
current_buf: String::new(),
37+
indent_buf: String::new(),
38+
}
39+
}
40+
41+
fn flush_current_buf(&mut self, mut writer: impl io::Write) {
42+
write!(writer, "{}", &self.current_buf).unwrap();
43+
self.current_buf.clear();
44+
}
45+
46+
fn flush_indent_buf(&mut self) {
47+
self.current_buf.push_str(&self.indent_buf);
48+
self.indent_buf.clear();
49+
}
50+
51+
fn indent_current(&mut self, indent: usize, indent_amount: usize) {
52+
indent_block(
53+
&mut self.current_buf,
54+
&mut self.indent_buf,
55+
indent,
56+
indent_amount,
57+
);
58+
self.current_buf.clear();
59+
}
1960
}
2061

2162
struct Data {
@@ -24,7 +65,7 @@ struct Data {
2465
}
2566

2667
struct FmtEvent<'a> {
27-
stdout: io::StdoutLock<'a>,
68+
bufs: &'a mut Buffers,
2869
comma: bool,
2970
}
3071

@@ -47,23 +88,27 @@ impl Visit for Data {
4788

4889
impl<'a> Visit for FmtEvent<'a> {
4990
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
50-
write!(
51-
&mut self.stdout,
52-
"{comma} ",
53-
comma = if self.comma { "," } else { "" },
54-
)
55-
.unwrap();
91+
let buf = &mut self.bufs.current_buf;
92+
write!(buf, "{comma} ", comma = if self.comma { "," } else { "" },).unwrap();
5693
let name = field.name();
5794
if name == "message" {
58-
write!(&mut self.stdout, "{:?}", value).unwrap();
95+
write!(buf, "{:?}", value).unwrap();
5996
self.comma = true;
6097
} else {
61-
write!(&mut self.stdout, "{}={:?}", name, value).unwrap();
98+
write!(buf, "{}={:?}", name, value).unwrap();
6299
self.comma = true;
63100
}
64101
}
65102
}
66103

104+
impl<'a> FmtEvent<'a> {
105+
fn finish(&mut self, indent: usize, indent_amount: usize) {
106+
self.bufs.current_buf.push('\n');
107+
self.bufs.indent_current(indent, indent_amount);
108+
self.bufs.flush_indent_buf();
109+
}
110+
}
111+
67112
struct ColorLevel<'a>(&'a Level);
68113

69114
impl<'a> fmt::Display for ColorLevel<'a> {
@@ -79,13 +124,26 @@ impl<'a> fmt::Display for ColorLevel<'a> {
79124
}
80125
}
81126

127+
fn indent_block(block: &mut String, buf: &mut String, indent: usize, indent_amount: usize) {
128+
let lines: Vec<_> = block.lines().collect();
129+
let indent_spaces = indent * indent_amount;
130+
buf.reserve(block.len() + (lines.len() * indent_spaces));
131+
let indent_str = String::from(" ").repeat(indent_spaces);
132+
for line in lines {
133+
buf.push_str(&indent_str);
134+
buf.push_str(line);
135+
buf.push('\n');
136+
}
137+
}
138+
82139
impl HierarchicalLayer {
83140
pub fn new(indent_amount: usize) -> Self {
84141
let ansi = atty::is(atty::Stream::Stdout);
85142
Self {
86143
indent_amount,
87144
stdout: io::stdout(),
88145
ansi,
146+
bufs: Mutex::new(Buffers::new()),
89147
}
90148
}
91149

@@ -103,41 +161,21 @@ impl HierarchicalLayer {
103161

104162
fn print_kvs<'a, I, K, V>(
105163
&self,
106-
writer: &mut impl io::Write,
164+
buf: &mut impl fmt::Write,
107165
kvs: I,
108166
leading: &str,
109-
) -> io::Result<()>
167+
) -> fmt::Result
110168
where
111169
I: IntoIterator<Item = (K, V)>,
112170
K: AsRef<str> + 'a,
113171
V: fmt::Display + 'a,
114172
{
115173
let mut kvs = kvs.into_iter();
116174
if let Some((k, v)) = kvs.next() {
117-
write!(
118-
writer,
119-
"{}{}={}",
120-
leading,
121-
// Style::new().fg(Color::Purple).bold().paint(k.as_ref()),
122-
k.as_ref(),
123-
v
124-
)?;
175+
write!(buf, "{}{}={}", leading, k.as_ref(), v)?;
125176
}
126177
for (k, v) in kvs {
127-
write!(
128-
writer,
129-
", {}={}",
130-
// Style::new().fg(Color::Purple).bold().paint(k.as_ref()),
131-
k.as_ref(),
132-
v
133-
)?;
134-
}
135-
Ok(())
136-
}
137-
138-
fn print_indent(&self, writer: &mut impl io::Write, indent: usize) -> io::Result<()> {
139-
for _ in 0..(indent * self.indent_amount) {
140-
write!(writer, " ")?;
178+
write!(buf, ", {}={}", k.as_ref(), v)?;
141179
}
142180
Ok(())
143181
}
@@ -154,47 +192,53 @@ where
154192
}
155193

156194
fn on_enter(&self, id: &tracing::Id, ctx: Context<S>) {
157-
let mut stdout = self.stdout.lock();
158195
let span = ctx.span(&id).expect("in on_enter but span does not exist");
159196
let ext = span.extensions();
160197
let data = ext.get::<Data>().expect("span does not have data");
161198

162-
let indent = ctx.scope().collect::<Vec<_>>().len() - 1;
163-
self.print_indent(&mut stdout, indent)
164-
.expect("Unable to write to stdout");
199+
let mut guard = self.bufs.lock().unwrap();
200+
let bufs = &mut *guard;
201+
let mut current_buf = &mut bufs.current_buf;
202+
203+
let indent = ctx.scope().count() - 1;
165204

166205
write!(
167-
&mut stdout,
206+
current_buf,
168207
"{name}",
169208
name = self.styled(Style::new().fg(Color::Green).bold(), span.metadata().name())
170209
)
171210
.unwrap();
172211
write!(
173-
&mut stdout,
212+
current_buf,
174213
"{}",
175214
self.styled(Style::new().fg(Color::Green).bold(), "{") // Style::new().fg(Color::Green).dimmed().paint("{")
176215
)
177216
.unwrap();
178-
self.print_kvs(&mut stdout, data.kvs.iter().map(|(k, v)| (k, v)), "")
217+
self.print_kvs(&mut current_buf, data.kvs.iter().map(|(k, v)| (k, v)), "")
179218
.unwrap();
180-
write!(
181-
&mut stdout,
219+
writeln!(
220+
current_buf,
182221
"{}",
183222
self.styled(Style::new().fg(Color::Green).bold(), "}") // Style::new().dimmed().paint("}")
184223
)
185224
.unwrap();
186-
writeln!(&mut stdout).unwrap();
225+
226+
bufs.indent_current(indent, self.indent_amount);
227+
bufs.flush_indent_buf();
228+
bufs.flush_current_buf(self.stdout.lock());
187229
}
188230

189231
fn on_event(&self, event: &Event<'_>, ctx: Context<S>) {
190-
let mut stdout = self.stdout.lock();
232+
let mut guard = self.bufs.lock().unwrap();
233+
let mut bufs = &mut *guard;
234+
let mut event_buf = &mut bufs.current_buf;
191235
// printing the indentation
192-
if let Some(_) = ctx.current_span().id() {
236+
let indent = if ctx.current_span().id().is_some() {
193237
// size hint isn't implemented on Scope.
194-
let indent = ctx.scope().collect::<Vec<_>>().len();
195-
self.print_indent(&mut stdout, indent)
196-
.expect("Unable to write to stdout");
197-
}
238+
ctx.scope().count()
239+
} else {
240+
0
241+
};
198242

199243
// check if this event occurred in the context of a span.
200244
// if it has, get the start time of this span.
@@ -215,31 +259,32 @@ where
215259
let now = Local::now();
216260
if let Some(start) = start {
217261
let elapsed = now - start;
218-
let level = event.metadata().level();
219-
let level = if self.ansi {
220-
ColorLevel(level).to_string()
221-
} else {
222-
level.to_string()
223-
};
224262
write!(
225-
&mut stdout,
226-
"{timestamp}{unit} {level}",
263+
&mut event_buf,
264+
"{timestamp}{unit} ",
227265
timestamp = self.styled(
228266
Style::new().dimmed(),
229267
elapsed.num_milliseconds().to_string()
230268
),
231269
unit = self.styled(Style::new().dimmed(), "ms"),
232-
level = level,
233270
)
234-
.expect("Unable to write to stdout");
271+
.expect("Unable to write to buffer");
235272
}
273+
let level = event.metadata().level();
274+
let level = if self.ansi {
275+
ColorLevel(level).to_string()
276+
} else {
277+
level.to_string()
278+
};
279+
write!(&mut event_buf, "{level}", level = level).expect("Unable to write to buffer");
236280
let mut visitor = FmtEvent {
237-
stdout,
238281
comma: false,
282+
bufs: &mut bufs,
239283
};
240284
event.record(&mut visitor);
241-
writeln!(&mut visitor.stdout).unwrap();
285+
visitor.finish(indent, self.indent_amount);
286+
bufs.flush_current_buf(self.stdout.lock());
242287
}
243288

244-
fn on_close(&self, _: Id, _: Context<S>) {}
289+
fn on_close(&self, _id: Id, _ctx: Context<S>) {}
245290
}

0 commit comments

Comments
 (0)