Log4Qt 日志格式化(TTCCLayout)
作者丨Waleon
来源丨高效程序员
1
TTCC 概要
SimpleLayout
对象采用的格式化风格非常简单,在某些情况下可能比较有用,但有时我们希望得到更详细的信息,特别是在多线程应用程序中。当多个客户端访问同一应用程序模块时,发布日志记录的时间、活动线程等信息非常重要,可以以此来区分多个独立的客户端行为。
TTCCLayout 负责提供有关日志事件的详细信息,通常它包含以下内容:
Time
:从启动应用程序开始,以毫秒数计算的时间;Thread
:调用线程;Category
:用于创建日志事件的类别或 Logger;Context
:NDC 信息。此信息不会自动包含在LoggingEvent
对象中,必须专门包含它。因此,这是TTCCLayout
的一个可选输出 - 即使启用了 NDC 设置,如果LoggingEvent
不包含任何 NDC 设置,TTCCLayout
也可能不会显示任何 NDC 数据。
注意:TTCC
正是这些单词的缩写组合,因此而得名。
此外,这几个字段中的每一个都可以单独启用或禁用(可选参数,并不强制)。
对于 TTCCLayout
来说,可以决定是否启用上面的可选参数。然而,即使不启用它们,也仍将输出以下信息:
Level
:日志消息的级别;Message
:日志消息本身;
换句话说,这两个是强制性信息,不受可选参数的影响!
日期格式,取决于 DateFormat
:
枚举 | 日期格式字符串 | 将被格式化为 |
---|---|---|
NONE | "NONE" | |
ISO8601 | "ISO8601" | yyyy-MM-dd hh:mm:ss.zzz |
ABSOLUTE | "ABSOLUTE" | HH:mm:ss.zzz |
DATE | "DATE" | MMM YYYY HH:mm:ss.zzzz |
RELATIVE | "RELATIVE" | 自程序启动以来经过的时间(以毫秒为单位) |
其中,RELATIVE
是默认值。
TTCCLayout
由好几部分组成,而最终各个部分能否出现在日志中,取决于它们是否作为 LoggingEvent
的一部分被提供到 TTCCLayout
。
通过下表中列出的属性或方法,TTCCLayout
可以灵活地控制日志消息的不同部分:
属性 | 方法 | 描述 | 默认值 |
---|---|---|---|
categoryPrefixing | setCategoryPrefixing(bool) | 指定 Logger 名称是否是格式化输出的一部分 | true |
contextPrinting | setContextPrinting(bool) | 指定嵌套的上下文信息是否是格式化输出的一部分 | true |
threadPrinting | setThreadPrinting(bool) | 指定线程名称是否是格式化输出的一部分 | true |
dateFormat | setDateFormat(const QString &) | 指定布局使用的日期格式 | "RELATIVE" |
有了这些知识,编写一个 TTCCLayout
的相关程序会简单很多。为了完整起见,我们首先会以编程方式配置 TTCCLayout
,随后再通过配置文件进行配置。
2
以编程方式配置
要在程序中配置日志,首先要获得一个 Logger
实例,然后将 ConsoleAppender
附加到这个实例上。为了格式化日志消息,我们还将创建一个 TTCCLayout
对象,并将其附加到 ConsoleAppender
中。
和前面一样,输出一个简单的信息:
#include <QCoreApplication>
#include <log4qt/logger.h>
#include <log4qt/ttcclayout.h>
#include <log4qt/consoleappender.h>
#include <log4qt/loggerrepository.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 创建一个 TTCCLayout(输出时间、线程、Logger 以及消息内容)
Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();
Log4Qt::TTCCLayout *layout = new Log4Qt::TTCCLayout();
layout->setName("My Layout");
// layout->setCategoryPrefixing(false); // 禁用 logger 名称
// layout->setContextPrinting(false); // 禁用嵌套的上下文信息
// layout->setThreadPrinting(false); // 禁用线程名
// layout->setDateFormat("ISO8601"); // 设置日期格式
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();
}
注意:可以通过注释部分,对可选属性进行灵活控制。
运行此程序,将在控制台中生成以下输出:
170 [0x000002ab780c14e0] DEBUG root - Hello, Log4Qt!
打开注释部分,再次运行程序,输出如下:
2021-09-16 22:57:44.243 DEBUG - Hello, Log4Qt!
可以看到,日期格式变了,并且 Logger、线程也被禁用了。
3
使用配置文件
现在,编写一个配置文件 - 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.TTCCLayout
log4j.appender.console.layout.categoryPrefixing=false
log4j.appender.console.layout.contextPrinting=false
log4j.appender.console.layout.threadPrinting=false
log4j.appender.console.layout.dateFormat=ISO8601
在此配置中,我们禁用了 categoryPrefixing
、contextPrinting
、以及 threadPrinting
属性,并为 dateFormat
指定了一个时间格式 ISO8601
。
然后,使用下面的程序:
#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();
}
运行此程序,将在控制台中生成以下输出:
2021-09-16 23:01:41.409 DEBUG - Hello, Log4Qt!
可以看到,无论是使用编程方式,还是配置文件方式,效果是一样的。
-End-
最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!
面试题
】即可获取