Qt 日志 log
第一种方式:
这里我将介绍三种日志方式,首先第一种是使用宽松的格式定制日志处理函数的方式,
log.cpp文件如下:
#include "log.h" #include <QString> #include <QLoggingCategory> #include <QIODevice> #include <QFile> #include <QDir> #include <QDebug> #include <QDateTime> #include <QMutex> #include <QApplication> #include <QRegExp> static QString logDirectory; static QString logFileName; static QMutex mutex; static QFile file; static QTextStream textStream; void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QString text; switch(type) { case QtDebugMsg: text = QString("[Debug]"); break; case QtInfoMsg: text = QString("[Info]"); break; case QtWarningMsg: text = QString("[Warning]"); break; case QtCriticalMsg: text = QString("[Critical]"); break; case QtFatalMsg: text = QString("[Fatal]"); } text.append(QString(" [%1] ").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))); text.append(QString(" [%1: Line: %2] ").arg(QString(context.file)).arg(context.line)); text.append(QString(" [Function: %1] ").arg(QString(context.function))); mutex.lock(); file.setFileName(logFileName); file.open(QIODevice::WriteOnly | QIODevice::Append); textStream.setDevice(&file); textStream << text << endl << QString("Message: %1").arg(msg) << endl; file.close(); mutex.unlock(); } void logInit() { logDirectory = QApplication::applicationDirPath() + "/Log/"; QDir dir(logDirectory); if(!dir.exists()) dir.mkdir(logDirectory); logFileName = logDirectory + (QApplication::applicationName()+".log"); /*以下这段代码的含义是初始化时检查日志文件是否存在一个月之前的日志,如果存在删除之*/ { QMutexLocker locker(&mutex); //mutex.lock(); QFile file(logFileName); file.open(QIODevice::ReadOnly); QTextStream textStream(&file); QString temp; QStringList tempList; QRegExp regExp(".*(20\\d\\d-\\d\\d-\\d\\d).*"); while ((temp = textStream.readLine()).isEmpty() == false) { if(temp.indexOf(regExp) >= 0) { QDate date = QDate::fromString(regExp.cap(1), "yyyy-MM-dd"); QDate currentDate = QDate::currentDate(); /*判断当前行所记载的日期和现今的日期天数之差是否大于记录该条日志时的那个月的天数*/ if(date.daysTo(currentDate) < date.day()) { tempList << temp; tempList << textStream.readLine(); } } } file.close(); file.open(QIODevice::Truncate | QIODevice::WriteOnly); textStream.setDevice(&file); for(auto iterator = tempList.begin(); iterator != tempList.end(); iterator++) { textStream << *iterator << endl; } file.close(); //mutex.unlock(); } /*安装上述自定义函数*/ qInstallMessageHandler(outputMessage); }
log.h文件如下:
#ifndef LOG_H #define LOG_H void logInit(); #endif // LOG_H
注意,release版本的日志中QMessageLogContext内容为空,解决方案请参考
https://blog.csdn.net/hong_chase/article/details/73379122
在pro文件中添加一个定义:
DEFINES += QT_MESSAGELOGCONTEXT
第二种方式
使用Qt5提供的格式定制日志处理函数,没有找到输出到文件的方式,只能输出到终端(QCreator下的应用程序输出):
只需要在调用qDebug()等宏之前调用以下函数:QSetMessagePattern()函数,或者在项目->构建环境变量中添加QT_MESSAGE_PATTERN环境变量即可,格式如下:
qSetMessagePattern("[%{type}] [%{time yyyy-MM-dd hh:mm:ss ddd}] [%{file} Line:%{line}] Function:%{function}() %{message}");
QT_MESSAGE_PATTERN="[%{time yyyyMMdd h:mm:ss.zzz t} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{file}:%{line} - %{message}"
下面参照:https://blog.csdn.net/liang19890820/article/details/51839233对其格式进行说明
占位符
支持以下占位符:
占位符 | 描述 |
---|---|
%{appname} | QCoreApplication::applicationName() |
%{category} | 日志类别 |
%{file} | 原文件路径 |
%{function} | 函数 |
%{line} | 源文件所在行 |
%{message} | 实际的消息 |
%{pid} | QCoreApplication::applicationPid() |
%{threadid} | 当前线程的系统范围ID(如果它可以获得) |
%{type} | “debug”、”warning”、”critical”或”fatal” |
%{time process} | “debug”、”warning”、”critical”或”fatal” |
%{time boot} | 消息的时间,启动进程的秒数 |
%{time [format]} | 消息产生时,系统时间被格式化通过把格式传递至QDateTime::toString()。如果没有指定的格式,使用Qt::ISODate。 |
%{backtrace [depth=N] [separator=”…”]} | 很多平台不支持,暂略… |
还可以使用条件类型,%{if-debug}, %{if-info} %{if-warning}, %{if-critical}
或 %{if-fatal}
后面跟着一个%{endif}
。如果类型匹配,%{if-*}
和 %{endif}
之间的内容会被打印。
最后,如果类别不是默认的一个,%{if-category} ... %{endif}
之间的内容将被打印。
例如:
QT_MESSAGE_PATTERN="[%{time yyyyMMdd h:mm:ss.zzz t} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{file}:%{line} - %{message}"
- 1
默认的模式是:”%{if-category}%{category}: %{endif}%{message}”。
也可以在运行时改变模式,通过设置QT_MESSAGE_PATTERN
环境变量。如果既调用了 qSetMessagePattern()
又设置了环境变量QT_MESSAGE_PATTERN
,那么,环境变量优先。
示例
qSetMessagePattern
下面,我们使用上面讲解的占位符,来改变缺省消息处理程序的输出。
int main(int argc, char **argv)
{
QApplication app(argc, argv);
// 改变缺省消息处理程序的输出
qSetMessagePattern("Message:%{message} File:%{file} Line:%{line} Function:%{function} DateTime:%{time [yyyy-MM-dd hh:mm:ss ddd]}");
// 打印信息
qDebug("This is a debug message.");
qInfo("This is a info message.");
qWarning("This is a warning message.");
qCritical("This is a critical message.");
qFatal("This is a fatal message.");
...
return app.exec();
}
- 输出如下:
Message:This is a debug message. File:..\MessagePattern\main.cpp Line:138 Function:main DateTime:[2016-07-06 15:21:40 周三]
Message:This is a info message. File:..\MessagePattern\main.cpp Line:139 Function:main DateTime:[2016-07-06 15:21:40 周三]
Message:This is a warning message. File:..\MessagePattern\main.cpp Line:140 Function:main DateTime:[2016-07-06 15:21:40 周三]
Message:This is a critical message. File:..\MessagePattern\main.cpp Line:141 Function:main DateTime:[2016-07-06 15:21:40 周三]
Message:This is a fatal message. File:..\MessagePattern\main.cpp Line:142 Function:main DateTime:[2016-07-06 15:21:40 周三]
QT_MESSAGE_PATTERN环境变量
选择:项目 -> 构建环境,添加环境变量:
QT_MESSAGE_PATTERN = [%{type}] %{appname} (%{file}:%{line}) - %{message}
- 1
int main(int argc, char **argv)
{
QApplication app(argc, argv);
// 改变缺省消息处理程序的输出
qSetMessagePattern("Message:%{message} File:%{file} Line:%{line} Function:%{function} DateTime:%{time [yyyy-MM-dd hh:mm:ss ddd]}");
// 打印信息
qDebug("This is a debug message.");
qInfo("This is a info message.");
qWarning("This is a warning message.");
qCritical("This is a critical message.");
qFatal("This is a fatal message.");
...
return app.exec();
}
- 输出如下:
[debug] MessagePattern (..\MessagePattern\main.cpp:138) - This is a debug message.
[info] MessagePattern (..\MessagePattern\main.cpp:139) - This is a info message.
[warning] MessagePattern (..\MessagePattern\main.cpp:140) - This is a warning message.
[critical] MessagePattern (..\MessagePattern\main.cpp:141) - This is a critical message.
[fatal] MessagePattern (..\MessagePattern\main.cpp:142) - This is a fatal message.
如上所述,这时即使我们使用了qSetMessagePattern也无济于事,因为,环境变量优先。
第三种方式
使用log4qt,目前没有使用过,详细参见:https://blog.csdn.net/dbzhang800/article/details/6916948
另外,我们可能会看到QCDebug(), QCInfo(), 等宏定义,它们需要传入一个日志类型的类对象,然后才能使用,具体不甚了解,待查,只是举个简单的例子:
QLoggingCategory category("qt.custom.log");
QLoggingCategory::setFilterRules("qt.custom.log.debug=true");
qCDebug(category) << "hello";
第一句是实例化日志种类对象,字符串部分为日志种类,第二句话是打开此日志种类的debug,第三句话是使用qCDebug(),可以写成QCDebug(category, "hello"); QCDebug(category, "%s", hello); 查看定义可知,为不定参数。
具体的字符串规则对于具体的字符串内容涉及的规则,不甚了解,这里有个规则案例仅供参考,