diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 000000000..38a5a2b6f --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,3 @@ +Release type: patch + +Address an issue where `--fatal=warnings|errors` would not honor entries in the `LOG_FILTER` setting. \ No newline at end of file diff --git a/pelican/log.py b/pelican/log.py index 325ac3ea6..6210ea5a6 100644 --- a/pelican/log.py +++ b/pelican/log.py @@ -149,24 +149,9 @@ def enable_filter(self): self.addFilter(LimitLogger.limit_filter) -class FatalLogger(LimitLogger): - warnings_fatal = False - errors_fatal = False - - def warning(self, *args, **kwargs): - super().warning(*args, **kwargs) - if FatalLogger.warnings_fatal: - raise RuntimeError('Warning encountered') - - def error(self, *args, **kwargs): - super().error(*args, **kwargs) - if FatalLogger.errors_fatal: - raise RuntimeError('Error encountered') - - -logging.setLoggerClass(FatalLogger) +logging.setLoggerClass(LimitLogger) # force root logger to be of our preferred class -logging.getLogger().__class__ = FatalLogger +logging.getLogger().__class__ = LimitLogger def supports_color(): @@ -194,11 +179,13 @@ def get_formatter(): return TextFormatter() +class FatalHandler(logging.Handler): + def emit(self, record): + sys.exit(1) + + def init(level=None, fatal='', handler=logging.StreamHandler(), name=None, logs_dedup_min_level=None): - FatalLogger.warnings_fatal = fatal.startswith('warning') - FatalLogger.errors_fatal = bool(fatal) - logger = logging.getLogger(name) handler.setFormatter(get_formatter()) @@ -209,6 +196,11 @@ def init(level=None, fatal='', handler=logging.StreamHandler(), name=None, if logs_dedup_min_level: LimitFilter.LOGS_DEDUP_MIN_LEVEL = logs_dedup_min_level + if fatal.startswith('warning'): + logger.addHandler(FatalHandler(level=logging.WARNING)) + if fatal: + logger.addHandler(FatalHandler(level=logging.ERROR)) + def log_warnings(): import warnings diff --git a/pelican/settings.py b/pelican/settings.py index ea3ee8eb7..393bee3ab 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -163,7 +163,7 @@ def load_source(name, path): 'WRITE_SELECTED': [], 'FORMATTED_FIELDS': ['summary'], 'PORT': 8000, - 'BIND': '127.0.0.1', + 'BIND': '127.0.0.1' } PYGMENTS_RST_OPTIONS = None diff --git a/pelican/tests/test_log.py b/pelican/tests/test_log.py index 3f9d72503..53d83d29b 100644 --- a/pelican/tests/test_log.py +++ b/pelican/tests/test_log.py @@ -2,6 +2,7 @@ import unittest from collections import defaultdict from contextlib import contextmanager +from unittest import mock from pelican import log from pelican.tests.support import LogCountHandler @@ -130,3 +131,48 @@ def do_logging(): self.assertEqual( self.handler.count_logs('Another log \\d', logging.WARNING), 0) + + +@mock.patch.object(log, 'sys') +class TestLogInit(unittest.TestCase): + def init(self, fatal, name): + logger = logging.getLogger(name) + log.init(fatal=fatal, name=name) + return logger + + def test_fatal_warnings(self, sys): + logger = self.init('warnings', 'test_fatal_warnings') + logger.warning('foo') + logger.error('bar') + sys.exit.assert_called_with(1) + + def test_fatal_errors(self, sys): + logger = self.init('errors', 'test_fatal_errors') + logger.warning('foo') + logger.error('bar') + sys.exit.assert_called_with(1) + + def test_no_fatal(self, sys): + logger = self.init('', 'test_no_fatal') + logger.warning('foo') + logger.error('bar') + sys.exit.assert_not_called() + + def test_fatal_warnings_log_filter(self, sys): + limit_filter = log.LimitFilter() + limit_filter._ignore = {(logging.WARNING, 'foo')} + lf = mock.PropertyMock(return_value=limit_filter) + with mock.patch('pelican.log.LimitLogger.limit_filter', new=lf): + logger = self.init('warnings', 'test_fatal_warnings_log_filter') + logger.warning('foo') + sys.exit.assert_not_called() + + def test_fatal_errors_log_filter(self, sys): + limit_filter = log.LimitFilter() + limit_filter.LOGS_DEDUP_MIN_LEVEL = logging.CRITICAL + limit_filter._ignore = {(logging.ERROR, 'bar')} + lf = mock.PropertyMock(return_value=limit_filter) + with mock.patch('pelican.log.LimitLogger.limit_filter', new=lf): + logger = self.init('errors', 'test_fatal_errors_log_filter') + logger.error('bar') + sys.exit.assert_not_called()