溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Log4Qt快速入門(mén)——Log4Qt日志格式化源碼解析

發(fā)布時(shí)間:2020-07-19 22:26:44 來(lái)源:網(wǎng)絡(luò) 閱讀:3534 作者:天山老妖S 欄目:軟件技術(shù)

Log4Qt快速入門(mén)——Log4Qt日志格式化源碼解析

一、Layout

1、Layout簡(jiǎn)介

Log4Qt提供了多種Layout對(duì)象,用于格式化日志輸出,指定日志級(jí)別、線程名稱(chēng)、Logger名稱(chēng)、日期時(shí)間等信息。
Log4Qt快速入門(mén)——Log4Qt日志格式化源碼解析
Layout類(lèi)是Log4Qt API中的抽象類(lèi)。
PatternLayout:根據(jù)一個(gè)模式字符串輸出日志事件;
SimpleLayout:輸出日志事件的級(jí)別和消息;
TTCCLayout:輸出日志事件的時(shí)間、線程名稱(chēng)、Logger名稱(chēng)和嵌套的診斷上下文信息。
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è)成員。
轉(zhuǎn)換字符:用于指定數(shù)據(jù)的類(lèi)型,例如:類(lèi)別、級(jí)別、日期、線程名稱(chēng)。Log4Qt中的轉(zhuǎn)換字符有:
c:Logger 名稱(chēng)。
d{format_string}:日期。參數(shù)?format_string?可選,用于格式化日期。
m:消息內(nèi)容
p:消息級(jí)別
r:?jiǎn)?dòng)程序的相對(duì)時(shí)間
t:線程名稱(chēng)
x:NDC(嵌套的診斷上下文)名稱(chēng)
X:MDC(映射的診斷上下文)名稱(chēng)
F:文件名稱(chēng)
M:方法名稱(chēng)
L:行號(hào)
l:位置信息
n:平臺(tái)相關(guān)的行分隔符,Windows:\r\n,Linux:\n

2、NDC簡(jiǎn)介

NDC(Nested Diagnostic Context)即嵌套診斷上下文,是log4J用于存儲(chǔ)上下文信息(context information)的類(lèi),NDC采用棧的機(jī)制push和pop上下文,每個(gè)線程有獨(dú)立的上下文,如果要存儲(chǔ)的上下文信息是堆棧式的在選擇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);
設(shè)置NDC棧的最大深度
static QString peek();
獲取NDC棧頂?shù)臄?shù)據(jù)
通常在context或servlet入口將線程相關(guān)的應(yīng)用信息保存,在需要記錄日志log信息等時(shí)將信息輸出,并保證在當(dāng)前線程的結(jié)束或servlet的出口使用clear()移除,防止信息泄露。

3、MDC簡(jiǎn)介

MDC(Mapped Diagnositc Context)即映射診斷上下文,是log4J用于存儲(chǔ)上下文信息(context information)的類(lèi),MDC內(nèi)部采用Hash容器實(shí)現(xiàn),是線程獨(dú)立的,但一個(gè)子線程會(huì)自動(dòng)獲得一個(gè)父線程MDC的copy,如果要存儲(chǔ)的上下文信息是key/value式的選擇MDC。
MDC常用接口如下:
static void put(const QString &rKey, const QString &rValue);
將rKey/rValue數(shù)據(jù)存儲(chǔ)到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容器中所有的內(nèi)容

4、Layout常用接口

QString footer() const;
獲取Layout對(duì)象的footer
QString header() const;
獲取Layout對(duì)象的header
QString name() const;
獲取Layout對(duì)象的對(duì)象名稱(chēng)
void setFooter(const QString &rFooter);
設(shè)置Layout對(duì)象的footer
void setHeader(const QString &rHeader);
設(shè)置Layout對(duì)象的header
void setName(const QString &rName);
設(shè)置Layout對(duì)象的對(duì)象名稱(chēng)
virtual QString format(const LoggingEvent &rEvent) = 0;
Layout對(duì)象的日志消息格式化接口,派生類(lèi)PatternLayout、SimpleLayout、TTCCLayout通過(guò)format函數(shù)來(lái)確定具體要輸出信息的格式。

