7.Glog 輕量級日誌庫
來自專欄松子の日常
1、簡介
Google Glog是Google的一個開源庫,用於實現應用級別的logging。 它提供了一系列類似於C++流風格的logging API,以及一些預定義的宏。它有點類似於C裡面的assert,但是比它具備更豐富的輸出信息以及使用靈活性。glog屬於輕量級日誌庫, 如果有不能滿足的功能就轉用 log4cplus,功能很全面,不過稍複雜些。
github開源地址: https://github.com/google/glog
2、編譯安裝
在Google的Glog項目主頁上下載相關的源碼,並編譯安裝。
日誌文件名稱默認格式:<program name>.<hostname>.<user name>.log.<severity level>.<date>.<time>.<pid>
3.1 基本使用方法
#include <iostream>#include <glog/logging.h>int main(int argc, char** argv) { FLAGS_alsologtostderr = 1; google::InitGoogleLogging(argv[0]); LOG(INFO) << "I am INFO!"; LOG(WARNING) << "I am WARNING!"; LOG(ERROR) << "I am ERROR!"; LOG(FATAL) << "I am FATAL!"; return 0;}
打開http:// test.INFO文件和test.ERROR文件,可以看到如下內容:
// test.INFO文件的內容Log file created at: 2017/03/27 11:35:32Running on machine: baina-game02Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msgI0327 11:35:32.576002 4849 glogtest.cc:9] I am INFO!W0327 11:35:32.576388 4849 glogtest.cc:10] I am WARNING!E0327 11:35:32.576573 4849 glogtest.cc:11] I am ERROR!F0327 11:35:32.576731 4849 glogtest.cc:12] I am FATAL!// test.ERROR文件的內容Log file created at: 2017/03/27 11:35:32Running on machine: baina-game02Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msgE0327 11:35:32.576573 4849 glogtest.cc:11] I am ERROR!F0327 11:35:32.576731 4849 glogtest.cc:12] I am FATAL!
可以說明:
info文件包含 所有等級的信息, error文件只包含了ERROR以及FATAL的信息;等級比較靠前(比較低級)的log類型,會包含其後面的所有log信息,而不會包含其前面的log信息。
glog的主要輸出方式就是上面兩種,一種是向屏幕終端輸出log信息(stderr設備),另一種將log信息寫入了磁碟文件。FLAGS_log_dir 日誌輸出目錄FLAGS_v 自定義VLOG(m)時,m值小於此處設置值的語句才有輸出FLAGS_max_log_size 每個日誌文件最大大小(MB級別)FLAGS_minloglevel 輸出日誌的最小級別,即高於等於該級別的日誌都將輸出。
3.2 使用標誌位
在標誌位前面加上FLAGS_字元串,即可以設置相應的標識,使用 VLOG_ 可以獨立於默認的日誌級別,用戶自己定義自己的日誌級別。例如:
#include <iostream>#include <glog/logging.h>int main(int argc, char** argv) {FLAGS_logtostderr = 1;google::InitGoogleLogging(argv[0]);FLAGS_v = 2;VLOG(0) << " i am 0";VLOG(1) << " i am 1";VLOG(2) << " i am 2";VLOG(3) << " i am 3";return 0;}
只有等級小於等於2的log才會顯示出來(或者被文件記錄)。
其他的log標識符的用法和上面的類似,都是在標誌位前面添加FLAGS_限定符,從而來設置相應的標識。
3.3 使用條件日誌
有時候需要在滿足一定條件下,才進行log操作,因此glog提供了如下了宏來滿足實際需求。
* LOG_IF(INFO, Condition expression) :只有當條件表達式成立時,才會輸出log信息。* LOG_EVERY_N(INFO, interval):當這條log語句被執行了1次,(1+interval)次,(1 + 2 * interval)次…才會輸出和記錄log信息。* LOG_IF_EVERY_N(INFO, Condition, interval):只有當滿足條件表達式時,才按照interval間隔來輸出和記錄log信息。* LOG_FIRST(INFO, nums):記錄前面nums次執行的log信息。
3.3 其他設置
其他設置可以參考 這個blog:http://www.yeolar.com/note/2014/12/20/glog/
4、glog修改部分功能修改
以下是我修改的部分:
<1>. 增加文件按天區分
glog是根據進程ID來區分文件的,如果你重新啟動了程序,則log文件的名字就會變,這樣似乎不太滿足我們的需求,而且應該要求可以每天生成文件,方便我們整理和分析log,其實也有辦法,在源碼添加我們需要的一個按天滾文件的函數就可以了。
在http://utilities.cc中增加函數如下:(此文件在glog工程源碼下)( 因為 PidHasChanged()在這個文件里)
static int32 g_main_day = 0;bool DayHasChanged(){time_t raw_time;struct tm* tm_info;time(&raw_time);tm_info = localtime(&raw_time);if (tm_info->tm_mday != g_main_day){g_main_day = tm_info->tm_mday;return true;}return false;}在logging.cc的LogFileObject::Write函數中將if (static_cast<int>(file_length_ >> 20) >= MaxLogSize() ||PidHasChanged()) {
不要忘了,包含頭文件(如果沒有包含的話)
#include logging.cc
<2>.一個分級一個文件
glog默認有四種log級別,高級別的log中會包含低級別的log,這個我也是不需要的,我希望每一個分級一個文件。
我增加了一個宏來控制這個開關,以免影響到原來的功能。
在glog/src/windows/glog/logging.h (我在windows的路徑)
DECLARE_bool(servitysinglelog);
然後修改 http://logging.cc中的LogDestination::LogToAllLogfiles為如下
inline void LogDestination::LogToAllLogfiles(LogSeverity severity,time_t timestamp,const char* message,size_t len) {if ( FLAGS_logtostderr ) { // global flag: never log to fileColoredWriteToStderr(severity, message, len);} else { if (FLAGS_servitysinglelog) { LogDestination::MaybeLogToLogfile(severity, timestamp, message, len); } else { for (int i = severity; i >= 0; --i) LogDestination::MaybeLogToLogfile(i, timestamp, message, len); }}}
然後用 .pro 工程問價你或者 .sln工程文件去編譯,編譯完成以後,就可以使用了
然後在自己的封裝介面的 Init函數中調用:
void CLog::initialize(){
//此函數已經被重構 yjs //判斷默認路徑是否存在 QDir dir; if(!dir.exists(m_Path.c_str())) { if(!dir.mkdir(m_Path.c_str())) { m_Be_Initialize = false; return; } } //判斷當前日誌文件夾的大小,如果超過最大日誌空間,則刪除所有以往的日誌 //因為glog暫未提供日誌清理功能,所以在此進行刪除操作 quint64 curLogByte; curLogByte = dirFileSize(QString::fromStdString(m_Path)); if(curLogByte > (m_Max_Size - 1) * 1024 * 1024) { removefilesindir(QString::fromStdString(m_Path)); } //返回持久應用程序數據所在的目錄位置 QString sProgram = QApplication::applicationName(); //glog 初始化 google::InitGoogleLogging(sProgram.toStdString().c_str()); FLAGS_logtostderr = false; // 是否將所有日誌輸出到stderr,而非文件. FLAGS_log_dir = m_Path.c_str(); //設置日誌路徑 FLAGS_max_log_size = m_Max_Size; //設置日誌最大大小 FLAGS_stop_logging_if_full_disk = true; //磁碟滿後是否停寫 //google::SetEmailLogging(0,"1061819014@qq.com"); m_Be_Initialize = true;#ifdef DEBUG_MODE google::SetStderrLogging(google::GLOG_WARNING); //設置級別高於 google::WARNING 的日誌同時輸出到屏幕#else google::SetStderrLogging(google::GLOG_FATAL);//設置級別高於 google::FATAL 的日誌同時輸出到屏幕#endif FLAGS_servitysinglelog = true;// 用來按照等級區分log文件 string fatal = "./Log_Files/log_fatal_"; string erro = "./Log_Files/log_error_"; string warning = "./Log_Files/log_warning_"; string info = "./Log_Files/log_info_"; google::SetLogDestination(google::GLOG_FATAL, fatal.data()); // 設置 google::FATAL 級別的日誌存儲路徑和文件名前綴 google::SetLogDestination(google::GLOG_ERROR,erro.data() ); //設置 google::ERROR 級別的日誌存儲路徑和文件名前綴 google::SetLogDestination(google::GLOG_WARNING,warning.data() ); //設置 google::WARNING 級別的日誌存儲路徑和文件名前綴 google::SetLogDestination(google::GLOG_INFO,info.data()); //設置 google::INFO 級別的日誌存儲路徑和文件名前綴 google::SetLogFilenameExtension("Tme_"); //設置文件名擴展,此處科自由添加自己需要的擴展名 FLAGS_logbufsecs = 0; //緩衝日誌輸出,默認為30秒,此處改為立即輸出}
最後可以在 在http://logging.cc的LogMessage::Init函數中修改 log的輸出排版格式,原來的log格式大致是這樣的 I1234 02/11 12:20:50.123456 xxx.cpp 12] 你的log內容,是 級別的首字母 線程ID 月/日 時分秒微秒 文件名 行號],
我將他改成了 [ 級別名 線程ID 年/月/日 時分秒 文件名 行號]
以上代碼均已經測試(環境Qt Creator4.6.2,MSVC_2015,32bit, )
推薦閱讀: