Skip to content

Commit 0399473

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

File tree

6 files changed

+201
-14
lines changed

6 files changed

+201
-14
lines changed

opentelemetry-sdk/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## vNext
44

5+
- **Feature**: Add support for `OTEL_SDK_DISABLED` environment variable ([#3088](https://github.com/open-telemetry/opentelemetry-rust/pull/3088))
6+
57
## 0.31.0
68

79
Released 2025-Sep-25

opentelemetry-sdk/src/logs/logger.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ impl SdkLogger {
2222
pub(crate) fn new(scope: InstrumentationScope, provider: SdkLoggerProvider) -> Self {
2323
SdkLogger { scope, provider }
2424
}
25+
26+
#[cfg(test)]
27+
pub(crate) fn provider(&self) -> &SdkLoggerProvider {
28+
&self.provider
29+
}
2530
}
2631

2732
impl opentelemetry::logs::Logger for SdkLogger {

opentelemetry-sdk/src/logs/logger_provider.rs

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{BatchLogProcessor, LogProcessor, SdkLogger, SimpleLogProcessor};
22
use crate::error::{OTelSdkError, OTelSdkResult};
33
use crate::logs::LogExporter;
44
use crate::Resource;
5-
use opentelemetry::{otel_debug, otel_info, InstrumentationScope};
5+
use opentelemetry::{otel_debug, otel_info, otel_warn, InstrumentationScope};
66
use std::time::Duration;
77
use std::{
88
borrow::Cow,
@@ -12,16 +12,32 @@ 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),
25+
is_disabled: false,
26+
}),
27+
})
28+
}
29+
// a no op logger provider used as placeholder when sdk is disabled with
30+
// help of environment variable `OTEL_SDK_DISABLED`
31+
// TODO - replace it with LazyLock once it is stable
32+
static DISABLED_LOGGER_PROVIDER: OnceLock<SdkLoggerProvider> = OnceLock::new();
33+
34+
#[inline]
35+
fn disabled_logger_provider() -> &'static SdkLoggerProvider {
36+
DISABLED_LOGGER_PROVIDER.get_or_init(|| SdkLoggerProvider {
37+
inner: Arc::new(LoggerProviderInner {
38+
processors: Vec::new(),
39+
is_shutdown: AtomicBool::new(false),
40+
is_disabled: true,
2541
}),
2642
})
2743
}
@@ -53,13 +69,23 @@ impl opentelemetry::logs::LoggerProvider for SdkLoggerProvider {
5369
}
5470

5571
fn logger_with_scope(&self, scope: InstrumentationScope) -> Self::Logger {
56-
// If the provider is shutdown, new logger will refer a no-op logger provider.
72+
// If the provider is shutdown, new logger will refer a shutdown no-op logger provider.
5773
if self.inner.is_shutdown.load(Ordering::Relaxed) {
5874
otel_debug!(
5975
name: "LoggerProvider.NoOpLoggerReturned",
6076
logger_name = scope.name(),
77+
reason = "shutdown"
78+
);
79+
return SdkLogger::new(scope, shutdown_logger_provider().clone());
80+
}
81+
// If the provider is disabled, new logger will refer a disabled no-op logger provider.
82+
if self.inner.is_disabled {
83+
otel_debug!(
84+
name: "LoggerProvider.NoOpLoggerReturned",
85+
logger_name = scope.name(),
86+
reason = "disabled via OTEL_SDK_DISABLED env var"
6187
);
62-
return SdkLogger::new(scope, noop_logger_provider().clone());
88+
return SdkLogger::new(scope, disabled_logger_provider().clone());
6389
}
6490
if scope.name().is_empty() {
6591
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.");
@@ -135,6 +161,7 @@ impl SdkLoggerProvider {
135161
struct LoggerProviderInner {
136162
processors: Vec<Box<dyn LogProcessor>>,
137163
is_shutdown: AtomicBool,
164+
is_disabled: bool,
138165
}
139166

140167
impl LoggerProviderInner {
@@ -267,10 +294,18 @@ impl LoggerProviderBuilder {
267294
processor.set_resource(&resource);
268295
}
269296

297+
let is_disabled =
298+
std::env::var("OTEL_SDK_DISABLED").is_ok_and(|var| var.to_lowercase() == "true");
299+
300+
if is_disabled {
301+
otel_warn!(name: "LoggerProvider.Disabled", message = "SDK is disabled through environment variable");
302+
}
303+
270304
let logger_provider = SdkLoggerProvider {
271305
inner: Arc::new(LoggerProviderInner {
272306
processors,
273307
is_shutdown: AtomicBool::new(false),
308+
is_disabled,
274309
}),
275310
};
276311

@@ -753,6 +788,7 @@ mod tests {
753788
flush_called.clone(),
754789
))],
755790
is_shutdown: AtomicBool::new(false),
791+
is_disabled: false,
756792
});
757793