二、PatternLayout

1、PatternLayout 簡(jiǎn)介

PatternLayout是Layout的一個(gè)派生類(lèi),如果想生成基于模式匹配的特定格式的日志信息,可以使用PatternLayout來(lái)進(jìn)行格式化。
PatternLayout的枚舉ConversionPattern定義了兩個(gè)常用的模式:

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

2、PatternLayout常用接口

QString conversionPattern() const;
獲取PatternLayout對(duì)象的轉(zhuǎn)換模式匹配字符串
void setConversionPattern(const QString &rPattern);
設(shè)置PatternLayout對(duì)象的轉(zhuǎn)換模式匹配字符串
void setConversionPattern(ConversionPattern conversionPattern);
設(shè)置PatternLayout對(duì)象的轉(zhuǎn)換模式匹配方式

3、format格式化實(shí)現(xiàn)

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

    return mpPatternFormatter->format(rEvent);
}

調(diào)用PatternFormatter格式化函數(shù)根據(jù)模式轉(zhuǎn)換器鏈表的每個(gè)模式轉(zhuǎn)換器格式化信息。

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使用模式匹配字符串創(chuàng)建一個(gè)模式轉(zhuǎn)換器mPatternConverters,每個(gè)轉(zhuǎn)換符對(duì)應(yīng)一個(gè)模式轉(zhuǎn)換器。

    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 <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);

    // 獲取rootLogger
    Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();
    // 創(chuàng)建PatternLayout(根據(jù)模式字符串輸出日志事件)
    Log4Qt::PatternLayout *layout = new Log4Qt::PatternLayout();
    // 設(shè)置標(biāo)頭信息
    layout->setHeader("----- start -----");
    // 設(shè)置頁(yè)腳信息
    layout->setFooter("----- end -----");
    // 設(shè)置轉(zhuǎn)換模式
    layout->setConversionPattern("%d{yyyy-MM-dd hh:mm:ss} [%p] - %m%n");
    // 激活Layout
    layout->activateOptions();

    // 創(chuàng)建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!");

    // 關(guān)閉 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:

# 定義 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=----- 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 <QCoreApplication>
#include <log4qt/logger.h>
#include <log4qt/loggerrepository.h>
#include <QThread>

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!");

    // 關(guān)閉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簡(jiǎn)介

SimpleLayout 是Layout的一個(gè)派生類(lèi),對(duì)日志消息的格式化只包含日志的級(jí)別和消息內(nèi)容。

2、format格式化實(shí)現(xiàn)

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

SimpleLayout對(duì)日志消息的格式化只包含日志的級(jí)別和消息內(nèi)容。

3、SimpleLayout示例

#include <QCoreApplication>
#include <log4qt/logger.h>
#include <log4qt/simplelayout.h>
#include <log4qt/consoleappender.h>
#include <log4qt/loggerrepository.h>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 創(chuàng)建SimpleLayout
    Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();
    Log4Qt::SimpleLayout *layout = new Log4Qt::SimpleLayout();
    layout->setFooter("end");
    layout->setHeader("start");
    layout->activateOptions();

    // 創(chuàng)建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!");

    // 關(guān)閉 logger
    logger->removeAllAppenders();
    logger->loggerRepository()->shutdown();

    return a.exec();
}
// output:
// start
// DEBUG - Debug, Log4Qt!
// INFO - Info, Log4Qt!
// end

4、配置SimpleLayout

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

# 定義 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.SimpleLayout
log4j.appender.console.layout.header=----- start -----
log4j.appender.console.layout.footer=----- end -----

程序使用示例:

#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!");
    logger->info("Hello, Log4Qt!");

    // 關(guān)閉 rootLogger
    logger->removeAllAppenders();
    logger->loggerRepository()->shutdown();

    return a.exec();
}
// output:
// ----- start -----
// DEBUG - Hello, Log4Qt!
// INFO - Hello, Log4Qt!
// ----- end -----

四、TTCCLayout

1、TTCCLayout簡(jiǎn)介

