Skip to content

Commit 3231e09

Browse files
feat: add support for OTEL_SDK_DISABLED environment variable
Signed-off-by: Saurav Sharma <appdroiddeveloper@gmail.com>
1 parent 42139cb commit 3231e09

File tree

4 files changed

+175
-12
lines changed

4 files changed

+175
-12
lines changed

opentelemetry-sdk/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
- *Fix* SpanProcessor::on_start is no longer called on non recording spans
77
- **Fix**: Restore true parallel exports in the async-native `BatchSpanProcessor` by honoring `OTEL_BSP_MAX_CONCURRENT_EXPORTS` ([#2959](https://github.com/open-telemetry/opentelemetry-rust/pull/3028)). A regression in [#2685](https://github.com/open-telemetry/opentelemetry-rust/pull/2685) inadvertently awaited the `export()` future directly in `opentelemetry-sdk/src/trace/span_processor_with_async_runtime.rs` instead of spawning it on the runtime, forcing all exports to run sequentially.
88
- **Feature**: Added `Clone` implementation to `SdkLogger` for API consistency with `SdkTracer` ([#3058](https://github.com/open-telemetry/opentelemetry-rust/issues/3058)).
9+
- **Feature**: Add support for `OTEL_SDK_DISABLED` environment variable ([#3088](https://github.com/open-telemetry/opentelemetry-rust/pull/3088))
10+
911

1012
## 0.30.0
1113

opentelemetry-sdk/src/logs/logger_provider.rs

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,33 @@ use std::{
1212
},
1313
};
1414

15-
// a no nop logger provider used as placeholder when the provider is shutdown
15+
// a no op logger provider used as placeholder when the provider is shutdown
1616
// TODO - replace it with LazyLock once it is stable
17-
static NOOP_LOGGER_PROVIDER: OnceLock<SdkLoggerProvider> = OnceLock::new();
17+
static SHUTDOWN_LOGGER_PROVIDER: OnceLock<SdkLoggerProvider> = OnceLock::new();
1818

1919
#[inline]
20-
fn noop_logger_provider() -> &'static SdkLoggerProvider {
21-
NOOP_LOGGER_PROVIDER.get_or_init(|| SdkLoggerProvider {
20+
fn shutdown_logger_provider() -> &'static SdkLoggerProvider {
21+
SHUTDOWN_LOGGER_PROVIDER.get_or_init(|| SdkLoggerProvider {
2222
inner: Arc::new(LoggerProviderInner {
2323
processors: Vec::new(),
2424
is_shutdown: AtomicBool::new(true),
2525
}),
2626
})
2727
}
28+
// a no op logger provider used as placeholder when sdk is disabled with
29+
// help of environment variable `OTEL_SDK_DISABLED`
30+
// TODO - replace it with LazyLock once it is stable
31+
static DISABLED_LOGGER_PROVIDER: OnceLock<SdkLoggerProvider> = OnceLock::new();
32+
33+
#[inline]
34+
fn disabled_logger_provider() -> &'static SdkLoggerProvider {
35+
DISABLED_LOGGER_PROVIDER.get_or_init(|| SdkLoggerProvider {
36+
inner: Arc::new(LoggerProviderInner {
37+
processors: Vec::new(),
38+
is_shutdown: AtomicBool::new(false),
39+
}),
40+
})
41+
}
2842

2943
#[derive(Debug, Clone)]
3044
/// Handles the creation and coordination of [`Logger`]s.
@@ -53,13 +67,21 @@ impl opentelemetry::logs::LoggerProvider for SdkLoggerProvider {
5367
}
5468

5569
fn logger_with_scope(&self, scope: InstrumentationScope) -> Self::Logger {
56-
// If the provider is shutdown, new logger will refer a no-op logger provider.
70+
// If the provider is shutdown, new logger will refer a shutdown no-op logger provider.
5771
if self.inner.is_shutdown.load(Ordering::Relaxed) {
5872
otel_debug!(
5973
name: "LoggerProvider.NoOpLoggerReturned",
6074
logger_name = scope.name(),
6175
);
62-
return SdkLogger::new(scope, noop_logger_provider().clone());
76+
return SdkLogger::new(scope, shutdown_logger_provider().clone());
77+
}
78+
// If the provider is disabled, new logger will refer a disabled no-op logger provider.
79+
if std::env::var("OTEL_SDK_DISABLED").is_ok_and(|var| var.to_lowercase() == "true") {
80+
otel_debug!(
81+
name: "LoggerProvider.NoOpLoggerReturned",
82+
logger_name = scope.name(),
83+
);
84+
return SdkLogger::new(scope, disabled_logger_provider().clone());
6385
}
6486
if scope.name().is_empty() {
6587
otel_info!(name: "LoggerNameEmpty", message = "Logger name is empty; consider providing a meaningful name. Logger will function normally and the provided name will be used as-is.");
@@ -773,6 +795,47 @@ mod tests {
773795
assert!(!*flush_called.lock().unwrap());
774796
}
775797

798+
#[test]
799+
fn otel_sdk_disabled_env() {
800+
temp_env::with_var("OTEL_SDK_DISABLED", Some("true"), || {
801+
let exporter = InMemoryLogExporter::default();
802+
let logger_provider = SdkLoggerProvider::builder()
803+
.with_simple_exporter(exporter.clone())
804+
.build();
805+
let logger = logger_provider.logger("noop");
806+
let mut record = logger.create_log_record();
807+
record.set_body("Testing sdk disabled logger".into());
808+
logger.emit(record);
809+
let mut record = logger.create_log_record();
810+
record.set_body("Testing sdk disabled logger".into());
811+
logger.emit(record);
812+
let mut record = logger.create_log_record();
813+
record.set_body("Testing sdk disabled logger".into());
814+
logger.emit(record);
815+
let emitted_logs = exporter.get_emitted_logs().unwrap();
816+
assert_eq!(emitted_logs.len(), 0);
817+
});
818+
819+
temp_env::with_var("OTEL_SDK_DISABLED", Some("false"), || {
820+
let exporter = InMemoryLogExporter::default();
821+
let logger_provider = SdkLoggerProvider::builder()
822+
.with_simple_exporter(exporter.clone())
823+
.build();
824+
let logger = logger_provider.logger("noop");
825+
let mut record = logger.create_log_record();
826+
record.set_body("Testing sdk disabled logger".into());
827+
logger.emit(record);
828+
let mut record = logger.create_log_record();
829+
record.set_body("Testing sdk disabled logger".into());
830+
logger.emit(record);
831+
let mut record = logger.create_log_record();
832+
record.set_body("Testing sdk disabled logger".into());
833+
logger.emit(record);
834+
let emitted_logs = exporter.get_emitted_logs().unwrap();
835+
assert_eq!(emitted_logs.len(), 3);
836+
});
837+
}
838+
776839
#[test]
777840
fn drop_after_shutdown_test_with_multiple_providers() {
778841
let shutdown_called = Arc::new(Mutex::new(0)); // Count the number of times shutdown is called

opentelemetry-sdk/src/metrics/meter_provider.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,9 @@ impl MeterProvider for SdkMeterProvider {
189189
}
190190

191191
fn meter_with_scope(&self, scope: InstrumentationScope) -> Meter {
192-
if self.inner.shutdown_invoked.load(Ordering::Relaxed) {
192+
if self.inner.shutdown_invoked.load(Ordering::Relaxed)
193+
|| std::env::var("OTEL_SDK_DISABLED").is_ok_and(|var| var.to_lowercase() == "true")
194+
{
193195
otel_debug!(
194196
name: "MeterProvider.NoOpMeterReturned",
195197
meter_name = scope.name(),
@@ -729,4 +731,29 @@ mod tests {
729731
);
730732
assert_eq!(resource.schema_url(), Some("http://example.com"));
731733
}
734+
735+
#[test]
736+
fn otel_sdk_disabled_env() {
737+
temp_env::with_var("OTEL_SDK_DISABLED", Some("true"), || {
738+
let meter_provider = super::SdkMeterProvider::builder().build();
739+
let _ = meter_provider.meter("noop1");
740+
let _ = meter_provider.meter("noop2");
741+
let _ = meter_provider.meter("noop3");
742+
let _ = meter_provider.meter("noop4");
743+
let _ = meter_provider.meter("noop5");
744+
745+
assert_eq!(meter_provider.inner.meters.lock().unwrap().len(), 0);
746+
});
747+
748+
temp_env::with_var("OTEL_SDK_DISABLED", Some("false"), || {
749+
let meter_provider = super::SdkMeterProvider::builder().build();
750+
let _ = meter_provider.meter("noop1");
751+
let _ = meter_provider.meter("noop2");
752+
let _ = meter_provider.meter("noop3");
753+
let _ = meter_provider.meter("noop4");
754+
let _ = meter_provider.meter("noop5");
755+
756+
assert_eq!(meter_provider.inner.meters.lock().unwrap().len(), 5);
757+
});
758+
}
732759
}

opentelemetry-sdk/src/trace/provider.rs

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,12 @@ use std::time::Duration;
7979

8080
static PROVIDER_RESOURCE: OnceLock<Resource> = OnceLock::new();
8181

82-
// a no nop tracer provider used as placeholder when the provider is shutdown
82+
// a no op tracer provider used as placeholder when the provider is shutdown
8383
// TODO Replace with LazyLock once it is stable
84-
static NOOP_TRACER_PROVIDER: OnceLock<SdkTracerProvider> = OnceLock::new();
84+
static SHUTDOWN_TRACER_PROVIDER: OnceLock<SdkTracerProvider> = OnceLock::new();
8585
#[inline]
86-
fn noop_tracer_provider() -> &'static SdkTracerProvider {
87-
NOOP_TRACER_PROVIDER.get_or_init(|| {
86+
fn shutdown_tracer_provider() -> &'static SdkTracerProvider {
87+
SHUTDOWN_TRACER_PROVIDER.get_or_init(|| {
8888
SdkTracerProvider {
8989
inner: Arc::new(TracerProviderInner {
9090
processors: Vec::new(),
@@ -101,6 +101,29 @@ fn noop_tracer_provider() -> &'static SdkTracerProvider {
101101
})
102102
}
103103

104+
// a no op tracer provider used as placeholder when sdk is disabled with
105+
// help of environment variable `OTEL_SDK_DISABLED`
106+
// TODO Replace with LazyLock once it is stable
107+
static DISABLED_TRACER_PROVIDER: OnceLock<SdkTracerProvider> = OnceLock::new();
108+
#[inline]
109+
fn disabled_tracer_provider() -> &'static SdkTracerProvider {
110+
DISABLED_TRACER_PROVIDER.get_or_init(|| {
111+
SdkTracerProvider {
112+
inner: Arc::new(TracerProviderInner {
113+
processors: Vec::new(),
114+
config: Config {
115+
// cannot use default here as the default resource is not empty
116+
sampler: Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn))),
117+
id_generator: Box::<RandomIdGenerator>::default(),
118+
span_limits: SpanLimits::default(),
119+
resource: Cow::Owned(Resource::empty()),
120+
},
121+
is_shutdown: AtomicBool::new(false),
122+
}),
123+
}
124+
})
125+
}
126+
104127
/// TracerProvider inner type
105128
#[derive(Debug)]
106129
pub(crate) struct TracerProviderInner {
@@ -286,7 +309,10 @@ impl opentelemetry::trace::TracerProvider for SdkTracerProvider {
286309

287310
fn tracer_with_scope(&self, scope: InstrumentationScope) -> Self::Tracer {
288311
if self.inner.is_shutdown.load(Ordering::Relaxed) {
289-
return SdkTracer::new(scope, noop_tracer_provider().clone());
312+
return SdkTracer::new(scope, shutdown_tracer_provider().clone());
313+
}
314+
if std::env::var("OTEL_SDK_DISABLED").is_ok_and(|var| var.to_lowercase() == "true") {
315+
return SdkTracer::new(scope, disabled_tracer_provider().clone());
290316
}
291317
if scope.name().is_empty() {
292318
otel_info!(name: "TracerNameEmpty", message = "Tracer name is empty; consider providing a meaningful name. Tracer will function normally and the provided name will be used as-is.");
@@ -740,6 +766,51 @@ mod tests {
740766
assert!(test_tracer_1.provider().is_shutdown());
741767
}
742768

769+
#[test]
770+
fn otel_sdk_disabled_env() {
771+
temp_env::with_var("OTEL_SDK_DISABLED", Some("true"), || {
772+
let processor = TestSpanProcessor::new(false);
773+
let assert_handle = processor.assert_info();
774+
let tracer_provider = super::SdkTracerProvider::new(TracerProviderInner {
775+
processors: vec![Box::from(processor)],
776+
config: Default::default(),
777+
is_shutdown: AtomicBool::new(false),
778+
});
779+
780+
assert!(assert_handle.started_span_count(0));
781+
let noop_tracer = tracer_provider.tracer("noop");
782+
783+
// noop tracer cannot start anything
784+
let _ = noop_tracer.start("test");
785+
let _ = noop_tracer.start("test2");
786+
let _ = noop_tracer.start("test3");
787+
assert!(assert_handle.started_span_count(0));
788+
789+
// noop tracer should have 0 processor
790+
assert_eq!(noop_tracer.provider().span_processors().len(), 0)
791+
});
792+
793+
temp_env::with_var("OTEL_SDK_DISABLED", Some("false"), || {
794+
let processor = TestSpanProcessor::new(false);
795+
let assert_handle = processor.assert_info();
796+
let tracer_provider = super::SdkTracerProvider::new(TracerProviderInner {
797+
processors: vec![Box::from(processor)],
798+
config: Default::default(),
799+
is_shutdown: AtomicBool::new(false),
800+
});
801+
802+
assert!(assert_handle.started_span_count(0));
803+
let noop_tracer = tracer_provider.tracer("noop");
804+
805+
let _ = noop_tracer.start("test");
806+
let _ = noop_tracer.start("test1");
807+
let _ = noop_tracer.start("test2");
808+
assert!(assert_handle.started_span_count(3));
809+
810+
assert_eq!(noop_tracer.provider().span_processors().len(), 1)
811+
});
812+
}
813+
743814
#[test]
744815
fn with_resource_multiple_calls_ensure_additive() {
745816
let resource = SdkTracerProvider::builder()

0 commit comments

Comments
 (0)