Skip to content

Commit

Permalink
Fix GUILogHandler lifetime
Browse files Browse the repository at this point in the history
separates out the logging.Handler part as the logging module
keeps around a weak reference until application exit.
  • Loading branch information
eivindjahren committed Jul 26, 2024
1 parent cf5af03 commit d5af720
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 16 deletions.
49 changes: 34 additions & 15 deletions src/ert/gui/tools/event_viewer/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,44 @@
from qtpy.QtCore import QObject
from qtpy.QtWidgets import QPlainTextEdit, QVBoxLayout

# Need to separate GUILogHandler into _Signaler & _GUILogHandler
# to avoid a object lifetime issue where logging keeps around a reference
# to the handler until application exit

class GUILogHandler(logging.Handler, QObject):

class _Signaler(QObject):
append_log_statement = QtCore.Signal(str)


class _GUILogHandler(logging.Handler):
def __init__(self, signaler: _Signaler):
super().__init__()
self.signaler = signaler

def emit(self, record: logging.LogRecord) -> None:
msg = self.format(record)
self.signaler.append_log_statement.emit(msg)


class GUILogHandler(_Signaler):
"""
Log handler which will emit a qt signal every time a
log is emitted
"""

append_log_statement = QtCore.Signal(str)

def __init__(self) -> None:
super().__init__()
self.setFormatter(logging.Formatter("%(levelname)-8s %(message)s"))
self.setLevel(logging.INFO)

QObject.__init__(self)
self.handler = _GUILogHandler(self)
self.handler.setFormatter(logging.Formatter("%(levelname)-8s %(message)s"))
self.handler.setLevel(logging.INFO)

def emit(self, record: logging.LogRecord) -> None:
msg = self.format(record)
self.append_log_statement.emit(msg)
@property
def level(self) -> int:
return self.handler.level

def handle(self, record: logging.LogRecord) -> bool:
return self.handler.handle(record)


class EventViewerPanel(QPlainTextEdit):
Expand Down Expand Up @@ -56,14 +75,14 @@ def val_changed(self, value: str) -> None:
@contextmanager
def add_gui_log_handler() -> Iterator[GUILogHandler]:
"""
Context manager for the GUILogHandler class. Will make sure that the handler
is removed prior to program exit.
Context manager for the GUILogHandler singleton. Will make sure that the
handler is removed prior to program exit.
"""
logger = logging.getLogger()

handler = GUILogHandler()
logger.addHandler(handler)
gui_handler = GUILogHandler()
logger.addHandler(gui_handler.handler)

yield handler
yield gui_handler

logger.removeHandler(handler)
logger.removeHandler(gui_handler.handler)
3 changes: 2 additions & 1 deletion src/ert/gui/tools/event_viewer/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from qtpy.QtGui import QIcon

from ert.gui.tools import Tool
from ert.gui.tools.event_viewer import EventViewerPanel, GUILogHandler

from .panel import EventViewerPanel, GUILogHandler


class EventViewerTool(Tool, QObject):
Expand Down

0 comments on commit d5af720

Please sign in to comment.