【发布时间】:2011-06-24 15:48:42
【问题描述】:
我使用大量qDebug() << 语句进行调试输出。是否有任何跨平台的方式可以将调试输出重定向到文件,而无需使用 shell 脚本?我猜open() 和 dup2() 会在 Linux 中完成这项工作,但它会在 Windows 中使用 MinGW 编译吗?
也许有一种 Qt 方法可以做到这一点?
【问题讨论】:
标签: c++ debugging qt mingw qdebug
我使用大量qDebug() << 语句进行调试输出。是否有任何跨平台的方式可以将调试输出重定向到文件,而无需使用 shell 脚本?我猜open() 和 dup2() 会在 Linux 中完成这项工作,但它会在 Windows 中使用 MinGW 编译吗?
也许有一种 Qt 方法可以做到这一点?
【问题讨论】:
标签: c++ debugging qt mingw qdebug
如果应用程序是从 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"...(用于控制台)处理。
【讨论】:
这是一个简单的、线程安全的惯用 Qt 示例,用于记录到 stderr 和文件:
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message)
{
静态 QMutex 互斥体;
QMutexLocker lock(&mutex);
静态 QFile 日志文件(LOGFILE_LOCATION);
静态 bool logFileIsOpen = logFile.open(QIODevice::Append | QIODevice::Text);
std::cerr
如其他答案中所述,使用qInstallMessageHandler(messageHandler) 安装它。
【讨论】:
好吧,我想说的是,当您需要将调试输出重定向到不同于 stderr 的任何内容时,您可以考虑使用一些日志记录工具。如果您觉得需要,我建议您使用来自Qxt 库的QxtLogger(“QxtLogger 类是一种易于使用、易于扩展的日志工具。”)。
【讨论】:
这是一个挂钩默认消息处理程序的工作示例。
谢谢@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;
}
【讨论】:
#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 而不是qInstallMsgHandler 来更改消息处理程序。
您必须使用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的文档(我只添加了cmets):
在上面的例子中,函数myMessageOutput使用了stderr,你可能想用其他文件流替换它,或者完全重写函数!
编写并安装此函数后,您的所有qDebug(以及qWarning、qCritical 等)消息将被重定向到您在处理程序中写入的文件。
【讨论】:
qDebug、qWarning、qCritical 等将不同的消息输出到不同的文件!
qInstallMsgHandler 在 Qt5 中已弃用并由 qInstallMessageHandler (相同的想法)取代。对于 5.0,qInstallMsgHandler 位于 qt-project.org/doc/qt-5.0/qtcore/…,qInstallMessageHandler 也在那里。对于 5.1,qInstallMsgHandler 已完全删除。
void myMessageOutput(QtMsgType type, const char *msg) { ... }