1616from  __future__ import  annotations 
1717
1818import  logging 
19+ import  logging .config 
1920from  logging  import  WARNING , getLogger 
2021from  os  import  environ 
2122from  typing  import  Iterable , Optional , Sequence 
@@ -641,62 +642,65 @@ def tearDown(self):
641642        ]
642643
643644    def  test_logging_init_empty (self ):
644-         auto_resource  =  Resource .create (
645-             {
646-                 "telemetry.auto.version" : "auto-version" ,
647-             }
648-         )
649-         _init_logging ({}, resource = auto_resource )
650-         self .assertEqual (self .set_provider_mock .call_count , 1 )
651-         provider  =  self .set_provider_mock .call_args [0 ][0 ]
652-         self .assertIsInstance (provider , DummyLoggerProvider )
653-         self .assertIsInstance (provider .resource , Resource )
654-         self .assertEqual (
655-             provider .resource .attributes .get ("telemetry.auto.version" ),
656-             "auto-version" ,
657-         )
658-         self .event_logger_provider_mock .assert_called_once_with (
659-             logger_provider = provider 
660-         )
661-         self .set_event_logger_provider_mock .assert_called_once_with (
662-             self .event_logger_provider_instance_mock 
663-         )
645+         with  ResetGlobalLoggingState ():
646+             auto_resource  =  Resource .create (
647+                 {
648+                     "telemetry.auto.version" : "auto-version" ,
649+                 }
650+             )
651+             _init_logging ({}, resource = auto_resource )
652+             self .assertEqual (self .set_provider_mock .call_count , 1 )
653+             provider  =  self .set_provider_mock .call_args [0 ][0 ]
654+             self .assertIsInstance (provider , DummyLoggerProvider )
655+             self .assertIsInstance (provider .resource , Resource )
656+             self .assertEqual (
657+                 provider .resource .attributes .get ("telemetry.auto.version" ),
658+                 "auto-version" ,
659+             )
660+             self .event_logger_provider_mock .assert_called_once_with (
661+                 logger_provider = provider 
662+             )
663+             self .set_event_logger_provider_mock .assert_called_once_with (
664+                 self .event_logger_provider_instance_mock 
665+             )
664666
665667    @patch .dict ( 
666668        environ , 
667669        {"OTEL_RESOURCE_ATTRIBUTES" : "service.name=otlp-service" }, 
668670    ) 
669671    def  test_logging_init_exporter (self ):
670-         resource  =  Resource .create ({})
671-         _init_logging ({"otlp" : DummyOTLPLogExporter }, resource = resource )
672-         self .assertEqual (self .set_provider_mock .call_count , 1 )
673-         provider  =  self .set_provider_mock .call_args [0 ][0 ]
674-         self .assertIsInstance (provider , DummyLoggerProvider )
675-         self .assertIsInstance (provider .resource , Resource )
676-         self .assertEqual (
677-             provider .resource .attributes .get ("service.name" ),
678-             "otlp-service" ,
679-         )
680-         self .assertIsInstance (provider .processor , DummyLogRecordProcessor )
681-         self .assertIsInstance (
682-             provider .processor .exporter , DummyOTLPLogExporter 
683-         )
684-         getLogger (__name__ ).error ("hello" )
685-         self .assertTrue (provider .processor .exporter .export_called )
672+         with  ResetGlobalLoggingState ():
673+             resource  =  Resource .create ({})
674+             _init_logging ({"otlp" : DummyOTLPLogExporter }, resource = resource )
675+             self .assertEqual (self .set_provider_mock .call_count , 1 )
676+             provider  =  self .set_provider_mock .call_args [0 ][0 ]
677+             self .assertIsInstance (provider , DummyLoggerProvider )
678+             self .assertIsInstance (provider .resource , Resource )
679+             self .assertEqual (
680+                 provider .resource .attributes .get ("service.name" ),
681+                 "otlp-service" ,
682+             )
683+             self .assertIsInstance (provider .processor , DummyLogRecordProcessor )
684+             self .assertIsInstance (
685+                 provider .processor .exporter , DummyOTLPLogExporter 
686+             )
687+             getLogger (__name__ ).error ("hello" )
688+             self .assertTrue (provider .processor .exporter .export_called )
686689
687690    def  test_logging_init_exporter_uses_exporter_args_map (self ):
688-         resource  =  Resource .create ({})
689-         _init_logging (
690-             {"otlp" : DummyOTLPLogExporter },
691-             resource = resource ,
692-             exporter_args_map = {
693-                 DummyOTLPLogExporter : {"compression" : "gzip" },
694-                 DummyOTLPMetricExporter : {"compression" : "no" },
695-             },
696-         )
697-         self .assertEqual (self .set_provider_mock .call_count , 1 )
698-         provider  =  self .set_provider_mock .call_args [0 ][0 ]
699-         self .assertEqual (provider .processor .exporter .compression , "gzip" )
691+         with  ResetGlobalLoggingState ():
692+             resource  =  Resource .create ({})
693+             _init_logging (
694+                 {"otlp" : DummyOTLPLogExporter },
695+                 resource = resource ,
696+                 exporter_args_map = {
697+                     DummyOTLPLogExporter : {"compression" : "gzip" },
698+                     DummyOTLPMetricExporter : {"compression" : "no" },
699+                 },
700+             )
701+             self .assertEqual (self .set_provider_mock .call_count , 1 )
702+             provider  =  self .set_provider_mock .call_args [0 ][0 ]
703+             self .assertEqual (provider .processor .exporter .compression , "gzip" )
700704
701705    @patch .dict ( 
702706        environ , 
@@ -883,7 +887,7 @@ def test_initialize_components_kwargs(
883887        )
884888
885889    def  test_basicConfig_works_with_otel_handler (self ):
886-         with  ClearLoggingHandlers ():
890+         with  ResetGlobalLoggingState ():
887891            _init_logging (
888892                {"otlp" : DummyOTLPLogExporter },
889893                Resource .create ({}),
@@ -905,7 +909,7 @@ def test_basicConfig_works_with_otel_handler(self):
905909            )
906910
907911    def  test_basicConfig_preserves_otel_handler (self ):
908-         with  ClearLoggingHandlers ():
912+         with  ResetGlobalLoggingState ():
909913            _init_logging (
910914                {"otlp" : DummyOTLPLogExporter },
911915                Resource .create ({}),
@@ -920,7 +924,6 @@ def test_basicConfig_preserves_otel_handler(self):
920924            )
921925            handler  =  root_logger .handlers [0 ]
922926            self .assertIsInstance (handler , LoggingHandler )
923- 
924927            logging .basicConfig ()
925928
926929            self .assertGreater (len (root_logger .handlers ), 1 )
@@ -936,6 +939,49 @@ def test_basicConfig_preserves_otel_handler(self):
936939                "Should still have exactly one OpenTelemetry LoggingHandler" ,
937940            )
938941
942+     def  test_dictConfig_preserves_otel_handler (self ):
943+         with  ResetGlobalLoggingState ():
944+             _init_logging (
945+                 {"otlp" : DummyOTLPLogExporter },
946+                 Resource .create ({}),
947+                 setup_logging_handler = True ,
948+             )
949+ 
950+             root  =  logging .getLogger ()
951+             self .assertEqual (
952+                 len (root .handlers ),
953+                 1 ,
954+                 "Should be exactly one OpenTelemetry LoggingHandler" ,
955+             )
956+             logging .config .dictConfig (
957+                 {
958+                     "version" : 1 ,
959+                     "disable_existing_loggers" : False ,  # If this is True all loggers are disabled. Many unit tests assert loggers emit logs. 
960+                     "handlers" : {
961+                         "console" : {
962+                             "class" : "logging.StreamHandler" ,
963+                             "level" : "DEBUG" ,
964+                             "stream" : "ext://sys.stdout" ,
965+                         },
966+                     },
967+                     "loggers" : {
968+                         "" : {  # root logger 
969+                             "handlers" : ["console" ],
970+                         },
971+                     },
972+                 }
973+             )
974+             self .assertEqual (len (root .handlers ), 2 )
975+ 
976+             logging_handlers  =  [
977+                 h  for  h  in  root .handlers  if  isinstance (h , LoggingHandler )
978+             ]
979+             self .assertEqual (
980+                 len (logging_handlers ),
981+                 1 ,
982+                 "Should still have exactly one OpenTelemetry LoggingHandler" ,
983+             )
984+ 
939985
940986class  TestMetricsInit (TestCase ):
941987    def  setUp (self ):
@@ -1187,8 +1233,14 @@ def test_custom_configurator(self, mock_init_comp):
11871233        mock_init_comp .assert_called_once_with (** kwargs )
11881234
11891235
1190- class  ClearLoggingHandlers :
1236+ # Any test that calls _init_logging with setup_logging_handler=True 
1237+ # should call _init_logging within this context manager, to 
1238+ # ensure the global logging state is reset after the test. 
1239+ class  ResetGlobalLoggingState :
11911240    def  __init__ (self ):
1241+         self .original_basic_config  =  logging .basicConfig 
1242+         self .original_dict_config  =  logging .config .dictConfig 
1243+         self .original_file_config  =  logging .config .fileConfig 
11921244        self .root_logger  =  getLogger ()
11931245        self .original_handlers  =  None 
11941246
@@ -1201,6 +1253,9 @@ def __exit__(self, exc_type, exc_val, exc_tb):
12011253        self .root_logger .handlers  =  []
12021254        for  handler  in  self .original_handlers :
12031255            self .root_logger .addHandler (handler )
1256+         logging .basicConfig  =  self .original_basic_config 
1257+         logging .config .dictConfig  =  self .original_dict_config 
1258+         logging .config .fileConfig  =  self .original_file_config 
12041259
12051260
12061261class  TestClearLoggingHandlers (TestCase ):
@@ -1212,7 +1267,7 @@ def test_preserves_handlers(self):
12121267        root_logger .addHandler (test_handler )
12131268        expected_handlers  =  initial_handlers  +  [test_handler ]
12141269
1215-         with  ClearLoggingHandlers ():
1270+         with  ResetGlobalLoggingState ():
12161271            self .assertEqual (len (root_logger .handlers ), 0 )
12171272            temp_handler  =  logging .StreamHandler ()
12181273            root_logger .addHandler (temp_handler )
@@ -1222,3 +1277,15 @@ def test_preserves_handlers(self):
12221277            self .assertIs (h1 , h2 )
12231278
12241279        root_logger .removeHandler (test_handler )
1280+ 
1281+     def  test_preserves_original_logging_fns (self ):
1282+         def  f (x ):
1283+             print ("f" )
1284+ 
1285+         with  ResetGlobalLoggingState ():
1286+             logging .basicConfig  =  f 
1287+             logging .config .dictConfig  =  f 
1288+             logging .config .fileConfig  =  f 
1289+         self .assertEqual (logging .config .dictConfig .__name__ , "dictConfig" )
1290+         self .assertEqual (logging .basicConfig .__name__ , "basicConfig" )
1291+         self .assertEqual (logging .config .fileConfig .__name__ , "fileConfig" )
0 commit comments