Qt轻量级日志库QsLog的使用
C加加下的日志庫有很多,如log4cpp、Easylogging++等,Qt下也有l(wèi)og4qt。
不過我們今天要說的是QsLog,它是一個(gè)基于Qt的輕量級(jí)開源日志庫。
git地址:https://github.com/victronenergy/QsLog
輕到什么程度,請(qǐng)看如下:
代碼文件就是這么點(diǎn)。花點(diǎn)時(shí)間閱讀一下,秒改造成你自己的私有輪子。
雖然輕量級(jí),但是對(duì)于基本的日志功能需求還是夠用的。
特征
- 六個(gè)日志級(jí)別(從跟蹤到致命)
- 運(yùn)行時(shí)可配置的日志級(jí)別閾值。
- 關(guān)閉日志記錄時(shí)的最小開銷。
- 支持多個(gè)目標(biāo),附帶文件和調(diào)試目標(biāo)。
- 線程安全
- 支持現(xiàn)成的常見Qt類型的日志記錄。
- 小依賴:直接把它放到你的項(xiàng)目中。
接下來,我們研究下它都有哪些功能。
一、QsLog使用方式
1. 源碼集成
在你的工程中,直接包含QsLog.pri文件,進(jìn)行源碼集成。
當(dāng)然你也可以包含QsLog.pri后,編譯為xx.dll,在應(yīng)用工程中去調(diào)用xx.dll。
2. 動(dòng)態(tài)庫集成
編譯QsLogSharedLibrary.pro,生成動(dòng)態(tài)鏈接庫QsLog2.dll,在你的工程中進(jìn)行調(diào)用。
二、日志級(jí)別
支持六個(gè)日志級(jí)別,優(yōu)先級(jí)從低到高依次為:Trace、Debug、Info、Warn、Error、Fatal、Off。如下:
enum Level {TraceLevel = 0,DebugLevel,InfoLevel,WarnLevel,ErrorLevel,FatalLevel,OffLevel };- Trace:跟蹤,最低等級(jí)的,用于打開所有日志記錄。
- Debug:調(diào)試,打印一些細(xì)粒度調(diào)試運(yùn)行信息。
- Info:信息,打印粗粒度信息,突出強(qiáng)調(diào)程序的運(yùn)行過程。打印一些感興趣或者重要的信息,可用于環(huán)境中輸出程序運(yùn)行的一些重要信息,但不能濫用,避免打印過多日志。
- Warn:警告,表明會(huì)出現(xiàn)潛在錯(cuò)誤的情形,有些信息不是錯(cuò)誤信息,但是也要給程序員的一些提示。
- Error:錯(cuò)誤,指出雖然發(fā)生錯(cuò)誤,但仍然不影響系統(tǒng)的繼續(xù)運(yùn)行。打印錯(cuò)誤和異常信息。
- Fatal:致命的,發(fā)生嚴(yán)重錯(cuò)誤,將導(dǎo)致應(yīng)用程序的退出。這個(gè)級(jí)別比較高,程序直接停止運(yùn)行了。
- Off:最高等級(jí)的,用于關(guān)閉所有日志記錄。
可以通過setLoggingLevel()設(shè)置記錄日志的級(jí)別。
void setLoggingLevel(Level newLevel)注意:
一般我們可以將日志級(jí)別保存到配置文件,以便程序發(fā)布后,可通過修改配置來改變記錄日志級(jí)別。
三、日志輸出目的地
QsLog的使用很簡(jiǎn)單,在我們自己的工程中直接include它的QsLog.pri文件,然后源文件中包含QsLog.h就可以使用了。
1. 輸出到文件(支持文件分割)
// 測(cè)試文件為目的地 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(); }-
代碼很簡(jiǎn)單,setLoggingLevel()設(shè)置記錄的日志級(jí)別;
目前為TraceLevel,則日志級(jí)別比TraceLevel高的都會(huì)輸出到文件;
若為ErrorLevel,則只有"5-error msg"和"6-fatal msg"這2條會(huì)輸出。 -
然后設(shè)置文件名和輸出目的地。其中目的地是由DestinationFactory::MakeFileDestination()函數(shù)進(jìn)行構(gòu)造的,其原型為:
函數(shù)參數(shù)含義:
filePath: 日志文件名
rotation: 取值DisableLogRotation和EnableLogRotation,
前者表示禁止日志文件分割,即日志始終往一個(gè)文件中寫入。
后者表示啟用日志文件分割,此時(shí)sizeInBytesToRotateAfter和oldLogsToKeep參數(shù)才有意義。
sizeInBytesToRotateAfter: 每個(gè)日志文件的字節(jié)數(shù)大小限制,即到達(dá)此大小后,自動(dòng)新建文件,在新文件中進(jìn)行寫入。
oldLogsToKeep: 舊日志文件保留(備份)個(gè)數(shù),超過此數(shù)量,自動(dòng)刪除最久遠(yuǎn)文件,備份文件最多支持10個(gè)。
若為2,則如下三個(gè)文件中內(nèi)容,按照時(shí)間先后順序排列為:log.txt.2->log.txt.1->log.txt,在log.txt中為最新日志,log.txt.1為次新,log.txt.2為最久遠(yuǎn)日志。
若此時(shí)log.txt超過sizeInBytesToRotateAfter限制,則會(huì)發(fā)生log.txt.2被刪除,log.txt.1被改名log.txt.2,log.txt被改名log.txt.1,新建log.txt。
運(yùn)行效果:
2. 輸出到控制臺(tái)stdout
// 測(cè)試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)行效果:
3. 輸出到處理函數(shù)
void logFunction(const QString &message, QsLogging::Level level) {qDebug() << "From log function: " << qPrintable(message) << " " << static_cast<int>(level); }// 測(cè)試函數(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)行效果:
4. 輸出到QTextEdit控件
除了上面的輸出方式,還可以輸出到一個(gè)QObject對(duì)象上,主要是通過信號(hào)槽機(jī)制,將打印日志發(fā)送到QObject的槽函數(shù)進(jìn)行處理。
void MainWindow::writeLog(const QString &message, int level) {ui->textEdit->append(message + " " + QString::number(level)); } // 測(cè)試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í),需要定義其槽函數(shù),為如下類型:
void xxxx(const QString &message, int level)寫本例子時(shí),發(fā)現(xiàn)TRACE信息不能輸出到QObject,是因?yàn)镼sLogDestFunctor.cpp文件中,write函數(shù)有個(gè)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)); }修改后的QsLog庫,下載鏈接:
https://download.csdn.net/download/u011832525/12520461
運(yùn)行效果:
小結(jié):
總結(jié)下,日志打印輸出目的地可以有4種,分別是:
- 輸出到文件;
- 輸出到控制臺(tái)stdout;
- 輸出到函數(shù);
- 輸出到QObject。
并且可以添加任意多個(gè)目的地址,比如輸出到文件的同時(shí),還要輸出到控制臺(tái)進(jìn)行顯示,以方便查看調(diào)試打印信息。
四、打印源文件名稱和行號(hào)
在QsLog.pri文件中
DEFINES += QS_LOG_LINE_NUMBERS打開此宏定義,重新編譯,即可打印帶源文件名稱和行號(hào)的日志。如下:
運(yùn)行效果:
五、禁止日志記錄
禁用日志記錄,有時(shí)候關(guān)閉日志記錄是有必要的。可以通過3種方式實(shí)現(xiàn):
- 全局地,在編譯時(shí),通過在QsLog.pri文件,打開DEFINES += QS_LOG_DISABLE宏定義。
- 全局地,在運(yùn)行時(shí),通過將日志級(jí)別設(shè)置為關(guān)閉,即setLoggingLevel(QsLogging::OffLevel)。
- 在編譯時(shí),通過在目標(biāo)文件中包含QsLogDisableForThisFile.h,為每個(gè)文件創(chuàng)建一個(gè)。
六、線程安全
使用日志宏進(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ù)不是線程安全的。
七、日志的異步打印
所謂的異步打印,其實(shí)就是單獨(dú)開一個(gè)線程來專門寫日志。
在QsLog.pri文件中
DEFINES += QS_LOG_SEPARATE_THREAD打開此宏定義,重新編譯,日志內(nèi)容就會(huì)在單獨(dú)的線程中排隊(duì)并寫入。
八、總結(jié)
以下內(nèi)容來自QsLog的git倉庫介紹:
QsLog is an easy to use logger that is based on Qt’s QDebug class. QsLog is released as open source, under the MIT license.
###Contribution policy### Bug fixes are welcome, larger changes however are not encouraged at this point due to the lack of time on my side for reviewing and integrating them. Your best bet in this case would be to open a ticket for your change or forking the project and implementing your change there, with the possibility of having it integrated in the future. All contributions will be credited, license of the contributions should be MIT.
意思就是有問題,歡迎提bug,不過我沒啥時(shí)間,修不修復(fù)就看我的心情了。如果你想玩,最好自己fork倉庫,以后,萬一未來哪天心情好了,想繼續(xù)迭代版本,你敲的代碼還是有可能merge進(jìn)來的,到時(shí)候給你頒朵小紅花,不過要遵守老麻的許可噢!
看完本文后,有需要的客官大老爺,請(qǐng)自行斟酌。
若對(duì)你有幫助,歡迎點(diǎn)贊、收藏、評(píng)論,你的支持就是我的最大動(dòng)力!!!
同時(shí),阿超為大家準(zhǔn)備了豐富的學(xué)習(xí)資料,歡迎關(guān)注公眾號(hào)“超哥學(xué)編程”,即可領(lǐng)取。
本文涉及工程代碼,公眾號(hào)回復(fù):47QsLog,即可下載。
總結(jié)
以上是生活随笔為你收集整理的Qt轻量级日志库QsLog的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ES6学习笔记二arrow functi
- 下一篇: 根据xml文件找到对应的图片文件