add ability to suppress http logging errors (#86)

This commit is contained in:
Evgenii Alekseev 2023-01-30 17:19:01 +02:00
parent 5af84955ac
commit 25eee9ca5e
5 changed files with 32 additions and 6 deletions

View File

@ -28,6 +28,7 @@ Base configuration settings.
* ``include`` - path to directory with configuration files overrides, string, required. * ``include`` - path to directory with configuration files overrides, string, required.
* ``database`` - path to SQLite database, string, required. * ``database`` - path to SQLite database, string, required.
* ``logging`` - path to logging configuration, string, required. Check ``logging.ini`` for reference. * ``logging`` - path to logging configuration, string, required. Check ``logging.ini`` for reference.
* ``suppress_http_log_errors`` - suppress http log errors, boolean, optional, default ``no``. If set to ``yes``, any http log errors (e.g. if web server is not available, but http logging is enabled) will be suppressed.
``alpm`` group ``alpm`` group
-------------- --------------

View File

@ -2,6 +2,7 @@
include = ahriman.ini.d include = ahriman.ini.d
logging = ahriman.ini.d/logging.ini logging = ahriman.ini.d/logging.ini
database = /var/lib/ahriman/ahriman.db database = /var/lib/ahriman/ahriman.db
suppress_http_log_errors = yes
[alpm] [alpm]
database = /var/lib/pacman database = /var/lib/pacman

View File

@ -47,6 +47,10 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
"required": True, "required": True,
"path_exists": True, "path_exists": True,
}, },
"suppress_http_log_errors": {
"type": "boolean",
"coerce": "boolean",
}
}, },
}, },
"alpm": { "alpm": {

View File

@ -31,22 +31,25 @@ class HttpLogHandler(logging.Handler):
Attributes: Attributes:
reporter(Client): build status reporter instance reporter(Client): build status reporter instance
suppress_errors(bool): suppress logging errors (e.g. if no web server available)
""" """
def __init__(self, configuration: Configuration, *, report: bool) -> None: def __init__(self, configuration: Configuration, *, report: bool, suppress_errors: bool) -> None:
""" """
default constructor default constructor
Args: Args:
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
suppress_errors(bool): suppress logging errors (e.g. if no web server available)
""" """
# we don't really care about those parameters because they will be handled by the reporter # we don't really care about those parameters because they will be handled by the reporter
logging.Handler.__init__(self) logging.Handler.__init__(self)
# client has to be importer here because of circular imports # client has to be imported here because of circular imports
from ahriman.core.status.client import Client from ahriman.core.status.client import Client
self.reporter = Client.load(configuration, report=report) self.reporter = Client.load(configuration, report=report)
self.suppress_errors = suppress_errors
@classmethod @classmethod
def load(cls, configuration: Configuration, *, report: bool) -> HttpLogHandler: def load(cls, configuration: Configuration, *, report: bool) -> HttpLogHandler:
@ -62,7 +65,8 @@ class HttpLogHandler(logging.Handler):
if (handler := next((handler for handler in root.handlers if isinstance(handler, cls)), None)) is not None: if (handler := next((handler for handler in root.handlers if isinstance(handler, cls)), None)) is not None:
return handler # there is already registered instance return handler # there is already registered instance
handler = cls(configuration, report=report) suppress_errors = configuration.getboolean("settings", "suppress_http_log_errors", fallback=False)
handler = cls(configuration, report=report, suppress_errors=suppress_errors)
root.addHandler(handler) root.addHandler(handler)
return handler return handler
@ -81,4 +85,6 @@ class HttpLogHandler(logging.Handler):
try: try:
self.reporter.logs(package_base, record) self.reporter.logs(package_base, record)
except Exception: except Exception:
if self.suppress_errors:
return
self.handleError(record) self.handleError(record)

View File

@ -42,7 +42,7 @@ def test_emit(configuration: Configuration, log_record: logging.LogRecord, packa
log_record.package_base = package_ahriman.base log_record.package_base = package_ahriman.base
log_mock = mocker.patch("ahriman.core.status.client.Client.logs") log_mock = mocker.patch("ahriman.core.status.client.Client.logs")
handler = HttpLogHandler(configuration, report=False) handler = HttpLogHandler(configuration, report=False, suppress_errors=False)
handler.emit(log_record) handler.emit(log_record)
log_mock.assert_called_once_with(package_ahriman.base, log_record) log_mock.assert_called_once_with(package_ahriman.base, log_record)
@ -56,18 +56,32 @@ def test_emit_failed(configuration: Configuration, log_record: logging.LogRecord
log_record.package_base = package_ahriman.base log_record.package_base = package_ahriman.base
mocker.patch("ahriman.core.status.client.Client.logs", side_effect=Exception()) mocker.patch("ahriman.core.status.client.Client.logs", side_effect=Exception())
handle_error_mock = mocker.patch("logging.Handler.handleError") handle_error_mock = mocker.patch("logging.Handler.handleError")
handler = HttpLogHandler(configuration, report=False) handler = HttpLogHandler(configuration, report=False, suppress_errors=False)
handler.emit(log_record) handler.emit(log_record)
handle_error_mock.assert_called_once_with(log_record) handle_error_mock.assert_called_once_with(log_record)
def test_emit_suppress_failed(configuration: Configuration, log_record: logging.LogRecord, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must not call handle error on exception if suppress flag is set
"""
log_record.package_base = package_ahriman.base
mocker.patch("ahriman.core.status.client.Client.logs", side_effect=Exception())
handle_error_mock = mocker.patch("logging.Handler.handleError")
handler = HttpLogHandler(configuration, report=False, suppress_errors=True)
handler.emit(log_record)
handle_error_mock.assert_not_called()
def test_emit_skip(configuration: Configuration, log_record: logging.LogRecord, mocker: MockerFixture) -> None: def test_emit_skip(configuration: Configuration, log_record: logging.LogRecord, mocker: MockerFixture) -> None:
""" """
must skip log record posting if no package base set must skip log record posting if no package base set
""" """
log_mock = mocker.patch("ahriman.core.status.client.Client.logs") log_mock = mocker.patch("ahriman.core.status.client.Client.logs")
handler = HttpLogHandler(configuration, report=False) handler = HttpLogHandler(configuration, report=False, suppress_errors=False)
handler.emit(log_record) handler.emit(log_record)
log_mock.assert_not_called() log_mock.assert_not_called()