Skip to content

Commit eb8dc27

Browse files
committed
Clean up start, end, drop
Signed-off-by: Caleb Schoepp <[email protected]>
1 parent d966e97 commit eb8dc27

File tree

3 files changed

+87
-32
lines changed

3 files changed

+87
-32
lines changed

crates/factor-observe/src/host.rs

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ use crate::{GuestSpan, InstanceState};
1515

1616
#[async_trait]
1717
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
2018
async fn start(
2119
&mut self,
2220
name: String,
23-
_options: Option<tracer::StartOptions>,
21+
options: Option<tracer::StartOptions>,
2422
) -> Result<Resource<tracer::Span>> {
2523
let mut state = self.state.write().unwrap();
24+
let options = options.unwrap_or_default();
2625

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() {
2828
state.original_host_span_id = Some(
2929
tracing::Span::current()
3030
.context()
@@ -34,31 +34,47 @@ impl tracer::Host for InstanceState {
3434
);
3535
}
3636

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
4242
.guest_spans
43-
.get(*state.active_spans.last().unwrap().1)
43+
.get(*state.active_spans.last().unwrap())
4444
.unwrap()
4545
.inner
4646
.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(),
4954
};
5055

5156
// 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);
5571

5672
// Wrap it in a GuestSpan for our own bookkeeping purposes
5773
let guest_span = GuestSpan { inner: otel_span };
5874

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
6076
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);
6278

6379
Ok(Resource::new_own(resource_id))
6480
}
@@ -203,30 +219,33 @@ impl tracer::HostSpan for InstanceState {
203219
resource: Resource<tracer::Span>,
204220
timestamp: Option<tracer::Datetime>,
205221
) -> 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()) {
213224
if let Some(timestamp) = timestamp {
214225
guest_span.inner.end_with_timestamp(timestamp.into());
215226
} else {
216227
guest_span.inner.end();
217228
}
229+
230+
// Remove the span from active_spans
231+
state.active_spans.shift_remove(&resource.rep());
232+
218233
Ok(())
219234
} else {
220235
Err(anyhow!("BUG: cannot find resource in table"))
221236
}
222237
}
223238

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+
226247
Ok(())
227248
}
228249
}
229250

230-
// TODO(Caleb): Move the tests from integration.rs to here
231251
// TODO(Caleb): Write tests somewhere for all the finicky type conversion stuff
232-
// TODO(Caleb): Maybe introduce macro to reduce boilerplate of finding resource

crates/factor-observe/src/lib.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ mod host;
22

33
use std::sync::{Arc, RwLock};
44

5-
use indexmap::IndexMap;
5+
use indexmap::IndexSet;
66
use opentelemetry::{
77
global::{self, BoxedTracer, ObjectSafeSpan},
88
trace::{SpanId, TraceContextExt},
@@ -78,7 +78,7 @@ pub(crate) struct State {
7878
/// Only a reference ID to the guest span is held here. The actual guest span must be looked up
7979
/// in the `guest_spans` table using the reference ID.
8080
/// TODO(Caleb): Fix comment
81-
pub(crate) active_spans: IndexMap<String, u32>,
81+
pub(crate) active_spans: IndexSet<u32>,
8282

8383
/// Id of the last span emitted from within the host before entering the guest.
8484
///
@@ -115,6 +115,7 @@ impl ObserveContext {
115115
/// Make sure to mention this should only be called from an instrumented function in a factor.
116116
/// Make sure this is called before any awaits
117117
pub fn reparent_tracing_span(&self) {
118+
// TODO(Caleb): Refactor to be similar to start
118119
let state = if let Some(state) = self.state.as_ref() {
119120
state.read().unwrap()
120121
} else {
@@ -133,14 +134,14 @@ impl ObserveContext {
133134
.span_id()
134135
.eq(&original_host_span_id)
135136
{
136-
panic!("TODO This should not happen")
137+
panic!("TODO(Caleb): This should not happen")
137138
}
138139
}
139140

140141
let parent_context = Context::new().with_remote_span_context(
141142
state
142143
.guest_spans
143-
.get(*state.active_spans.last().unwrap().1)
144+
.get(*state.active_spans.last().unwrap())
144145
.unwrap()
145146
.inner
146147
.span_context()

crates/world/src/conversions.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,46 @@ mod observe {
318318
}
319319
}
320320

321+
impl From<tracer::SpanKind> for opentelemetry::trace::SpanKind {
322+
fn from(kind: tracer::SpanKind) -> Self {
323+
match kind {
324+
tracer::SpanKind::Client => opentelemetry::trace::SpanKind::Client,
325+
tracer::SpanKind::Server => opentelemetry::trace::SpanKind::Server,
326+
tracer::SpanKind::Producer => opentelemetry::trace::SpanKind::Producer,
327+
tracer::SpanKind::Consumer => opentelemetry::trace::SpanKind::Consumer,
328+
tracer::SpanKind::Internal => opentelemetry::trace::SpanKind::Internal,
329+
}
330+
}
331+
}
332+
333+
impl From<tracer::Link> for opentelemetry::trace::Link {
334+
fn from(link: tracer::Link) -> Self {
335+
Self::new(
336+
link.span_context.into(),
337+
link.attributes.into_iter().map(Into::into).collect(),
338+
0,
339+
)
340+
}
341+
}
342+
321343
impl From<tracer::Datetime> for SystemTime {
322344
fn from(timestamp: tracer::Datetime) -> Self {
323345
UNIX_EPOCH
324346
+ Duration::from_secs(timestamp.seconds)
325347
+ Duration::from_nanos(timestamp.nanoseconds as u64)
326348
}
327349
}
350+
351+
#[allow(clippy::derivable_impls)]
352+
impl Default for tracer::StartOptions {
353+
fn default() -> Self {
354+
Self {
355+
new_root: false,
356+
span_kind: None,
357+
attributes: None,
358+
links: None,
359+
timestamp: None,
360+
}
361+
}
362+
}
328363
}

0 commit comments

Comments
 (0)