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 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!

面试题】即可获取