Qt日志重定向qInstallMessageHandler,輸出至文件及網絡
https://blog.csdn.net/libaineu2004/article/details/88801336
Qt有Debug、Warning、Info、Critical、Fatal五種級別的調試信息。
qDebug:調試信息
qWarning:警告信息
qInfo:警告信息
qCritical:嚴重錯誤
qFatal:致命錯誤
Qt4提供了qInstallMsgHandler(Qt5:qInstallMessageHandler)對qDebug、qWarning、qCritical、qFatal等函數輸出信息的重定向處理。
qInstallMsgHandler是一個回調函數,由qDebug、qWarnng、qCritical、qFatal函數進行觸發,qDebug、qWarnng、qCritical、qFatal函數處理的消息文本會被qInstallMsgHandler所指向的回調函數截獲,允許用戶自己來處理輸出的消息文本。
一、來看官方的例子:
void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QString text;
switch(type)
{
case QtDebugMsg:
text = QString("Debug:");
break;
case QtWarningMsg:
text = QString("Warning:");
break;
case QtCriticalMsg:
text = QString("Critical:");
break;
case QtFatalMsg:
text = QString("Fatal:");
}
QDateTime current_date_time = QDateTime::currentDateTime();
QString current_date = current_date_time.toString("yyyy-MM-dd hh:mm:ss ddd");
QString message = text.append(msg).append("(").append(current_date).append(")");
QFile file("log.txt");
file.open(QIODevice::WriteOnly | QIODevice::Append);
QTextStream text_stream(&file);
text_stream<<message<<"\r\n";
file.close();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
//注冊MessageHandler
qInstallMessageHandler(outputMessage);
//打印日志到文件中
qDebug("This is a debug message");
qWarning("This is a warning message");
qCritical("This is a critical message");
qFatal("This is a fatal message");
return app.exec();
}
Qt自帶5個向外寫警告和調試文本的方法。可以把它們使用在如下目的:
qDebug():用於寫自定調試信息的輸出;
qWarning():用於報告程序中的警告和可恢復的錯誤;
qCritical():用於寫關鍵錯誤信息和報告系統錯誤;
qFatal():用於退出前簡要地描述致命錯誤消息;
qInfo():用於寫自定調試信息的輸出。
如果包含<QtDebug>頭文件,qDebug()可以當做輸出流來使用。例如:
qDebug() << "Widget" << widget << "at position" << widget->pos();
二、開源項目http://www.qtcn.org/bbs/read-htm-tid-85387-page-e.html使用了qInstallMessageHandler的機制,封裝了日志庫。
本人在它基礎之上,略微修改,封裝了更強大和易用的日志庫。
void Log(QtMsgType type, const QMessageLogContext &context, const QString &msg)
#endif
{
//加鎖,防止多線程中qdebug太頻繁導致崩潰
QMutex mutex;
QMutexLocker locker(&mutex);
//這里可以根據不同的類型加上不同的頭部用於區分
//Release 版本默認不包含這些信息:文件名、函數名、行數,需要在.pro項目文件加入以下代碼,加入后最好重新構建項目使之生效:
//DEFINES += QT_MESSAGELOGCONTEXT
//此外,在.pro文件定義以下的宏,可以屏蔽相應的日志輸出
//DEFINES += QT_NO_WARNING_OUTPUT
//DEFINES += QT_NO_DEBUG_OUTPUT
//DEFINES += QT_NO_INFO_OUTPUT
QByteArray localMsg = msg.toLocal8Bit();
QString content;
switch (type)
{
case QtDebugMsg:
content = QString("Debug: %1 (%2:%3, %4)\n").arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function);
break;
case QtInfoMsg:
content = QString("Info: %1 (%2:%3, %4)\n").arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function);
break;
case QtWarningMsg:
content = QString("Warning: %1 (%2:%3, %4)\n").arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function);
break;
case QtCriticalMsg:
content = QString("Critical: %1 (%2:%3, %4)\n").arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function);
break;
case QtFatalMsg:
content = QString("Fatal: %1 (%2:%3, %4)\n").arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function);
break;
default:
content = QString("Default: %1 (%2:%3, %4)\n").arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function);
break;
}
content = QDateTime::currentDateTime().toString("yyyy-MM-dd hh.mm.ss.zzz ") + content;
SaveLog::Instance()->save(content);
}
完整的工程源碼請下載:https://download.csdn.net/download/libaineu2004/11058474
三、注意事項:
1、Release 版本默認不包含這些信息:文件名、函數名、行數,需要在.pro項目文件加入以下代碼,加入后最好重新構建項目使之生效:
DEFINES += QT_MESSAGELOGCONTEXT
2、此外,在.pro文件定義以下的宏,可以屏蔽相應的日志輸出
DEFINES += QT_NO_WARNING_OUTPUT
DEFINES += QT_NO_DEBUG_OUTPUT
DEFINES += QT_NO_INFO_OUTPUT
記得把工程清除之后,再重新構建。
也可以靈活一點:
在.pro文件中加入
release:DEFINES += QT_NO_WARNING_OUTPUT \
QT_NO_DEBUG_OUTPUT
這樣一來,編譯debug不受影響,繼續有輸出,release的時候停止輸出。
3、如果使用的IDE是Visual Studio,那么
在VC項目配置里C/C++ /Preprocessor /Preprocessor Definitions屬性里面加入宏定義:
QT_MESSAGELOGCONTEXT
QT_NO_DEBUG_OUTPUT
QT_NO_WARNING_OUTPUT
四、參考文獻
https://qtdebug.com/qt-logger/ Qt 自定義日志工具
五、姊妹篇
《Qt日志庫Log4Qt的使用,支持文件名/行號/函數名的打印輸出》
《Spdlog日志庫的使用,支持文件名/行號/函數名的打印輸出》
============== End