@@ -63,17 +63,23 @@ use tracing_log::NormalizeEvent;
63
63
/// the root
64
64
/// - [`Json::with_current_span`] can be used to control logging of the current
65
65
/// span
66
+ /// - [`Json::flatten_current_span`] can be used to enable flattening fields of
67
+ /// the current span into the root
66
68
/// - [`Json::with_span_list`] can be used to control logging of the span list
67
69
/// object.
70
+ /// - [`Json::flatten_span_list`] can be used to enable flattening all fields of
71
+ /// the span list into the root
68
72
///
69
- /// By default, event fields are not flattened, and both current span and span
73
+ /// By default, event and span fields are not flattened, and both current span and span
70
74
/// list are logged.
71
75
///
72
76
#[ derive( Debug , Copy , Clone , Eq , PartialEq ) ]
73
77
pub struct Json {
74
78
pub ( crate ) flatten_event : bool ,
75
79
pub ( crate ) display_current_span : bool ,
76
80
pub ( crate ) display_span_list : bool ,
81
+ pub ( crate ) flatten_current_span : bool ,
82
+ pub ( crate ) flatten_span_list : bool ,
77
83
}
78
84
79
85
impl Json {
@@ -92,6 +98,16 @@ impl Json {
92
98
pub fn with_span_list ( & mut self , display_span_list : bool ) {
93
99
self . display_span_list = display_span_list;
94
100
}
101
+
102
+ /// If set to `true`, the current span will be flattened into the root object.
103
+ pub fn flatten_current_span ( & mut self , flatten_current_span : bool ) {
104
+ self . flatten_current_span = flatten_current_span;
105
+ }
106
+
107
+ /// If set to `true`, the span list will be flattened into the root object.
108
+ pub fn flatten_span_list ( & mut self , flatten_span_list : bool ) {
109
+ self . flatten_span_list = flatten_span_list;
110
+ }
95
111
}
96
112
97
113
struct SerializableContext < ' a , ' b , Span , N > (
@@ -132,17 +148,15 @@ where
132
148
Span : for < ' lookup > crate :: registry:: LookupSpan < ' lookup > ,
133
149
N : for < ' writer > FormatFields < ' writer > + ' static ;
134
150
135
- impl < ' a , ' b , Span , N > serde :: ser :: Serialize for SerializableSpan < ' a , ' b , Span , N >
151
+ impl < ' a , ' b , Span , N > SerializableSpan < ' a , ' b , Span , N >
136
152
where
137
153
Span : for < ' lookup > crate :: registry:: LookupSpan < ' lookup > ,
138
154
N : for < ' writer > FormatFields < ' writer > + ' static ,
139
155
{
140
- fn serialize < Ser > ( & self , serializer : Ser ) -> Result < Ser :: Ok , Ser :: Error >
156
+ fn serialize_fields < Ser > ( & self , serializer : & mut Ser ) -> Result < ( ) , Ser :: Error >
141
157
where
142
- Ser : serde:: ser:: Serializer ,
158
+ Ser : serde:: ser:: SerializeMap ,
143
159
{
144
- let mut serializer = serializer. serialize_map ( None ) ?;
145
-
146
160
let ext = self . 0 . extensions ( ) ;
147
161
let data = ext
148
162
. get :: < FormattedFields < N > > ( )
@@ -188,6 +202,25 @@ where
188
202
// that the fields are not supposed to be missing.
189
203
Err ( e) => serializer. serialize_entry ( "field_error" , & format ! ( "{}" , e) ) ?,
190
204
} ;
205
+
206
+ Ok ( ( ) )
207
+ }
208
+ }
209
+
210
+ impl < ' a , ' b , Span , N > serde:: ser:: Serialize for SerializableSpan < ' a , ' b , Span , N >
211
+ where
212
+ Span : for < ' lookup > crate :: registry:: LookupSpan < ' lookup > ,
213
+ N : for < ' writer > FormatFields < ' writer > + ' static ,
214
+ {
215
+ fn serialize < Ser > ( & self , serializer : Ser ) -> Result < Ser :: Ok , Ser :: Error >
216
+ where
217
+ Ser : serde:: ser:: Serializer ,
218
+ {
219
+ let mut serializer = serializer. serialize_map ( None ) ?;
220
+ self . serialize_fields ( & mut serializer) ?;
221
+ // The span name is not a field and will only
222
+ // be provided if the span is not flattened
223
+ // at root level.
191
224
serializer. serialize_entry ( "name" , self . 0 . metadata ( ) . name ( ) ) ?;
192
225
serializer. end ( )
193
226
}
@@ -271,17 +304,31 @@ where
271
304
272
305
if self . format . display_current_span {
273
306
if let Some ( ref span) = current_span {
274
- serializer
275
- . serialize_entry ( "span" , & SerializableSpan ( span, format_field_marker) )
276
- . unwrap_or ( ( ) ) ;
307
+ let serializable_span = SerializableSpan ( span, format_field_marker) ;
308
+ if self . format . flatten_current_span {
309
+ serializable_span. serialize_fields ( & mut serializer) ?;
310
+ } else {
311
+ serializer
312
+ . serialize_entry ( "span" , & serializable_span)
313
+ . unwrap_or ( ( ) ) ;
314
+ }
277
315
}
278
316
}
279
317
280
318
if self . format . display_span_list && current_span. is_some ( ) {
281
- serializer. serialize_entry (
282
- "spans" ,
283
- & SerializableContext ( & ctx. ctx , format_field_marker) ,
284
- ) ?;
319
+ if self . format . flatten_span_list {
320
+ if let Some ( leaf_span) = ctx. ctx . lookup_current ( ) {
321
+ for span in leaf_span. scope ( ) . from_root ( ) {
322
+ SerializableSpan ( & span, format_field_marker)
323
+ . serialize_fields ( & mut serializer) ?;
324
+ }
325
+ }
326
+ } else {
327
+ serializer. serialize_entry (
328
+ "spans" ,
329
+ & SerializableContext ( & ctx. ctx , format_field_marker) ,
330
+ ) ?;
331
+ }
285
332
}
286
333
287
334
if self . display_thread_name {
@@ -318,6 +365,8 @@ impl Default for Json {
318
365
flatten_event : false ,
319
366
display_current_span : true ,
320
367
display_span_list : true ,
368
+ flatten_current_span : false ,
369
+ flatten_span_list : false ,
321
370
}
322
371
}
323
372
}
@@ -789,6 +838,66 @@ mod test {
789
838
} ) ;
790
839
}
791
840
841
+ #[ test]
842
+ fn json_flatten_current_span ( ) {
843
+ let expected =
844
+ "{\" timestamp\" :\" fake time\" ,\" level\" :\" INFO\" ,\" answer\" :42,\" number\" :3,\" target\" :\" tracing_subscriber::fmt::format::json::test\" ,\" fields\" :{\" message\" :\" some json test\" }}\n " ;
845
+ let collector = collector ( )
846
+ . flatten_event ( false )
847
+ . with_current_span ( true )
848
+ . flatten_current_span ( true )
849
+ . with_span_list ( false ) ;
850
+ test_json ( expected, collector, || {
851
+ let span = tracing:: span!( tracing:: Level :: INFO , "json_span" , answer = 42 , number = 3 ) ;
852
+ let _guard = span. enter ( ) ;
853
+ tracing:: info!( "some json test" ) ;
854
+ } ) ;
855
+ }
856
+
857
+ #[ test]
858
+ fn json_flatten_span_list ( ) {
859
+ let expected =
860
+ "{\" timestamp\" :\" fake time\" ,\" level\" :\" INFO\" ,\" outer\" :\" outer\" ,\" inner\" :\" inner\" ,\" number\" :3,\" target\" :\" tracing_subscriber::fmt::format::json::test\" ,\" fields\" :{\" message\" :\" some json test\" }}\n " ;
861
+ let collector = collector ( )
862
+ . flatten_event ( false )
863
+ . with_current_span ( false )
864
+ . with_span_list ( true )
865
+ . flatten_span_list ( true ) ;
866
+ test_json ( expected, collector, || {
867
+ let outer_span = tracing:: span!(
868
+ tracing:: Level :: INFO ,
869
+ "json_outer_span" ,
870
+ outer = "outer" ,
871
+ number = 0
872
+ ) ;
873
+ let _outer_guard = outer_span. enter ( ) ;
874
+ let inner_span = tracing:: span!(
875
+ tracing:: Level :: INFO ,
876
+ "json_inner_span" ,
877
+ inner = "inner" ,
878
+ number = 3
879
+ ) ;
880
+ let _inner_guard = inner_span. enter ( ) ;
881
+ tracing:: info!( "some json test" ) ;
882
+ } ) ;
883
+ }
884
+
885
+ #[ test]
886
+ fn json_flatten_current_span_with_list ( ) {
887
+ let expected =
888
+ "{\" timestamp\" :\" fake time\" ,\" level\" :\" INFO\" ,\" answer\" :42,\" number\" :3,\" spans\" :[{\" answer\" :42,\" name\" :\" json_span\" ,\" number\" :3}],\" target\" :\" tracing_subscriber::fmt::format::json::test\" ,\" fields\" :{\" message\" :\" some json test\" }}\n " ;
889
+ let collector = collector ( )
890
+ . flatten_event ( false )
891
+ . with_current_span ( true )
892
+ . flatten_current_span ( true )
893
+ . with_span_list ( true ) ;
894
+ test_json ( expected, collector, || {
895
+ let span = tracing:: span!( tracing:: Level :: INFO , "json_span" , answer = 42 , number = 3 ) ;
896
+ let _guard = span. enter ( ) ;
897
+ tracing:: info!( "some json test" ) ;
898
+ } ) ;
899
+ }
900
+
792
901
fn parse_as_json ( buffer : & MockMakeWriter ) -> serde_json:: Value {
793
902
let buf = String :: from_utf8 ( buffer. buf ( ) . to_vec ( ) ) . unwrap ( ) ;
794
903
let json = buf
0 commit comments