758794
{
@@ -781,6 +817,32 @@ mod tests {
781817
assert!(!*flush_called.lock().unwrap());
782818
}
783819

820+
#[test]
821+
#[ignore = "modifies OTEL_SDK_DISABLED env var which can affect other test"]
822+
fn otel_sdk_disabled_env() {
823+
temp_env::with_var("OTEL_SDK_DISABLED", Some("true"), || {
824+
let exporter = InMemoryLogExporter::default();
825+
let logger_provider = SdkLoggerProvider::builder()
826+
.with_simple_exporter(exporter.clone())
827+
.build();
828+
let logger = logger_provider.logger("noop");
829+
let mut record = logger.create_log_record();
830+
record.set_body("Testing sdk disabled logger".into());
831+
logger.emit(record);
832+
let mut record = logger.create_log_record();
833+
record.set_body("Testing sdk disabled logger".into());
834+
logger.emit(record);
835+
let mut record = logger.create_log_record();
836+
record.set_body("Testing sdk disabled logger".into());
837+
logger.emit(record);
838+
let emitted_logs = exporter.get_emitted_logs().unwrap();
839+
assert_eq!(emitted_logs.len(), 0);
840+
841+
assert!(logger.provider().shutdown().is_ok());
842+
assert!(logger.provider().shutdown().is_err());
843+
});
844+
}
845+
784846
#[test]
785847
fn drop_after_shutdown_test_with_multiple_providers() {
786848
let shutdown_called = Arc::new(Mutex::new(0)); // Count the number of times shutdown is called
@@ -793,6 +855,7 @@ mod tests {
793855
flush_called.clone(),
794856
))],
795857
is_shutdown: AtomicBool::new(false),
858+
is_disabled: false,
796859
});
797860

798861
// Create a scope to test behavior when providers are dropped

opentelemetry-sdk/src/metrics/meter_provider.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::fmt;
22
use opentelemetry::{
33
metrics::{Meter, MeterProvider},
4-
otel_debug, otel_error, otel_info, InstrumentationScope,
4+
otel_debug, otel_error, otel_info, otel_warn, InstrumentationScope,
55
};
66
use std::time::Duration;
77
use std::{
@@ -41,6 +41,7 @@ struct SdkMeterProviderInner {
4141
pipes: Arc<Pipelines>,
4242
meters: Mutex<HashMap<InstrumentationScope, Arc<SdkMeter>>>,
4343
shutdown_invoked: AtomicBool,
44+
is_disabled: bool,
4445
}
4546

4647
impl Default for SdkMeterProvider {
@@ -193,6 +194,15 @@ impl MeterProvider for SdkMeterProvider {
193194
otel_debug!(
194195
name: "MeterProvider.NoOpMeterReturned",
195196
meter_name = scope.name(),
197+
reason = "shutdown"
198+
);
199+
return Meter::new(Arc::new(NoopMeter::new()));
200+
}
201+
if self.inner.is_disabled {
202+
otel_debug!(
203+
name: "MeterProvider.DisabledNoOpMeterReturned",
204+
meter_name = scope.name(),
205+
reason = "disabled via OTEL_SDK_DISABLED env var"
196206
);
197207
return Meter::new(Arc::new(NoopMeter::new()));
198208
}
@@ -379,6 +389,13 @@ impl MeterProviderBuilder {
379389
builder = format!("{:?}", &self),
380390
);
381391

392+
let is_disabled =
393+
std::env::var("OTEL_SDK_DISABLED").is_ok_and(|var| var.to_lowercase() == "true");
394+
395+
if is_disabled {
396+
otel_warn!(name: "MeterProvider.Disabled", message = "SDK is disabled through environment variable");
397+
}
398+
382399
let meter_provider = SdkMeterProvider {
383400
inner: Arc::new(SdkMeterProviderInner {
384401
pipes: Arc::new(Pipelines::new(
@@ -388,6 +405,7 @@ impl MeterProviderBuilder {
388405
)),
389406
meters: Default::default(),
390407
shutdown_invoked: AtomicBool::new(false),
408+
is_disabled,
391409
}),
392410
};
393411

@@ -729,4 +747,21 @@ mod tests {
729747
);
730748
assert_eq!(resource.schema_url(), Some("http://example.com"));
731749
}
750+
751+
#[test]
752+
#[ignore = "modifies OTEL_SDK_DISABLED env var which can affect other test"]
753+
fn otel_sdk_disabled_env() {
754+
temp_env::with_var("OTEL_SDK_DISABLED", Some("true"), || {
755+
let meter_provider = super::SdkMeterProvider::builder().build();
756+
let _ = meter_provider.meter("noop1");
757+
let _ = meter_provider.meter("noop2");
758+
let _ = meter_provider.meter("noop3");
759+
let _ = meter_provider.meter("noop4");
760+
let _ = meter_provider.meter("noop5");
761+
762+
assert_eq!(meter_provider.inner.meters.lock().unwrap().len(), 0);
763+
assert!(meter_provider.shutdown().is_ok());
764+
assert!(meter_provider.shutdown().is_err());
765+
});
766+
}
732767
}

0 commit comments

Comments
 (0)