3838
3939# pylint: disable=too-many-public-methods
4040class TestLoggingHandler (unittest .TestCase ):
41+ def test_warns_when_used (self ):
42+ with self .assertWarnsRegex (
43+ DeprecationWarning ,
44+ "`LoggingHandler` in `opentelemetry-sdk` is deprecated" ,
45+ ):
46+ LoggingHandler ()
47+
4148 def test_handler_default_log_level (self ):
42- processor , logger = set_up_test_logging (logging .NOTSET )
49+ processor , logger , handler = set_up_test_logging (logging .NOTSET )
4350
4451 # Make sure debug messages are ignored by default
4552 logger .debug ("Debug message" )
@@ -50,8 +57,10 @@ def test_handler_default_log_level(self):
5057 logger .warning ("Warning message" )
5158 self .assertEqual (processor .emit_count (), 1 )
5259
60+ logger .removeHandler (handler )
61+
5362 def test_handler_custom_log_level (self ):
54- processor , logger = set_up_test_logging (logging .ERROR )
63+ processor , logger , handler = set_up_test_logging (logging .ERROR )
5564
5665 with self .assertLogs (level = logging .WARNING ):
5766 logger .warning ("Warning message test custom log level" )
@@ -64,6 +73,8 @@ def test_handler_custom_log_level(self):
6473 logger .critical ("No Time For Caution" )
6574 self .assertEqual (processor .emit_count (), 2 )
6675
76+ logger .removeHandler (handler )
77+
6778 # pylint: disable=protected-access
6879 def test_log_record_emit_noop (self ):
6980 noop_logger_provder = NoOpLoggerProvider ()
@@ -78,9 +89,10 @@ def test_log_record_emit_noop(self):
7889 with self .assertLogs (level = logging .WARNING ):
7990 logger .warning ("Warning message" )
8091
92+ logger .removeHandler (handler_mock )
93+
8194 def test_log_flush_noop (self ):
8295 no_op_logger_provider = NoOpLoggerProvider ()
83- no_op_logger_provider .force_flush = Mock ()
8496
8597 logger = logging .getLogger ("foo" )
8698 handler = LoggingHandler (
@@ -91,11 +103,19 @@ def test_log_flush_noop(self):
91103 with self .assertLogs (level = logging .WARNING ):
92104 logger .warning ("Warning message" )
93105
94- logger .handlers [0 ].flush ()
95- no_op_logger_provider .force_flush .assert_not_called ()
106+ # the LoggingHandler flush method will call the force_flush method of LoggerProvider in
107+ # a separate thread if present. NoOpLoggerProvider is not supposed to have that
108+ with patch (
109+ "opentelemetry.sdk._logs._internal.threading"
110+ ) as threading_mock :
111+ logger .handlers [0 ].flush ()
112+
113+ threading_mock .Thread .assert_not_called ()
114+
115+ logger .removeHandler (handler )
96116
97117 def test_log_record_no_span_context (self ):
98- processor , logger = set_up_test_logging (logging .WARNING )
118+ processor , logger , handler = set_up_test_logging (logging .WARNING )
99119
100120 # Assert emit gets called for warning message
101121 with self .assertLogs (level = logging .WARNING ):
@@ -115,18 +135,22 @@ def test_log_record_no_span_context(self):
115135 INVALID_SPAN_CONTEXT .trace_flags ,
116136 )
117137
138+ logger .removeHandler (handler )
139+
118140 def test_log_record_observed_timestamp (self ):
119- processor , logger = set_up_test_logging (logging .WARNING )
141+ processor , logger , handler = set_up_test_logging (logging .WARNING )
120142
121143 with self .assertLogs (level = logging .WARNING ):
122144 logger .warning ("Warning message" )
123145
124146 record = processor .get_log_record (0 )
125147 self .assertIsNotNone (record .log_record .observed_timestamp )
126148
149+ logger .removeHandler (handler )
150+
127151 def test_log_record_user_attributes (self ):
128152 """Attributes can be injected into logs by adding them to the ReadWriteLogRecord"""
129- processor , logger = set_up_test_logging (logging .WARNING )
153+ processor , logger , handler = set_up_test_logging (logging .WARNING )
130154
131155 # Assert emit gets called for warning message
132156 with self .assertLogs (level = logging .WARNING ):
@@ -155,9 +179,11 @@ def test_log_record_user_attributes(self):
155179 isinstance (record .log_record .attributes , BoundedAttributes )
156180 )
157181
182+ logger .removeHandler (handler )
183+
158184 def test_log_record_exception (self ):
159185 """Exception information will be included in attributes"""
160- processor , logger = set_up_test_logging (logging .ERROR )
186+ processor , logger , handler = set_up_test_logging (logging .ERROR )
161187
162188 try :
163189 raise ZeroDivisionError ("division by zero" )
@@ -189,9 +215,11 @@ def test_log_record_exception(self):
189215 self .assertTrue ("division by zero" in stack_trace )
190216 self .assertTrue (__file__ in stack_trace )
191217
218+ logger .removeHandler (handler )
219+
192220 def test_log_record_recursive_exception (self ):
193221 """Exception information will be included in attributes even though it is recursive"""
194- processor , logger = set_up_test_logging (logging .ERROR )
222+ processor , logger , handler = set_up_test_logging (logging .ERROR )
195223
196224 try :
197225 raise ZeroDivisionError (
@@ -224,9 +252,11 @@ def test_log_record_recursive_exception(self):
224252 self .assertTrue ("division by zero" in stack_trace )
225253 self .assertTrue (__file__ in stack_trace )
226254
255+ logger .removeHandler (handler )
256+
227257 def test_log_exc_info_false (self ):
228258 """Exception information will not be included in attributes"""
229- processor , logger = set_up_test_logging (logging .NOTSET )
259+ processor , logger , handler = set_up_test_logging (logging .NOTSET )
230260
231261 try :
232262 raise ZeroDivisionError ("division by zero" )
@@ -251,8 +281,10 @@ def test_log_exc_info_false(self):
251281 record .log_record .attributes ,
252282 )
253283
284+ logger .removeHandler (handler )
285+
254286 def test_log_record_exception_with_object_payload (self ):
255- processor , logger = set_up_test_logging (logging .ERROR )
287+ processor , logger , handler = set_up_test_logging (logging .ERROR )
256288
257289 class CustomException (Exception ):
258290 def __str__ (self ):
@@ -287,8 +319,10 @@ def __str__(self):
287319 self .assertTrue ("CustomException" in stack_trace )
288320 self .assertTrue (__file__ in stack_trace )
289321
322+ logger .removeHandler (handler )
323+
290324 def test_log_record_trace_correlation (self ):
291- processor , logger = set_up_test_logging (logging .WARNING )
325+ processor , logger , handler = set_up_test_logging (logging .WARNING )
292326
293327 tracer = trace .TracerProvider ().get_tracer (__name__ )
294328 with tracer .start_as_current_span ("test" ) as span :
@@ -325,8 +359,10 @@ def test_log_record_trace_correlation(self):
325359 span_context .trace_flags ,
326360 )
327361
362+ logger .removeHandler (handler )
363+
328364 def test_log_record_trace_correlation_deprecated (self ):
329- processor , logger = set_up_test_logging (logging .WARNING )
365+ processor , logger , handler = set_up_test_logging (logging .WARNING )
330366
331367 tracer = trace .TracerProvider ().get_tracer (__name__ )
332368 with tracer .start_as_current_span ("test" ) as span :
@@ -349,22 +385,28 @@ def test_log_record_trace_correlation_deprecated(self):
349385 record .log_record .trace_flags , span_context .trace_flags
350386 )
351387
388+ logger .removeHandler (handler )
389+
352390 def test_warning_without_formatter (self ):
353- processor , logger = set_up_test_logging (logging .WARNING )
391+ processor , logger , handler = set_up_test_logging (logging .WARNING )
354392 logger .warning ("Test message" )
355393
356394 record = processor .get_log_record (0 )
357395 self .assertEqual (record .log_record .body , "Test message" )
358396
397+ logger .removeHandler (handler )
398+
359399 def test_exception_without_formatter (self ):
360- processor , logger = set_up_test_logging (logging .WARNING )
400+ processor , logger , handler = set_up_test_logging (logging .WARNING )
361401 logger .exception ("Test exception" )
362402
363403 record = processor .get_log_record (0 )
364404 self .assertEqual (record .log_record .body , "Test exception" )
365405
406+ logger .removeHandler (handler )
407+
366408 def test_warning_with_formatter (self ):
367- processor , logger = set_up_test_logging (
409+ processor , logger , handler = set_up_test_logging (
368410 logging .WARNING ,
369411 formatter = logging .Formatter (
370412 "%(name)s - %(levelname)s - %(message)s"
@@ -377,8 +419,10 @@ def test_warning_with_formatter(self):
377419 record .log_record .body , "foo - WARNING - Test message"
378420 )
379421
422+ logger .removeHandler (handler )
423+
380424 def test_log_body_is_always_string_with_formatter (self ):
381- processor , logger = set_up_test_logging (
425+ processor , logger , handler = set_up_test_logging (
382426 logging .WARNING ,
383427 formatter = logging .Formatter (
384428 "%(name)s - %(levelname)s - %(message)s"
@@ -389,17 +433,21 @@ def test_log_body_is_always_string_with_formatter(self):
389433 record = processor .get_log_record (0 )
390434 self .assertIsInstance (record .log_record .body , str )
391435
436+ logger .removeHandler (handler )
437+
392438 @patch .dict (os .environ , {"OTEL_SDK_DISABLED" : "true" })
393439 def test_handler_root_logger_with_disabled_sdk_does_not_go_into_recursion_error (
394440 self ,
395441 ):
396- processor , logger = set_up_test_logging (
442+ processor , logger , handler = set_up_test_logging (
397443 logging .NOTSET , root_logger = True
398444 )
399445 logger .warning ("hello" )
400446
401447 self .assertEqual (processor .emit_count (), 0 )
402448
449+ logger .removeHandler (handler )
450+
403451 @patch .dict (os .environ , {OTEL_ATTRIBUTE_COUNT_LIMIT : "3" })
404452 def test_otel_attribute_count_limit_respected_in_logging_handler (self ):
405453 """Test that OTEL_ATTRIBUTE_COUNT_LIMIT is properly respected by LoggingHandler."""
@@ -439,6 +487,8 @@ def test_otel_attribute_count_limit_respected_in_logging_handler(self):
439487 f"Should have 10 dropped attributes, got { record .dropped_attributes } " ,
440488 )
441489
490+ logger .removeHandler (handler )
491+
442492 @patch .dict (os .environ , {OTEL_ATTRIBUTE_COUNT_LIMIT : "5" })
443493 def test_otel_attribute_count_limit_includes_code_attributes (self ):
444494 """Test that OTEL_ATTRIBUTE_COUNT_LIMIT applies to all attributes including code attributes."""
@@ -476,9 +526,11 @@ def test_otel_attribute_count_limit_includes_code_attributes(self):
476526 f"Should have 6 dropped attributes, got { record .dropped_attributes } " ,
477527 )
478528
529+ logger .removeHandler (handler )
530+
479531 def test_logging_handler_without_env_var_uses_default_limit (self ):
480532 """Test that without OTEL_ATTRIBUTE_COUNT_LIMIT, default limit (128) should apply."""
481- processor , logger = set_up_test_logging (logging .WARNING )
533+ processor , logger , handler = set_up_test_logging (logging .WARNING )
482534
483535 # Create a log record with many attributes (more than default limit of 128)
484536 extra_attrs = {f"attr_{ i } " : f"value_{ i } " for i in range (150 )}
@@ -505,6 +557,8 @@ def test_logging_handler_without_env_var_uses_default_limit(self):
505557 f"Should have 25 dropped attributes, got { record .dropped_attributes } " ,
506558 )
507559
560+ logger .removeHandler (handler )
561+
508562
509563def set_up_test_logging (level , formatter = None , root_logger = False ):
510564 logger_provider = LoggerProvider ()
@@ -515,7 +569,7 @@ def set_up_test_logging(level, formatter=None, root_logger=False):
515569 if formatter :
516570 handler .setFormatter (formatter )
517571 logger .addHandler (handler )
518- return processor , logger
572+ return processor , logger , handler
519573
520574
521575class FakeProcessor (LogRecordProcessor ):
0 commit comments