11use crate :: { OtelData , PreSampledTracer } ;
22use once_cell:: unsync;
33use opentelemetry:: {
4- trace:: { self as otel, noop, TraceContextExt } ,
4+ trace:: { self as otel, noop, SpanBuilder , SpanKind , Status , TraceContextExt } ,
55 Context as OtelContext , Key , KeyValue , StringValue , Value ,
66} ;
7- use std:: any:: TypeId ;
87use std:: fmt;
98use std:: marker;
109use std:: thread;
1110#[ cfg( not( target_arch = "wasm32" ) ) ]
1211use std:: time:: Instant ;
12+ use std:: { any:: TypeId , borrow:: Cow } ;
1313use tracing_core:: span:: { self , Attributes , Id , Record } ;
1414use tracing_core:: { field, Event , Subscriber } ;
1515#[ cfg( feature = "tracing-log" ) ]
@@ -117,9 +117,45 @@ fn str_to_status(s: &str) -> otel::Status {
117117 }
118118}
119119
120+ #[ derive( Default ) ]
121+ struct SpanBuilderUpdates {
122+ name : Option < Cow < ' static , str > > ,
123+ span_kind : Option < SpanKind > ,
124+ status : Option < Status > ,
125+ attributes : Option < Vec < KeyValue > > ,
126+ }
127+
128+ impl SpanBuilderUpdates {
129+ fn update ( self , span_builder : & mut SpanBuilder ) {
130+ let Self {
131+ name,
132+ span_kind,
133+ status,
134+ attributes,
135+ } = self ;
136+
137+ if let Some ( name) = name {
138+ span_builder. name = name;
139+ }
140+ if let Some ( span_kind) = span_kind {
141+ span_builder. span_kind = Some ( span_kind) ;
142+ }
143+ if let Some ( status) = status {
144+ span_builder. status = status;
145+ }
146+ if let Some ( attributes) = attributes {
147+ if let Some ( builder_attributes) = & mut span_builder. attributes {
148+ builder_attributes. extend ( attributes) ;
149+ } else {
150+ span_builder. attributes = Some ( attributes) ;
151+ }
152+ }
153+ }
154+ }
155+
120156struct SpanEventVisitor < ' a , ' b > {
121157 event_builder : & ' a mut otel:: Event ,
122- span_builder : Option < & ' b mut otel :: SpanBuilder > ,
158+ span_builder_updates : & ' b mut Option < SpanBuilderUpdates > ,
123159 sem_conv_config : SemConvConfig ,
124160}
125161
@@ -186,9 +222,10 @@ impl<'a, 'b> field::Visit for SpanEventVisitor<'a, 'b> {
186222 // In both cases, an event with an empty name and with an error attribute is created.
187223 "error" if self . event_builder . name . is_empty ( ) => {
188224 if self . sem_conv_config . error_events_to_status {
189- if let Some ( span) = & mut self . span_builder {
190- span. status = otel:: Status :: error ( format ! ( "{:?}" , value) ) ;
191- }
225+ self . span_builder_updates
226+ . get_or_insert_with ( SpanBuilderUpdates :: default)
227+ . status
228+ . replace ( otel:: Status :: error ( format ! ( "{:?}" , value) ) ) ;
192229 }
193230 if self . sem_conv_config . error_events_to_exceptions {
194231 self . event_builder . name = EVENT_EXCEPTION_NAME . into ( ) ;
@@ -225,9 +262,10 @@ impl<'a, 'b> field::Visit for SpanEventVisitor<'a, 'b> {
225262 // In both cases, an event with an empty name and with an error attribute is created.
226263 "error" if self . event_builder . name . is_empty ( ) => {
227264 if self . sem_conv_config . error_events_to_status {
228- if let Some ( span) = & mut self . span_builder {
229- span. status = otel:: Status :: error ( format ! ( "{:?}" , value) ) ;
230- }
265+ self . span_builder_updates
266+ . get_or_insert_with ( SpanBuilderUpdates :: default)
267+ . status
268+ . replace ( otel:: Status :: error ( format ! ( "{:?}" , value) ) ) ;
231269 }
232270 if self . sem_conv_config . error_events_to_exceptions {
233271 self . event_builder . name = EVENT_EXCEPTION_NAME . into ( ) ;
@@ -288,25 +326,27 @@ impl<'a, 'b> field::Visit for SpanEventVisitor<'a, 'b> {
288326 }
289327
290328 if self . sem_conv_config . error_records_to_exceptions {
291- if let Some ( span) = & mut self . span_builder {
292- if let Some ( attrs) = span. attributes . as_mut ( ) {
293- attrs. push ( KeyValue :: new (
294- FIELD_EXCEPTION_MESSAGE ,
295- Value :: String ( error_msg. clone ( ) . into ( ) ) ,
296- ) ) ;
329+ let attributes = self
330+ . span_builder_updates
331+ . get_or_insert_with ( SpanBuilderUpdates :: default)
332+ . attributes
333+ . get_or_insert_with ( Vec :: new) ;
297334
298- // NOTE: This is actually not the stacktrace of the exception. This is
299- // the "source chain". It represents the heirarchy of errors from the
300- // app level to the lowest level such as IO. It does not represent all
301- // of the callsites in the code that led to the error happening.
302- // `std::error::Error::backtrace` is a nightly-only API and cannot be
303- // used here until the feature is stabilized.
304- attrs. push ( KeyValue :: new (
305- FIELD_EXCEPTION_STACKTRACE ,
306- Value :: Array ( chain. clone ( ) . into ( ) ) ,
307- ) ) ;
308- }
309- }
335+ attributes. push ( KeyValue :: new (
336+ FIELD_EXCEPTION_MESSAGE ,
337+ Value :: String ( error_msg. clone ( ) . into ( ) ) ,
338+ ) ) ;
339+
340+ // NOTE: This is actually not the stacktrace of the exception. This is
341+ // the "source chain". It represents the heirarchy of errors from the
342+ // app level to the lowest level such as IO. It does not represent all
343+ // of the callsites in the code that led to the error happening.
344+ // `std::error::Error::backtrace` is a nightly-only API and cannot be
345+ // used here until the feature is stabilized.
346+ attributes. push ( KeyValue :: new (
347+ FIELD_EXCEPTION_STACKTRACE ,
348+ Value :: Array ( chain. clone ( ) . into ( ) ) ,
349+ ) ) ;
310350 }
311351
312352 self . event_builder
@@ -354,16 +394,16 @@ struct SemConvConfig {
354394}
355395
356396struct SpanAttributeVisitor < ' a > {
357- span_builder : & ' a mut otel :: SpanBuilder ,
397+ span_builder_updates : & ' a mut SpanBuilderUpdates ,
358398 sem_conv_config : SemConvConfig ,
359399}
360400
361401impl < ' a > SpanAttributeVisitor < ' a > {
362402 fn record ( & mut self , attribute : KeyValue ) {
363- debug_assert ! ( self . span_builder . attributes . is_some ( ) ) ;
364- if let Some ( v ) = self . span_builder . attributes . as_mut ( ) {
365- v . push ( KeyValue :: new ( attribute . key , attribute . value ) ) ;
366- }
403+ self . span_builder_updates
404+ . attributes
405+ . get_or_insert_with ( Vec :: new)
406+ . push ( KeyValue :: new ( attribute . key , attribute . value ) ) ;
367407 }
368408}
369409
@@ -394,11 +434,11 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> {
394434 /// [`Span`]: opentelemetry::trace::Span
395435 fn record_str ( & mut self , field : & field:: Field , value : & str ) {
396436 match field. name ( ) {
397- SPAN_NAME_FIELD => self . span_builder . name = value. to_string ( ) . into ( ) ,
398- SPAN_KIND_FIELD => self . span_builder . span_kind = str_to_span_kind ( value) ,
399- SPAN_STATUS_CODE_FIELD => self . span_builder . status = str_to_status ( value) ,
437+ SPAN_NAME_FIELD => self . span_builder_updates . name = Some ( value. to_string ( ) . into ( ) ) ,
438+ SPAN_KIND_FIELD => self . span_builder_updates . span_kind = str_to_span_kind ( value) ,
439+ SPAN_STATUS_CODE_FIELD => self . span_builder_updates . status = Some ( str_to_status ( value) ) ,
400440 SPAN_STATUS_MESSAGE_FIELD => {
401- self . span_builder . status = otel:: Status :: error ( value. to_string ( ) )
441+ self . span_builder_updates . status = Some ( otel:: Status :: error ( value. to_string ( ) ) )
402442 }
403443 _ => self . record ( KeyValue :: new ( field. name ( ) , value. to_string ( ) ) ) ,
404444 }
@@ -410,15 +450,15 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> {
410450 /// [`Span`]: opentelemetry::trace::Span
411451 fn record_debug ( & mut self , field : & field:: Field , value : & dyn fmt:: Debug ) {
412452 match field. name ( ) {
413- SPAN_NAME_FIELD => self . span_builder . name = format ! ( "{:?}" , value) . into ( ) ,
453+ SPAN_NAME_FIELD => self . span_builder_updates . name = Some ( format ! ( "{:?}" , value) . into ( ) ) ,
414454 SPAN_KIND_FIELD => {
415- self . span_builder . span_kind = str_to_span_kind ( & format ! ( "{:?}" , value) )
455+ self . span_builder_updates . span_kind = str_to_span_kind ( & format ! ( "{:?}" , value) )
416456 }
417457 SPAN_STATUS_CODE_FIELD => {
418- self . span_builder . status = str_to_status ( & format ! ( "{:?}" , value) )
458+ self . span_builder_updates . status = Some ( str_to_status ( & format ! ( "{:?}" , value) ) )
419459 }
420460 SPAN_STATUS_MESSAGE_FIELD => {
421- self . span_builder . status = otel:: Status :: error ( format ! ( "{:?}" , value) )
461+ self . span_builder_updates . status = Some ( otel:: Status :: error ( format ! ( "{:?}" , value) ) )
422462 }
423463 _ => self . record ( Key :: new ( field. name ( ) ) . string ( format ! ( "{:?}" , value) ) ) ,
424464 }
@@ -904,10 +944,13 @@ where
904944 }
905945 }
906946
947+ let mut updates = SpanBuilderUpdates :: default ( ) ;
907948 attrs. record ( & mut SpanAttributeVisitor {
908- span_builder : & mut builder ,
949+ span_builder_updates : & mut updates ,
909950 sem_conv_config : self . sem_conv_config ,
910951 } ) ;
952+
953+ updates. update ( & mut builder) ;
911954 extensions. insert ( OtelData { builder, parent_cx } ) ;
912955 }
913956
@@ -946,12 +989,14 @@ where
946989 /// [`attributes`]: opentelemetry::trace::SpanBuilder::attributes
947990 fn on_record ( & self , id : & Id , values : & Record < ' _ > , ctx : Context < ' _ , S > ) {
948991 let span = ctx. span ( id) . expect ( "Span not found, this is a bug" ) ;
992+ let mut updates = SpanBuilderUpdates :: default ( ) ;
993+ values. record ( & mut SpanAttributeVisitor {
994+ span_builder_updates : & mut updates,
995+ sem_conv_config : self . sem_conv_config ,
996+ } ) ;
949997 let mut extensions = span. extensions_mut ( ) ;
950998 if let Some ( data) = extensions. get_mut :: < OtelData > ( ) {
951- values. record ( & mut SpanAttributeVisitor {
952- span_builder : & mut data. builder ,
953- sem_conv_config : self . sem_conv_config ,
954- } ) ;
999+ updates. update ( & mut data. builder ) ;
9551000 }
9561001 }
9571002
@@ -1023,24 +1068,24 @@ where
10231068 #[ cfg( not( feature = "tracing-log" ) ) ]
10241069 let target = target. string ( meta. target ( ) ) ;
10251070
1026- // Move out extension data to not hold the extensions lock across the event.record() call, which could result in a deadlock
1027- let mut otel_data = span. extensions_mut ( ) . remove :: < OtelData > ( ) ;
1028- let span_builder = otel_data. as_mut ( ) . map ( |data| & mut data. builder ) ;
1029-
10301071 let mut otel_event = otel:: Event :: new (
10311072 String :: new ( ) ,
10321073 crate :: time:: now ( ) ,
10331074 vec ! [ Key :: new( "level" ) . string( meta. level( ) . as_str( ) ) , target] ,
10341075 0 ,
10351076 ) ;
10361077
1078+ let mut builder_updates = None ;
10371079 event. record ( & mut SpanEventVisitor {
10381080 event_builder : & mut otel_event,
1039- span_builder ,
1081+ span_builder_updates : & mut builder_updates ,
10401082 sem_conv_config : self . sem_conv_config ,
10411083 } ) ;
10421084
1043- if let Some ( mut otel_data) = otel_data {
1085+ let mut extensions = span. extensions_mut ( ) ;
1086+ let otel_data = extensions. get_mut :: < OtelData > ( ) ;
1087+
1088+ if let Some ( otel_data) = otel_data {
10441089 let builder = & mut otel_data. builder ;
10451090
10461091 if builder. status == otel:: Status :: Unset
@@ -1049,6 +1094,10 @@ where
10491094 builder. status = otel:: Status :: error ( "" )
10501095 }
10511096
1097+ if let Some ( builder_updates) = builder_updates {
1098+ builder_updates. update ( builder) ;
1099+ }
1100+
10521101 if self . location {
10531102 #[ cfg( not( feature = "tracing-log" ) ) ]
10541103 let normalized_meta: Option < tracing_core:: Metadata < ' _ > > = None ;
@@ -1085,8 +1134,6 @@ where
10851134 } else {
10861135 builder. events = Some ( vec ! [ otel_event] ) ;
10871136 }
1088-
1089- span. extensions_mut ( ) . replace ( otel_data) ;
10901137 }
10911138 } ;
10921139 }
0 commit comments