你需要使用qInstallMessageHandler
函数安装一个消息处理程序,然后可以使用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();
}
以下内容摘自qInstallMessageHandler
的文档(我只加了注释):
在上面的示例中,函数myMessageOutput
使用了stderr
,您可能希望将其替换为其他文件流或完全重写此函数!
一旦您编写并安装了此函数,所有您的qDebug
(以及qWarning
,qCritical
等)消息都将被重定向到处理程序中写入的文件。
#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);
abort();
}
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
来更改消息处理程序。 - SuBmain()
函数内打开文件并实例化QTextStream
。并将QTextStream
作为一个静态变量放在函数外部。 - Paul Masri-Stone这里是挂钩默认消息处理程序的工作示例。
感谢 @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;
}
以下是一个跨平台的解决方案,用于在从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"...
(用于控制台)处理。
Inspiration:https://gist.github.com/polovik/10714049。
我认为当你需要将调试输出重定向到与stderr不同的地方时,你可以考虑一些日志记录工具。如果你感觉需要一个,我推荐使用QxtLogger
("QxtLogger类是一个易于使用、易于扩展的日志记录工具。")从Qxt
库中。
这是一个简单的、线程安全的典型Qt示例,用于将日志记录到stderr
和文件中:
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { static QMutex mutex; QMutexLocker lock(&mutex);
static QFile logFile(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)
进行安装。
main()
退出或显式调用标准C库函数exit()
时被调用。大多数实现中,当main()
终止时,会调用exit()
。所以一切都很好。 - mrtscase
只设置了txt
的值,而txt
只在switch
之后打印,所以QtFatalMsg
会在打印任何内容之前abort()
。这意味着致命错误不会被记录!我的版本修复了这个问题。QTextStream
,不如在程序启动时只设置一次。这样可以减少记录消息的开销,正如Paul Masri-Stone在评论中建议的那样 in a comment。#include <QApplication>
#include <QtDebug>
#include <QFile>
#include <QTextStream>
static QTextStream output_ts;
void myMessageHandler(QtMsgType type, const QMessageLogContext&, const QString& msg)
{
switch (type) {
case QtDebugMsg:
output_ts << QString("Debug: %1").arg(msg) << endl;
break;
case QtWarningMsg:
output_ts << QString("Warning: %1").arg(msg) << endl;
break;
case QtCriticalMsg:
output_ts << QString("Critical: %1").arg(msg) << endl;
break;
case QtFatalMsg:
output_ts << QString("Fatal: %1").arg(msg) << endl;
abort();
}
}
int main(int argc, char* argv[])
{
QString logfilePath = QStringLiteral("C:\\mydir\\log.txt");
QFile outFile(logfilePath);
outFile.open(QIODevice::WriteOnly | QIODevice::Append);
output_ts.setDevice(&outFile);
qInstallMessageHandler(messageHandler);
QApplication app(argc, argv);
...
return app.exec();
}
qDebug
、qWarning
、qCritical
等输出不同的消息到不同的文件! - NawazqInstallMsgHandler
已被弃用并替换为qInstallMessageHandler
(意思相同)。对于版本 5.0,qInstallMsgHandler
可在 http://qt-project.org/doc/qt-5.0/qtcore/qtglobal.html#qInstallMsgHandler 找到,同时也提供了qInstallMessageHandler
。但是在版本 5.1 中,qInstallMsgHandler
被完全删除了。 - Jason Cvoid myMessageOutput(QtMsgType type, const char *msg) { ... }
- Nawaz