Log4Qt 日志格式化(PatternLayout)
作者丨Waleon
来源丨高效程序员
1
继承关系图
Log4Qt 提供了各种布局对象,通过使用这些 Layout,我们可以根据自己的喜好来格式化日志输出,自由指定日志级别、线程名称、Logger 名称、日期时间等信息。
Log4Qt::Layout
继承关系图:
在该层次结构中,顶级类是 Layout,它是 Log4Qt API 中所有其他布局类的基类。
PatternLayout
:根据一个模式字符串输出日志事件SimpleLayout
:输出日志事件的级别和消息TTCCLayout
:输出日志事件的时间、线程名称、Logger 名称和嵌套的诊断上下文信息
注意:这里列出来的这几个 Layout 比较常用,也是我们重点讲解的内容。此外,还有一些其它 Layout(例如:BinaryLayout
、XMLLayout
等),这里并没有列出,希望通过后面分享的知识,大家能够快速熟悉它们的用法。
这些类扩展了 Layout,并根据提供的模式重写了 format() 方法来构造日志信息。
在内部,PatternLayout
和 TTCCLayout
通过 PatternFormatter
来实现格式化。当 PatternFormatter
解析模式字符串时,它会根据发现的信息创建了一个 PatternConverter
链,每个 PatternConverter
会处理 LoggingEvent
的某个成员。
2
转换字符
转换字符:用于指定数据的类型,例如:类别、级别、日期、线程名称。
转换说明符以百分号(%)开始,后跟转换字符。Log4Qt 中的转换字符有:
转换字符 | 含义 |
---|---|
c{section_count} | Logger 名称。参数 section_count 可选,从 logger 名称的末尾处计数,分隔符是“::” 。 |
d{format_string} | 日期。参数 format_string 可选,被用于 QDateTime::toString() 。 |
m | 消息 |
p | 级别名称 |
r | 启动应用程序的相对日期/时间 |
t | 线程名称 |
x | NDC(嵌套的诊断上下文)名称 |
X | MDC(映射的诊断上下文)名称 |
F | 文件名称 |
M | 方法名称 |
L | 行号 |
l | 位置信息 |
n | 平台相关的行分隔符(Windows:\r\n,Linux:\n) |
% | 序列 %% 输出一个百分号 % |
3
PatternLayout
如果想生成基于模式的特定格式的日志信息,那么可以使用 PatternLayout
来进行格式化。
枚举 ConversionPattern
定义了两个常用的模式:
枚举 | 模式字符串 |
---|---|
DEFAULT_CONVERSION_PATTERN | “%m,%n” |
TTCC_CONVERSION_PATTERN | “%r [%t] %p %c %x - %m%n” |
创建一个 PatternLayout
,并将日志信息输出至控制台中:
#include <QCoreApplication>
#include <log4qt/logger.h>
#include <log4qt/patternlayout.h>
#include <log4qt/consoleappender.h>
#include <log4qt/loggerrepository.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 创建一个 PatternLayout(根据模式字符串输出日志事件)
Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();
Log4Qt::PatternLayout *layout = new Log4Qt::PatternLayout();
layout->setHeader("----- Header -----"); // 设置标头信息
layout->setFooter("----- Footer -----"); // 设置页脚信息
layout->setName("My Layout");
// layout->setConversionPattern(Log4Qt::PatternLayout::TTCC_CONVERSION_PATTERN);
// layout->setConversionPattern("%d{yyyy-MM-dd hh:mm:ss} - %m%n");
// layout->setConversionPattern("The output message is: %m%n");
layout->activateOptions();
// 创建一个 ConsoleAppender(将日志内容输出到控制台上)
Log4Qt::ConsoleAppender *appender = new Log4Qt::ConsoleAppender(layout, Log4Qt::ConsoleAppender::STDOUT_TARGET);
appender->setName("My Appender");
appender->activateOptions();
logger->addAppender(appender);
logger->setLevel(Log4Qt::Level::DEBUG_INT);
logger->debug("Hello, Log4Qt!");
// 关闭 logger
logger->removeAllAppenders();
logger->loggerRepository()->shutdown();
return a.exec();
}
注意:除正文之外,还可以为日志消息指定标头和页脚。布局对象的内容类型默认为 text/plain
,如果要自定义布局并制定其他类型,需要重写 Layout 的 contentType()
方法。
默认情况下,转换模式为 DEFAULT_CONVERSION_PATTERN
,只会输出简单的日志信息:
----- Header -----
Hello, Log4Qt!
----- Footer -----
由于我们在代码中指定了标头和页脚,所以在日志信息的前后会输出相关信息,这有时在区分日志时会很有用。
和其他布局相比,PatternLayout
很大的一个优势在于灵活。除了上述方式之外,还可以指定其它模式。
若要修改默认模式,可以打开代码中的注释部分:
layout->setConversionPattern(Log4Qt::PatternLayout::TTCC_CONVERSION_PATTERN);
运行程序,这时不仅会输出日志信息,还会输出启动时间、线程名称、logger 名称:
4 [0x000001bdc8415750] DEBUG root - Hello, Log4Qt!
实际上,这采用的是和 TTCCLayout
相同的模式,从名字就可以看出。
此外,还可以通过自定义模式字符串来指定日期时间:
layout->setConversionPattern("%d{yyyy-MM-dd hh:mm:ss} - %m%n");
运行程序,输出如下:
2021-08-17 22:54:04 - Hello, Log4Qt!
如果想额外为消息添加一些文本,也非常简单:
layout->setConversionPattern("The output message is: %m%n");
运行程序,输出如下:
The output message is: Hello, Log4Qt!
通过这种方式,我们可以自由地在转换模式中插入任何文本,使用起来相当方便。
出于灵活性考虑,在以后的使用中,配置文件将是我们的首选,所以务必要学会如何有效地利用它。
编写一个配置文件 - log4qt.properties
,执行与上例中使用相同的任务:
# 定义 rootLogger
log4j.rootLogger=DEBUG, console
# 定义 ConsoleAppender
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.immediateFlush=true
log4j.appender.console.target=STDOUT_TARGET
# 为 ConsoleAppender 定义 Layout
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.header=----- Header -----
log4j.appender.console.layout.footer=----- Footer -----
log4j.appender.console.layout.conversionPattern=%r [%t] %p %c %x - %m%n
#include <QCoreApplication>
#include <log4qt/logger.h>
#include <log4qt/loggerrepository.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 获取 rootLogger
Log4Qt::Logger* logger = Log4Qt::Logger::rootLogger();
// 打印消息
logger->debug("Hello, Log4Qt!");
// 关闭 rootLogger
logger->removeAllAppenders();
logger->loggerRepository()->shutdown();
return a.exec();
}
注意:最后记得关闭 logger,否则不会释放资源,也不会输出 Footer。
运行程序,输出如下:
----- Header -----
65 [0x000001d25ec81f70] DEBUG root - Hello, Log4Qt!
----- Footer -----
可以看出,使用配置文件和纯代码的效果是一样的。
-End-
最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!
面试题
】即可获取