Qt日志输出及QsLog日志库
本文主要介绍Qt日志输出系统和QsLog日志库的使用,QsLog是一个基于Qt的QDebug类的易于使用的记录器。
目录
Qt日志输出及QsLog日志库
日志输出
Qt提供了多种方式进行日志输出,常用的有qDebug()
, qInfo()
, qWarning()
, qCritical()
和qFatal()
。
这些输出函数定义在#include <QDebug>
中,并且可以像标准C++的输出流一样使用。
分类 | 说明 |
---|---|
qDebug() | 用于调试信息输出,通常用于开发阶段输出调试信息。 |
qInfo() | 用于一般的信息输出,适合输出一般运行状态信息。 |
qWarning() | 用于警告信息输出,通常用于提示可能的问题。 |
qCritical() | 用于严重错误信息输出,通常用于提示不可恢复的错误。 |
qFatal() | 用于致命错误信息输出,通常会中止程序的运行。 |
C风格输出
qDebug("我是%s,今年%d岁了~","qDebug",20);
qInfo("老铁%d",666);
qWarning("hello %s","warning");
qCritical("helo %s","critical");
qFatal("hello %s","qFatal"); // 注意:qFatal 会中断程序执行
C++风格
qDebug()<<"qDebug";
qInfo()<<"qInfo";
qWarning()<<"qWarnning";
qCritical()<<"qCritical";
#qFatal()<<"qFatal"; // qFatal()不能用"<<"输出
格式化日志
默认情况下,日志格式是只输出对应的日志内容没有额外信息的。可以通过修改环境变量QT_MESSAGE_PATTERN
或者调用方法 qSetMessagePattern
来修改日志的输出格式。日志格式中常用的占位符号如下所示:
%{appname} 应用程序的名称(QCoreApplication::applicationName())
%{category} 日志所处的领域
%{file} 打印该日志的文件路径
%{function} 打印日志的函数
%{line} 打印日志在文件中的行数
%{message} 日志的内容
%{pid} 打印日志的程序的PID(QCoreApplication::applicationPid())
%{threadid} 打印日志的线程ID
%{qthreadptr} 打印日志的线程指针
%{type} 日志级别("debug", "warning", "critical" or "fatal")
%{time process}日志发生时程序启动了多久
%{time boot} 日志发生时系统启动了多久
%{time [format]}以固定时间格式输出日志打印的时间,默认为QISODate格式
普通格式化
格式化日志方法如下:
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} [%{type}] %{file} [%{function}(%{line})] %{message}");
qInfo()<<"info";
qDebug()<<"debug";
qWarning()<<"warning";
qCritical()<<"Critical";
return a.exec();
}
输出的日志内容如下:
2024-09-19 10:35:25 [info] ..\..\main.cpp [qMain(9)] info
2024-09-19 10:35:25 [debug] ..\..\main.cpp [qMain(10)] debug
2024-09-19 10:35:25 [warning] ..\..\main.cpp [qMain(11)] warning
2024-09-19 10:35:25 [critical] ..\..\main.cpp [qMain(12)] Critical
注意:在Release模式下,文件名、函数名、行号获取不到,需要添加编译时宏QT_MESSAGELOGCONTEXT
条件格式化
在消息参数中还可以使用条件,给不同级别的日志指定不同的格式,语法如下:
%{if-<debug | info | warning | critical | fatal>} ... %{endif}
比如,只想在debug级别下输出文件名、函数名以及行号,代码格式如下:
qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} [%{type}] %{if-debug}%{file}%{endif} %{if-} [%{function}(%{line})] %{message}");
环境变量设置格式化
格式也可以在运行时通过设置QT_MESSAGE_PATTERN
环境变量来更改;
如果调用了qSetMessagePattern()
并且设置了QT_MESSAGE_PATTERN
,则环境变量优先。
qputenv("QT_MESSAGE_PATTERN", QByteArray("%{time yyyy-MM-dd hh:mm:ss} [%{type}] %{file} [%{function}(%{line})] %{message}"));
日志输出位置
Qt 默认的日志内容是输出到终端的,不会输出到文件里面,如果需要将日志内容输出到文件中,需要通过qInstallMessageHandler
设置日志信息处理函数。使用方法如下:
#include <QApplication>
#include <QFile>
#include <QDebug>
#include <QTextStream>
// 日志消息的处理函数
void logMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
{
// 获取格式化的日志信息
QString typeStr = qFormatLogMessage(type, context, message);
// 可以根据日志的级别进行过滤(比如不想要 Debug 输出,可以直接 return)
QString levelText;
switch (type)
{
case QtDebugMsg:
levelText = "Debug";
// return; // 加上 return 之后就不会打印 debug 日志了
break;
case QtInfoMsg:
levelText = "Info";
break;
case QtWarningMsg:
levelText = "Warning";
break;
case QtCriticalMsg:
levelText = "Critical";
break;
case QtFatalMsg:
levelText = "Fatal";
break;
}
QFile file("log.log");
file.open(QIODevice::WriteOnly | QIODevice::Append);
QTextStream textStream(&file);
textStream << typeStr << "\n";
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} [%{type}]%{if-warning}[%{function}]%{endif}%{if-fatal}[%{function}--%{line}]%{endif}:%{message}");
qInstallMessageHandler(logMessageHandler);
qDebug() << "debug info occurred";
qInfo() << "call other function";
qWarning() << "doesn't work";
qFatal("fatal error");
return app.exec();
}
如果需要关闭日志输出,取消之前注册的日志处理函数,可以调用qInstallMessageHandler(nullptr);
日志输出对象信息
在调试一些复杂对象的时候,需要输出对象的成员信息到日志当中。但是默认情况下 Qt 的日志库是不支持输出自定义对象的。这时候可以通过重写操作符实现对自定义对象的日志输出。使用方法如下:
class Person
{
public:
QString name;
quint8 age;
inline friend QDebug operator<<(QDebug debug,const Person& person)
{
debug<<"Person("<<person.name<<","<<person.age<<")";
return debug;
}
};
int main(int argc,char*argv[])
{
QCoreApplication app(argc, argv);
Person person{"shayebushi",18}; // 输出:Person( "shayebushi" , 18 )
qDebug()<<person;
return app.exec();
}
禁用输出
在开发或者调试时,我们必须借助日志来进行判断,但是当程序需要发布时,调试的日志信息将不再需要,此时如果把代码删除,又不太方便,万一出bug了,又需要调试了呢?
所以Qt提供了禁用qInfo
、qWarning
、qDebug
输出的宏,qCritical
、qFatal
是错误不能屏蔽!
CMakeLists.txt 文件中禁用日志输出
在CMakeLists.txt文件中添加如下三行,即可禁用qInfo
、qWarning
、qDebug
的输出。
add_compile_definitions(QT_NO_INFO_OUTPUT)
add_compile_definitions(QT_NO_DEBUG_OUTPUT)
add_compile_definitions(QT_NO_WARNING_OUTPUT)
#或
add_compile_definitions(
QT_NO_INFO_OUTPUT
QT_NO_DEBUG_OUTPUT
QT_NO_WARNING_OUTPUT)
.pro 文件中禁用日志输出
在 .pro 文件中添加如下三行,即可禁用 qInfo
、qWarning
、qDebug
的输出。
DEFINES += QT_NO_INFO_OUTPUT
DEFINES += QT_NO_DEBUG_OUTPUT
DEFINES += QT_NO_WARNING_OUTPUT
QsLog日志库
QsLog是一个基于Qt的QDebug类的易于使用的记录器。QsLog是在MIT许可下以开源形式发布的。
QsLog的特征:
- 六个日志级别(从跟踪到致命);
- 运行时可配置的日志级别阈值;
- 关闭日志记录时的最小开销;
- 支持多个目标,附带文件和调试目标;
- 线程安全;
- 支持现成的常见Qt类型的日志记录;
- 小依赖:直接把它放到你的项目中。
使用方法
1. 将QsLog目录添加到项目中
将QsLog目录直接拷贝到项目的根目录中,与CMakeLists.txt
或.pro
文件同级。
2. 配置CMakeLists.txt文件
打开项目的CMakeLists.txt
文件,输入如下代码:
# 添加子目录
add_subdirectory(./QsLog)
# 添加可执行文件
add_executable(QsLog_test main.cpp)
# 把QsLog库链接到目标 QsLog_test
target_link_libraries(QsLog_test Qt${QT_VERSION_MAJOR}::Core QsLog)
3. 配置.pro文件
如果你使用的是qmake构建系统,打开项目的.pro
文件,输入如下代码:
# 指定包含QsLog目录
include(QsLog/QsLog.pri)
4. 日志记录器的配置
在你的代码中进行日志记录器的配置:
#include <QCoreApplication>
#include "QsLog/QsLog.h"
#include "QsLog/QsLogDest.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
using namespace QsLogging;
// 1. 获取日志单例
Logger &logger = Logger::instance();
logger.setLoggingLevel(QsLogging::DebugLevel);
// 2. 添加两个日志输出目的地
DestinationPtr file_dest(DestinationFactory::MakeFileDestination("log.txt"));
DestinationPtr console_dest(DestinationFactory::MakeDebugOutputDestination());
logger.addDestination(file_dest);
logger.addDestination(console_dest);
// 3. 开始日志记录
QLOG_DEBUG() << "Program started";
return a.exec();
}
5. 运行程序
运行程序,控制台会输出日志,同时指定的文件也会记录日志内容。日志内容如下:
DEBUG 2024-09-19T18:07:04.434 Program started
6. 启用行号和文件名
输出的日志记录默认是没有文件名和行号的,如果需要,在CMakeLists.txt
或.pro
文件中添加宏定义即可。
CMakeLists.txt
# 开启行号
add_compile_definitions(QS_LOG_LINE_NUMBERS)
.pro 文件
# 开启行号
DEFINES += QS_LOG_LINE_NUMBERS
7. 禁用日志输出
如果要禁用日志输出,定义宏 QS_LOG_DISABLE
即可。
CMakeLists.txt
# 禁用日志输出
add_compile_definitions(QS_LOG_DISABLE)
.pro 文件
# 禁用日志输出
DEFINES += QS_LOG_DISABLE
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)