Come redirect l’output qDebug, qWarning, qCritical etc?

Sto usando un sacco di qDebug() << debug qDebug() << per l’output di debug. C’è un modo multipiattaforma in cui posso redirect l’output di debug su un file, senza ricorrere agli script di shell? Immagino che open () e dup2 () faranno il lavoro in Linux, ma funzionerà compilato con MinGW in Windows?

E forse c’è un modo per farlo?

È necessario installare un gestore di messaggi utilizzando la funzione qInstallMsgHandler e quindi, è ansible utilizzare QTextStream per scrivere il messaggio di debug su un file. Ecco un esempio di esempio:

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

Tratto dal documento di qInstallMsgHandler (ho solo aggiunto i commenti):

  • QtMsgHandler qInstallMessageHandler (gestore QtMsgHandler)

Nell’esempio precedente, la funzione myMessageOutput utilizza stderr che potresti voler sostituire con un altro stream di file o riscrivere completamente la funzione!

Dopo aver scritto e installato questa funzione, tutti i messaggi qDebug (così come qWarning , qCritical etc) verrebbero reindirizzati al file che stai scrivendo nel gestore.

Da qui tutto il merito va allo spirito .

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

Ecco un esempio funzionante di aghook del gestore di messaggi predefinito.

Grazie @ Rog 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; } 

Bene, direi che il momento in cui è necessario redirect l’output di debug a qualcosa di diverso da stderr è quando si potrebbe pensare a qualche strumento di registrazione. Se ritieni di averne bisogno, ti consiglio di utilizzare QxtLogger ( “La class QxtLogger è uno strumento di registrazione facile da usare e facile da estendere.” ) Qxt libreria Qxt .

Ecco una soluzione multipiattaforma per accedere alla console, se l’app è stata eseguita da Qt Creator e nel file debug.log , quando viene compilata e viene eseguita come app autonoma.

main.cpp :

 #include  #include  #include  #include  #include  #include  #include  #include  const QString logFilePath = "debug.log"; bool logToFile = false; void customMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QHash 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 

La formattazione del registro è gestita da QString("%1 %2: %3 (%4)").arg... (per il file) e fprintf(stderr, "%s %s: %s (%s:%u, %s)\n"... (per console).

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