web-dev-qa-db-fra.com

Comment rediriger la sortie de qDebug, qWarning, qCritical, etc.?

J'utilise beaucoup d'instructions qDebug() << pour la sortie de débogage. Existe-t-il un moyen multiplateforme de rediriger cette sortie de débogage vers un fichier, sans recourir aux scripts Shell? Je suppose que open () et dup2 () fera le travail sous Linux, mais cela fonctionnera-t-il compilé avec MinGW sous Windows?

Et peut-être qu'il y a une façon Qt de le faire?

77
Septagram

Vous devez installer un gestionnaire de messages à l'aide de la fonction qInstallMsgHandler, puis vous pouvez utiliser QTextStream pour écrire le débogage dans un fichier. Voici un exemple d'exemple:

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

Tiré du doc ​​de qInstallMsgHandler (j'ai seulement ajouté les commentaires):

Dans l'exemple ci-dessus, la fonction myMessageOutput utilise stderr que vous voudrez peut-être remplacer par un autre flux de fichiers, ou réécrire complètement la fonction!

Une fois que vous avez écrit et installé cette fonction, tous vos messages qDebug (ainsi que qWarning, qCritical etc) seraient redirigés vers le fichier dans lequel vous écrivez dans le gestionnaire .

105
Nawaz

De ici tous les crédits vont à esprit .

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

Voici un exemple pratique de raccordement du gestionnaire de messages par défaut.

Merci @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;
}
8
Andrew

Voici une solution multiplateforme pour vous connecter à la console, si l'application a été exécutée à partir de Qt Creator et dans le fichier debug.log, Lorsqu'elle est compilée et exécutée en tant qu'application autonome.

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

Le formatage du journal est géré par QString("%1 %2: %3 (%4)").arg... (pour le fichier) et fprintf(stderr, "%s %s: %s (%s:%u, %s)\n"... (pour console).

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

6
TranslucentCloud

Eh bien, je dirais que le moment où vous devez rediriger votre sortie de débogage vers quelque chose de différent de stderr, c'est quand vous pourriez penser à un outil de journalisation. Si vous sentez que vous en avez besoin, je vous recommande d'utiliser QxtLogger ( "La classe QxtLogger est un outil de journalisation facile à utiliser et à étendre." ) de la bibliothèque Qxt.

5
Piotr Dobrogost