Skip to content

Commit ccf4599

Browse files
authored
Ensure is_recording is false and all methods are no-ops after span ends (#341)
1 parent 40b8909 commit ccf4599

File tree

1 file changed

+43
-18
lines changed

1 file changed

+43
-18
lines changed

opentelemetry/src/sdk/trace/span.rs

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub struct Span {
1919
inner: Arc<SpanInner>,
2020
}
2121

22-
/// Inner data, processed and exported on drop
22+
/// Inner data, processed and exported on end
2323
#[derive(Debug)]
2424
struct SpanInner {
2525
span_context: SpanContext,
@@ -107,8 +107,14 @@ impl crate::trace::Span for Span {
107107

108108
/// Returns true if this `Span` is recording information like events with the `add_event`
109109
/// operation, attributes using `set_attributes`, status with `set_status`, etc.
110+
/// Always returns false after span `end`.
110111
fn is_recording(&self) -> bool {
111-
self.inner.data.is_some()
112+
if let Some(data) = &self.inner.data {
113+
if let Ok(span_data) = data.lock() {
114+
return span_data.is_some();
115+
}
116+
}
117+
false
112118
}
113119

114120
/// Sets a single `Attribute` where the attribute properties are passed as arguments.
@@ -140,24 +146,25 @@ impl crate::trace::Span for Span {
140146

141147
/// Finishes the span with given timestamp.
142148
fn end_with_timestamp(&self, timestamp: SystemTime) {
143-
self.with_data(|data| {
144-
data.end_time = timestamp;
145-
});
149+
self.inner.ensure_ended_and_exported(Some(timestamp));
146150
}
147151
}
148152

149-
impl Drop for SpanInner {
150-
/// Report span on inner drop
151-
fn drop(&mut self) {
152-
if let Some(data) = self.data.take() {
153+
impl SpanInner {
154+
fn ensure_ended_and_exported(&self, timestamp: Option<SystemTime>) {
155+
if let Some(data) = &self.data {
153156
if let Ok(mut span_data) = data.lock().map(|mut data| data.take()) {
154-
if let Some(provider) = self.tracer.provider() {
155-
// Set end time if unset or invalid
156-
if let Some(data) = span_data.as_mut() {
157-
if data.end_time <= data.start_time {
158-
data.end_time = SystemTime::now();
159-
}
157+
// Ensure end time is set via explicit end or implicitly on drop
158+
if let Some(span_data) = span_data.as_mut() {
159+
if let Some(timestamp) = timestamp {
160+
span_data.end_time = timestamp;
161+
} else if span_data.end_time == span_data.start_time {
162+
span_data.end_time = SystemTime::now();
160163
}
164+
}
165+
166+
// Notify each span processor that the span has ended
167+
if let Some(provider) = self.tracer.provider() {
161168
let mut processors = provider.span_processors().iter().peekable();
162169
while let Some(processor) = processors.next() {
163170
let span_data = if processors.peek().is_none() {
@@ -182,6 +189,13 @@ impl Drop for SpanInner {
182189
}
183190
}
184191

192+
impl Drop for SpanInner {
193+
/// Report span on inner drop
194+
fn drop(&mut self) {
195+
self.ensure_ended_and_exported(None);
196+
}
197+
}
198+
185199
fn build_export_data(
186200
data: SpanData,
187201
span_context: SpanContext,
@@ -374,7 +388,20 @@ mod tests {
374388
}
375389

376390
#[test]
377-
#[ignore = "not yet implemented"]
391+
fn allows_to_get_span_context_after_end() {
392+
let span = create_span();
393+
span.end();
394+
assert_eq!(span.span_context(), &SpanContext::empty_context());
395+
}
396+
397+
#[test]
398+
fn allows_to_get_span_context_after_clone_drop() {
399+
let span = create_span();
400+
drop(span.clone());
401+
assert_eq!(span.span_context(), &SpanContext::empty_context());
402+
}
403+
404+
#[test]
378405
fn end_only_once() {
379406
let span = create_span();
380407
let timestamp = SystemTime::now();
@@ -384,7 +411,6 @@ mod tests {
384411
}
385412

386413
#[test]
387-
#[ignore = "not yet implemented"]
388414
fn noop_after_end() {
389415
let span = create_span();
390416
let initial = span.with_data(|data| data.clone()).unwrap();
@@ -417,7 +443,6 @@ mod tests {
417443
}
418444

419445
#[test]
420-
#[ignore = "not yet implemented"]
421446
fn is_recording_false_after_end() {
422447
let span = create_span();
423448
span.end();

0 commit comments

Comments
 (0)