From e9a7ce0086b009524fb525dd0a89c9f12666b135 Mon Sep 17 00:00:00 2001 From: Stefan Tatschner Date: Fri, 8 Nov 2024 09:51:25 +0100 Subject: [PATCH 1/3] chore: Refactor _format_record() Tracking the size of the string is not necessary. Just reset the cursor and truncate at the terminal width. If the line is colored, then restore the RESET code. --- src/gallia/log.py | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/gallia/log.py b/src/gallia/log.py index f3ad090e5..0674389a2 100644 --- a/src/gallia/log.py +++ b/src/gallia/log.py @@ -344,9 +344,9 @@ class _PenlogRecordV2(msgspec.Struct, omit_defaults=True, tag=2, tag_field="vers _PenlogRecord: TypeAlias = _PenlogRecordV2 -def _colorize_msg(data: str, levelno: int) -> tuple[str, int]: +def _colorize_msg(data: str, levelno: int) -> str: if sys.platform == "win32" or not sys.stderr.isatty(): - return data, 0 + return data out = "" match levelno: @@ -371,7 +371,12 @@ def _colorize_msg(data: str, levelno: int) -> tuple[str, int]: out += data out += _Color.RESET.value - return out, len(style) + return out + + +def _delete_cur_line() -> None: + sys.stderr.write("\33[2K\r") + sys.stderr.flush() def _format_record( # noqa: PLR0913 @@ -384,10 +389,11 @@ def _format_record( # noqa: PLR0913 colored: bool = False, volatile_info: bool = False, ) -> str: + delete_line = volatile_info and levelno <= Loglevel.INFO + if delete_line: + _delete_cur_line() + msg = "" - if volatile_info: - msg += "\33[2K" - extra_len = 4 msg += dt.strftime("%b %d %H:%M:%S.%f")[:-3] msg += " " msg += name @@ -396,24 +402,25 @@ def _format_record( # noqa: PLR0913 msg += ": " if colored: - tmp_msg, extra_len_tmp = _colorize_msg(data, levelno) - msg += tmp_msg - extra_len += extra_len_tmp + msg += _colorize_msg(data, levelno) else: msg += data - if volatile_info and levelno <= Loglevel.INFO: - terminal_width, _ = shutil.get_terminal_size() - msg = msg[: terminal_width + extra_len - 1] # Adapt length to invisible ANSI colors - msg += _Color.RESET.value - msg += "\r" - else: - msg += "\n" - if stacktrace is not None: msg += "\n" msg += stacktrace + if delete_line: + # Truncate the line that gets deleted in + # in case the terminal wraps the line. + cols, _ = shutil.get_terminal_size() + msg = msg[:cols] + if colored: + msg = msg[:-2] + _Color.RESET.value + msg += "\r" + else: + msg += "\n" + return msg From 90fed0af45278002803b9bbdb27832f25106107b Mon Sep 17 00:00:00 2001 From: Stefan Tatschner Date: Fri, 8 Nov 2024 10:00:01 +0100 Subject: [PATCH 2/3] feat(log): Add support for logging under systemd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If gallia is run as a systemd service, then set the env variable `GALLIA_LOGGING_SYSTEMD`. Then timestamps are omitted in log output and the priority information (info, warning, …) is added to the journal. --- docs/env.md | 4 ++++ src/gallia/log.py | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/env.md b/docs/env.md index 8264b5ed6..10e8f8141 100644 --- a/docs/env.md +++ b/docs/env.md @@ -20,5 +20,9 @@ GALLIA_LOGLEVEL Mostly useful in own scripts or tests. This variable is not read when using the gallia cli. +GALLIA_LOGGING_SYSTEMD +: Tells gallia to omit colors and status bars in logging output. + Additionally, the priority information gets added such that the journal can add it. + NO_COLOR : If this variable is set, `gallia` by default does not use color codes, see: https://no-color.org/ diff --git a/src/gallia/log.py b/src/gallia/log.py index 0674389a2..a83872948 100644 --- a/src/gallia/log.py +++ b/src/gallia/log.py @@ -389,13 +389,24 @@ def _format_record( # noqa: PLR0913 colored: bool = False, volatile_info: bool = False, ) -> str: + systemd = True if "GALLIA_LOGGING_SYSTEMD" in os.environ else False + if systemd: + colored = False + volatile_info = False + delete_line = volatile_info and levelno <= Loglevel.INFO if delete_line: _delete_cur_line() msg = "" - msg += dt.strftime("%b %d %H:%M:%S.%f")[:-3] - msg += " " + + # Add the priority info for the systemd journal… + if systemd: + msg += f"<{PenlogPriority.from_level(levelno).value}>" + # …else add timestamps if gallia runs under a terminal. + else: + msg += f"{dt.strftime('%b %d %H:%M:%S.%f')[:-3]} " + msg += name if tags is not None and len(tags) > 0: msg += f" [{', '.join(tags)}]" From 1c1789cbc6936ceed3d1b5ee47c3269a5a045a73 Mon Sep 17 00:00:00 2001 From: Stefan Tatschner Date: Fri, 8 Nov 2024 10:01:55 +0100 Subject: [PATCH 3/3] !cleanup: Remove unused and confusing GALLIA_LOGLEVEL variable --- docs/env.md | 7 ------- src/gallia/log.py | 8 +------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/docs/env.md b/docs/env.md index 10e8f8141..748fb4809 100644 --- a/docs/env.md +++ b/docs/env.md @@ -13,13 +13,6 @@ GALLIA_CONFIG : The path to the config file usually called `gallia.toml`. Disables autodiscovery of the config. -GALLIA_LOGLEVEL -: When {meth}`gallia.log.setup_logging()` is called without an argument this environment variable is read to set the loglevel. - Supported value are: `trace`, `debug`, `info`, `notice`, `warning`, `error`, `critical`. - As an alternative, the int values from 0 to 7 can be used. - Mostly useful in own scripts or tests. - This variable is not read when using the gallia cli. - GALLIA_LOGGING_SYSTEMD : Tells gallia to omit colors and status bars in logging output. Additionally, the priority information gets added such that the journal can add it. diff --git a/src/gallia/log.py b/src/gallia/log.py index a83872948..f3e4dd2e3 100644 --- a/src/gallia/log.py +++ b/src/gallia/log.py @@ -243,18 +243,12 @@ def setup_logging( logging. :param level: The loglevel to enable for the console handler. - If this argument is None, the env variable - ``GALLIA_LOGLEVEL`` (see :doc:`../env`) is read. :param file_level: The loglevel to enable for the file handler. :param path: The path to the logfile containing json records. :param color_mode: The color mode to use for the console. """ if level is None: - # FIXME why is this here and not in config? - if (raw := os.getenv("GALLIA_LOGLEVEL")) is not None: - level = PenlogPriority.from_str(raw).to_level() - else: - level = Loglevel.DEBUG + level = Loglevel.DEBUG # These are slow and not used by gallia. logging.logMultiprocessing = False