From 1297a093443ac2243b4fcca402434f7cdf364d3f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 17 May 2020 07:39:27 -0500 Subject: [PATCH] Avoid locking in the logging queue handler (#35700) * Avoid locking in the logging queue handler We do not need a lock here as the underlying queue is already thread safe. * Add coverage for logging handle --- homeassistant/util/logging.py | 18 ++++++++++++++++++ tests/util/test_logging.py | 11 +++++++++++ 2 files changed, 29 insertions(+) diff --git a/homeassistant/util/logging.py b/homeassistant/util/logging.py index 07ee6608141e..943e701a1446 100644 --- a/homeassistant/util/logging.py +++ b/homeassistant/util/logging.py @@ -39,6 +39,24 @@ class HomeAssistantQueueHandler(logging.handlers.QueueHandler): except Exception: # pylint: disable=broad-except self.handleError(record) + def handle(self, record: logging.LogRecord) -> Any: + """ + Conditionally emit the specified logging record. + + Depending on which filters have been added to the handler, push the new + records onto the backing Queue. + + The default python logger Handler acquires a lock + in the parent class which we do not need as + SimpleQueue is already thread safe. + + See https://bugs.python.org/issue24645 + """ + return_value = self.filter(record) + if return_value: + self.emit(record) + return return_value + @callback def async_activate_log_queue_handler(hass: HomeAssistant) -> None: diff --git a/tests/util/test_logging.py b/tests/util/test_logging.py index a1183ee16372..04d6f133381b 100644 --- a/tests/util/test_logging.py +++ b/tests/util/test_logging.py @@ -38,6 +38,17 @@ async def test_logging_with_queue_handler(): ): handler.emit(log_record) + with patch.object(handler, "emit") as emit_mock: + handler.handle(log_record) + emit_mock.assert_called_once() + + with patch.object(handler, "filter") as filter_mock, patch.object( + handler, "emit" + ) as emit_mock: + filter_mock.return_value = False + handler.handle(log_record) + emit_mock.assert_not_called() + with patch.object(handler, "enqueue", side_effect=OSError), patch.object( handler, "handleError" ) as mock_handle_error: