C++ 如何重定向 qDebug、qWarning、qCritical 等输出?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4954140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:00:40  来源:igfitidea点击:

How to redirect qDebug, qWarning, qCritical etc output?

c++debuggingqtmingwqdebug

提问by Septagram

I'm using a lot of qDebug() <<statements for debug output. Is there any cross-platform way I can redirect that debug output to a file, without resorting to shell scripts? I'm guessing that open()and dup2()will do the job in Linux, but will it work compiled with MinGW in Windows?

我在qDebug() <<调试输出中使用了很多语句。是否有任何跨平台的方式可以将调试输出重定向到文件,而无需求助于 shell 脚本?我猜open()dup2()可以在 Linux 中完成这项工作,但它可以在 Windows 中使用 MinGW 编译吗?

And maybe there is a Qt way to do it?

也许有一种 Qt 方法可以做到这一点?

回答by Nawaz

You've to install a message handler using qInstallMsgHandlerfunction, and then, you can use QTextStreamto write the debugmessage to a file. Here is a sample example:

您必须使用qInstallMsgHandler函数安装消息处理程序,然后,您可以使用QTextStream调试消息写入文件。这是一个示例示例:

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

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

int main(int argc, char **argv)
{
    qInstallMessageHandler(myMessageOutput); // Install the handler
    QApplication app(argc, argv);
    ...
    return app.exec();
}

Taken from the doc of qInstallMsgHandler(I only added the comments):

取自qInstallMsgHandler(我只添加了评论)的文档:

In the above example, the function myMessageOutputuses stderrwhich you might want to replace with some other file stream, or completely re-write the function!

在上面的例子中,功能myMessageOutput用途stderr,你可能要与其他一些文件流更换或完全重新编写的功能!

Once you write and install this function, all your qDebug(as well as qWarning, qCriticaletc) messages would be redirected to the file you're writing to in the handler.

一旦你写并安装此功能,您所有的qDebug(以及qWarningqCritical等),消息将在处理程序被重定向到文件,您写信。

回答by Autodidact

From hereall credit goes to spirit.

这里开始,所有功劳都归功于精神

#include <QApplication>
#include <QtDebug>
#include <QFile>
#include <QTextStream>

void myMessageHandler(QtMsgType type, const QMessageLogContext &, const QString & msg)
{
    QString txt;
    switch (type) {
    case QtDebugMsg:
        txt = QString("Debug: %1").arg(msg);
        break;
    case QtWarningMsg:
        txt = QString("Warning: %1").arg(msg);
    break;
    case QtCriticalMsg:
        txt = QString("Critical: %1").arg(msg);
    break;
    case QtFatalMsg:
        txt = QString("Fatal: %1").arg(msg);
    break;
    }
    QFile outFile("log");
    outFile.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream ts(&outFile);
    ts << txt << endl;
}

int main( int argc, char * argv[] )
{
    QApplication app( argc, argv );
    qInstallMessageHandler(myMessageHandler);   
    ...
    return app.exec();
}

回答by Andrew

Here is a working example of hooking the default message handler.

这是挂钩默认消息处理程序的工作示例。

Thank you @Ross Rogers!

谢谢@罗斯罗杰斯!

// -- main.cpp

// Get the default Qt message handler.
static const QtMessageHandler QT_DEFAULT_MESSAGE_HANDLER = qInstallMessageHandler(0);

void myCustomMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    // Handle the messages!

    // Call the default handler.
    (*QT_DEFAULT_MESSAGE_HANDLER)(type, context, msg);
}

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

    QApplication a(argc, argv);

    qDebug() << "Wello Horld!";

    return 0;
}

回答by Neurotransmitter

Here is a cross-platform solution to log to the console, if the app was ran from the Qt Creator and to the debug.logfile, when it is compiled and being ran as a standalone app.

如果应用程序是从 Qt Creator 运行并登录到debug.log文件,则当它被编译并作为独立应用程序运行时,这是一个登录到控制台的跨平台解决方案。

main.cpp:

主.cpp:

#include <QApplication>
#include <QtGlobal>
#include <QtDebug>
#include <QTextStream>
#include <QTextCodec>
#include <QLocale>
#include <QTime>
#include <QFile>   

const QString logFilePath = "debug.log";
bool logToFile = false;

void customMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QHash<QtMsgType, QString> msgLevelHash({{QtDebugMsg, "Debug"}, {QtInfoMsg, "Info"}, {QtWarningMsg, "Warning"}, {QtCriticalMsg, "Critical"}, {QtFatalMsg, "Fatal"}});
    QByteArray localMsg = msg.toLocal8Bit();
    QTime time = QTime::currentTime();
    QString formattedTime = time.toString("hh:mm:ss.zzz");
    QByteArray formattedTimeMsg = formattedTime.toLocal8Bit();
    QString logLevelName = msgLevelHash[type];
    QByteArray logLevelMsg = logLevelName.toLocal8Bit();

    if (logToFile) {
        QString txt = QString("%1 %2: %3 (%4)").arg(formattedTime, logLevelName, msg,  context.file);
        QFile outFile(logFilePath);
        outFile.open(QIODevice::WriteOnly | QIODevice::Append);
        QTextStream ts(&outFile);
        ts << txt << endl;
        outFile.close();
    } else {
        fprintf(stderr, "%s %s: %s (%s:%u, %s)\n", formattedTimeMsg.constData(), logLevelMsg.constData(), localMsg.constData(), context.file, context.line, context.function);
        fflush(stderr);
    }

    if (type == QtFatalMsg)
        abort();
}

int main(int argc, char *argv[])
{
    QByteArray envVar = qgetenv("QTDIR");       //  check if the app is ran in Qt Creator

    if (envVar.isEmpty())
        logToFile = true;

    qInstallMessageHandler(customMessageOutput); // custom message handler for debugging

    QApplication a(argc, argv);
    // ...and the rest of 'main' follows

Log formatting is handled by QString("%1 %2: %3 (%4)").arg...(for the file) and fprintf(stderr, "%s %s: %s (%s:%u, %s)\n"...(for console).

日志格式由QString("%1 %2: %3 (%4)").arg...(对于文件)和fprintf(stderr, "%s %s: %s (%s:%u, %s)\n"...(对于控制台)处理。

Inspiration: https://gist.github.com/polovik/10714049.

灵感:https: //gist.github.com/polovik/10714049

回答by Piotr Dobrogost

Well, I would say that the moment when you need to redirect your debug output to anything different than stderr is when you could think about some logging tool. If you feel you need one I would recommend using QxtLogger("The QxtLogger class is an easy to use, easy to extend logging tool.") from Qxtlibrary.

好吧,我想说的是,当您需要将调试输出重定向到与 stderr 不同的任何内容时,您可以考虑使用某些日志记录工具。如果您觉得需要,我建议您使用库中的QxtLogger“QxtLogger 类是一种易于使用、易于扩展的日志记录工具。”Qxt