11use crate :: { OtelData , PreSampledTracer } ;
22use once_cell:: unsync;
33use opentelemetry:: {
4- trace:: { self as otel, noop, TraceContextExt } ,
4+ trace:: { self as otel, noop, Status , TraceContextExt } ,
55 Context as OtelContext , Key , KeyValue , StringValue , Value ,
66} ;
77use std:: any:: TypeId ;
@@ -117,9 +117,15 @@ fn str_to_status(s: &str) -> otel::Status {
117117 }
118118}
119119
120+ #[ derive( Default ) ]
121+ struct ErrorState {
122+ status : Option < Status > ,
123+ attributes : Option < Vec < KeyValue > > ,
124+ }
125+
120126struct SpanEventVisitor < ' a , ' b > {
121127 event_builder : & ' a mut otel:: Event ,
122- span_builder : Option < & ' b mut otel :: SpanBuilder > ,
128+ error_state : & ' b mut Option < ErrorState > ,
123129 sem_conv_config : SemConvConfig ,
124130}
125131
@@ -186,9 +192,10 @@ impl<'a, 'b> field::Visit for SpanEventVisitor<'a, 'b> {
186192 // In both cases, an event with an empty name and with an error attribute is created.
187193 "error" if self . event_builder . name . is_empty ( ) => {
188194 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- }
195+ self . error_state
196+ . get_or_insert_with ( ErrorState :: default)
197+ . status
198+ . replace ( otel:: Status :: error ( format ! ( "{:?}" , value) ) ) ;
192199 }
193200 if self . sem_conv_config . error_events_to_exceptions {
194201 self . event_builder . name = EVENT_EXCEPTION_NAME . into ( ) ;
@@ -225,9 +232,10 @@ impl<'a, 'b> field::Visit for SpanEventVisitor<'a, 'b> {
225232 // In both cases, an event with an empty name and with an error attribute is created.
226233 "error" if self . event_builder . name . is_empty ( ) => {
227234 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- }
235+ self . error_state
236+ . get_or_insert_with ( ErrorState :: default)
237+ . status
238+ . replace ( otel:: Status :: error ( format ! ( "{:?}" , value) ) ) ;
231239 }
232240 if self . sem_conv_config . error_events_to_exceptions {
233241 self . event_builder . name = EVENT_EXCEPTION_NAME . into ( ) ;
@@ -288,25 +296,27 @@ impl<'a, 'b> field::Visit for SpanEventVisitor<'a, 'b> {
288296 }
289297
290298 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- ) ) ;
299+ let attributes = self
300+ . error_state
301+ . get_or_insert_with ( ErrorState :: default)
302+ . attributes
303+ . get_or_insert_with ( Vec :: new) ;
297304
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- }
305+ attributes. push ( KeyValue :: new (
306+ FIELD_EXCEPTION_MESSAGE ,
307+ Value :: String ( error_msg. clone ( ) . into ( ) ) ,
308+ ) ) ;
309+
310+ // NOTE: This is actually not the stacktrace of the exception. This is
311+ // the "source chain". It represents the heirarchy of errors from the
312+ // app level to the lowest level such as IO. It does not represent all
313+ // of the callsites in the code that led to the error happening.
314+ // `std::error::Error::backtrace` is a nightly-only API and cannot be
315+ // used here until the feature is stabilized.
316+ attributes. push ( KeyValue :: new (
317+ FIELD_EXCEPTION_STACKTRACE ,
318+ Value :: Array ( chain. clone ( ) . into ( ) ) ,
319+ ) ) ;
310320 }
311321
312322 self . event_builder
@@ -1023,24 +1033,24 @@ where
10231033 #[ cfg( not( feature = "tracing-log" ) ) ]
10241034 let target = target. string ( meta. target ( ) ) ;
10251035
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-
10301036 let mut otel_event = otel:: Event :: new (
10311037 String :: new ( ) ,
10321038 crate :: time:: now ( ) ,
10331039 vec ! [ Key :: new( "level" ) . string( meta. level( ) . as_str( ) ) , target] ,
10341040 0 ,
10351041 ) ;
10361042
1043+ let mut error_state = None ;
10371044 event. record ( & mut SpanEventVisitor {
10381045 event_builder : & mut otel_event,
1039- span_builder ,
1046+ error_state : & mut error_state ,
10401047 sem_conv_config : self . sem_conv_config ,
10411048 } ) ;
10421049
1043- if let Some ( mut otel_data) = otel_data {
1050+ let mut extensions = span. extensions_mut ( ) ;
1051+ let otel_data = extensions. get_mut :: < OtelData > ( ) ;
1052+
1053+ if let Some ( otel_data) = otel_data {
10441054 let builder = & mut otel_data. builder ;
10451055
10461056 if builder. status == otel:: Status :: Unset
@@ -1049,6 +1059,18 @@ where
10491059 builder. status = otel:: Status :: error ( "" )
10501060 }
10511061
1062+ if let Some ( error_state) = error_state {
1063+ if let Some ( status) = error_state. status {
1064+ builder. status = status;
1065+ }
1066+ if let Some ( attributes) = error_state. attributes {
1067+ builder
1068+ . attributes
1069+ . get_or_insert_with ( Vec :: new)
1070+ . extend ( attributes) ;
1071+ }
1072+ }
1073+
10521074 if self . location {
10531075 #[ cfg( not( feature = "tracing-log" ) ) ]
10541076 let normalized_meta: Option < tracing_core:: Metadata < ' _ > > = None ;
@@ -1085,8 +1107,6 @@ where
10851107 } else {
10861108 builder. events = Some ( vec ! [ otel_event] ) ;
10871109 }
1088-
1089- span. extensions_mut ( ) . replace ( otel_data) ;
10901110 }
10911111 } ;
10921112 }
0 commit comments