Как перенаправить вывод qDebug, qWarning, qCritical и т. Д.? - PullRequest
74 голосов
/ 10 февраля 2011

Я использую много операторов qDebug() << для вывода отладки.Есть ли какой-нибудь кроссплатформенный способ, которым я могу перенаправить этот вывод отладки в файл, не прибегая к сценариям оболочки?Я предполагаю, что open () и dup2 () выполнят эту работу в Linux, но будет ли она работать с MinGW в Windows?Qt способ сделать это?

Ответы [ 5 ]

102 голосов
/ 10 февраля 2011

Вы должны установить обработчик сообщений, используя функцию qInstallMsgHandler, а затем вы можете использовать QTextStream, чтобы записать сообщение debug в файл. Вот пример примера:

#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();
}

Взято из документа qInstallMsgHandler (я только добавил комментарии):

В приведенном выше примере функция myMessageOutput использует stderr, который вы можете заменить другим потоком файлов или полностью переписать функцию!

Как только вы напишите и установите эту функцию, все ваши сообщения qDebug (а также qWarning, qCritical и т. Д.) Будут перенаправлены в файл, в который вы пишете в обработчике.

14 голосов
/ 26 июня 2012

С здесь все кредиты идут на дух .

#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();
}
7 голосов
/ 27 апреля 2017

Вот рабочий пример подключения обработчика сообщений по умолчанию.

Спасибо, Росс Роджерс!

// -- 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;
}
6 голосов
/ 30 июля 2017

Вот кроссплатформенное решение для входа в консоль, если приложение запускалось из 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

Форматирование журнала обрабатывается QString("%1 %2: %3 (%4)").arg... (для файла) и fprintf(stderr, "%s %s: %s (%s:%u, %s)\n"... (для консоли).

Вдохновение:https://gist.github.com/polovik/10714049.

5 голосов
/ 10 февраля 2011

Ну, я бы сказал, что момент, когда вам нужно перенаправить вывод отладочной информации на что-то отличное от stderr, - это когда вы можете подумать о каком-либо инструменте регистрации. Если вы считаете, что он вам нужен, я бы порекомендовал использовать QxtLogger ( "Класс QxtLogger - это простой в использовании, легко расширяемый инструмент ведения журнала." ) из библиотеки Qxt.

...