Skip to content

Commit 0d7d1ab

Browse files
committed
fix unit test
1 parent 36012dc commit 0d7d1ab

File tree

2 files changed

+120
-58
lines changed

2 files changed

+120
-58
lines changed

opentelemetry-sdk/src/trace/provider.rs

Lines changed: 118 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616
/// The `TracerProvider` is designed to be lightweight and clonable. Cloning a `TracerProvider`
1717
/// creates a new reference to the same provider, not a new instance. Dropping the last reference
1818
/// to the `TracerProvider` will automatically trigger its shutdown. During shutdown, the provider
19-
/// will flush all remaining spans for **batch processors**, ensuring they are exported to the configured
20-
/// exporters. However, **simple processors** do not require a flush, as they export spans immediately
21-
/// when they end. Users can also manually trigger shutdown using the [`shutdown`](TracerProvider::shutdown)
22-
/// method, which will ensure the same behavior (flushing for batch processors, but no additional action
23-
/// for simple processors).
19+
/// will flush all remaining spans, ensuring they are exported to the configured exporters.
20+
/// Users can also manually trigger shutdown using the [`shutdown`](TracerProvider::shutdown)
21+
/// method, which will ensure the same behavior.
2422
///
2523
/// Once shut down, the `TracerProvider` transitions into a disabled state. In this state, further
2624
/// operations on its associated `Tracer` instances will result in no-ops, ensuring that no spans
@@ -31,15 +29,14 @@
3129
/// The `TracerProvider` manages the lifecycle of span processors, which are responsible for
3230
/// collecting, processing, and exporting spans. To ensure all spans are processed before shutdown,
3331
/// users can call the [`force_flush`](TracerProvider::force_flush) method at any time to trigger
34-
/// an immediate flush of all pending spans for **batch processors** to the exporters. Note that
35-
/// calling [`force_flush`](TracerProvider::force_flush) is optional before shutdown, as `shutdown`
36-
/// will automatically trigger a flush for batch processors, but not for simple processors.
32+
/// an immediate flush of all pending spans to the exporters.
3733
///
3834
/// # Examples
3935
///
4036
/// ```
4137
/// use opentelemetry::global;
4238
/// use opentelemetry_sdk::trace::TracerProvider;
39+
/// use opentelemetry::trace::Tracer;
4340
///
4441
/// fn init_tracing() -> TracerProvider {
4542
/// let provider = TracerProvider::default();
@@ -53,19 +50,16 @@
5350
/// fn main() {
5451
/// let provider = init_tracing();
5552
///
56-
/// // create spans...
53+
/// // create tracer..
54+
/// let tracer = global::tracer("example/client");
5755
///
58-
/// // Flush all spans before shutdown (optional for batch processors)
59-
/// for result in provider.force_flush() {
60-
/// if let Err(err) = result {
61-
/// // Handle flush error...
62-
/// }
63-
/// }
56+
/// // create span...
57+
/// let span = tracer
58+
/// .span_builder("test_span")
59+
/// .start(&tracer);
6460
///
65-
/// // Dropping the provider ensures remaining spans are flushed for batch processors
66-
/// // and shuts down the global tracer provider.
67-
/// drop(provider);
68-
/// global::shutdown_tracer_provider();
61+
/// // Explicitly shut down the provider
62+
/// provider.shutdown();
6963
/// }
7064
/// ```
7165
use crate::runtime::RuntimeChannel;
@@ -249,7 +243,7 @@ impl TracerProvider {
249243
Err(TraceError::Other(format!("{errs:?}").into()))
250244
}
251245
} else {
252-
Err(TraceError::AlreadyShutdown("TracerProvider".to_string()))
246+
Err(TraceError::AlreadyShutdown)
253247
}
254248
}
255249
}
@@ -391,6 +385,7 @@ mod tests {
391385
use std::env;
392386
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
393387
use std::sync::Arc;
388+
use std::sync::Mutex;
394389

395390
// fields below is wrapped with Arc so we can assert it
396391
#[derive(Default, Debug)]
@@ -648,57 +643,124 @@ mod tests {
648643
assert!(assert_handle.started_span_count(2));
649644
}
650645

646+
#[derive(Debug)]
647+
struct CountingShutdownProcessor {
648+
shutdown_count: Arc<Mutex<i32>>,
649+
flush_called: Arc<Mutex<bool>>,
650+
}
651+
652+
impl CountingShutdownProcessor {
653+
fn new(shutdown_count: Arc<Mutex<i32>>, flush_called: Arc<Mutex<bool>>) -> Self {
654+
CountingShutdownProcessor {
655+
shutdown_count,
656+
flush_called,
657+
}
658+
}
659+
}
660+
661+
impl SpanProcessor for CountingShutdownProcessor {
662+
fn on_start(&self, _span: &mut Span, _cx: &Context) {
663+
// No operation needed for this processor
664+
}
665+
666+
fn on_end(&self, _span: SpanData) {
667+
// No operation needed for this processor
668+
}
669+
670+
fn force_flush(&self) -> TraceResult<()> {
671+
*self.flush_called.lock().unwrap() = true;
672+
Ok(())
673+
}
674+
675+
fn shutdown(&self) -> TraceResult<()> {
676+
let mut count = self.shutdown_count.lock().unwrap();
677+
*count += 1;
678+
Ok(())
679+
}
680+
}
681+
651682
#[test]
652-
fn test_tracer_provider_inner_drop_shutdown() {
653-
// Test 1: Already shutdown case
683+
fn drop_test_with_multiple_providers() {
684+
let shutdown_called = Arc::new(Mutex::new(0));
685+
let flush_called = Arc::new(Mutex::new(false));
686+
654687
{
655-
let processor = TestSpanProcessor::new(true);
656-
let assert_handle = processor.assert_info();
657-
let provider = super::TracerProvider::new(TracerProviderInner {
658-
processors: vec![Box::from(processor)],
659-
config: Default::default(),
688+
// Create a shared TracerProviderInner and use it across multiple providers
689+
let shared_inner = Arc::new(TracerProviderInner {
690+
processors: vec![Box::new(CountingShutdownProcessor::new(
691+
shutdown_called.clone(),
692+
flush_called.clone(),
693+
))],
694+
config: Config::default(),
660695
is_shutdown: AtomicBool::new(false),
661696
});
662697

663-
// Create multiple providers sharing same inner
664-
let provider2 = provider.clone();
665-
let provider3 = provider.clone();
698+
{
699+
let tracer_provider1 = super::TracerProvider {
700+
inner: shared_inner.clone(),
701+
};
702+
let tracer_provider2 = super::TracerProvider {
703+
inner: shared_inner.clone(),
704+
};
666705

667-
// Shutdown explicitly first
668-
assert!(provider.shutdown().is_ok());
706+
let tracer1 = tracer_provider1.tracer("test-tracer1");
707+
let tracer2 = tracer_provider2.tracer("test-tracer2");
669708

670-
// Drop all providers - should not trigger another shutdown in TracerProviderInner::drop
671-
drop(provider);
672-
drop(provider2);
673-
drop(provider3);
709+
let _span1 = tracer1.start("span1");
710+
let _span2 = tracer2.start("span2");
674711

675-
// Verify shutdown was called exactly once
676-
assert!(assert_handle.0.is_shutdown.load(Ordering::SeqCst));
712+
// TracerProviderInner should not be dropped yet, since both providers and `shared_inner`
713+
// are still holding a reference.
714+
}
715+
// At this point, both `tracer_provider1` and `tracer_provider2` are dropped,
716+
// but `shared_inner` still holds a reference, so `TracerProviderInner` is NOT dropped yet.
717+
assert_eq!(*shutdown_called.lock().unwrap(), 0);
677718
}
719+
// Verify shutdown was called during the drop of the shared TracerProviderInner
720+
assert_eq!(*shutdown_called.lock().unwrap(), 1);
721+
// Verify flush was not called during drop
722+
assert!(!*flush_called.lock().unwrap());
723+
}
678724

679-
// Test 2: Not shutdown case
725+
#[test]
726+
fn drop_after_shutdown_test_with_multiple_providers() {
727+
let shutdown_called = Arc::new(Mutex::new(0)); // Count the number of times shutdown is called
728+
let flush_called = Arc::new(Mutex::new(false));
729+
730+
// Create a shared TracerProviderInner and use it across multiple providers
731+
let shared_inner = Arc::new(TracerProviderInner {
732+
processors: vec![Box::new(CountingShutdownProcessor::new(
733+
shutdown_called.clone(),
734+
flush_called.clone(),
735+
))],
736+
config: Config::default(),
737+
is_shutdown: AtomicBool::new(false),
738+
});
739+
740+
// Create a scope to test behavior when providers are dropped
680741
{
681-
let processor = TestSpanProcessor::new(true);
682-
let assert_handle = processor.assert_info();
683-
let provider = super::TracerProvider::new(TracerProviderInner {
684-
processors: vec![Box::from(processor)],
685-
config: Default::default(),
686-
is_shutdown: AtomicBool::new(false),
687-
});
742+
let tracer_provider1 = super::TracerProvider {
743+
inner: shared_inner.clone(),
744+
};
745+
let tracer_provider2 = super::TracerProvider {
746+
inner: shared_inner.clone(),
747+
};
688748

689-
// Create multiple providers sharing same inner
690-
let provider2 = provider.clone();
691-
let provider3 = provider.clone();
749+
// Explicitly shut down the tracer provider
750+
let shutdown_result = tracer_provider1.shutdown();
751+
assert!(shutdown_result.is_ok());
692752

693-
// Drop providers without explicit shutdown
694-
drop(provider);
695-
drop(provider2);
753+
// Verify that shutdown was called exactly once
754+
assert_eq!(*shutdown_called.lock().unwrap(), 1);
696755

697-
// Last drop should trigger shutdown in TracerProviderInner::drop
698-
drop(provider3);
756+
// TracerProvider2 should observe the shutdown state but not trigger another shutdown
757+
let shutdown_result2 = tracer_provider2.shutdown();
758+
assert!(shutdown_result2.is_err());
699759

700-
// Verify shutdown was called exactly once
701-
assert!(assert_handle.0.is_shutdown.load(Ordering::SeqCst));
760+
// Both tracer providers will be dropped at the end of this scope
702761
}
762+
763+
// Verify that shutdown was only called once, even after drop
764+
assert_eq!(*shutdown_called.lock().unwrap(), 1);
703765
}
704766
}

opentelemetry/src/trace/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ pub enum TraceError {
201201
ExportTimedOut(time::Duration),
202202

203203
/// already shutdown error
204-
#[error("{0} already shutdown")]
205-
AlreadyShutdown(String),
204+
#[error("TracerProvider already shutdown")]
205+
AlreadyShutdown,
206206

207207
/// Other errors propagated from trace SDK that weren't covered above
208208
#[error(transparent)]

0 commit comments

Comments
 (0)