Qt log output class QtMessageHandler

1. Open the QT help document and find the class to see the description of the class

typedef <QtGlobal>::QtMessageHandler
This is a typedef for a pointer to a function with the following signature:

  void myMessageHandler(QtMsgType, const QMessageLogContext &, const QString &);

Obviously, it points to a function

2. See what the following entry parameters mean

enum <QtGlobal>::QtMsgType
This enum describes the messages that can be sent to a message handler (QtMessageHandler). You can use the enum to identify and associate the various message types with the appropriate actions.

Constant                  Value      Description
<QtGlobal>::QtDebugMsg      0        A message generated by the qDebug() function.
<QtGlobal>::QtInfoMsg       4        A message generated by the qInfo() function.
<QtGlobal>::QtWarningMsg    1        A message generated by the qWarning() function.
<QtGlobal>::QtCriticalMsg   2        A message generated by the qCritical() function.
<QtGlobal>::QtFatalMsg      3        A message generated by the qFatal() function.
<QtGlobal>::QtSystemMsg     QtCriticalMsg
 

QtMsgType this is an enumeration type that lists six types of messages

  • qDebug: debugging information
  • qInfo: normal information
  • qWarning: warning message
  • qCritical: critical error
  • qFatal: fatal error

Look again. QMessageLogContext

Detailed Description
The class provides information about the source code location a qDebug(), qInfo(), qWarning(), qCritical() or qFatal() message was generated.
Note: By default, this information is recorded only in debug builds. You can overwrite this explicitly by defining QT_MESSAGELOGCONTEXT or QT_NO_MESSAGELOGCONTEXT.
See also QMessageLogger, QtMessageHandler, and qInstallMessageHandler(). 

Here's an important message: by default, this information is only recorded in the debug build. You can explicitly override it by defining QT? Messagelogcontext or QT? No? Messagelogcontext.

This is what you need to add to the pro file when you want to build with Release

DEFINES += QT_MESSAGELOGCONTEXT

3. There is also a related function qInstallMessageHandler().

Look at the description.

QtMessageHandler <QtGlobal>::qInstallMessageHandler(QtMessageHandler handler)
Installs a Qt message handler which has been defined previously. Returns a pointer to the previous message handler.
The message handler is a function that prints out debug messages, warnings, critical and fatal error messages. The Qt library (debug mode) contains hundreds of warning messages that are printed when internal errors (usually invalid function arguments) occur. Qt built in release mode also contains such warnings unless QT_NO_WARNING_OUTPUT and/or QT_NO_DEBUG_OUTPUT have been set during compilation. If you implement your own message handler, you get total control of these messages.
The default message handler prints the message to the standard output under X11 or to the debugger under Windows. If it is a fatal message, the application aborts immediately.
Only one message handler can be defined, since this is usually done on an application-wide basis to control debug output.
To restore the message handler, call qInstallMessageHandler(0).

Translate

Install the previously defined Qt message handler. Returns a pointer to the previous message handler.
Message handlers are functions that output debug, warning, critical, and fatal error messages. The Qt library (debug mode) contains hundreds of warning messages that are printed when an internal error (usually an invalid function parameter) occurs. QT built in release mode also contains such warnings unless QT ﹣ no ﹣ warning ﹣ output and / or QT ﹣ no ﹣ debug ﹣ output are set during compilation. If you implement your own message handlers, you have full control over the messages.
The default message handler prints messages to standard output under X11 or to a debugger under Windows. If it is a fatal message, the application is immediately aborted.
Only one message handler can be defined, because this is usually done within the scope of the application in order to control the debug output.
To recover the message handler, call qInstallMessageHandler(0).

As you can see from this description, we need to define a function. The official has given an example:

void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
  {
      QByteArray localMsg = msg.toLocal8Bit();
      const char *file = context.file ? context.file : "";
      const char *function = context.function ? context.function : "";
      switch (type) {
      case QtDebugMsg:
          fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
          break;
      case QtInfoMsg:
          fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
          break;
      case QtWarningMsg:
          fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
          break;
      case QtCriticalMsg:
          fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
          break;
      case QtFatalMsg:
          fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
          break;
      }
  }

This function isQ tMessageHandler refers to the function, where type refers to the message type, context refers to the collection of the file, function and line number lamp information to save the generated message, and msg refers to the message

When using it, you need to use the qinstallmessagehandler( QtMessageHandler handler) to register

qInstallMessageHandler(myMessageOutput);

4. Now create a new project to debug the function

Declare a function in the header file

static void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);

