@@ -6,6 +6,7 @@ use opentelemetry::{
66 Context , Key , KeyValue , Value ,
77} ;
88use std:: { borrow:: Cow , time:: SystemTime } ;
9+ use thiserror:: Error ;
910
1011/// Utility functions to allow tracing [`Span`]s to accept and return
1112/// [OpenTelemetry] [`Context`]s.
@@ -17,6 +18,13 @@ pub trait OpenTelemetrySpanExt {
1718 /// Associates `self` with a given OpenTelemetry trace, using the provided
1819 /// parent [`Context`].
1920 ///
21+ /// This method exists primarily to make it possible to inject a _distributed_ incoming
22+ /// context, e.g. span IDs, etc.
23+ ///
24+ /// A span's parent should only be set _once_, for the purpose described above.
25+ /// Additionally, once a span has been fully built - and the SpanBuilder has been
26+ /// consumed - the parent _cannot_ be mutated.
27+ ///
2028 /// This method provides error handling for cases where the span context
2129 /// cannot be set, such as when the OpenTelemetry layer is not present
2230 /// or when the span has already been started.
@@ -50,7 +58,7 @@ pub trait OpenTelemetrySpanExt {
5058 /// // Or if the current span has been created elsewhere:
5159 /// let _ = Span::current().set_parent(parent_context);
5260 /// ```
53- fn set_parent ( & self , cx : Context ) -> Result < ( ) , & ' static str > ;
61+ fn set_parent ( & self , cx : Context ) -> Result < ( ) , SetParentError > ;
5462
5563 /// Associates `self` with a given OpenTelemetry trace, using the provided
5664 /// followed span [`SpanContext`].
@@ -218,29 +226,31 @@ pub trait OpenTelemetrySpanExt {
218226 ) ;
219227}
220228
229+ #[ derive( Error , Debug ) ]
230+ pub enum SetParentError {
231+ #[ error( "OpenTelemetry layer not found" ) ]
232+ LayerNotFound ,
233+ #[ error( "Span has already been started, cannot set parent" ) ]
234+ AlreadyStarted ,
235+ #[ error( "Span disabled" ) ]
236+ SpanDisabled ,
237+ }
238+
221239impl OpenTelemetrySpanExt for tracing:: Span {
222- ///
223- /// Allows us to set the parent context of this span. This method exists primarily to allow
224- /// us to pull in distributed_ incoming context - e.g. span IDs, etc - that have been read
225- /// into an existing context.
226- ///
227- /// A span's parent should only be set _once_, for the purpose described above.
228- /// Additionally, once a span has been fully built - and the SpanBuilder has been consumed -
229- /// the parent _cannot_ be mutated.
230- ///
231- fn set_parent ( & self , cx : Context ) -> Result < ( ) , & ' static str > {
240+ fn set_parent ( & self , cx : Context ) -> Result < ( ) , SetParentError > {
232241 let mut cx = Some ( cx) ;
233- let mut result = Ok ( ( ) ) ;
234- let result_ref = & mut result;
235242
236243 self . with_subscriber ( move |( id, subscriber) | {
237244 let Some ( get_context) = subscriber. downcast_ref :: < WithContext > ( ) else {
238- * result_ref = Err ( "OpenTelemetry layer not found" ) ;
239- return ;
245+ return Err ( SetParentError :: LayerNotFound ) ;
240246 } ;
247+
248+ let mut result = Ok ( ( ) ) ;
249+ let result_ref = & mut result;
241250 // Set the parent OTel for the current span
242251 get_context. with_context ( subscriber, id, move |data| {
243252 let Some ( new_cx) = cx. take ( ) else {
253+ * result_ref = Err ( SetParentError :: AlreadyStarted ) ;
244254 return ;
245255 } ;
246256 // Create a new context with the new parent but preserve our span.
@@ -254,13 +264,13 @@ impl OpenTelemetrySpanExt for tracing::Span {
254264 * parent_cx = new_cx;
255265 }
256266 OtelDataState :: Context { .. } => {
257- * result_ref = Err ( "Span has already been started, cannot set parent" ) ;
267+ * result_ref = Err ( SetParentError :: AlreadyStarted ) ;
258268 }
259269 }
260270 } ) ;
261- } ) ;
262-
263- result
271+ result
272+ } )
273+ . unwrap_or ( Err ( SetParentError :: SpanDisabled ) )
264274 }
265275
266276 fn add_link ( & self , cx : SpanContext ) {
@@ -324,8 +334,7 @@ impl OpenTelemetrySpanExt for tracing::Span {
324334 let Some ( get_context) = subscriber. downcast_ref :: < WithContext > ( ) else {
325335 return ;
326336 } ;
327- let mut key = Some ( key. into ( ) ) ;
328- let mut value = Some ( value. into ( ) ) ;
337+ let mut key_value = Some ( KeyValue :: new ( key. into ( ) , value. into ( ) ) ) ;
329338 get_context. with_context ( subscriber, id, move |data| {
330339 match & mut data. state {
331340 OtelDataState :: Builder { builder, .. } => {
@@ -336,12 +345,11 @@ impl OpenTelemetrySpanExt for tracing::Span {
336345 . attributes
337346 . as_mut ( )
338347 . unwrap ( )
339- . push ( KeyValue :: new ( key . take ( ) . unwrap ( ) , value . take ( ) . unwrap ( ) ) ) ;
348+ . push ( key_value . take ( ) . unwrap ( ) ) ;
340349 }
341350 OtelDataState :: Context { current_cx } => {
342351 let span = current_cx. span ( ) ;
343- let key_value = KeyValue :: new ( key. take ( ) . unwrap ( ) , value. take ( ) . unwrap ( ) ) ;
344- span. set_attribute ( key_value) ;
352+ span. set_attribute ( key_value. take ( ) . unwrap ( ) ) ;
345353 }
346354 } ;
347355 } ) ;
0 commit comments