From 6fa0ee4a2b6bbb5db750aa67efcd32824302bc52 Mon Sep 17 00:00:00 2001 From: Martin Kolman Date: Thu, 24 Oct 2024 19:59:14 +0200 Subject: [PATCH 1/4] Redirect only GLib loggers to Journal Previously we redirected all output from the main Anaconda process to Journal to avoid GTK log messages (as GTK runs in the main process) from spamming TTY. Turns out this broke a couple things, such as the shell prompt in rescue mode. So drop the wholesale process output redirection and instead just redirect (hopefully) all GLib based loggers (used by GTK) to Journal. Related: RHEL-58834 --- pyanaconda/anaconda_logging.py | 40 +++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/pyanaconda/anaconda_logging.py b/pyanaconda/anaconda_logging.py index 5c86de610ff..95b18577eec 100644 --- a/pyanaconda/anaconda_logging.py +++ b/pyanaconda/anaconda_logging.py @@ -29,6 +29,10 @@ from pyanaconda.core import constants from pyanaconda.core.path import set_mode +import gi +gi.require_version("GLib", "2.0") +from gi.repository import GLib + ENTRY_FORMAT = "%(asctime)s,%(msecs)03d %(levelname)s %(name)s: %(message)s" STDOUT_FORMAT = "%(asctime)s %(message)s" DATE_FORMAT = "%H:%M:%S" @@ -187,8 +191,8 @@ def __init__(self, write_to_journal=False): self.addFileHandler(MAIN_LOG_FILE, simpleline_logger) self.forwardToJournal(simpleline_logger) - # Redirect all stderr messages from process to journal - self.stderrToJournal() + # Redirect GLib logging (e.g. GTK) to Journal + self.redirect_glib_logging_to_journal() # Create a second logger for just the stuff we want to dup on # stdout. Anything written here will also get passed up to the @@ -235,19 +239,35 @@ def forwardToJournal(self, logr, log_formatter=None, log_filter=None): journal_handler.setFormatter(log_formatter) logr.addHandler(journal_handler) - def stderrToJournal(self): - """Print all stderr messages from Anaconda to journal instead. + def redirect_glib_logging_to_journal(self): + """Redirect GLib based library logging to the journal. + + Some GLib based libraries (such as GTK) do direct their + sometimes quite verbose log messages to the output of the + process in which they are running. In the Anaconda case, + this creates issues with TTY1 being spammed with those + messages, with important content (such as RDP connection instructions) + being scrolled out of view. - Redirect Anaconda main process stderr to Journal, as otherwise this could end up writing - all over the TUI on TTY1. + :param log: anaconda log handler """ + if not self.write_to_journal: return - # create an appropriately named Journal writing stream - anaconda_stderr_stream = journal.stream("anaconda", priority=journal.LOG_ERR) - # redirect stderr of this process to the stream - os.dup2(anaconda_stderr_stream.fileno(), sys.stderr.fileno()) + # create functions that convert the messages coming + # from GLib into something that fits to the anaconda logging format + def log_adapter(domain, level, message, user_data): + self.anaconda_logger.debug("GLib: %s", message) + + def structured_log_adapter(level, fields, field_count, user_data): + message = GLib.log_writer_format_fields(level, fields, True) + self.anaconda_logger.debug("GLib: %s", message) + return GLib.LogWriterOutput.HANDLED + + # redirect GLib log output via the functions + GLib.log_set_handler(None, GLib.LogLevelFlags.LEVEL_MASK, log_adapter, None) + GLib.log_set_writer_func(structured_log_adapter, None) # pylint: disable=redefined-builtin def showwarning(self, message, category, filename, lineno, From 310a6c38c0bba392be62c9632b3803df49efeb0e Mon Sep 17 00:00:00 2001 From: Jiri Konecny Date: Mon, 4 Nov 2024 15:05:29 +0100 Subject: [PATCH 2/4] Move GLib imports to pyanaconda.core.glib This place is used for all GLib imports to avoid gi.require import across the code base. Related: RHEL-58834 --- pyanaconda/anaconda_logging.py | 16 +++++++--------- pyanaconda/core/glib.py | 4 ++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pyanaconda/anaconda_logging.py b/pyanaconda/anaconda_logging.py index 95b18577eec..fe607904e1e 100644 --- a/pyanaconda/anaconda_logging.py +++ b/pyanaconda/anaconda_logging.py @@ -1,7 +1,7 @@ # # anaconda_logging.py: Support for logging to multiple destinations with log # levels - basically an extension to the Python logging -# module with Anaconda specififc enhancements. +# module with Anaconda specific enhancements. # # Copyright (C) 2000, 2001, 2002, 2005, 2017 Red Hat, Inc. All rights reserved. # @@ -28,10 +28,8 @@ from pyanaconda.core import constants from pyanaconda.core.path import set_mode - -import gi -gi.require_version("GLib", "2.0") -from gi.repository import GLib +from pyanaconda.core.glib import log_set_handler, log_set_writer_func, log_writer_format_fields, \ + LogLevelFlags, LogWriterOutput ENTRY_FORMAT = "%(asctime)s,%(msecs)03d %(levelname)s %(name)s: %(message)s" STDOUT_FORMAT = "%(asctime)s %(message)s" @@ -261,13 +259,13 @@ def log_adapter(domain, level, message, user_data): self.anaconda_logger.debug("GLib: %s", message) def structured_log_adapter(level, fields, field_count, user_data): - message = GLib.log_writer_format_fields(level, fields, True) + message = log_writer_format_fields(level, fields, True) self.anaconda_logger.debug("GLib: %s", message) - return GLib.LogWriterOutput.HANDLED + return LogWriterOutput.HANDLED # redirect GLib log output via the functions - GLib.log_set_handler(None, GLib.LogLevelFlags.LEVEL_MASK, log_adapter, None) - GLib.log_set_writer_func(structured_log_adapter, None) + log_set_handler(None, LogLevelFlags.LEVEL_MASK, log_adapter, None) + log_set_writer_func(structured_log_adapter, None) # pylint: disable=redefined-builtin def showwarning(self, message, category, filename, lineno, diff --git a/pyanaconda/core/glib.py b/pyanaconda/core/glib.py index cb2be16f490..7de67391441 100644 --- a/pyanaconda/core/glib.py +++ b/pyanaconda/core/glib.py @@ -31,9 +31,11 @@ io_add_watch, child_watch_add, \ source_remove, timeout_source_new, \ spawn_close_pid, spawn_async_with_pipes, \ + log_writer_format_fields, log_set_handler, log_set_writer_func, \ MainLoop, MainContext, \ GError, Variant, VariantType, Bytes, \ IOCondition, IOChannel, SpawnFlags, \ + LogWriterOutput, LogLevelFlags, \ MAXUINT from gi.repository.Gio import Cancellable @@ -47,8 +49,10 @@ "io_add_watch", "child_watch_add", "source_remove", "timeout_source_new", "spawn_close_pid", "spawn_async_with_pipes", + "log_writer_format_fields", "log_set_handler", "log_set_writer_func", "GError", "Variant", "VariantType", "Bytes", "IOCondition", "IOChannel", "SpawnFlags", + "LogWriterOutput", "LogLevelFlags", "MAXUINT", "Cancellable"] From 78b9127589f62ee3342751d2828190162484fab8 Mon Sep 17 00:00:00 2001 From: Jiri Konecny Date: Mon, 4 Nov 2024 15:12:17 +0100 Subject: [PATCH 3/4] Remove GLib logging condition for HW logging This is not required because we solve that on level of LogHandler which is used in this solution. Related: RHEL-58834 --- pyanaconda/anaconda_logging.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyanaconda/anaconda_logging.py b/pyanaconda/anaconda_logging.py index fe607904e1e..eef3b66e2aa 100644 --- a/pyanaconda/anaconda_logging.py +++ b/pyanaconda/anaconda_logging.py @@ -249,10 +249,6 @@ def redirect_glib_logging_to_journal(self): :param log: anaconda log handler """ - - if not self.write_to_journal: - return - # create functions that convert the messages coming # from GLib into something that fits to the anaconda logging format def log_adapter(domain, level, message, user_data): From 1b146398383ce0829926232cf1598787946abbcb Mon Sep 17 00:00:00 2001 From: Jiri Konecny Date: Mon, 4 Nov 2024 15:33:43 +0100 Subject: [PATCH 4/4] Use log levels when getting logs from GLib Do not ignore log levels from GLib when redirecting these logs to our logs. Related: RHEL-58834 --- pyanaconda/anaconda_logging.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyanaconda/anaconda_logging.py b/pyanaconda/anaconda_logging.py index eef3b66e2aa..b18af72a24c 100644 --- a/pyanaconda/anaconda_logging.py +++ b/pyanaconda/anaconda_logging.py @@ -252,6 +252,12 @@ def redirect_glib_logging_to_journal(self): # create functions that convert the messages coming # from GLib into something that fits to the anaconda logging format def log_adapter(domain, level, message, user_data): + if level in (LogLevelFlags.LEVEL_ERROR, + LogLevelFlags.LEVEL_CRITICAL): + self.anaconda_logger.error("GLib: %s", message) + elif level is LogLevelFlags.LEVEL_WARNING: + self.anaconda_logger.warning("GLib: %s", message) + self.anaconda_logger.debug("GLib: %s", message) def structured_log_adapter(level, fields, field_count, user_data):