天天看點

Qt qInstallMessageHandler(自定義消息處理)前言調試宏使用自定義消息處理程式自定義輸出到檔案

前言

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).

這是官方說明,主要的意思就是:

安裝自定義的消息處理程式,傳回指向上一個消息處理程式的指針。

消息處理程式是一個支援列印調試資訊、警告、關鍵和緻命錯誤資訊的函數。Qt庫(debug模式)包含數以百計的警告資訊,當内部錯誤(通常是無效的函數參數)發生時,會列印出來。在Release模式下建構也包含這些警告,除非在編譯時設定QT_NO_WARNING_OUTPUT和/或QT_NO_DEBUG_OUTPUT。如果你實作了自己的消息處理程式,你就可以完全控制這些消息。

預設消息處理程式将消息列印到 X11 下的标準輸出或 Windows 下的調試器。如果是緻命消息,應用程式會立即中止。

隻能定義一個消息處理程式,因為這通常是在應用程式範圍内完成的,以控制調試輸出。

調用qInstallMessageHandler(0)可以恢複消息處理程式。

調試宏

Qt調試資訊相關的宏有以下5種:

  • qDebug() 調試消息
  • qInfo() 資訊消息
  • qWarning() 警告消息
  • qCritical() 錯誤消息
  • qFatal() 緻命錯誤消息

使用

在使用預設消息處理程式時,我們看一下調試輸出的内容:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 列印資訊
    qDebug() << "This is a debug message";
    qDebug("This is a debug message");
    qInfo("This is a info message");
    qWarning("This is a warning message");
    qCritical("This is a critical message");
    qFatal("This is a fatal message");
    
    return a.exec();
}
           

輸出:

This is a debug message

This is a debug message

This is a info message

This is a warning message

This is a critical message

This is a fatal message

自定義消息處理程式

我們直接拿官網的示例來測試:

#include <qapplication.h>
#include <stdio.h>
#include <stdlib.h>

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;
    }
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    // 安裝消息處理程式
    auto front = qInstallMessageHandler(myMessageOutput);
    // 列印資訊
    qDebug() << "This is a debug message";
    qDebug("This is a debug message");
    qInfo("This is a info message");
    qWarning("This is a warning message");
    qCritical("This is a critical message");
    qFatal("This is a fatal message");
    
    return a.exec();
}
           

輸出:

Debug: This is a debug message (…\main.cpp:88, int __cdecl main(int,char *[]))

Debug: This is a debug message (…\main.cpp:89, int __cdecl main(int,char *[]))

Info: This is a info message (…\main.cpp:90, int __cdecl main(int,char *[]))

Warning: This is a warning message (…\main.cpp:91, int __cdecl main(int,char *[]))

Critical: This is a critical message (…\main.cpp:92, int __cdecl main(int,char *[]))

Fatal: This is a fatal message (…\main.cpp:93, int __cdecl main(int,char *[]))

從上面示例看出我們可以去規範輸出的格式,那麼我們能不能決定輸出的地方呢?比如直接輸出到檔案中?

自定義輸出到檔案

直接上代碼:

void myMessageOutputToFile(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
    QByteArray msgAry = msg.toLocal8Bit();

    QString msgTypeStr;
    switch (type) {
    case QtDebugMsg:
        msgTypeStr = QString("Debug");
        break;
    case QtInfoMsg:
        msgTypeStr = QString("Info");
        break;
    case QtWarningMsg:
        msgTypeStr = QString("Warning");
        break;
    case QtCriticalMsg:
        msgTypeStr = QString("Critical");
        break;
    case QtFatalMsg:
        msgTypeStr = QString("Fatal");
        break;
    }
    
    // 輸出字元串格式化
    QString dateTimeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    QString msgStr = QString("[%1][%2] [%3:%4:%5]:%6").arg(dateTimeStr).arg(msgTypeStr)
                             .arg(context.file).arg(context.line).arg(context.function).arg(msgAry.constData());
    
    // 讀寫檔案
    QFile file("log.txt");
    file.open(QIODevice::ReadWrite | QIODevice::Append);
    QTextStream stream(&file);
    stream << msgStr << "\r\n";
    file.flush();
    file.close();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    // 安裝消息處理程式
    auto front = qInstallMessageHandler(myMessageOutputToFile);
    
    // 列印資訊
    qDebug() << "This is a debug message";
    qDebug("This is a debug message");
    qInfo("This is a info message");
    qWarning("This is a warning message");
    qCritical("This is a critical message");
    qFatal("This is a fatal message");
    
    return a.exec();
}
           

輸出:

Qt qInstallMessageHandler(自定義消息處理)前言調試宏使用自定義消息處理程式自定義輸出到檔案

注意:

1.多線程下I/O操作需要加鎖

2.這種方式隻針對那些不在乎性能的小項目,因為檔案讀寫和QDateTime擷取時間這些操作是比較耗時的,是以對于性能要求較高的項目還是建議用開源的日志庫,比如:log4qt、spdlog、log4cpp等等。

繼續閱讀