1
1
use ansi_term:: { Color , Style } ;
2
2
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
+
4
9
use tracing:: {
5
10
field:: { Field , Visit } ,
6
11
span:: { Attributes , Id } ,
@@ -16,6 +21,42 @@ pub struct HierarchicalLayer {
16
21
stdout : io:: Stdout ,
17
22
indent_amount : usize ,
18
23
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
+ }
19
60
}
20
61
21
62
struct Data {
@@ -24,7 +65,7 @@ struct Data {
24
65
}
25
66
26
67
struct FmtEvent < ' a > {
27
- stdout : io :: StdoutLock < ' a > ,
68
+ bufs : & ' a mut Buffers ,
28
69
comma : bool ,
29
70
}
30
71
@@ -47,23 +88,27 @@ impl Visit for Data {
47
88
48
89
impl < ' a > Visit for FmtEvent < ' a > {
49
90
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 ( ) ;
56
93
let name = field. name ( ) ;
57
94
if name == "message" {
58
- write ! ( & mut self . stdout , "{:?}" , value) . unwrap ( ) ;
95
+ write ! ( buf , "{:?}" , value) . unwrap ( ) ;
59
96
self . comma = true ;
60
97
} else {
61
- write ! ( & mut self . stdout , "{}={:?}" , name, value) . unwrap ( ) ;
98
+ write ! ( buf , "{}={:?}" , name, value) . unwrap ( ) ;
62
99
self . comma = true ;
63
100
}
64
101
}
65
102
}
66
103
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
+
67
112
struct ColorLevel < ' a > ( & ' a Level ) ;
68
113
69
114
impl < ' a > fmt:: Display for ColorLevel < ' a > {
@@ -79,13 +124,26 @@ impl<'a> fmt::Display for ColorLevel<'a> {
79
124
}
80
125
}
81
126
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
+
82
139
impl HierarchicalLayer {
83
140
pub fn new ( indent_amount : usize ) -> Self {
84
141
let ansi = atty:: is ( atty:: Stream :: Stdout ) ;
85
142
Self {
86
143
indent_amount,
87
144
stdout : io:: stdout ( ) ,
88
145
ansi,
146
+ bufs : Mutex :: new ( Buffers :: new ( ) ) ,
89
147
}
90
148
}
91
149
@@ -103,41 +161,21 @@ impl HierarchicalLayer {
103
161
104
162
fn print_kvs < ' a , I , K , V > (
105
163
& self ,
106
- writer : & mut impl io :: Write ,
164
+ buf : & mut impl fmt :: Write ,
107
165
kvs : I ,
108
166
leading : & str ,
109
- ) -> io :: Result < ( ) >
167
+ ) -> fmt :: Result
110
168
where
111
169
I : IntoIterator < Item = ( K , V ) > ,
112
170
K : AsRef < str > + ' a ,
113
171
V : fmt:: Display + ' a ,
114
172
{
115
173
let mut kvs = kvs. into_iter ( ) ;
116
174
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) ?;
125
176
}
126
177
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) ?;
141
179
}
142
180
Ok ( ( ) )
143
181
}
@@ -154,47 +192,53 @@ where
154
192
}
155
193
156
194
fn on_enter ( & self , id : & tracing:: Id , ctx : Context < S > ) {
157
- let mut stdout = self . stdout . lock ( ) ;
158
195
let span = ctx. span ( & id) . expect ( "in on_enter but span does not exist" ) ;
159
196
let ext = span. extensions ( ) ;
160
197
let data = ext. get :: < Data > ( ) . expect ( "span does not have data" ) ;
161
198
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 ;
165
204
166
205
write ! (
167
- & mut stdout ,
206
+ current_buf ,
168
207
"{name}" ,
169
208
name = self . styled( Style :: new( ) . fg( Color :: Green ) . bold( ) , span. metadata( ) . name( ) )
170
209
)
171
210
. unwrap ( ) ;
172
211
write ! (
173
- & mut stdout ,
212
+ current_buf ,
174
213
"{}" ,
175
214
self . styled( Style :: new( ) . fg( Color :: Green ) . bold( ) , "{" ) // Style::new().fg(Color::Green).dimmed().paint("{")
176
215
)
177
216
. 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) ) , "" )
179
218
. unwrap ( ) ;
180
- write ! (
181
- & mut stdout ,
219
+ writeln ! (
220
+ current_buf ,
182
221
"{}" ,
183
222
self . styled( Style :: new( ) . fg( Color :: Green ) . bold( ) , "}" ) // Style::new().dimmed().paint("}")
184
223
)
185
224
. 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 ( ) ) ;
187
229
}
188
230
189
231
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 ;
191
235
// printing the indentation
192
- if let Some ( _ ) = ctx. current_span ( ) . id ( ) {
236
+ let indent = if ctx. current_span ( ) . id ( ) . is_some ( ) {
193
237
// 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
+ } ;
198
242
199
243
// check if this event occurred in the context of a span.
200
244
// if it has, get the start time of this span.
@@ -215,31 +259,32 @@ where
215
259
let now = Local :: now ( ) ;
216
260
if let Some ( start) = start {
217
261
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
- } ;
224
262
write ! (
225
- & mut stdout ,
226
- "{timestamp}{unit} {level} " ,
263
+ & mut event_buf ,
264
+ "{timestamp}{unit} " ,
227
265
timestamp = self . styled(
228
266
Style :: new( ) . dimmed( ) ,
229
267
elapsed. num_milliseconds( ) . to_string( )
230
268
) ,
231
269
unit = self . styled( Style :: new( ) . dimmed( ) , "ms" ) ,
232
- level = level,
233
270
)
234
- . expect ( "Unable to write to stdout " ) ;
271
+ . expect ( "Unable to write to buffer " ) ;
235
272
}
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" ) ;
236
280
let mut visitor = FmtEvent {
237
- stdout,
238
281
comma : false ,
282
+ bufs : & mut bufs,
239
283
} ;
240
284
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 ( ) ) ;
242
287
}
243
288
244
- fn on_close ( & self , _ : Id , _ : Context < S > ) { }
289
+ fn on_close ( & self , _id : Id , _ctx : Context < S > ) { }
245
290
}
0 commit comments