Qt 5.4 - Sending qDebug() to a file (aka logging) - (SOLVED)



  • I apologize in advance for asking a newbie level question.

    I would like to send all the qDebug(), qWarning(), qCritical() and similar output to a file rather than the console for debug logging purposes. So far I cannot make heads or tails of the docs provided that apply to this purpose.

    First how do I configure debug to know to send ouput to a file of my choosing? I know I could open a file with QIODevice, and write messages to that ... but it is my understanding there is another way within the Qt Logging Framework.

    Secondly, I see documentation on QLoggingCategory and QMessageLogger. The docs are written as though I am supposed to know what to do with this information to start with. There is no cross-reference that provides any more information. I mean, yes it explains the use of the specific library object, but not how it is a part of the Qt Logging Framework nor any example of the type that may give me any usable idea how to proceed.

    I have had other developers tell me that QDebug() is quite capable of doing this ... but I have yet to figure out how.

    Is anyone doing anything similar?





  • Diabolic (qute)

    Thanks for the reply. This looks like a temporary soluition.

    However, should I decide to provide the app user with an option to send log messages to a file this would not work.

    Secondly, there is no indication where the class you presented goes. Is this in the main.cpp, in every class to be debugged? What?

    It appears it is not in main.cpp because you mention that
    qInstallMessageHandler(customMessageHandler);
    has to be in the main().

    Also, if friend QDebug operator << (QDebug d, const Protocol &p);
    is to be in the class to debug, then the customMessageHandler() has to be accessible to the class being debugged.

    Is it possible to use the QLoggingCategory and QMessageLogger in this context?


  • Lifetime Qt Champion

    Hi,

    "Here":http://blog.qt.io/blog/2014/03/11/qt-weekly-1-categorized-logging/ you have an interesting article on how to use QLoggingCategory to write your debugging to a file.



  • I am not sure what is not clear

    in main:
    @qInstallMsgHandler( releaseMessageOutput );@

    somewhere:
    @void releaseMessageOutput( QtMsgType type, const char *msg )
    {
    // Switch structure left to be converted to write into the file in the future
    switch ( type ) {
    case QtDebugMsg:
    fprintf( stderr, "Debug: %s\n", msg );
    break;
    case QtWarningMsg:
    fprintf( stderr, "Warning: %s\n", msg );
    break;
    case QtFatalMsg:
    fprintf( stderr, "Fatal: %s\n", msg );
    abort(); // deliberately core dump
    }
    }
    @



  • Exactly what does "somewhere" mean. In a class, in main.cpp, in a .cpp file? ? ? Does it not it have to be at least a friend to anything that uses it?



  • Somewhere means anywhere. this is global function.

    You can put function above your main or add it anywhere but add declaration
    void releaseMessageOutput( QtMsgType type, const char *msg ); above main.



  • OK here is the progress I have made so far:

    main.cpp
    @
    #include <stdio.h>
    #include <stdlib.h>

    #include <QtCore/QDebug>
    #include <QtCore/QtGlobal>
    #include <QtCore/QFile>
    #include <QtCore/QMessageLogger>
    #include <QtCore/QMessageLogContext>
    #include <QtCore/QtMessageHandler>
    #include <QtWidgets/QApplication>

    #include "mainwindow.hpp"

    #define QT_MESSAGE_PATTERN = "[%{type}] %{function}:%{line} - %{message}"

    void debugMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
    {
    Q_UNUSED(context);
    QByteArray txt = QString("").toLocal8Bit();
    // Switch structure left to be converted to write into the file in the future
    switch ( type )
    {
    case QtDebugMsg:
    txt += QString("{Debug} \t\t %1").arg(msg);
    break;
    case QtWarningMsg:
    txt += QString("{Warning:} \t %1").arg(msg);
    break;
    case QtCriticalMsg:
    txt += QString("{Critical:} \t %1").arg(msg);
    break;
    case QtFatalMsg:
    txt += QString("{Fatal:} \t %1").arg(msg);
    abort(); // deliberately core dump
    }
    QFile outFile("Debug.log");
    outFile.open(QIODevice::WriteOnly | QIODevice::Append);

    QTextStream textStream(&outFile);
    textStream << txt << endl;
    

    }

    int main(int argc, char *argv[])
    {
    qInstallMessageHandler(debugMessageOutput);

    QApplication a(argc, argv);
    
    qDebug() << "Loading from Main()";
    MainWindow w;
    
    w.show();
    
    return a.exec&#40;&#41;;
    

    }
    @

    The problem is that the compiler complains of undefined reference to QDebug::QDebug()

    As can be seen in the main.cpp there is a include for QDebug.

    Actually this error occurs for any use of qDebug() anywhere.

    Any help...what am I doing wrong?



  • Could you show exact compiler message?
    My code works fine in QT 4 and it looks like you made required for qt 5 changes.



  • Also I would suggest to open file and keep it opened once instead of opening it for every string output, especially cause you current directory can be changed and you will and up with parts of the log in different locations.



  • By the way have you tried:
    #include <QDebug>

    instead of

    #include <QtCore/QDebug>



  • Alex_malyu

    The only thing missing from the compiler message is the line number - which is the qDebug() statement.

    main.cpp:49: undefined reference to `QDebug::~QDebug()'

    I am using Qt 5.4 so the recommendation from the docs is to be specific by using <QtCore/QDebug> rather than the more general <QDebug> from earlier versions.

    I do plan to open once and write many, but I have to get past this error first.



  • You might have problem with old libraries picked up.
    At least people with similar issues solved it by cleaning and/or rebuilding.

    Check below link for example:
    "https://bugreports.qt.io/browse/QTBUG-40458":https://bugreports.qt.io/browse/QTBUG-40458



  • Alex_Malyu

    Well I rather doubt that is the case since Qt 5.4 is the only version I am referencing in the tool chain. However, I will check just to be sure.

    BTW without the redirection, QDebug() works fine.



  • As suspected...no diff after a thorough clean and re-compile attempt.



  • i just grabbed your code in main.cpp and it worked.. output in log file:

    @$ cat Debug.log
    {Debug} Loading from Main()
    @

    so it must be environmental



  • [quote author="ad5xj" date="1423516765"]As can be seen in the main.cpp there is a include for QDebug.

    Actually this error occurs for any use of qDebug() anywhere.

    Any help...what am I doing wrong?[/quote]

    You have to #include <QDebug> (or, #include <QtCore/QDebug>) in every file you want to use qDebug() from.



  • The include does not clear the error.

    An environmental error as suggested would not allow QDebug() to work normally as it does.
    The only problem I have is the redirection as stated earlier.



  • I think I have come up with at least a minimal solution:

    main.cpp
    @
    #include <stdio.h>
    #include <stdlib.h>

    #include <QtCore/QDebug>
    #include <QtCore/QtGlobal>
    #include <QtCore/QFile>
    #include <QtCore/QDateTime>
    #include <QtCore/QString>
    #include <QtCore/QMessageLogger>
    #include <QtCore/QMessageLogContext>
    #include <QtCore/QtMessageHandler>
    #include <QtWidgets/QApplication>

    #include "myGUI.hpp"

    void debugMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
    {
    //Q_UNUSED(context);
    QString timestr;
    timestr = QDateTime::currentDateTime().toString("ddd d MMMM yyyy hh:mm:ss ");
    QByteArray txt;
    txt += timestr;
    // Switch structure left to be converted to write into the file in the future
    switch ( type )
    {
    case QtDebugMsg:
    txt += " Debug ";
    txt += context.file;
    txt += ":";
    txt += QString("%1").arg(context.line);
    txt += QString(" - %1").arg(msg);
    break;
    case QtWarningMsg:
    txt += context.function;
    txt += ":";
    txt += context.line;
    txt += QString(" - Warning: \t %1").arg(msg);
    break;
    case QtCriticalMsg:
    txt += context.function;
    txt += ":";
    txt += context.line;
    txt += QString(" - Critical: \t %1").arg(msg);
    break;
    case QtFatalMsg:
    txt += context.function;
    txt += ":";
    txt += context.line;
    txt += QString(" - Fatal: \t %1").arg(msg);
    abort(); // deliberately core dump
    }
    QFile outFile("Debug.log");
    outFile.open(QIODevice::WriteOnly | QIODevice::Append);

    QTextStream textStream(&outFile);
    textStream << txt << endl;
    

    }

    int main(int argc, char *argv[])
    {
    qInstallMessageHandler(debugMessageOutput);

    QApplication a(argc, argv);
    QMessageLogger("MAIN",58,"main").debug("Loading from MAIN");
    MyGui g;
    
    g.show();
    
    return a.exec&#40;&#41;;
    

    }
    @

    then in any module you want to log from...
    @

    include <QtCore/QDebug>

    include <QtCore/QMessageLogger>

    ...
    void myFunc()
    {
    #ifdef DEBUG_MYDEF
    QString errmsg
    errmsg += "This is my message - ";
    errmsg += QString("%1").arg(errno);

    QMessageLogger("MyModule",int mylineno,"funcname").debug(errmsg.toLocal8Bit());
    

    #endif

    }
    @

    It creates a Debug.log file with time stamped entries.

    I have conditioned the logger with DEFINES I created but there are a number of other ways this could work just as well.


Log in to reply
 

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