From 1c61ea6b5684236a62301d94117b32cedc096112 Mon Sep 17 00:00:00 2001 From: AsmPrgmC3 Date: Thu, 28 Sep 2023 00:57:37 +0200 Subject: [PATCH] Fix potential deadlock (#59) ## Motivation Some `Debug` implementations access a span's extensions, for example a `color_eyre` `Report` when printing a Spantrace. This can currently lead to a deadlock because `tracing-opentelemetry`'s tracing `Layer` holds an `extensions_mut()` guard for its Span while recording the event. ## Solution Move the the `OtelData` out of the span to not hold the lock and later write the extension back. --- src/layer.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/layer.rs b/src/layer.rs index 450f146..8bb0069 100644 --- a/src/layer.rs +++ b/src/layer.rs @@ -835,10 +835,9 @@ where #[cfg(not(feature = "tracing-log"))] let target = target.string(meta.target()); - let mut extensions = span.extensions_mut(); - let span_builder = extensions - .get_mut::() - .map(|data| &mut data.builder); + // Move out extension data to not hold the extensions lock across the event.record() call, which could result in a deadlock + let mut otel_data = span.extensions_mut().remove::(); + let span_builder = otel_data.as_mut().map(|data| &mut data.builder); let mut otel_event = otel::Event::new( String::new(), @@ -852,7 +851,9 @@ where exception_config: self.exception_config, }); - if let Some(OtelData { builder, .. }) = extensions.get_mut::() { + if let Some(mut otel_data) = otel_data { + let builder = &mut otel_data.builder; + if builder.status == otel::Status::Unset && *meta.level() == tracing_core::Level::ERROR { @@ -895,6 +896,8 @@ where } else { builder.events = Some(vec![otel_event]); } + + span.extensions_mut().replace(otel_data); } }; }