如何重定向qDebug,qWarning,qCritical等输出?

Sep*_*ram 77 c++ debugging qt mingw qdebug

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

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

Naw*_*waz 106

您将使用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();
}
Run Code Online (Sandbox Code Playgroud)

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

在上面的示例中,函数myMessageOutput使用stderr您可能想要替换的其他文件流,或者完全重写函数!

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

  • 文档链接和API已经发生了一些变化.`qInstallMsgHandler`在Qt5中被弃用并被`qInstallMessageHandler`(同样的想法)取代.对于5.0`qInstallMsgHandler`位于http://qt-project.org/doc/qt-5.0/qtcore/qtglobal.html#qInstallMsgHandler,并且`qInstallMessageHandler`也在那里.对于5.1,`qInstallMsgHandler`被完全删除. (8认同)
  • 嘿,非常感谢.它不仅可以让我将调试输出重定向到文件,还可以让我打印更多有用的信息,比如时间戳:) (3认同)
  • @Septagram:没错.您可以在hanlder中添加一些有用的消息; 根据您使用的`qDebug`,`qWarning`,`qCritical`等等,您甚至可以将不同的消息输出到不同的文件! (2认同)

Aut*_*act 15

这里,所有的荣誉归于精神.

#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();
}
Run Code Online (Sandbox Code Playgroud)

  • 此消息处理程序不是线程安全的。如果它们同时由两个线程发送,您将丢失日志消息(outFile.open() 将为其中一个线程返回 false)。您可以在尝试打开文件之前锁定 QMutex,然后在关闭文件后解锁互斥锁。这是最简单的方法,但会引入线程争用。否则,您将需要查看低开销线程安全消息队列……并且您可能会更好地使用框架。 (2认同)

And*_*rew 8

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

谢谢@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;
}
Run Code Online (Sandbox Code Playgroud)


Tra*_*oud 6

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

main.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
Run Code Online (Sandbox Code Playgroud)

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

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


mrt*_*rts 6

这是一个简单的、线程安全的惯用 Qt 示例,用于记录日志stderr和文件:

void messageHandler(QtMsgType 类型,const QMessageLogContext& 上下文,const QString& 消息)
{
    静态 QMutex 互斥体;
    QMutexLocker 锁(&mutex);

    静态 QFile 日志文件(LOGFILE_LOCATION);
    static bool logFileIsOpen = logFile.open(QIODevice::Append | QIODevice::Text);

    std::cerr << qPrintable(qFormatLogMessage(类型、上下文、消息)) << std::endl;

    if (logFileIsOpen) {
        logFile.write(qFormatLogMessage(类型,上下文,消息).toUtf8() + '\n');
        logFile.flush();
    }
}

按照其他答案中的描述安装它qInstallMessageHandler(messageHandler)


Pio*_*ost 5

好吧,我想说当你需要将调试输出重定向到与stderr不同的任何东西时,你可以考虑一些日志工具.如果您觉得需要,我建议使用QxtLogger("QxtLogger类是一个易于使用,易于扩展的日志记录工具.")来自Qxt库.