Add definition in cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    qInstallMessageHandler(myMessageOutput);

    qDebug() << "Debug";
    qWarning() << "Warning";
    qInfo() << "Info";
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QByteArray localMsg = msg.toLocal8Bit();
    const char *file = context.file ? context.file : "";
    const char *function = context.function ? context.function : "";
    switch (type) {
    case QtDebugMsg:
        fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        break;
    case QtInfoMsg:
        fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        break;
    case QtWarningMsg:
        fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        break;
    case QtCriticalMsg:
        fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        break;
    case QtFatalMsg:
        fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
        break;
    }
}

Run, nothing

Close the program and print out some information

Debug: Debug (..\log\mainwindow.cpp:11, MainWindow::MainWindow(QWidget*))
Warning: Warning (..\log\mainwindow.cpp:12, MainWindow::MainWindow(QWidget*))
Info: Info (..\log\mainwindow.cpp:13, MainWindow::MainWindow(QWidget*))

It can be seen that Qt log can be used to accurately locate the message location, but this is only after the program is closed. If this information can be output in real time, it will be more intuitive when debugging the program

Think of the macro about debugging in C language

__FILE name
 __FUNCTION name
 __LINE: number of lines
 __DATE:
__TIME:

So in Qt, Baidu has a look. It's the same as C

such as

    qInstallMessageHandler(myMessageOutput);
    qInstallMessageHandler(nullptr);
    qDebug() << "[" <<__FILE__ <<":"<<__FUNCTION__<<":"<<__LINE__ <<"]" << "Debug";
    qWarning() << "[" <<__FILE__ <<":"<<__FUNCTION__<<":"<<__LINE__ <<"]" << "Warning";
    qInfo() << "[" <<__FILE__ <<":"<<__FUNCTION__<<":"<<__LINE__ <<"]" << "Info";

output

[ ..\log\mainwindow.cpp : MainWindow : 10 ] Debug
[ ..\log\mainwindow.cpp : MainWindow : 11 ] Warning
[ ..\log\mainwindow.cpp : MainWindow : 12 ] Info

You need to recover the message handler before you can see the output. This is ok

But it's too much trouble to write debug like this. Declare a macro directly in the header file

#define cout qDebug() << "[" <<__FILE__ <<":"<<__FUNCTION__<<":"<<__LINE__ <<"]"

In this way, you can use cout < ""; directly

Back to the subject

Now we can see the log output. Next, save the log as a file in. Log format

It depends on what information is written. I'm going to write all the information here

First change the function to get the desired information

Encapsulate the information

    QString str_type = QString("Message type:%1\n").arg(localMsg.constData());
    QString str_file_line_function = QString("Message location:%1:%2,%3\n").arg(file).arg(context.line).arg(function);
    QString str_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd") + '\n';
    QString message = str_type + str_file_line_function + str_date_time;

What we want to write to. log is message

Finally, modify the function as follows:

void MainWindow::myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{

    QByteArray localMsg = msg.toLocal8Bit();
    const char *file = context.file ? context.file : "";
    const char *function = context.function ? context.function : "";
    QString str_type = QString("type:%1\n").arg(localMsg.constData());
    QString str_file_line_function = QString("position:%1:%2,%3\n").arg(file).arg(context.line).arg(function);
    QString str_date_time = "time" + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd") + '\n';
    QString message = str_type + str_file_line_function + str_date_time;


    QString logPath = qApp->applicationDirPath() + "/log/"; /* log Folder */

    QDir dir(logPath);
    if(!dir.exists())
    {
        dir.mkpath(logPath);
    }
    /* log file */
    QString filePath = QString("%1%2.log").arg(logPath).arg(QDateTime::currentDateTime().toString("yyyy-MM-dd"));
    QFile logFile(filePath); /* Create a log file */
    /* Open in write only mode, append data */
    logFile.open(QIODevice::WriteOnly | QIODevice::Append);
    /* Text data flow */
    QTextStream text_stream(&logFile);
    /* Write data */
    text_stream << message << "\r\n";
    logFile.flush();
    logFile.close();
}

I've removed the enumeration here. If you want to write a certain message type, you can add the switch and make a judgment. It's ok to use if directly

After the final run

 

In this case, the daily log will be saved as a file

Open file

Type: Debug
 Location:. \ log\mainwindow.cpp:10,MainWindow::MainWindow(QWidget *)
Time: January 15, 2020 14:25:15 Wednesday

Type: Warning
 Location:. \ log\mainwindow.cpp:11,MainWindow::MainWindow(QWidget *)
Time: January 15, 2020 14:25:15 Wednesday

Type: Info
 Location:. \ log\mainwindow.cpp:12,MainWindow::MainWindow(QWidget *)
Time: January 15, 2020 14:25:15 Wednesday

Saved successfully!

Published 12 original articles, won praise 6, visited 2475
Private letter follow

Tags: Qt Windows C

Posted on Tue, 14 Jan 2020 23:22:23 -0800 by barrowvian