From 25eee9ca5e7b973f323dbe4ef89c8dd218764cd3 Mon Sep 17 00:00:00 2001 From: Evgeniy Alekseev Date: Mon, 30 Jan 2023 17:19:01 +0200 Subject: [PATCH] add ability to suppress http logging errors (#86) --- docs/configuration.rst | 1 + package/share/ahriman/settings/ahriman.ini | 1 + src/ahriman/core/configuration/schema.py | 4 ++++ src/ahriman/core/log/http_log_handler.py | 12 ++++++++--- .../ahriman/core/log/test_http_log_handler.py | 20 ++++++++++++++++--- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 1fa7b47a..b64c586b 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -28,6 +28,7 @@ Base configuration settings. * ``include`` - path to directory with configuration files overrides, string, required. * ``database`` - path to SQLite database, string, required. * ``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 -------------- diff --git a/package/share/ahriman/settings/ahriman.ini b/package/share/ahriman/settings/ahriman.ini index 2288be4d..9008c57d 100644 --- a/package/share/ahriman/settings/ahriman.ini +++ b/package/share/ahriman/settings/ahriman.ini @@ -2,6 +2,7 @@ include = ahriman.ini.d logging = ahriman.ini.d/logging.ini database = /var/lib/ahriman/ahriman.db +suppress_http_log_errors = yes [alpm] database = /var/lib/pacman diff --git a/src/ahriman/core/configuration/schema.py b/src/ahriman/core/configuration/schema.py index 6db0dd52..76e182ba 100644 --- a/src/ahriman/core/configuration/schema.py +++ b/src/ahriman/core/configuration/schema.py @@ -47,6 +47,10 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = { "required": True, "path_exists": True, }, + "suppress_http_log_errors": { + "type": "boolean", + "coerce": "boolean", + } }, }, "alpm": { diff --git a/src/ahriman/core/log/http_log_handler.py b/src/ahriman/core/log/http_log_handler.py index 6e511dff..3347f990 100644 --- a/src/ahriman/core/log/http_log_handler.py +++ b/src/ahriman/core/log/http_log_handler.py @@ -31,22 +31,25 @@ class HttpLogHandler(logging.Handler): Attributes: 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 Args: configuration(Configuration): configuration instance 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 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 self.reporter = Client.load(configuration, report=report) + self.suppress_errors = suppress_errors @classmethod 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: 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) return handler @@ -81,4 +85,6 @@ class HttpLogHandler(logging.Handler): try: self.reporter.logs(package_base, record) except Exception: + if self.suppress_errors: + return self.handleError(record) diff --git a/tests/ahriman/core/log/test_http_log_handler.py b/tests/ahriman/core/log/test_http_log_handler.py index f99770c8..5927b1fc 100644 --- a/tests/ahriman/core/log/test_http_log_handler.py +++ b/tests/ahriman/core/log/test_http_log_handler.py @@ -42,7 +42,7 @@ def test_emit(configuration: Configuration, log_record: logging.LogRecord, packa log_record.package_base = package_ahriman.base 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) 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 mocker.patch("ahriman.core.status.client.Client.logs", side_effect=Exception()) 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) 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: """ must skip log record posting if no package base set """ 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) log_mock.assert_not_called()