国产精品视频被艹_九九自拍视频精品_亚洲国产清纯系在线观看_十八禁深夜福利老司机视频_熟女日韩精品2区_午夜激情经典日韩_亚洲国产成人欧美在线观看_中文字幕人成乱码熟女超碰_大陆一级成人毛片_18禁在线看网站

返回列表
基于Qt開發(fā)的日志庫QsLog的使用

基于Qt開發(fā)的日志庫QsLog的使用

概述

C++下的日志庫有很多,如log4cpp、Easylogging++等,Qt下也有l(wèi)og4qt。

這里介紹QsLog,它是一個基于Qt的輕量級開源日志庫。

git地址:https://github.com/victronenergy/QsLog

源代碼結(jié)構(gòu)如下圖:

圖片1.png

特征

六個日志級別(從跟蹤到致命)

運(yùn)行時可配置的日志級別閾值。

關(guān)閉日志記錄時的最小開銷。

支持多個目標(biāo),附帶文件和調(diào)試目標(biāo)。

線程安全

支持現(xiàn)成的常見Qt類型的日志記錄。

小依賴:直接把它放到你的項目中。

一、QsLog使用方式

1. 源碼集成

在你的工程中,直接包含QsLog.pri文件,進(jìn)行源碼集成。

當(dāng)然你也可以包含QsLog.pri后,編譯為xx.dll,在應(yīng)用工程中去調(diào)用xx.dll。

2. 動態(tài)庫集成

編譯QsLogSharedLibrary.pro,生成動態(tài)鏈接庫QsLog2.dll,在你的工程中進(jìn)行調(diào)用。

二、日志級別

支持六個日志級別,優(yōu)先級從低到高依次為:Trace、Debug、Info、Warn、Error、Fatal、Off。如下:

enum Level

{

    TraceLevel = 0,

    DebugLevel,

    InfoLevel,

    WarnLevel,

    ErrorLevel,

    FatalLevel,

    OffLevel

};

Trace:跟蹤,最低等級的,用于打開所有日志記錄。

Debug:調(diào)試,打印一些細(xì)粒度調(diào)試運(yùn)行信息。

Info:信息,打印粗粒度信息,突出強(qiáng)調(diào)程序的運(yùn)行過程。打印一些感興趣或者重要的信息,可用于環(huán)境中輸出程序運(yùn)行的一些重要信息,但不能濫用,避免打印過多日志。

Warn:警告,表明會出現(xiàn)潛在錯誤的情形,有些信息不是錯誤信息,但是也要給程序員的一些提示。

Error:錯誤,指出雖然發(fā)生錯誤,但仍然不影響系統(tǒng)的繼續(xù)運(yùn)行。打印錯誤和異常信息。

Fatal:致命的,發(fā)生嚴(yán)重錯誤,將導(dǎo)致應(yīng)用程序的退出。這個級別比較高,程序直接停止運(yùn)行了。

Off:最高等級的,用于關(guān)閉所有日志記錄。

可以通過setLoggingLevel()設(shè)置記錄日志的級別。

void setLoggingLevel(Level newLevel)

一般我們可以將日志級別保存到配置文件,以便程序發(fā)布后,可通過修改配置來改變記錄日志級別。

三、日志輸出目的地

QsLog的使用很簡單,在我們自己的工程中直接include它的QsLog.pri文件,然后源文件中包含QsLog.h就可以使用了。日志打印輸出目的地可以有4種,分別是:

1. 輸出到文件;

2. 輸出到控制臺stdout;

3. 輸出到函數(shù);

4. 輸出到QObject。

并且可以添加任意多個目的地址,比如輸出到文件的同時,還要輸出到控制臺進(jìn)行顯示,以方便查看調(diào)試打印信息。

1. 輸出到文件(支持文件分割)

// 測試文件為目的地

void test_output_file()

{

    // 初始化日志機(jī)制

    Logger& logger = Logger::instance();

    logger.setLoggingLevel(QsLogging::TraceLevel);

    // 添加文件為目的地

    const QString sLogPath(QDir(QApplication::applicationDirPath()).filePath("log.txt"));

    DestinationPtr fileDestination(DestinationFactory::MakeFileDestination(

    sLogPath, EnableLogRotation, MaxSizeBytes(512*1024), MaxOldLogCount(5)));

    logger.addDestination(fileDestination);

    // 打印日志

    QLOG_TRACE() << "1-trace msg";

    QLOG_DEBUG() << "2-debug msg";

    QLOG_INFO() << "3-info msg";

    QLOG_WARN() << "4-warn msg";

    QLOG_ERROR() << "5-error msg";

    QLOG_FATAL()  << "6-fatal msg";

    QsLogging::Logger::destroyInstance();

}

代碼很簡單,setLoggingLevel()設(shè)置記錄的日志級別;
目前為TraceLevel,則日志級別比TraceLevel高的都會輸出到文件;
若為ErrorLevel,則只有"5-error msg"和"6-fatal msg"這2條會輸出。

然后設(shè)置文件名和輸出目的地。其中目的地是由DestinationFactory::MakeFileDestination()函數(shù)進(jìn)行構(gòu)造的,其原型為:

static DestinationPtr MakeFileDestination(

    const QString& filePath,

    LogRotationOption rotation = DisableLogRotation,

    const MaxSizeBytes &sizeInBytesToRotateAfter = MaxSizeBytes(),

const MaxOldLogCount &oldLogsToKeep = MaxOldLogCount());

函數(shù)參數(shù)含義:

filePath: 日志文件名

rotation: 取值DisableLogRotation和EnableLogRotation,

前者表示禁止日志文件分割,即日志始終往一個文件中寫入。

后者表示啟用日志文件分割,此時sizeInBytesToRotateAfter和oldLogsToKeep參數(shù)才有意義。

sizeInBytesToRotateAfter: 每個日志文件的字節(jié)數(shù)大小限制,即到達(dá)此大小后,自動新建文件,在新文件中進(jìn)行寫入。

oldLogsToKeep: 舊日志文件保留(備份)個數(shù),超過此數(shù)量,自動刪除最久遠(yuǎn)文件,備份文件最多支持10個。

若為2,則如下三個文件中內(nèi)容,按照時間先后順序排列為:log.txt.2->log.txt.1->log.txt,在log.txt中為最新日志,log.txt.1為次新,log.txt.2為最久遠(yuǎn)日志。

若此時log.txt超過sizeInBytesToRotateAfter限制,則會發(fā)生log.txt.2被刪除,log.txt.1被改名log.txt.2,log.txt被改名log.txt.1,新建log.txt。

圖片3.png

運(yùn)行效果

圖片4.png

2. 輸出到控制臺stdout

// 測試stdout為目的地

void test_output_stdout()

{

    // 初始化日志機(jī)制

    Logger& logger = Logger::instance();

    logger.setLoggingLevel(QsLogging::TraceLevel);

    // 添加stdout為目的地

    DestinationPtr debugDestination(DestinationFactory::MakeDebugOutputDestination());

    logger.addDestination(debugDestination);

    // 打印日志

    QLOG_TRACE() << "1-trace msg";

    QLOG_DEBUG() << "2-debug msg";

    QLOG_INFO() << "3-info msg";

    QLOG_WARN() << "4-warn msg";

    QLOG_ERROR() << "5-error msg";

    QLOG_FATAL()  << "6-fatal msg";

    QsLogging::Logger::destroyInstance();

}

運(yùn)行效果:

圖片5.png

3. 輸出到處理函數(shù)

void logFunction(const QString &message, QsLogging::Level level)

{

qDebug()<<"From log function: "<<qPrintable(message)<<" " << static_cast<int>(level);

}

// 測試函數(shù)為目的地

void test_output_function()

{

    // 初始化日志機(jī)制

    Logger& logger = Logger::instance();

    logger.setLoggingLevel(QsLogging::TraceLevel);

    // 添加函數(shù)為目的地

    DestinationPtr functorDestination(DestinationFactory::MakeFunctorDestination(&logFunction));

    logger.addDestination(functorDestination);

    // 打印日志

    QLOG_TRACE() << "1-trace msg";

    QLOG_DEBUG() << "2-debug msg";

    QLOG_INFO() << "3-info msg";

    QLOG_WARN() << "4-warn msg";

    QLOG_ERROR() << "5-error msg";

    QLOG_FATAL()  << "6-fatal msg";

    QsLogging::Logger::destroyInstance();

}

輸出到函數(shù),該函數(shù)需要定義為如下類型:

typedef void (*LogFunction)(const QString &message, Level level);

運(yùn)行效果:

圖片6.png

4. 輸出到QTextEdit控件

除了上面的輸出方式,還可以輸出到一個QObject對象上,主要是通過信號槽機(jī)制,將打印日志發(fā)送到QObject的槽函數(shù)進(jìn)行處理。

void MainWindow::writeLog(const QString &message, int level)

{

    ui->textEdit->append(message + " " + QString::number(level));

}

// 測試QObject為目的地

void test_output_qobject(MainWindow* window)

{

    // 初始化日志機(jī)制

    Logger& logger = Logger::instance();

    logger.setLoggingLevel(QsLogging::TraceLevel);

    // 添加QObject為目的地

    DestinationPtr objectDestination(DestinationFactory::MakeFunctorDestination(window, SLOT(writeLog(QString,int))));

    logger.addDestination(objectDestination);

    // 打印日志

    QLOG_TRACE() << "1-trace msg";

    QLOG_DEBUG() << "2-debug msg";

    QLOG_INFO() << "3-info msg";

    QLOG_WARN() << "4-warn msg";

    QLOG_ERROR() << "5-error msg";

    QLOG_FATAL()  << "6-fatal msg";

    QsLogging::Logger::destroyInstance();

}

輸出到QObject時,需要定義其槽函數(shù),為如下類型:

void xxxx(const QString &message, int level)

寫本例子時,發(fā)現(xiàn)TRACE信息不能輸出到QObject,是因為QsLogDestFunctor.cpp文件中,write函數(shù)有個bug,如下:

void QsLogging::FunctorDestination::write(const QString &message, QsLogging::Level level)

{

    if (mLogFunction)

        mLogFunction(message, level);

    if (level > QsLogging::TraceLevel)

        emit logMessageReady(message, static_cast<int>(level));

}

應(yīng)將>改為>=,修改后即可解決,如下:

void QsLogging::FunctorDestination::write(const QString &message, QsLogging::Level level)

{

    if (mLogFunction)

        mLogFunction(message, level);

    if (level >= QsLogging::TraceLevel)

        emit logMessageReady(message, static_cast<int>(level));

}

運(yùn)行效果:

圖片7.png

四、打印源文件名稱和行號

QsLog.pri文件中

DEFINES += QS_LOG_LINE_NUMBERS

打開此宏定義,重新編譯,即可打印帶源文件名稱和行號的日志。如下:

圖片8.png

運(yùn)行效果

圖片9.png

五、禁止日志記錄

禁用日志記錄,有時候關(guān)閉日志記錄是有必要的??梢酝ㄟ^3種方式實現(xiàn):

全局地,在編譯時,通過在QsLog.pri文件,打開DEFINES += QS_LOG_DISABLE宏定義。

全局地,在運(yùn)行時,通過將日志級別設(shè)置為關(guān)閉,即setLoggingLevel(QsLogging::OffLevel)。

在編譯時,通過在目標(biāo)文件中包含QsLogDisableForThisFile.h,為每個文件創(chuàng)建一個。

六、線程安全

使用日志宏進(jìn)行打印日志是線程安全的,日志宏如下:

QLOG_TRACE() << "1-trace msg";

QLOG_DEBUG() << "2-debug msg";

QLOG_INFO() << "3-info msg";

QLOG_WARN() << "4-warn msg";

QLOG_ERROR() << "5-error msg";

QLOG_FATAL()  << "6-fatal msg";

這在前面我們已經(jīng)使用過了。

setLoggingLevel()、addDestination()函數(shù)不是線程安全的。

七、日志的異步打印

所謂的異步打印,其實就是單獨(dú)開一個線程來專門寫日志。

QsLog.pri文件中

DEFINES += QS_LOG_SEPARATE_THREAD

打開此宏定義,重新編譯,日志內(nèi)容就會在單獨(dú)的線程中排隊并寫入。


網(wǎng)站編輯:小優(yōu)智能科技有限公司 發(fā)布時間:Aug 30,2024
給我們留言
驗證碼