TTCCLayout 是Layout的一個(gè)派生類(lèi),負(fù)責(zé)提供有關(guān)日志事件的詳細(xì)信息,通常包含以下內(nèi)容:
Time:從啟動(dòng)應(yīng)用程序開(kāi)始,以毫秒數(shù)計(jì)算的時(shí)間;
Thread:調(diào)用線程;
Category:用于創(chuàng)建日志事件的類(lèi)別或Logger;
Context:NDC信息。NDC信息不會(huì)自動(dòng)包含在LoggingEvent 對(duì)象中,必須專(zhuān)門(mén)包含NDC信息。因此,Context是TTCCLayout的一個(gè)可選輸出,即使啟用NDC設(shè)置,如果LoggingEvent 不包含任何NDC設(shè)置,TTCCLayout也可能不會(huì)顯示任何NDC 數(shù)據(jù)。
?TTCCLayout有多個(gè)可選參數(shù),但即使不設(shè)置任何選項(xiàng),?TTCCLayout仍然會(huì)輸出下列信息:
Level:日志消息的級(jí)別;
Message:日志消息本身。
TTCCLayout預(yù)定義了多種日期格式,定義如下:

enum DateFormat
{
    NONE,//沒(méi)有日期格式
    ISO8601,// yyyy-MM-dd hh:mm:ss.zzz
    ABSOLUTE,// HH:mm:ss.zzz
    DATE,//MMM YYYY HH:mm:ss.zzzz
    RELATIVE // 程序啟動(dòng)開(kāi)始的毫秒數(shù)量
};

2、TTCCLayout常用接口

bool categoryPrefixing() const;
獲取是否格式化輸出Logger名稱(chēng)
bool contextPrinting() const;
獲取是否格式化輸出NDC信息
QString dateFormat() const;
獲取日期格式的字符串
bool threadPrinting() const;
獲取是否格式化輸出線程名稱(chēng)
void setCategoryPrefixing(bool categoryPrefixing);
設(shè)置指定Logger名稱(chēng)是否是格式化輸出。
void setContextPrinting(bool contextPrinting);
設(shè)置是否格式化輸出NDC信息
void setDateFormat(const QString &rDateFormat);
設(shè)置rDateFormat字符串表示的日期格式
void setDateFormat(DateFormat dateFormat);
設(shè)置DateFormat枚舉類(lèi)型定義的日期格式類(lèi)型
void setThreadPrinting(bool threadPrinting);
設(shè)置是否格式化輸出線程名稱(chēng)
virtual QString format(const LoggingEvent &rEvent);
格式化日志信息接口
static void Log4Qt::NDC::push(const QString &rMessage);
將rMessage信息壓入NDC棧
static QString Log4Qt::NDC::pop();
將NDC棧頂信息出棧

3、format格式化實(shí)現(xiàn)

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

    return mpPatternFormatter->format(rEvent);
}

TTCCLayout的格式化與PatternLayout的格式化方法相同,都是根據(jù)模式匹配字符串創(chuàng)建的模式轉(zhuǎn)換器鏈表的每個(gè)模式轉(zhuǎn)換器格式化信息。

4、TTCCLayout示例

#include <QCoreApplication>
#include <log4qt/logger.h>
#include <log4qt/ttcclayout.h>
#include <log4qt/consoleappender.h>
#include <log4qt/loggerrepository.h>
#include <log4qt/ndc.h>
#include <QThread>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QThread::currentThread()->setObjectName("MainThread");

    Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();
    // 創(chuàng)建TTCCLayout
    Log4Qt::TTCCLayout *layout = new Log4Qt::TTCCLayout();
    layout->setDateFormat("yyyy-mm-dd hh:mm:ss");
    layout->activateOptions();

    // 創(chuàng)建一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!");

    // 關(guān)閉 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:

# 定義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=true
log4j.appender.console.layout.contextPrinting=true
log4j.appender.console.layout.threadPrinting=true
log4j.appender.console.layout.dateFormat=ISO8601

程序使用示例:

#include <QCoreApplication>
#include <log4qt/logger.h>
#include <log4qt/ttcclayout.h>
#include <log4qt/consoleappender.h>
#include <log4qt/loggerrepository.h>
#include <log4qt/ndc.h>
#include <QThread>

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!");

    // 關(guān)閉 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!
向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI