@@ -2,7 +2,7 @@ use super::{BatchLogProcessor, LogProcessor, SdkLogger, SimpleLogProcessor};
22use crate :: error:: { OTelSdkError , OTelSdkResult } ;
33use crate :: logs:: LogExporter ;
44use crate :: Resource ;
5- use opentelemetry:: { otel_debug, otel_info, InstrumentationScope } ;
5+ use opentelemetry:: { otel_debug, otel_info, otel_warn , InstrumentationScope } ;
66use std:: time:: Duration ;
77use 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 {
135161struct LoggerProviderInner {
136162 processors : Vec < Box < dyn LogProcessor > > ,
137163 is_shutdown : AtomicBool ,
164+ is_disabled : bool ,
138165}
139166
140167impl 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
0 commit comments