How to redirect logger output to PyQt text widget

The code sent to output redirection in PyQt does two good things at once: it uses the logging module to conveniently format messages and redirects the standard stdout and stderr to a QT QTextBrowser widget. But I would like QTextBrowser get all print output coming out of the current code. In particular, I want to forward well-formatted messages that come from the registrar. An ideal solution would be to redirect every registrar. QTextBrowser to QTextBrowser (and not just stdout and stderr ). Actually, I would prefer to forward the logger messages instead of stdout and stderr if I need to choose between two ... So, here are the commands used to print formatted messages:

 logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') 

And here is the code: enter image description here

========

 import sys from PyQt4 import QtCore, QtGui import logging logger = logging.getLogger(__name__) class XStream(QtCore.QObject): _stdout = None _stderr = None messageWritten = QtCore.pyqtSignal(str) def flush( self ): pass def fileno( self ): return -1 def write( self, msg ): if ( not self.signalsBlocked() ): self.messageWritten.emit(unicode(msg)) @staticmethod def stdout(): if ( not XStream._stdout ): XStream._stdout = XStream() sys.stdout = XStream._stdout return XStream._stdout @staticmethod def stderr(): if ( not XStream._stderr ): XStream._stderr = XStream() sys.stderr = XStream._stderr return XStream._stderr class MyDialog(QtGui.QDialog): def __init__( self, parent = None ): super(MyDialog, self).__init__(parent) self._console = QtGui.QTextBrowser(self) self._button = QtGui.QPushButton(self) self._button.setText('Test Me') layout = QtGui.QVBoxLayout() layout.addWidget(self._console) layout.addWidget(self._button) self.setLayout(layout) XStream.stdout().messageWritten.connect( self._console.insertPlainText ) XStream.stderr().messageWritten.connect( self._console.insertPlainText ) self._button.clicked.connect(self.test) def test( self ): print 'printing LINE 1' print 'printing LINE 2' logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') # error out something print blah if ( __name__ == '__main__' ): # logging.basicConfig() # logging.basicConfig(filename='example.log',level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG) app = None if ( not QtGui.QApplication.instance() ): app = QtGui.QApplication([]) dlg = MyDialog() dlg.show() if ( app ): app.exec_() 

LAST AFTER: A FULLY WORKING EXAMPLE :: SOLVES Mr.Dano

 import sys from PyQt4 import QtCore, QtGui import logging class QtHandler(logging.Handler): def __init__(self): logging.Handler.__init__(self) def emit(self, record): record = self.format(record) if record: XStream.stdout().write('%s\n'%record) # originally: XStream.stdout().write("{}\n".format(record)) logger = logging.getLogger(__name__) handler = QtHandler() handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s")) logger.addHandler(handler) logger.setLevel(logging.DEBUG) class XStream(QtCore.QObject): _stdout = None _stderr = None messageWritten = QtCore.pyqtSignal(str) def flush( self ): pass def fileno( self ): return -1 def write( self, msg ): if ( not self.signalsBlocked() ): self.messageWritten.emit(unicode(msg)) @staticmethod def stdout(): if ( not XStream._stdout ): XStream._stdout = XStream() sys.stdout = XStream._stdout return XStream._stdout @staticmethod def stderr(): if ( not XStream._stderr ): XStream._stderr = XStream() sys.stderr = XStream._stderr return XStream._stderr class MyDialog(QtGui.QDialog): def __init__( self, parent = None ): super(MyDialog, self).__init__(parent) self._console = QtGui.QTextBrowser(self) self._button = QtGui.QPushButton(self) self._button.setText('Test Me') layout = QtGui.QVBoxLayout() layout.addWidget(self._console) layout.addWidget(self._button) self.setLayout(layout) XStream.stdout().messageWritten.connect( self._console.insertPlainText ) XStream.stderr().messageWritten.connect( self._console.insertPlainText ) self._button.clicked.connect(self.test) def test( self ): logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') print 'Old school hand made print message' if ( __name__ == '__main__' ): app = None if ( not QtGui.QApplication.instance() ): app = QtGui.QApplication([]) dlg = MyDialog() dlg.show() if ( app ): app.exec_() 
+6
source share
2 answers

You can create a custom logging.Handler and add it to your logger :

 import logging logger = logging.getLogger(__name__) class QtHandler(logging.Handler): def __init__(self): logging.Handler.__init__(self) def emit(self, record): record = self.format(record) XStream.stdout().write("{}\n".format(record)) handler = QtHandler() handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s")) logger.addHandler(handler) logger.setLevel(logging.DEBUG) 

Then delete the line logging.basisConfig(level=logging.DEBUG) in the if __name__ == "__main__": block. You will see that your log messages are displayed only in the dialog box.

+9
source

Dano's answer works on 2.7.x but not 3.x.

To get the code provided by @dano working in 3.4.3, I had to make explicit changes to the print statements, as well as change the write () method in the XStream class from self.messageWritten.emit(unicode(msg)) to self.messageWritten.emit(msg) . This call from Unicode simply made the dialogue sit and look at me with pleasure.

0
source

All Articles