qDebug() <<
デバッグ出力に多くのステートメントを使用しています。シェルスクリプトに頼らずに、そのデバッグ出力をファイルにリダイレクトできるクロスプラットフォームの方法はありますか?私は推測しているオープン()とdup2の()は、 Linuxの中で仕事をするだろうが、それはWindowsでのMinGWでコンパイルした動作しますか?
そして多分それをするQtの方法がありますか?
回答:
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();
}
qInstallMsgHandler
(コメントを追加しただけです)のドキュメントから引用:
上記の例では、関数myMessageOutput
はstderr
これを使用して、他のファイルストリームに置き換えるか、関数を完全に書き直します。
あなたが書くと、この機能をインストールすると、すべてのqDebug
(だけでなく、などqWarning
、qCritical
など)のメッセージは、ハンドラ内に、あなたしている書き込みファイルにリダイレクトされます。
qDebug
、qWarning
、qCritical
およびにそう!
qInstallMsgHandler
非推奨になり、qInstallMessageHandler
(同じアイデア)に置き換えられました。5.0の場合qInstallMsgHandler
であるqt-project.org/doc/qt-5.0/qtcore/...とqInstallMessageHandler
そこにもあります。5.1では、qInstallMsgHandler
完全に削除されました。
void myMessageOutput(QtMsgType type, const char *msg) { ... }
#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();
}
qInstallMessageHandler
代わりに、QT5から開始する必要がありqInstallMsgHandler
ます。
これは、デフォルトのメッセージハンドラーをフックする実際の例です。
ありがとう@ロスロジャース!
// -- 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;
}
これは、アプリが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。
さて、デバッグ出力をstderrとは異なるものにリダイレクトする必要があるのは、ロギングツールについて考えることができるときです。必要だと思われる場合は、ライブラリからQxtLogger
(「QxtLoggerクラスは使いやすく、拡張しやすいロギングツールです。」)を使用することをお勧めしQxt
ます。
これは、ログstderr
とファイルの両方にログインするための、単純でスレッドセーフな慣用的なQtの例です。
void messageHandler(QtMsgType type、const QMessageLogContext&context、const QString&message) {{ 静的QMutexミューテックス; QMutexLockerロック(&mutex); 静的QFilelogFile(LOGFILE_LOCATION); static bool logFileIsOpen = logFile.open(QIODevice :: Append | QIODevice :: Text); std :: cerr << qPrintable(qFormatLogMessage(type、context、message))<< std :: endl; if(logFileIsOpen){ logFile.write(qFormatLogMessage(type、context、message).toUtf8()+ '\ n'); logFile.flush(); } }
qInstallMessageHandler(messageHandler)
他の回答の説明に従ってインストールしてください。