Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force --fatal=warnings|errors to honor LOG_FILTER #2856

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Release type: patch

Address an issue where `--fatal=warnings|errors` would not honor entries in the `LOG_FILTER` setting.
32 changes: 12 additions & 20 deletions pelican/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down Expand Up @@ -194,11 +179,13 @@ def get_formatter():
return TextFormatter()


class FatalHandler(logging.Handler):
def emit(self, record):
sys.exit(1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor suggestion, but perhaps change sys.exit(1) to the following?

raise SystemExit(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())
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pelican/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless this change is somehow related to the other changes in this pull request, I suggest that this change be reverted.

}

PYGMENTS_RST_OPTIONS = None
Expand Down
46 changes: 46 additions & 0 deletions pelican/tests/test_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()