Skip to content

Commit 74c8e11

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

6 files changed

Lines changed: 203 additions & 14 deletions

File tree

opentelemetry-sdk/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
Miri instead of calling `std::env::current_exe()`, avoiding an abort in Miri
1010
isolation mode while preserving the normal
1111
`unknown_service:<process.executable.name>` fallback outside Miri.
12+
- **Feature**: Add support for `OTEL_SDK_DISABLED` environment variable [#3088][3088]
13+
14+
[3088]: https://github.com/open-telemetry/opentelemetry-rust/pull/3088
1215

1316
## 0.32.1
1417

opentelemetry-sdk/src/logs/logger.rs

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

2631
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 = "already_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_env_variable"
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 {
@@ -295,10 +322,18 @@ impl LoggerProviderBuilder {
295322
processor.set_resource(&resource);
296323
}
297324

325+
let is_disabled =
326+
std::env::var("OTEL_SDK_DISABLED").is_ok_and(|var| var.to_lowercase() == "true");
327+
328+
if is_disabled {
329+
otel_warn!(name: "LoggerProvider.Disabled", message = "SDK is disabled through environment variable");
330+
}
331+
298332
let logger_provider = SdkLoggerProvider {
299333
inner: Arc::new(LoggerProviderInner {
300334
processors,
301335
is_shutdown: AtomicBool::new(false),
336+
is_disabled,
302337
}),
303338
};
304339

@@ -793,6 +828,7 @@ mod tests {
793828
flush_called.clone(),
794829
))],
795830
is_shutdown: AtomicBool::new(false),
831+
is_disabled: false,
796832
});
797833

798834
{
@@ -821,6 +857,32 @@ mod tests {
821857
assert!(!*flush_called.lock().unwrap());
822858
}
823859

860+
#[test]
861+
#[ignore = "modifies OTEL_SDK_DISABLED env var which can affect other test"]
862+
fn otel_sdk_disabled_env() {
863+
temp_env::with_var("OTEL_SDK_DISABLED", Some("true"), || {
864+
let exporter = InMemoryLogExporter::default();
865+
let logger_provider = SdkLoggerProvider::builder()
866+
.with_simple_exporter(exporter.clone())
867+
.build();
868+
let logger = logger_provider.logger("noop");
869+
let mut record = logger.create_log_record();
870+
record.set_body("Testing sdk disabled logger".into());
871+
logger.emit(record);
872+
let mut record = logger.create_log_record();
873+
record.set_body("Testing sdk disabled logger".into());
874+
logger.emit(record);
875+
let mut record = logger.create_log_record();
876+
record.set_body("Testing sdk disabled logger".into());
877+
logger.emit(record);
878+
let emitted_logs = exporter.get_emitted_logs().unwrap();
879+
assert_eq!(emitted_logs.len(), 0);
880+
881+
assert!(logger.provider().shutdown().is_ok());
882+
assert!(logger.provider().shutdown().is_err());
883+
});
884+
}
885+
824886
#[test]
825887
fn drop_after_shutdown_test_with_multiple_providers() {
826888
let shutdown_called = Arc::new(Mutex::new(0)); // Count the number of times shutdown is called
@@ -833,6 +895,7 @@ mod tests {
833895
flush_called.clone(),
834896
))],
835897
is_shutdown: AtomicBool::new(false),
898+
is_disabled: false,
836899
});
837900

838901
// 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 = "already_shutdown"
198+
);
199+
return Meter::new(Arc::new(NoopMeter::new()));
200+
}
201+
if self.inner.is_disabled {
202+
otel_debug!(
203+
name: "MeterProvider.NoOpMeterReturned",
204+
meter_name = scope.name(),
205+
reason = "disabled_via_env_variable"
196206
);
197207
return Meter::new(Arc::new(NoopMeter::new()));
198208
}
@@ -401,6 +411,13 @@ impl MeterProviderBuilder {
401411
builder = format!("{:?}", &self),
402412
);
403413

414+
let is_disabled =
415+
std::env::var("OTEL_SDK_DISABLED").is_ok_and(|var| var.to_lowercase() == "true");
416+
417+
if is_disabled {
418+
otel_warn!(name: "MeterProvider.Disabled", message = "SDK is disabled through environment variable");
419+
}
420+
404421
let meter_provider = SdkMeterProvider {
405422
inner: Arc::new(SdkMeterProviderInner {
406423
pipes: Arc::new(Pipelines::new(
@@ -410,6 +427,7 @@ impl MeterProviderBuilder {
410427
)),
411428
meters: Default::default(),
412429
shutdown_invoked: AtomicBool::new(false),
430+
is_disabled,
413431
}),
414432
};
415433

@@ -778,4 +796,21 @@ mod tests {
778796
);
779797
assert_eq!(resource.schema_url(), Some("http://example.com"));
780798
}
799+
800+
#[test]
801+
#[ignore = "modifies OTEL_SDK_DISABLED env var which can affect other test"]
802+
fn otel_sdk_disabled_env() {
803+
temp_env::with_var("OTEL_SDK_DISABLED", Some("true"), || {
804+
let meter_provider = super::SdkMeterProvider::builder().build();
805+
let _ = meter_provider.meter("noop1");
806+
let _ = meter_provider.meter("noop2");
807+
let _ = meter_provider.meter("noop3");
808+
let _ = meter_provider.meter("noop4");
809+
let _ = meter_provider.meter("noop5");
810+
811+
assert_eq!(meter_provider.inner.meters.lock().unwrap().len(), 0);
812+
assert!(meter_provider.shutdown().is_ok());
813+
assert!(meter_provider.shutdown().is_err());
814+
});
815+
}
781816
}

0 commit comments

Comments
 (0)