2121from opentelemetry .instrumentation .logging import ( # pylint: disable=no-name-in-module
2222 DEFAULT_LOGGING_FORMAT ,
2323 LoggingInstrumentor ,
24+ apply_log_settings ,
2425)
2526from opentelemetry .test .test_base import TestBase
2627from opentelemetry .trace import ProxyTracer , get_tracer
@@ -106,28 +107,28 @@ def test_trace_context_injection(self):
106107 def test_trace_context_injection_without_span (self ):
107108 self .assert_trace_context_injected ("0" , "0" , False )
108109
109- @mock .patch ("logging.basicConfig " )
110- def test_basic_config_called (self , basic_config_mock ):
110+ @mock .patch ("opentelemetry.instrumentation. logging.apply_log_settings " )
111+ def test_basic_config_called (self , apply_log_settings_mock ):
111112 LoggingInstrumentor ().uninstrument ()
112113 LoggingInstrumentor ().instrument ()
113- self .assertFalse ( basic_config_mock .called )
114+ self .assertTrue ( apply_log_settings_mock .called )
114115 LoggingInstrumentor ().uninstrument ()
115116
116117 env_patch = mock .patch .dict (
117118 "os.environ" , {"OTEL_PYTHON_LOG_CORRELATION" : "true" }
118119 )
119120 env_patch .start ()
120121 LoggingInstrumentor ().instrument ()
121- basic_config_mock .assert_called_with (
122+ apply_log_settings_mock .assert_called_with (
122123 format = DEFAULT_LOGGING_FORMAT , level = logging .INFO
123124 )
124125 env_patch .stop ()
125126
126- @mock .patch ("logging.basicConfig " )
127- def test_custom_format_and_level_env (self , basic_config_mock ):
127+ @mock .patch ("opentelemetry.instrumentation. logging.apply_log_settings " )
128+ def test_custom_format_and_level_env (self , apply_log_settings_mock ):
128129 LoggingInstrumentor ().uninstrument ()
129130 LoggingInstrumentor ().instrument ()
130- self .assertFalse ( basic_config_mock .called )
131+ self .assertTrue ( apply_log_settings_mock .called )
131132 LoggingInstrumentor ().uninstrument ()
132133
133134 env_patch = mock .patch .dict (
@@ -140,22 +141,22 @@ def test_custom_format_and_level_env(self, basic_config_mock):
140141 )
141142 env_patch .start ()
142143 LoggingInstrumentor ().instrument ()
143- basic_config_mock .assert_called_with (
144+ apply_log_settings_mock .assert_called_with (
144145 format = "%(message)s %(otelSpanID)s" , level = logging .ERROR
145146 )
146147 env_patch .stop ()
147148
148- @mock .patch ("logging.basicConfig " )
149+ @mock .patch ("opentelemetry.instrumentation. logging.apply_log_settings " )
149150 def test_custom_format_and_level_api (
150- self , basic_config_mock
151+ self , apply_log_settings_mock
151152 ): # pylint: disable=no-self-use
152153 LoggingInstrumentor ().uninstrument ()
153154 LoggingInstrumentor ().instrument (
154155 set_logging_format = True ,
155156 logging_format = "%(message)s span_id=%(otelSpanID)s" ,
156157 log_level = logging .WARNING ,
157158 )
158- basic_config_mock .assert_called_with (
159+ apply_log_settings_mock .assert_called_with (
159160 format = "%(message)s span_id=%(otelSpanID)s" , level = logging .WARNING
160161 )
161162
@@ -207,3 +208,77 @@ def test_uninstrumented(self):
207208 self .assertFalse (hasattr (record , "otelTraceID" ))
208209 self .assertFalse (hasattr (record , "otelServiceName" ))
209210 self .assertFalse (hasattr (record , "otelTraceSampled" ))
211+
212+
213+ class TestLogSetup (TestBase ):
214+ """
215+ Tests the apply_log_settings function
216+ """
217+
218+ @mock .patch ("logging.Formatter" )
219+ @mock .patch ("logging.getLogger" )
220+ @mock .patch ("logging.basicConfig" )
221+ def test_apply_log_settings_initialized (
222+ self ,
223+ basic_config_mock ,
224+ get_logger_mock ,
225+ formatter_mock , # pylint: disable=no-self-use
226+ ):
227+ """
228+ Tests that apply_log_settings tries to apply format and loglevel to the
229+ configured logging module if the logging module has already been initialized
230+ """
231+ # Prepare
232+ log_level = logging .DEBUG
233+ log_format = "custom %(message)s"
234+ formatter = "formatter"
235+
236+ formatter_mock .return_value = formatter
237+
238+ handler_mock = mock .MagicMock ()
239+
240+ root_logger_mock = mock .MagicMock ()
241+ root_logger_mock .hasHandlers .return_value = True
242+ root_logger_mock .handlers = [handler_mock ]
243+
244+ get_logger_mock .return_value = root_logger_mock
245+
246+ # Act
247+ apply_log_settings (log_format , log_level )
248+
249+ # Assert
250+ get_logger_mock .assert_called_once_with ()
251+ root_logger_mock .hasHandlers .assert_called_once ()
252+ root_logger_mock .setLevel .assert_called_once_with (log_level )
253+ handler_mock .setFormatter .assert_called_once_with (formatter )
254+ formatter_mock .assert_called_once_with (log_format )
255+
256+ self .assertFalse (basic_config_mock .called )
257+
258+ @mock .patch ("logging.getLogger" )
259+ @mock .patch ("logging.basicConfig" )
260+ def test_apply_log_settings_uninitialized (
261+ self , basic_config_mock , get_logger_mock # pylint: disable=no-self-use
262+ ):
263+ """
264+ Tests that apply_log_settings calls logging.basicConfig with the
265+ provided format and level when the logging module has not been
266+ initialized
267+ """
268+ log_level = logging .DEBUG
269+ log_format = "custom %(message)s"
270+
271+ root_logger_mock = mock .MagicMock ()
272+ root_logger_mock .hasHandlers .return_value = False
273+
274+ get_logger_mock .return_value = root_logger_mock
275+
276+ apply_log_settings (log_format , log_level )
277+
278+ root_logger_mock .hasHandlers .assert_called_once ()
279+ get_logger_mock .assert_called_once_with ()
280+
281+ self .assertTrue (basic_config_mock .called )
282+ basic_config_mock .assert_called_once_with (
283+ format = log_format , level = log_level
284+ )
0 commit comments