千家信息网

Log4Qt快速入门——Log4Qt日志格式化源码解析

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,Log4Qt快速入门--Log4Qt日志格式化源码解析一、Layout1、Layout简介Log4Qt提供了多种Layout对象,用于格式化日志输出,指定日志级别、线程名称、Logger名称、日期时间
千家信息网最后更新 2026年10月31日Log4Qt快速入门——Log4Qt日志格式化源码解析

Log4Qt快速入门--Log4Qt日志格式化源码解析

一、Layout

1、Layout简介

Log4Qt提供了多种Layout对象,用于格式化日志输出,指定日志级别、线程名称、Logger名称、日期时间等信息。

Layout类是Log4Qt API中的抽象类。
PatternLayout:根据一个模式字符串输出日志事件;
SimpleLayout:输出日志事件的级别和消息;
TTCCLayout:输出日志事件的时间、线程名称、Logger名称和嵌套的诊断上下文信息。
PatternLayout和TTCCLayout通过PatternFormatter来实现格式化。当PatternFormatter解析模式字符串时,会根据发现的信息创建一个PatternConverter链,每个PatternConverter会处理LoggingEvent的某个成员。
转换字符:用于指定数据的类型,例如:类别、级别、日期、线程名称。Log4Qt中的转换字符有:
c:Logger 名称。
d{format_string}:日期。参数 format_string 可选,用于格式化日期。
m:消息内容
p:消息级别
r:启动程序的相对时间
t:线程名称
x:NDC(嵌套的诊断上下文)名称
X:MDC(映射的诊断上下文)名称
F:文件名称
M:方法名称
L:行号
l:位置信息
n:平台相关的行分隔符,Windows:\r\n,Linux:\n

2、NDC简介

NDC(Nested Diagnostic Context)即嵌套诊断上下文,是log4J用于存储上下文信息(context information)的类,NDC采用栈的机制push和pop上下文,每个线程有独立的上下文,如果要存储的上下文信息是堆栈式的在选择NDC。
NDC常用接口如下:
static QString pop();
将NDC栈顶元素弹出
static void push(const QString &rMessage);
将rMessage压入NDC栈
static void clear();
清空NDC栈
static int depth();
获取NDC栈的深度
static void setMaxDepth(int maxDepth);
设置NDC栈的最大深度
static QString peek();
获取NDC栈顶的数据
通常在context或servlet入口将线程相关的应用信息保存,在需要记录日志log信息等时将信息输出,并保证在当前线程的结束或servlet的出口使用clear()移除,防止信息泄露。

3、MDC简介

MDC(Mapped Diagnositc Context)即映射诊断上下文,是log4J用于存储上下文信息(context information)的类,MDC内部采用Hash容器实现,是线程独立的,但一个子线程会自动获得一个父线程MDC的copy,如果要存储的上下文信息是key/value式的选择MDC。
MDC常用接口如下:
static void put(const QString &rKey, const QString &rValue);
将rKey/rValue数据存储到Hash容器中
static void remove(const QString &rKey);
从Hash容器中删除key为rKey的key/value
static QString get(const QString &rKey);
从Hash容器中获取key为rKey的key/value
static QHash<QString, QString> context();
获取Hash容器中所有的内容

4、Layout常用接口

QString footer() const;
获取Layout对象的footer
QString header() const;
获取Layout对象的header
QString name() const;
获取Layout对象的对象名称
void setFooter(const QString &rFooter);
设置Layout对象的footer
void setHeader(const QString &rHeader);
设置Layout对象的header
void setName(const QString &rName);
设置Layout对象的对象名称
virtual QString format(const LoggingEvent &rEvent) = 0;
Layout对象的日志消息格式化接口,派生类PatternLayout、SimpleLayout、TTCCLayout通过format函数来确定具体要输出信息的格式。

二、PatternLayout

1、PatternLayout 简介

PatternLayout是Layout的一个派生类,如果想生成基于模式匹配的特定格式的日志信息,可以使用PatternLayout来进行格式化。
PatternLayout的枚举ConversionPattern定义了两个常用的模式:

enum ConversionPattern{    DEFAULT_CONVERSION_PATTERN,// "%m,%n"    TTCC_CONVERSION_PATTERN,//"%r [%t] %p %c %x - %m%n"};

2、PatternLayout常用接口

QString conversionPattern() const;
获取PatternLayout对象的转换模式匹配字符串
void setConversionPattern(const QString &rPattern);
设置PatternLayout对象的转换模式匹配字符串
void setConversionPattern(ConversionPattern conversionPattern);
设置PatternLayout对象的转换模式匹配方式

3、format格式化实现

QString PatternLayout::format(const LoggingEvent &rEvent){    Q_ASSERT_X(mpPatternFormatter, "PatternLayout::format()", "mpPatternConverter must not be null");    return mpPatternFormatter->format(rEvent);}

调用PatternFormatter格式化函数根据模式转换器链表的每个模式转换器格式化信息。

QString PatternFormatter::format(const LoggingEvent &rLoggingEvent) const    {        QString result;        PatternConverter *p_converter;        Q_FOREACH(p_converter, mPatternConverters)            p_converter->format(result, rLoggingEvent);        return result;    }

PatternFormatter使用模式匹配字符串创建一个模式转换器mPatternConverters,每个转换符对应一个模式转换器。

