I have a large program that takes a long time that needs ample logging. I have a GUI that is on the front end that includes a custom logging handler as defined below:
class QHandler(logging.Handler, QTextEdit):
def __init__(self, parent=None):
QTextEdit.__init__(self, parent)
logging.Handler.__init__(self)
self.setLineWrapMode(QTextEdit.NoWrap)
self.setReadOnly(True)
self.emit_lock = Lock()
def emit(self, record):
with self.emit_lock:
self.append(self.format(record))
self.autoScroll()
def format(self, record):
if (record.levelno <= logging.INFO):
bgcolor = WHITE
fgcolor = BLACK
if (record.levelno <= logging.WARNING):
bgcolor = YELLOW
fgcolor = BLACK
if (record.levelno <= logging.ERROR):
bgcolor = ORANGE
fgcolor = BLACK
if (record.levelno <= logging.CRITICAL):
bgcolor = RED
fgcolor = BLACK
else:
bgcolor = BLACK
fgcolor = WHITE
self.setTextBackgroundColor(bgcolor)
self.setTextColor(fgcolor)
self.setFont(DEFAULT_FONT)
record = logging.Handler.format(self, record)
return record
def autoScroll(self):
self.verticalScrollBar().setSliderPosition(self.verticalScrollBar().maximum())
I have the main gui (QMainWindow) that adds this handler via:
# inside __init__ of main GUI (QMainWindow):
self.status_handler = QHandler()
# Main gui is divided into tabs and the status handler box is added to the second tab
main_tabs.addTab(self.status_handler, 'Status')
And I have the controller function that initializes the logging handler via:
# inside controller initializing function
gui = gui_class() # this is the main gui that initializes the handler among other things
logger = logging.getLogger()
gui.status_handler.setFormatter(file_formatter) # defined elsewhere
logger.addHandler(gui.status_handler)
Once the GUI is raised and logging is initialized, I finish the python execution with:
app = QApplication.instance()
if (app is None):
app = QApplication([])
app.setStyle('Fusion')
app.exec_()
The GUI has a few slots connected to pushbutton signals that spawns threads to do the actual processing. Each processing thread has it's own logging call which seems to work as intended. They are defined like follows:
class Subprocess_Thread(Thread):
def __init__(self, <args>):
Thread.__init__(self)
self.logger = logging.getLogger(self.__class__.__name__)
self.logger.info('Subprocess Thread Created')
def run(self):
# does a bunch of stuff
self.logger.info('Running stuff')
# iterates over other objects and calls on them to do stuff
# where they also have a logger attached and called just like above
When I run my application without a GUI or even with the GUI minimized, it runs fine every time. I can see my log messages in the console (either command prompt or spyder
).
If I run the same application without minimizing the GUI, I will see the log messages in the GUI for initialization and some of the first parts of the threaded process, but then it will hang at seemingly random times. There is no error message and the CPU usage seems to be maxed out for the single core that is being used. I included a lock just to make sure logging
wasn't coming in from different threads, but that also didn't help.
I've tried going to a QPlainTextEdit
and a QListWidget
but I get the same problem every time.
Does anyone have an idea of why this GUI element would cause the entire Python interpreter to hang when in view and messages are logged to it?