@@ -15,16 +15,16 @@ use crate::{GuestSpan, InstanceState};
15
15
16
16
#[ async_trait]
17
17
impl tracer:: Host for InstanceState {
18
- // TODO(Caleb): Make this implicit logic make more sense (the indexmap seems wrong)
19
- // TODO(Caleb): Properly implement this
20
18
async fn start (
21
19
& mut self ,
22
20
name : String ,
23
- _options : Option < tracer:: StartOptions > ,
21
+ options : Option < tracer:: StartOptions > ,
24
22
) -> Result < Resource < tracer:: Span > > {
25
23
let mut state = self . state . write ( ) . unwrap ( ) ;
24
+ let options = options. unwrap_or_default ( ) ;
26
25
27
- if state. active_spans . is_empty ( ) {
26
+ // Before we ever create any new spans make sure we track the original host span ID
27
+ if state. original_host_span_id . is_none ( ) {
28
28
state. original_host_span_id = Some (
29
29
tracing:: Span :: current ( )
30
30
. context ( )
@@ -34,31 +34,47 @@ impl tracer::Host for InstanceState {
34
34
) ;
35
35
}
36
36
37
- // TODO(Caleb): Make this cleaner
38
- let parent_context = match state. active_spans . is_empty ( ) {
39
- true => tracing :: Span :: current ( ) . context ( ) ,
40
- false => Context :: new ( ) . with_remote_span_context (
41
- state
37
+ // Get span's parent based on whether it's a new root and whether there are any active spans
38
+ let parent_context = match ( options . new_root , state. active_spans . is_empty ( ) ) {
39
+ // Not a new root | Active spans -> Last active guest span is parent
40
+ ( false , false ) => {
41
+ let span_context = state
42
42
. guest_spans
43
- . get ( * state. active_spans . last ( ) . unwrap ( ) . 1 )
43
+ . get ( * state. active_spans . last ( ) . unwrap ( ) )
44
44
. unwrap ( )
45
45
. inner
46
46
. span_context ( )
47
- . clone ( ) ,
48
- ) ,
47
+ . clone ( ) ;
48
+ Context :: new ( ) . with_remote_span_context ( span_context)
49
+ }
50
+ // Not a new root | No active spans -> Current host span is parent
51
+ ( false , true ) => tracing:: Span :: current ( ) . context ( ) ,
52
+ // New root | n/a -> No parent
53
+ ( true , _) => Context :: new ( ) ,
49
54
} ;
50
55
51
56
// Create the underlying opentelemetry span
52
- let otel_span = self . tracer . start_with_context ( name, & parent_context) ;
53
-
54
- let span_id = otel_span. span_context ( ) . span_id ( ) . to_string ( ) ;
57
+ let mut builder = self . tracer . span_builder ( name) ;
58
+ if let Some ( kind) = options. span_kind {
59
+ builder = builder. with_kind ( kind. into ( ) ) ;
60
+ }
61
+ if let Some ( attributes) = options. attributes {
62
+ builder = builder. with_attributes ( attributes. into_iter ( ) . map ( Into :: into) ) ;
63
+ }
64
+ if let Some ( links) = options. links {
65
+ builder = builder. with_links ( links. into_iter ( ) . map ( Into :: into) . collect ( ) ) ;
66
+ }
67
+ if let Some ( timestamp) = options. timestamp {
68
+ builder = builder. with_start_time ( timestamp) ;
69
+ }
70
+ let otel_span = builder. start_with_context ( & self . tracer , & parent_context) ;
55
71
56
72
// Wrap it in a GuestSpan for our own bookkeeping purposes
57
73
let guest_span = GuestSpan { inner : otel_span } ;
58
74
59
- // Put the GuestSpan in our resource table and push it to our stack of active spans
75
+ // Put the GuestSpan in our resource table and push it on to our stack of active spans
60
76
let resource_id = state. guest_spans . push ( guest_span) . unwrap ( ) ;
61
- state. active_spans . insert ( span_id , resource_id) ;
77
+ state. active_spans . insert ( resource_id) ;
62
78
63
79
Ok ( Resource :: new_own ( resource_id) )
64
80
}
@@ -203,30 +219,33 @@ impl tracer::HostSpan for InstanceState {
203
219
resource : Resource < tracer:: Span > ,
204
220
timestamp : Option < tracer:: Datetime > ,
205
221
) -> Result < ( ) > {
206
- if let Some ( guest_span) = self
207
- . state
208
- . write ( )
209
- . unwrap ( )
210
- . guest_spans
211
- . get_mut ( resource. rep ( ) )
212
- {
222
+ let mut state = self . state . write ( ) . unwrap ( ) ;
223
+ if let Some ( guest_span) = state. guest_spans . get_mut ( resource. rep ( ) ) {
213
224
if let Some ( timestamp) = timestamp {
214
225
guest_span. inner . end_with_timestamp ( timestamp. into ( ) ) ;
215
226
} else {
216
227
guest_span. inner . end ( ) ;
217
228
}
229
+
230
+ // Remove the span from active_spans
231
+ state. active_spans . shift_remove ( & resource. rep ( ) ) ;
232
+
218
233
Ok ( ( ) )
219
234
} else {
220
235
Err ( anyhow ! ( "BUG: cannot find resource in table" ) )
221
236
}
222
237
}
223
238
224
- fn drop ( & mut self , _: Resource < tracer:: Span > ) -> Result < ( ) > {
225
- // Dropping the resource automatically calls drop on the Span which ends itself with the current timestamp
239
+ fn drop ( & mut self , resource : Resource < tracer:: Span > ) -> Result < ( ) > {
240
+ // Dropping the resource automatically calls drop on the Span which ends itself with the
241
+ // current timestamp if the Span is not already ended.
242
+
243
+ // Ensure that the span has been removed from active_spans
244
+ let mut state = self . state . write ( ) . unwrap ( ) ;
245
+ state. active_spans . shift_remove ( & resource. rep ( ) ) ;
246
+
226
247
Ok ( ( ) )
227
248
}
228
249
}
229
250
230
- // TODO(Caleb): Move the tests from integration.rs to here
231
251
// TODO(Caleb): Write tests somewhere for all the finicky type conversion stuff
232
- // TODO(Caleb): Maybe introduce macro to reduce boilerplate of finding resource
0 commit comments