Code for qInstallMessageHandler()



  • I have a couple of questions about my own qInstallMessageHandler() function. I program in Python3/PyQt5, I don't have the Qt sources and I don't fancy downloading them and looking through myself, so I hope someone will be kind enough to enlighten me....

    def qtMessageHandler(type: QtCore.QtMsgType, context: QtCore.QMessageLogContext, msg: str):
        # Message handler for Qt qDebug() etc.
        # see https://evileg.com/en/post/154/,
        # https://stackoverflow.com/questions/35894171/redirect-qdebug-output-to-file-with-pyqt5,
        # http://thispageintentionally.blogspot.co.uk/2014/03/trapping-qt-log-messages.html
        if type == QtCore.QtCriticalMsg:    # qCritical()
            level = logging.CRITICAL
        elif type == QtCore.QtFatalMsg:     # qFatal()
            level = logging.ERROR
        elif type == QtCore.QtWarningMsg:   # qWarning()
            level = logging.WARNING
        elif type == QtCore.QtInfoMsg:      # qInfo()
            level = logging.INFO
        elif type == QtCore.QtDebugMsg:     # qDebug()
            level = logging.DEBUG
        else:
            level = logging.DEBUG
        rootLogger.log(level, "%s", msg)
        if type == QtCore.QtFatalMsg:
            # this is the C++ "abort()" they tell you to do for a "fatal" message...
            import sys
            sys.exit("abort")
    
    
    rootLogger = logging.getLogger()
    # install qtMessageHandler() to handle qDebug() etc.
    QtCore.qInstallMessageHandler(qtMessageHandler)
    
    
    1. I do not want to call the original, default handler from my code. In the code example http://doc.qt.io/qt-5/qtglobal.html#qInstallMessageHandler they tell you to call abort() for QtFatalMsg but not for QtCriticalMsg (I think they are the same log level). Is that correct? Or should QtCriticalMsg level also abort() after its message?

    2. [Python question, see also https://docs.python.org/3/library/logging.html] The code is all great. However, because I call rootLogger.log() via QtCore.qInstallMessageHandler(qtMessageHandler), and my output for all log formatters is format="%(levelname)s %(name)s [%(filename)s, %(lineno)d, %(funcName)s()]: %(message)s" the output is WARNING root [errfunctions.py, 56, qtMessageHandler()]: ..., i.e. it tells us it came from qtMessageHandler(); I want it to appear to come from the caller of qtMessageHandler(), i.e. somewhere in the outside world. Is there a simple way to achieve this? (Probably not...)


  • Lifetime Qt Champion

    Hi,

    1. They do not call any default handler. What is done is that they keep the same behaviour for fatal level message. Critical means that something bad happened but your application may continue to work, a fatal condition is that, everything has to stop otherwise bad consequence could happen.

    2. I don't know.


  • Qt Champions 2016

    Hi
    When i need to look at Qt code, i like
    https://code.woboq.org/



  • @SGaist said in Code for qInstallMessageHandler():

    Hi,

    1. They do not call any default handler. What is done is that they keep the same behaviour for fatal level message. Critical means that something bad happened but your application may continue to work, a fatal condition is that, everything has to stop otherwise bad consequence could happen.

    Thanks. Got it! To me, in computer-speak "critical" sounded more serious than "fatal" (though now that I come to think about it for humans, maybe not...) :)

    #2 remains unanswered. If there are any Python gurus out there, please let me know your thoughts on the traceback output in logger.log().


  • Moderators



  • @jsulm
    Thanks, I do use that principle already when when I'm doing my own explicit stuff. However, the issue here is to get it integrated (nicely) with what what Python's logger.log() does.

    It's printing out %(funcName)s, which is the calling function's name:

    def myMethod():
        logger.log("Whoops")
    

    shows myMethod as calling function --- good. However:

    def myMethod():
        # Call something in Qt which does an internal `qDebug()`
        # e.g. some widget does not like the `setStyleSheet()` it's been given
        widget.show()
    
    qInstallMessageHandler(qtMessageHandler)
    

    Now the caller of logger.log() is qtMessageHandler(), and that's the function name output. I'd like the function name to be myMethod (else I have no idea where in my code it was called from), which is the caller of the caller, so I'd like something like %(funcName[1])s in logger.log(), but I don't think that exists.

    I can probably do it all by writing explicit code in logger.log() (I think), but wanted to leverage its existing neatness. Thanks anyway!


  • Moderators

    @JNBarchan That's why I suggested to print the whole call stack, then you will see all function calls.



  • @jsulm
    Python's logger.log() formatter has %(funcName)s support for calling function name, but not inbuilt support for whole stack. Which is why I'd have to rewrite the logging. But thanks anyway.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.