Log4Qt 日志格式化(PatternLayout)

星標(biāo)/置頂 公眾號(hào)??,硬核文章第一時(shí)間送達(dá)!
1
繼承關(guān)系圖
Log4Qt 提供了各種布局對(duì)象,通過(guò)使用這些 Layout,我們可以根據(jù)自己的喜好來(lái)格式化日志輸出,自由指定日志級(jí)別、線程名稱、Logger 名稱、日期時(shí)間等信息。
Log4Qt::Layout 繼承關(guān)系圖:

在該層次結(jié)構(gòu)中,頂級(jí)類是 Layout,它是 Log4Qt API 中所有其他布局類的基類。
PatternLayout:根據(jù)一個(gè)模式字符串輸出日志事件SimpleLayout:輸出日志事件的級(jí)別和消息TTCCLayout:輸出日志事件的時(shí)間、線程名稱、Logger 名稱和嵌套的診斷上下文信息
注意:這里列出來(lái)的這幾個(gè) Layout 比較常用,也是我們重點(diǎn)講解的內(nèi)容。此外,還有一些其它 Layout(例如:BinaryLayout、XMLLayout 等),這里并沒(méi)有列出,希望通過(guò)后面分享的知識(shí),大家能夠快速熟悉它們的用法。
這些類擴(kuò)展了 Layout,并根據(jù)提供的模式重寫(xiě)了 format() 方法來(lái)構(gòu)造日志信息。
在內(nèi)部,PatternLayout 和 TTCCLayout 通過(guò) PatternFormatter 來(lái)實(shí)現(xiàn)格式化。當(dāng) PatternFormatter 解析模式字符串時(shí),它會(huì)根據(jù)發(fā)現(xiàn)的信息創(chuàng)建了一個(gè) PatternConverter 鏈,每個(gè) PatternConverter 會(huì)處理 LoggingEvent 的某個(gè)成員。
2
轉(zhuǎn)換字符
轉(zhuǎn)換字符:用于指定數(shù)據(jù)的類型,例如:類別、級(jí)別、日期、線程名稱。
轉(zhuǎn)換說(shuō)明符以百分號(hào)(%)開(kāi)始,后跟轉(zhuǎn)換字符。Log4Qt 中的轉(zhuǎn)換字符有:
| 轉(zhuǎn)換字符 | 含義 |
|---|---|
| c{section_count} | Logger 名稱。參數(shù) section_count 可選,從 logger 名稱的末尾處計(jì)數(shù),分隔符是“::”。 |
| d{format_string} | 日期。參數(shù) format_string 可選,被用于 QDateTime::toString()。 |
| m | 消息 |
| p | 級(jí)別名稱 |
| r | 啟動(dòng)應(yīng)用程序的相對(duì)日期/時(shí)間 |
| t | 線程名稱 |
| x | NDC(嵌套的診斷上下文)名稱 |
| X | MDC(映射的診斷上下文)名稱 |
| F | 文件名稱 |
| M | 方法名稱 |
| L | 行號(hào) |
| l | 位置信息 |
| n | 平臺(tái)相關(guān)的行分隔符(Windows:\r\n,Linux:\n) |
| % | 序列 %% 輸出一個(gè)百分號(hào) % |
3
PatternLayout
如果想生成基于模式的特定格式的日志信息,那么可以使用 PatternLayout 來(lái)進(jìn)行格式化。
枚舉 ConversionPattern 定義了兩個(gè)常用的模式:
| 枚舉 | 模式字符串 |
|---|---|
| DEFAULT_CONVERSION_PATTERN | “%m,%n” |
| TTCC_CONVERSION_PATTERN | “%r [%t] %p %c %x - %m%n” |
創(chuàng)建一個(gè) PatternLayout,并將日志信息輸出至控制臺(tái)中:
#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);
// 創(chuàng)建一個(gè) PatternLayout(根據(jù)模式字符串輸出日志事件)
Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();
Log4Qt::PatternLayout *layout = new Log4Qt::PatternLayout();
layout->setHeader("----- Header -----"); // 設(shè)置標(biāo)頭信息
layout->setFooter("----- Footer -----"); // 設(shè)置頁(yè)腳信息
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();
// 創(chuàng)建一個(gè) ConsoleAppender(將日志內(nèi)容輸出到控制臺(tái)上)
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!");
// 關(guān)閉 logger
logger->removeAllAppenders();
logger->loggerRepository()->shutdown();
return a.exec();
}
注意:除正文之外,還可以為日志消息指定標(biāo)頭和頁(yè)腳。布局對(duì)象的內(nèi)容類型默認(rèn)為 text/plain,如果要自定義布局并制定其他類型,需要重寫(xiě) Layout 的 contentType() 方法。
默認(rèn)情況下,轉(zhuǎn)換模式為 DEFAULT_CONVERSION_PATTERN,只會(huì)輸出簡(jiǎn)單的日志信息:
----- Header -----
Hello, Log4Qt!
----- Footer -----
由于我們?cè)诖a中指定了標(biāo)頭和頁(yè)腳,所以在日志信息的前后會(huì)輸出相關(guān)信息,這有時(shí)在區(qū)分日志時(shí)會(huì)很有用。
和其他布局相比,PatternLayout 很大的一個(gè)優(yōu)勢(shì)在于靈活。除了上述方式之外,還可以指定其它模式。
若要修改默認(rèn)模式,可以打開(kāi)代碼中的注釋部分:
layout->setConversionPattern(Log4Qt::PatternLayout::TTCC_CONVERSION_PATTERN);
運(yùn)行程序,這時(shí)不僅會(huì)輸出日志信息,還會(huì)輸出啟動(dòng)時(shí)間、線程名稱、logger 名稱:
4 [0x000001bdc8415750] DEBUG root - Hello, Log4Qt!
實(shí)際上,這采用的是和 TTCCLayout 相同的模式,從名字就可以看出。
此外,還可以通過(guò)自定義模式字符串來(lái)指定日期時(shí)間:
layout->setConversionPattern("%d{yyyy-MM-dd hh:mm:ss} - %m%n");
運(yùn)行程序,輸出如下:
2021-08-17 22:54:04 - Hello, Log4Qt!
如果想額外為消息添加一些文本,也非常簡(jiǎn)單:
layout->setConversionPattern("The output message is: %m%n");
運(yùn)行程序,輸出如下:
The output message is: Hello, Log4Qt!
通過(guò)這種方式,我們可以自由地在轉(zhuǎn)換模式中插入任何文本,使用起來(lái)相當(dāng)方便。
出于靈活性考慮,在以后的使用中,配置文件將是我們的首選,所以務(wù)必要學(xué)會(huì)如何有效地利用它。
編寫(xiě)一個(gè)配置文件 - log4qt.properties,執(zhí)行與上例中使用相同的任務(wù):
# 定義 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!");
// 關(guān)閉 rootLogger
logger->removeAllAppenders();
logger->loggerRepository()->shutdown();
return a.exec();
}
注意:最后記得關(guān)閉 logger,否則不會(huì)釋放資源,也不會(huì)輸出 Footer。
運(yùn)行程序,輸出如下:
----- Header -----
65 [0x000001d25ec81f70] DEBUG root - Hello, Log4Qt!
----- Footer -----
可以看出,使用配置文件和純代碼的效果是一樣的。




關(guān)注公眾號(hào)「高效程序員」??,一起優(yōu)秀!