    void PatternFormatter::createConverter(const QChar &rChar,                                            const FormattingInfo &rFormattingInfo,                                            const QString &rOption)    {        Q_ASSERT_X(mConversionCharacters.indexOf(rChar) >= 0, "PatternFormatter::createConverter", "Unknown conversion character" );        LogError e("Creating Converter for character '%1' min %2, max %3, left %4 and option '%5'");        e << QString(rChar)          << FormattingInfo::intToString(rFormattingInfo.mMinLength)           << FormattingInfo::intToString(rFormattingInfo.mMaxLength)           << rFormattingInfo.mLeftAligned           << rOption;        logger()->trace(e);        switch (rChar.toLatin1())        {            case 'c':                mPatternConverters << new LoggerPatternConverter(rFormattingInfo,                                                                  parseIntegerOption(rOption));                break;            case 'd':            {                QString option = rOption;                if (rOption.isEmpty())                   option = QLatin1String("ISO8601");                mPatternConverters << new DatePatternConverter(rFormattingInfo,                                                                option);                 break;            }            case 'm':                mPatternConverters << new BasicPatternConverter(rFormattingInfo,                                                                BasicPatternConverter::MESSAGE_CONVERTER);                 break;            case 'p':                mPatternConverters << new BasicPatternConverter(rFormattingInfo,                                                                BasicPatternConverter::LEVEL_CONVERTER);                 break;            case 'r':                mPatternConverters << new DatePatternConverter(rFormattingInfo,                                                               QLatin1String("RELATIVE"));                 break;            case 't':                mPatternConverters << new BasicPatternConverter(rFormattingInfo,                                                                BasicPatternConverter::THREAD_CONVERTER);                 break;            case 'x':                mPatternConverters << new BasicPatternConverter(rFormattingInfo,                                                                BasicPatternConverter::NDC_CONVERTER);                 break;            case 'X':                mPatternConverters << new MDCPatternConverter(rFormattingInfo,                                                               rOption);                 break;            default:                Q_ASSERT_X(false, "PatternFormatter::createConverter", "Unknown pattern character");        }    }

4、PatternLayout使用示例

#include #include #include #include #include int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    // 获取rootLogger    Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();    // 创建PatternLayout(根据模式字符串输出日志事件)    Log4Qt::PatternLayout *layout = new Log4Qt::PatternLayout();    // 设置标头信息    layout->setHeader("----- start -----");    // 设置页脚信息    layout->setFooter("----- end -----");    // 设置转换模式    layout->setConversionPattern("%d{yyyy-MM-dd hh:mm:ss} [%p] - %m%n");    // 激活Layout    layout->activateOptions();    // 创建ConsoleAppender    Log4Qt::ConsoleAppender *appender = new Log4Qt::ConsoleAppender(layout, Log4Qt::ConsoleAppender::STDOUT_TARGET);    appender->activateOptions();    logger->addAppender(appender);    logger->setLevel(Log4Qt::Level::DEBUG_INT);    logger->debug("Debug, Log4Qt!");    logger->info("Info, Log4Qt!");    // 关闭 logger    logger->removeAllAppenders();    logger->loggerRepository()->shutdown();    return a.exec();}// output:// ----- start -----// 2018-10-11 21:25:30 [DEBUG] - Debug, Log4Qt!// 2018-10-11 21:25:30 [INFO] - Info, Log4Qt!// ----- end -----

5、配置PatternLayout

使用log4qt.properties配置文件配置PatternLayout:

# 定义 rootLoggerlog4j.rootLogger=DEBUG, console# 定义 ConsoleAppenderlog4j.appender.console=org.apache.log4j.ConsoleAppenderlog4j.appender.console.immediateFlush=truelog4j.appender.console.target=STDOUT_TARGET# 为 ConsoleAppender 定义 Layoutlog4j.appender.console.layout=org.apache.log4j.PatternLayoutlog4j.appender.console.layout.header=----- start -----log4j.appender.console.layout.footer=----- end -----log4j.appender.console.layout.conversionPattern=%d{yyyy-MM-dd hh:mm:ss} [%t] %p %c %x - %m%n

程序使用示例:

#include #include #include #include int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    QThread::currentThread()->setObjectName("MainThread");    // 获取rootLogger    Log4Qt::Logger* logger = Log4Qt::Logger::rootLogger();    // 打印消息    logger->debug("Debug, Log4Qt!");    logger->info("Info, Log4Qt!");    // 关闭rootLogger    logger->removeAllAppenders();    logger->loggerRepository()->shutdown();    return a.exec();}// output:// ----- start -----// 2018-10-11 21:35:58 [MainThread] DEBUG root  - Debug, Log4Qt!// 2018-10-11 21:35:58 [MainThread] INFO root  - Info, Log4Qt!// ----- end -----

三、SimpleLayout

1、SimpleLayout简介

SimpleLayout 是Layout的一个派生类,对日志消息的格式化只包含日志的级别和消息内容。

2、format格式化实现

QString SimpleLayout::format(const LoggingEvent &rEvent)    {        return rEvent.level().toString() + QLatin1String(" - ") + rEvent.message() + Layout::endOfLine();    }

SimpleLayout对日志消息的格式化只包含日志的级别和消息内容。

3、SimpleLayout示例

#include #include #include #include #include int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    // 创建SimpleLayout    Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();    Log4Qt::SimpleLayout *layout = new Log4Qt::SimpleLayout();    layout->setFooter("end");    layout->setHeader("start");    layout->activateOptions();    // 创建ConsoleAppender    Log4Qt::ConsoleAppender *appender = new Log4Qt::ConsoleAppender(layout, Log4Qt::ConsoleAppender::STDOUT_TARGET);    appender->activateOptions();    logger->addAppender(appender);    logger->setLevel(Log4Qt::Level::DEBUG_INT);    logger->debug("Debug, Log4Qt!");    logger->info("Info, Log4Qt!");    // 关闭 logger    logger->removeAllAppenders();    logger->loggerRepository()->shutdown();    return a.exec();}// output:// start// DEBUG - Debug, Log4Qt!// INFO - Info, Log4Qt!// end

4、配置SimpleLayout

使用log4qt.properties配置文件配置SimpleLayout:

# 定义 rootLoggerlog4j.rootLogger=DEBUG, console# 定义 ConsoleAppenderlog4j.appender.console=org.apache.log4j.ConsoleAppenderlog4j.appender.console.immediateFlush=truelog4j.appender.console.target=STDOUT_TARGET# 为 ConsoleAppender 定义 Layoutlog4j.appender.console.layout=org.apache.log4j.SimpleLayoutlog4j.appender.console.layout.header=----- start -----log4j.appender.console.layout.footer=----- end -----

程序使用示例:

#include #include #include int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    // 获取 rootLogger    Log4Qt::Logger* logger = Log4Qt::Logger::rootLogger();    // 打印消息    logger->debug("Hello, Log4Qt!");    logger->info("Hello, Log4Qt!");    // 关闭 rootLogger    logger->removeAllAppenders();    logger->loggerRepository()->shutdown();    return a.exec();}// output:// ----- start -----// DEBUG - Hello, Log4Qt!// INFO - Hello, Log4Qt!// ----- end -----

四、TTCCLayout

1、TTCCLayout简介

TTCCLayout 是Layout的一个派生类,负责提供有关日志事件的详细信息,通常包含以下内容:
Time:从启动应用程序开始,以毫秒数计算的时间;
Thread:调用线程;
Category:用于创建日志事件的类别或Logger;
Context:NDC信息。NDC信息不会自动包含在LoggingEvent 对象中,必须专门包含NDC信息。因此,Context是TTCCLayout的一个可选输出,即使启用NDC设置,如果LoggingEvent 不包含任何NDC设置,TTCCLayout也可能不会显示任何NDC 数据。
TTCCLayout有多个可选参数,但即使不设置任何选项, TTCCLayout仍然会输出下列信息:
Level:日志消息的级别;
Message:日志消息本身。
TTCCLayout预定义了多种日期格式,定义如下:

enum DateFormat{    NONE,//没有日期格式    ISO8601,// yyyy-MM-dd hh:mm:ss.zzz    ABSOLUTE,// HH:mm:ss.zzz    DATE,//MMM YYYY HH:mm:ss.zzzz    RELATIVE // 程序启动开始的毫秒数量};

2、TTCCLayout常用接口

bool categoryPrefixing() const;
获取是否格式化输出Logger名称
bool contextPrinting() const;
获取是否格式化输出NDC信息
QString dateFormat() const;
获取日期格式的字符串
bool threadPrinting() const;
获取是否格式化输出线程名称
void setCategoryPrefixing(bool categoryPrefixing);
设置指定Logger名称是否是格式化输出。
void setContextPrinting(bool contextPrinting);
设置是否格式化输出NDC信息
void setDateFormat(const QString &rDateFormat);
设置rDateFormat字符串表示的日期格式
void setDateFormat(DateFormat dateFormat);
设置DateFormat枚举类型定义的日期格式类型
void setThreadPrinting(bool threadPrinting);
设置是否格式化输出线程名称
virtual QString format(const LoggingEvent &rEvent);
格式化日志信息接口
static void Log4Qt::NDC::push(const QString &rMessage);
将rMessage信息压入NDC栈
static QString Log4Qt::NDC::pop();
将NDC栈顶信息出栈

3、format格式化实现

QString TTCCLayout::format(const LoggingEvent &rEvent){    Q_ASSERT_X(mpPatternFormatter, "TTCCLayout::format()", "mpPatternConverter must not be null");    return mpPatternFormatter->format(rEvent);}

TTCCLayout的格式化与PatternLayout的格式化方法相同,都是根据模式匹配字符串创建的模式转换器链表的每个模式转换器格式化信息。

4、TTCCLayout示例

#include #include #include #include #include #include #include int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    QThread::currentThread()->setObjectName("MainThread");    Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();    // 创建TTCCLayout    Log4Qt::TTCCLayout *layout = new Log4Qt::TTCCLayout();    layout->setDateFormat("yyyy-mm-dd hh:mm:ss");    layout->activateOptions();    // 创建一ConsoleAppender    Log4Qt::ConsoleAppender *appender = new Log4Qt::ConsoleAppender(layout, Log4Qt::ConsoleAppender::STDOUT_TARGET);    appender->activateOptions();    logger->addAppender(appender);    logger->setLevel(Log4Qt::Level::DEBUG_INT);    // NDC信息    Log4Qt::NDC::push("Thread start");    logger->debug("Hello, Log4Qt!");    Log4Qt::NDC::pop();    logger->info("Hello, Log4Qt!");    // 关闭 logger    logger->removeAllAppenders();    logger->loggerRepository()->shutdown();    return a.exec();}// output:// 2018-18-11 23:18:12 [MainThread] DEBUG root Thread start - Hello, Log4Qt!// 2018-18-11 23:18:12 [MainThread] INFO  root  - Hello, Log4Qt!

5、配置TTCCLayout

使用log4qt.properties配置文件配置TTCCLayout:

# 定义rootLoggerlog4j.rootLogger=DEBUG, console# 定义ConsoleAppenderlog4j.appender.console=org.apache.log4j.ConsoleAppenderlog4j.appender.console.immediateFlush=truelog4j.appender.console.target=STDOUT_TARGET# 为ConsoleAppender定义Layoutlog4j.appender.console.layout=org.apache.log4j.TTCCLayoutlog4j.appender.console.layout.categoryPrefixing=truelog4j.appender.console.layout.contextPrinting=truelog4j.appender.console.layout.threadPrinting=truelog4j.appender.console.layout.dateFormat=ISO8601

程序使用示例:

#include #include #include #include #include #include #include int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    QThread::currentThread()->setObjectName("MainThread");    Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();    // NDC信息    Log4Qt::NDC::push("Thread start");    logger->debug("Hello, Log4Qt!");    Log4Qt::NDC::pop();    logger->info("Hello, Log4Qt!");    // 关闭 logger    logger->removeAllAppenders();    logger->loggerRepository()->shutdown();    return a.exec();}// output:// 2018-10-11 23:22:09.936 [MainThread] DEBUG root Thread start - Hello, Log4Qt!// 2018-10-11 23:22:09.936 [MainThread] INFO  root  - Hello, Log4Qt!
格式 信息 日志 名称 模式 输出 对象 线程 消息 上下 上下文 字符 字符串 日期 配置 接口 级别 事件 常用 示例 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 深圳九邦互联网科技有限公司 科技创新与互联网经济 互联网下的科技发展 合肥互联网科技公司 亿策互联网科技 友谊互联网络科技 四川狮子座互联网科技 国外互联网科技网站 金融科技和互联网金融 互联网公司会议桌创意科技软装饰 新兴科技互联网创新大赛颁奖典礼 中国互联网十大科技股排名 想开互联网科技公司怎么样 中国科技创新与世界互联网大会 电子商务与互联网科技的关系 产业互联网科技服务公司 互联网科技快讯热点 广州有谷有贝互联网科技有限公司 容联科技互联网电商 互联网界的黑科技 互联网科技深圳 互联网巨头反垄断金融科技 深圳互联网科技怎么样 卫星互联网科技股票 昊天互联网科技有限公司 互联网科技创新的路径 江苏互联网智能科技软件 2021世界互联网领先科技成果发布 悟空问答互联网科技 承德科技产业互联网平台
0