mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Significantly improve logging performance when no integrations are requesting debug level (#37776)
This commit is contained in:
parent
401dd4a32a
commit
f16090caf4
@ -13,6 +13,8 @@ DATA_LOGGER = "logger"
|
|||||||
SERVICE_SET_DEFAULT_LEVEL = "set_default_level"
|
SERVICE_SET_DEFAULT_LEVEL = "set_default_level"
|
||||||
SERVICE_SET_LEVEL = "set_level"
|
SERVICE_SET_LEVEL = "set_level"
|
||||||
|
|
||||||
|
HIGHEST_LOG_LEVEL = logging.CRITICAL
|
||||||
|
|
||||||
LOGSEVERITY = {
|
LOGSEVERITY = {
|
||||||
"CRITICAL": 50,
|
"CRITICAL": 50,
|
||||||
"FATAL": 50,
|
"FATAL": 50,
|
||||||
@ -55,7 +57,7 @@ class HomeAssistantLogFilter(logging.Filter):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self._default = None
|
self._default = None
|
||||||
self._logs = None
|
self._logs = {}
|
||||||
self._log_rx = None
|
self._log_rx = None
|
||||||
|
|
||||||
def update_default_level(self, default_level):
|
def update_default_level(self, default_level):
|
||||||
@ -77,6 +79,23 @@ class HomeAssistantLogFilter(logging.Filter):
|
|||||||
self._log_rx = re.compile("".join(["^(?:", "|".join(names_by_len), ")"]))
|
self._log_rx = re.compile("".join(["^(?:", "|".join(names_by_len), ")"]))
|
||||||
self._logs = logs
|
self._logs = logs
|
||||||
|
|
||||||
|
def set_logger_level(self):
|
||||||
|
"""Find the lowest log level set to allow logger to pre-filter log messages."""
|
||||||
|
#
|
||||||
|
# We set the root logger level to lowest log level
|
||||||
|
# specified in default or for in the log filter so
|
||||||
|
# logger.isEnabledFor function will work as designed
|
||||||
|
# to avoid making logger records that will always be
|
||||||
|
# discarded.
|
||||||
|
#
|
||||||
|
# This can make the logger performance significantly
|
||||||
|
# faster if no integrations are requesting debug logs
|
||||||
|
# because we can avoid the record creation and filtering
|
||||||
|
# overhead.
|
||||||
|
#
|
||||||
|
logger = logging.getLogger("")
|
||||||
|
logger.setLevel(min(HIGHEST_LOG_LEVEL, self._default, *self._logs.values()))
|
||||||
|
|
||||||
def filter(self, record):
|
def filter(self, record):
|
||||||
"""Filter the log entries."""
|
"""Filter the log entries."""
|
||||||
# Log with filtered severity
|
# Log with filtered severity
|
||||||
@ -121,9 +140,6 @@ async def async_setup(hass, config):
|
|||||||
else:
|
else:
|
||||||
set_default_log_level("DEBUG")
|
set_default_log_level("DEBUG")
|
||||||
|
|
||||||
logger = logging.getLogger("")
|
|
||||||
logger.setLevel(logging.NOTSET)
|
|
||||||
|
|
||||||
# Set log filter for all log handler
|
# Set log filter for all log handler
|
||||||
for handler in logging.root.handlers:
|
for handler in logging.root.handlers:
|
||||||
handler.setLevel(logging.NOTSET)
|
handler.setLevel(logging.NOTSET)
|
||||||
@ -132,12 +148,15 @@ async def async_setup(hass, config):
|
|||||||
if LOGGER_LOGS in config.get(DOMAIN):
|
if LOGGER_LOGS in config.get(DOMAIN):
|
||||||
set_log_levels(config.get(DOMAIN)[LOGGER_LOGS])
|
set_log_levels(config.get(DOMAIN)[LOGGER_LOGS])
|
||||||
|
|
||||||
|
hass_filter.set_logger_level()
|
||||||
|
|
||||||
async def async_service_handler(service):
|
async def async_service_handler(service):
|
||||||
"""Handle logger services."""
|
"""Handle logger services."""
|
||||||
if service.service == SERVICE_SET_DEFAULT_LEVEL:
|
if service.service == SERVICE_SET_DEFAULT_LEVEL:
|
||||||
set_default_log_level(service.data.get(ATTR_LEVEL))
|
set_default_log_level(service.data.get(ATTR_LEVEL))
|
||||||
else:
|
else:
|
||||||
set_log_levels(service.data)
|
set_log_levels(service.data)
|
||||||
|
hass_filter.set_logger_level()
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
@ -37,6 +37,8 @@ async def test_logger_test_filters(hass):
|
|||||||
"""Test resulting filter operation."""
|
"""Test resulting filter operation."""
|
||||||
log_filter = await async_setup_logger(hass, TEST_CONFIG)
|
log_filter = await async_setup_logger(hass, TEST_CONFIG)
|
||||||
|
|
||||||
|
assert logging.getLogger("").isEnabledFor(logging.DEBUG) is True
|
||||||
|
|
||||||
# Blocked default record
|
# Blocked default record
|
||||||
assert not log_filter.filter(RECORD("asdf", logging.DEBUG))
|
assert not log_filter.filter(RECORD("asdf", logging.DEBUG))
|
||||||
|
|
||||||
@ -66,13 +68,27 @@ async def test_set_filter_empty_config(hass):
|
|||||||
"""Test change log level from empty configuration."""
|
"""Test change log level from empty configuration."""
|
||||||
log_filter = await async_setup_logger(hass, NO_LOGS_CONFIG)
|
log_filter = await async_setup_logger(hass, NO_LOGS_CONFIG)
|
||||||
|
|
||||||
|
assert logging.getLogger("").isEnabledFor(logging.DEBUG) is False
|
||||||
|
|
||||||
assert not log_filter.filter(RECORD("test", logging.DEBUG))
|
assert not log_filter.filter(RECORD("test", logging.DEBUG))
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
logger.DOMAIN, "set_default_level", {"level": "warning"}
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert not log_filter.filter(RECORD("test", logging.DEBUG))
|
||||||
|
|
||||||
|
assert logging.getLogger("").isEnabledFor(logging.DEBUG) is False
|
||||||
|
assert logging.getLogger("").isEnabledFor(logging.WARNING) is True
|
||||||
|
|
||||||
await hass.services.async_call(logger.DOMAIN, "set_level", {"test": "debug"})
|
await hass.services.async_call(logger.DOMAIN, "set_level", {"test": "debug"})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert log_filter.filter(RECORD("test", logging.DEBUG))
|
assert log_filter.filter(RECORD("test", logging.DEBUG))
|
||||||
|
|
||||||
|
assert logging.getLogger("").isEnabledFor(logging.DEBUG) is True
|
||||||
|
|
||||||
|
|
||||||
async def test_set_filter(hass):
|
async def test_set_filter(hass):
|
||||||
"""Test change log level of existing filter."""
|
"""Test change log level of existing filter."""
|
||||||
@ -94,6 +110,9 @@ async def test_set_default_filter_empty_config(hass):
|
|||||||
"""Test change default log level from empty configuration."""
|
"""Test change default log level from empty configuration."""
|
||||||
log_filter = await async_setup_logger(hass, NO_DEFAULT_CONFIG)
|
log_filter = await async_setup_logger(hass, NO_DEFAULT_CONFIG)
|
||||||
|
|
||||||
|
assert logging.getLogger("").isEnabledFor(logging.DEBUG) is True
|
||||||
|
assert logging.getLogger("").isEnabledFor(logging.WARNING) is True
|
||||||
|
|
||||||
assert log_filter.filter(RECORD("test", logging.DEBUG))
|
assert log_filter.filter(RECORD("test", logging.DEBUG))
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -103,6 +122,10 @@ async def test_set_default_filter_empty_config(hass):
|
|||||||
|
|
||||||
assert not log_filter.filter(RECORD("test", logging.DEBUG))
|
assert not log_filter.filter(RECORD("test", logging.DEBUG))
|
||||||
|
|
||||||
|
assert logging.getLogger("").isEnabledFor(logging.DEBUG) is False
|
||||||
|
assert logging.getLogger("").isEnabledFor(logging.INFO) is False
|
||||||
|
assert logging.getLogger("").isEnabledFor(logging.WARNING) is True
|
||||||
|
|
||||||
|
|
||||||
async def test_set_default_filter(hass):
|
async def test_set_default_filter(hass):
|
||||||
"""Test change default log level with existing default."""
|
"""Test change default log level with existing default."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user