@@ -6,6 +6,7 @@ use opentelemetry::{
6
6
Context , Key , KeyValue , Value ,
7
7
} ;
8
8
use std:: { borrow:: Cow , time:: SystemTime } ;
9
+ use thiserror:: Error ;
9
10
10
11
/// Utility functions to allow tracing [`Span`]s to accept and return
11
12
/// [OpenTelemetry] [`Context`]s.
@@ -17,6 +18,13 @@ pub trait OpenTelemetrySpanExt {
17
18
/// Associates `self` with a given OpenTelemetry trace, using the provided
18
19
/// parent [`Context`].
19
20
///
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
+ ///
20
28
/// This method provides error handling for cases where the span context
21
29
/// cannot be set, such as when the OpenTelemetry layer is not present
22
30
/// or when the span has already been started.
@@ -50,7 +58,7 @@ pub trait OpenTelemetrySpanExt {
50
58
/// // Or if the current span has been created elsewhere:
51
59
/// let _ = Span::current().set_parent(parent_context);
52
60
/// ```
53
- fn set_parent ( & self , cx : Context ) -> Result < ( ) , & ' static str > ;
61
+ fn set_parent ( & self , cx : Context ) -> Result < ( ) , SetParentError > ;
54
62
55
63
/// Associates `self` with a given OpenTelemetry trace, using the provided
56
64
/// followed span [`SpanContext`].
@@ -218,29 +226,31 @@ pub trait OpenTelemetrySpanExt {
218
226
) ;
219
227
}
220
228
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
+
221
239
impl 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 > {
232
241
let mut cx = Some ( cx) ;
233
- let mut result = Ok ( ( ) ) ;
234
- let result_ref = & mut result;
235
242
236
243
self . with_subscriber ( move |( id, subscriber) | {
237
244
let Some ( get_context) = subscriber. downcast_ref :: < WithContext > ( ) else {
238
- * result_ref = Err ( "OpenTelemetry layer not found" ) ;
239
- return ;
245
+ return Err ( SetParentError :: LayerNotFound ) ;
240
246
} ;
247
+
248
+ let mut result = Ok ( ( ) ) ;
249
+ let result_ref = & mut result;
241
250
// Set the parent OTel for the current span
242
251
get_context. with_context ( subscriber, id, move |data| {
243
252
let Some ( new_cx) = cx. take ( ) else {
253
+ * result_ref = Err ( SetParentError :: AlreadyStarted ) ;
244
254
return ;
245
255
} ;
246
256
// Create a new context with the new parent but preserve our span.
@@ -254,13 +264,13 @@ impl OpenTelemetrySpanExt for tracing::Span {
254
264
* parent_cx = new_cx;
255
265
}
256
266
OtelDataState :: Context { .. } => {
257
- * result_ref = Err ( "Span has already been started, cannot set parent" ) ;
267
+ * result_ref = Err ( SetParentError :: AlreadyStarted ) ;
258
268
}
259
269
}
260
270
} ) ;
261
- } ) ;
262
-
263
- result
271
+ result
272
+ } )
273
+ . unwrap_or ( Err ( SetParentError :: SpanDisabled ) )
264
274
}
265
275
266
276
fn add_link ( & self , cx : SpanContext ) {
@@ -324,8 +334,7 @@ impl OpenTelemetrySpanExt for tracing::Span {
324
334
let Some ( get_context) = subscriber. downcast_ref :: < WithContext > ( ) else {
325
335
return ;
326
336
} ;
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 ( ) ) ) ;
329
338
get_context. with_context ( subscriber, id, move |data| {
330
339
match & mut data. state {
331
340
OtelDataState :: Builder { builder, .. } => {
@@ -336,12 +345,11 @@ impl OpenTelemetrySpanExt for tracing::Span {
336
345
. attributes
337
346
. as_mut ( )
338
347
. unwrap ( )
339
- . push ( KeyValue :: new ( key . take ( ) . unwrap ( ) , value . take ( ) . unwrap ( ) ) ) ;
348
+ . push ( key_value . take ( ) . unwrap ( ) ) ;
340
349
}
341
350
OtelDataState :: Context { current_cx } => {
342
351
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 ( ) ) ;
345
353
}
346
354
} ;
347
355
} ) ;
0 commit comments