glog Google開源日誌庫

glog爲google開源庫用於實現應用層日誌記錄,提供了基於C++ Stream流及各類幫助宏定義的日誌記錄接口,提供到控制檯、文件的日誌記錄功能; 如下以基於windows平臺下,最基本框架使用入手,分析該開源項目,示例代碼; #define GOOGLE_GLOG_DLL_DECL
  #define GLOG_NO_ABBREVIATED_SEVERITIES   #include "glog/logging.h"
  int main(int argc, char* argv[])   {     FLAGS_log_dir = "./glog_log"; google::InitGoogleLogging(argv[0]);   LOG(INFO) <<"Found "<<15<<" cookies";   google::ShutdownGoogleLogging();   return 0;   } 該基本實例代碼中,通常在靜態連接libglog_static.lib時需預先聲明的宏GOOGLE_GLOG_DLL_DECL,此外在包含logging.h 頭文件前須要先聲明宏 GLOG_NO_ABBREVIATED_SEVERITIES,因有時候用戶可能使用到windows.h頭文件並將該頭文件放置在logging.h以後卻沒有聲明WIN32_LEAN_AND_MEAN 或GLOG_NO_ABBREVIATED_SEVERITIES,此致使會與當前的glog中的宏ERROR衝突,故須要先聲明在loggging.h前聲明; google::InitGoogleLogging(argv[0]),該語句初始化日誌庫(事實上爲初始化日誌文件中的短文件名區域段); FLAGS_log_dir:設置日誌文件保存目錄(該目錄應該先存在,不然沒法保存日誌); LOG(INFO):日誌等級宏,記錄日誌信息; google::ShutdownGoogleLogging:關閉日誌庫,釋放內部資源; 以上爲整個基本操做流程,接下來咱們分別對各個內部定義、宏聲明、結構定義等進行深刻分析; config.h:   配置相關,內部主要聲明瞭google命名空間、導入和導出相關宏,該導入導出宏用在dll時,故若使用靜態連接時須要在loggging.h前聲明GOOGLE_GLOG_DLL_DECL宏; commandlineflags.h:   內部聲明瞭幾種宏(bool、int3二、string的聲明和定義專用於glog內部,分別爲DECLARE_bool、DECLARE_int3二、DECLARE_string)各宏擴展後置於命名空間中,以DECLARE_bool(name)爲例擴展後爲namespace fLB{bool FLAGS_name},定義DEFINE_bool(name, value, meaning)被擴展爲namespace fLB{bool FLAGS_##name(a);char FLAGS_no##name;}以及環境變量的獲取並轉化EnvToString、EnvToBool、EnvToInt; googleinit.h:   內部定義了類GoogleInitializer初始化器(跟蹤源碼,其做爲MyUserNameInitializer函數中獲取環境變量中當前用戶名的一個操做必要實現,以初始化g_my_user_name全局變量),此外宏REGISTER_MODULE_INITIALIZER (name, body)用以聲明glog應用進程加載時初始化全局變量,經過構造全局變量調用全局靜態函數,實如今函數入口點」main」前預先調用接口(事實上只用在utilities中); log_severity.h: 定義了幾種日誌嚴重等級LogSeverity:GLOG_INFO、GLOG_WARNING、GLOG_ERROR、GLOG_FATAL、NUM_SEVERITIES並將前四個分別用INFO、WARNING、ERROR、FATAL做爲用戶保存日誌等級使用的參數,分別爲信息、警告、錯誤、致命,此外針對DFATAL_LEVEL在不一樣的模式下使用不一樣的日誌等級,DEBUG模式下位FATAL,RELEASE模式爲ERROR;定義全局變量LogSeverityNames,分別用以標識以上幾種日誌等級字符串名稱; mutex.h: Windows下內部封裝了CRITICAL_SECTION臨界區,實現Mutex鎖機制,以及封裝自動鎖MutexLock,讀寫鎖ReaderMutexLock、WriterMutexLock;目前glog內部只是用到WriterMutexLock,(事實上ReaderMutexLock與WriterMutexLock內部實現一致); port.h: 從google-perftools中的部分拷貝,內部主要針對windows下的VC編譯器服務,主要實現了類型重聲明相關便於統一使用,如對C-run time中的文件I/O相關、文件拷貝、字符串比較、Sleep、字符串格式化輸出、系統進程、線程、localtime_r、strerror_r,基本以上均爲對已存在的接口的重命名和簡單處理便於跨平臺統一接口、調用而已; vlog_is_on.h: 提供了參數自定義的控制日誌記錄,其日誌詳細記錄相關宏、接口,主要用在VLOG和VLOG_IF和RAW_VLOG等中以觸發記錄;聲明宏VLOG_IS_ON,當前記錄標記FLAGS_v小於等於verboselevel則返回TRUE;此外SetVLOGLevel:設置指定的模塊模式的VLOG(_IS_ON)爲log_level級別;內部遍歷類型爲VModuleInfo的vmodule_list列表,經過模糊匹配查找到指定的模塊模式並設置相應級別;kLogSiteUninitialized目前只支持__GNUC__編譯器下使用;FLAGS_v默認初始值爲0,FLAGS_vmodule初始值爲」」; vmodule_lock模塊鎖、inited_vmodule(flase)是否爲初始化的模塊列表; utilities.h: 提供內部使用的實用工具函數,ARRAYSIZE獲取元素容器大小;   ProgramInvocationShortName:獲取程序log保存段名,該段名做爲log文件保存的名稱段之一(g_program_invocation_short_name);   IsGoogleLoggingInitialized:是否Glog已被初始化,內部經過判斷程序log段g_program_invocation_short_name是否爲NULL來判斷;
  is_default_thread:是否爲默認的線程,內部經過g_program_invocation_short_name是否爲NULL來判斷此外若不爲空則結合g_main_thread_id來判斷;
  CycleClock_Now:獲取當前系統時間,
  UsecToCycles:將微秒計時轉化爲Cycle計時(事實上內部未做任何處理),
  WallTime_Now:獲取當前系統時間的微秒;
  GetMainThreadPid:獲取當前主線程進程PID(g_main_thread_pid);
  PidHasChanged:判斷是否主線程進程ID是否被改變,若已改變則修改成當前主線程進程PID;
  GetTID:內部經過GetCurrentThreadId獲取當前線程ID;
  MyUserName:獲取當前用戶名;
  const_basename:獲取文件路徑的文件名;
  sync_val_compare_and_swap:判斷當前值與舊值是否相等,若相等則將當前值設置爲新值;
  CrashReason:Crash緣由結構信息,內部包含文件名、行號、信息以及crash堆棧上下文、深度;   SetCrashReason:設置crash緣由內容;
  InitGoogleLoggingUtilities:初始化glog工具函數相關,
  ShutdownGoogleLoggingUtilities:關閉glog工具函數,內部設置初始化g_program_invocation_short_name、g_main_thread_id   (事實上以上兩個接口分別被InitGoogleLogging、ShutdownGoogleLogging調用); logging.h: 基本上保存日誌記錄均會包含的頭文件,內部實現了各類可供使用的記錄方式,統一針對不一樣編譯器、平臺下的變量類型重聲明以及各類宏、流定義; GOOGLE_STRIP_LOG:全局的截斷宏,編譯器將會移除嚴重等級低於該指定數值的日誌消息;該宏應在logging.h頭文件前定義值即
#define GOOGLE_STRIP_LOG SomeValue; 定義了各類標識,大部分用來控制輸出行爲,通常狀況下可經過環境變量、命令行、以及進入log記錄輸出前可直接設置,部分標識在使用中間設置可能會不生效,需注意;這些標識值分別以下:   logtostderr:輸出log到stderr,默認值爲false;   alsologtostderr:輸出log到stderr,默認值爲false;   colorlogtostderr:彩色輸出log信息至stderr,默認值爲false;並根據不一樣的日誌等級設置爲不一樣的顏色,GLOG_INFO :默認顏色黑色,GLOG_WARNING :警告爲黃色,GLOG_ERROR 與GLOG_FATAL 爲紅色(經過SetConsoleTextAttribute設置);   stderrthreshol:設置輸出log極限,即當輸出到stderr的信息大於當前標識值時,將被寫入到stderr中;默認值爲2即包括INFO、WARNING、ERROR;   log_prefix:設置log記錄行中的前綴,默認值爲2,前綴格式爲:     [log level, GMT month, date, time, thread_id, file basename, line];   logbuflevel:設置log記錄緩衝級別,默認值爲0,當級別大於當前值則當即寫入,不然將被緩衝至緩衝區中,此外當記錄字節數達到了10^6字節也會被寫入文件;   logbufsecs:設置緩衝區記錄秒數,默認值爲30;   minloglevel:設置最小的log級別,低於該級別將不會被記錄,默認值爲0;   log_dir:log日誌記錄保存目錄,默認值爲從環境變量GOOGLE_LOG_DIR或TEST_TMPDIR中獲取;   log_link:log文件連接路徑,windows下不支持;   v:顯示全部等於小於m的VLOG消息,能夠用--vmodule來代替;   max_log_size:設置日誌記錄文件最大大小,MB爲單位,默認值爲1800,當前超過當前大小,則保存剩餘數據至文件,並建立新的文件保存其餘日誌信息;   stop_logging_if_full_disk:設置當磁盤已滿,是否繼續保存,默認值爲false;   根據用戶設置的宏GOOGLE_STRIP_LOG定義值肯定編譯時支持那些保存宏記錄級別,如:COMPACT_GOOGLE_LOG_INFO、LOG_TO_STRING_INFO;     COMPACT_GOOGLE_LOG_WARNING、LOG_TO_STRING_WARNING;     COMPACT_GOOGLE_LOG_ERROR、LOG_TO_STRING_ERROR;     COMPACT_GOOGLE_LOG_FATAL、LOG_TO_STRING_FATAL;用戶根據須要設置宏定義值;   此外也定義了google風格的LOG宏和SYSLOG宏,如:     GOOGLE_LOG_INFO、SYSLOG_INFO;     GOOGLE_LOG_WARNING、SYSLOG_WARNING;     GOOGLE_LOG_ERROR、SYSLOG_ERROR;     GOOGLE_LOG_FATAL、SYSLOG_FATAL;     GOOGLE_LOG_DFATAL、SYSLOG_DFATAL;   以上宏主要便於用戶簡單的使用LOG宏和SYSLOG宏而定義的;內部根據不一樣的級別調用不一樣的LogMessage的SendMethod;   LOG_SYSRESULT:提供錯誤碼格式化消息串並寫入日誌(事實上內部判斷是否有異常,對於有異常的將調用FormatMessageA並寫入日誌文件);   LOG、SYSLOG宏:便於用戶使用的宏相似使用方式爲LOG(INFO)、SYSLOG(ERROR)   InitGoogleLogging/ ShutdownGoogleLogging:初始化庫和關閉庫,內部主要初始化部分參數以及釋放申請的資源(實際上爲釋放log_destinations_日誌目的地對象數組和logging_directories_list日誌目錄列表);   InstallFailureFunction:安裝失敗時的函數調用(在調用LOG(FATAL)時會觸發安裝的函數調用);   LOG_TO_SINK、LOG_TO_SINK_BUT_NOT_TO_LOGFILE:保存消息信息至槽,便於將指定的消息保存到指定的槽和取出消息信息;前者會調用SendToSinkAndLog保存並輸出至log,後者只是保存消息信息,此外若參數slink爲NULL,則也不會保存直接打印輸出log;   LOG_TO_STRING:保存消息信息至string中,若爲參數爲NULL,則直接輸出打印log;   LOG_STRING:保存消息信息至vector<string>中,若爲參數爲NULL,則直接輸出打印log;   LOG_IF/SYSLOG_IF:條件log宏,內部經過條件調用LOG(severity)、SYSLOG(severity);   LOG_ASSERT/SYSLOG_ASSERT:斷言宏,內部調用條件宏(其參數FATAL);   CHECK:條件檢測宏,失敗時會中止測試,內部調用條件宏(其參數FATAL);   CheckOpString:檢測選項字符串,常做爲字符串數據容器;   GetReferenceableValue:一系列的重載版本獲取值引用的內部使用函數集;   DummyClassToDefineOperator:空類,主要用來實現重載std::ostream& operator<<(std::ostream& out,…);這樣便於用戶實現本身的類以實現宏CHECK條件檢測,但用戶應實現std::ostream& operator<<(std::ostream& out,…);   MakeCheckOpValueString:一系列重載版本以實現operator<<操做;   CheckOpMessageBuilder:消息構建器,輔助MakeCheckOpString,生成格式化的消息信息;   DEFINE_CHECK_OP_IMPL/ CHECK_OP_LOG/ CHECK_OP:主要輔助宏CHECK_XXX實現檢驗宏和調試宏DCHECK;   VLOG、DLOG:調試宏與詳細日誌宏;   接下來針對內部使用的重要結構和類分析:   LogStreamBuf:日誌流緩衝類,具備緩衝功能,繼承於std::streambuf,主要實現過濾最後的兩個」\n」字符;另外LogStreamBuf也做爲LogStream日誌流類的引用對象;   LogStream:日誌流類,繼承於std::ostream,做爲日誌數據信息輸出流,爲LogMessage日誌信息類的內部類;此外NullStream空流類也繼承於LogStream,其意義主要爲GOOGLE_STRIP_LOG宏用戶的定義值,將編譯支持空操做的流類,支持operator<<操做而已;   LogMessage:日誌信息類,基本上此類完成了大多數的日誌信息相關操做的接口,實現;許多宏(如:LOG())內部均會建立該類的對象並初始化該類,實現日誌信息保持、打印等操做;此外LogMessageFatal致命消息類和ErrnoLogMessage錯誤消息類(用在PLOG相關宏)均繼承於LogMessage;   LogMessageData:日誌消息數據類,內部主要保存錯誤碼、消息內容(至多可容納kMaxLogMessageLen(30000)字節的信息)、嚴重級別、日誌流、所在行、文件路徑名和文件名、析構時調用的send_method_、消息時間戳、信息長度等;其做爲LogMessage的引用對象;   LogDestination:日誌目的地類,主要實現日誌數據信息流向;目前在glog中做爲單例存在(事實上爲一個包含4個元素的數組)分別爲GLOG_INFO、GLOG_WARNING、GLOG_ERROR、GLOG_FATAL;內部提供多個操做的靜態成員函數;目前提供了日誌數據信息至stderr、email、logfile、sink;針對不一樣的宏使用不一樣的日誌目的對象以及不一樣的日誌數據信息流向;   Logger:日誌寫入者,主要負責維護日誌的寫入、時間戳、緩衝、格式化操做;   LogFileObject:日誌文件寫入者,負責寫入文件相關的操做,繼承於Logger;且做爲LogDestination日誌目的地類的成員對象;以輔助LogDestination操做日誌文件;   LogSink:日誌槽類,用戶可繼承自該類並實現send接口,以實現用戶的日誌信息操做方式,目前也做爲獨立存在的類; 最後再從新分析LogMessage日誌信息類: 類中重載了多個版本的構造函數,以支持日誌信息到字符串string、vector<string>容器、LogSink槽、log信息檢測,此外還有日誌統計、獲取當前數據流等; 重要的全局變量或靜態變量: kMaxLogMessageLen:最大日誌字節大小,默認值爲30000字節; log_destinations_:日誌目的地類對象數組; log_mutex:全局鎖,只容許一個時刻只能一個線程操做日誌數據信息; num_messages_:消息計數數組,分別保存當前對應嚴重級別的消息數; stop_writing:全局禁用寫操做,通常用在磁盤滿而不可寫的時候; LogSeverityNames:嚴重級別字符串名稱數組; email_logging_severity_:email的嚴重級別(99999); addresses_:email接收地址; hostname_:當前發送email的主機名; sinks_:全局log槽vector容器,在日誌目的地類對象調用中遍歷該槽容器; sink_mutex_:全局log槽鎖,保護槽資源; terminal_supports_color_:控制檯終端輸出是否支持色彩輸出; fatal_msg_lock:致命消息鎖;以保護多線程下調用LOG(FATAL)數據,主要針對類型爲LogMessageData的fatal_msg_data_exclusive和fatal_msg_data_shared這兩份致命消息數據的保護,採起的策略爲第一個線程在第一次致命消息則使用fatal_msg_data_exclusive,之後的線程則使用fatal_msg_data_shared; crash_reason:crash緣由,主要用在第一次致命錯誤時獲取crash緣由並根據是否相等與g_reason互換; fatal_msg_exclusive:致命消息獨享標識,用以切換fatal_msg_data_exclusive和fatal_msg_data_shared; fatal_time:發生致命消息時的時間戳; fatal_message:發生致命消息時的消息內容; logging_directories_list:日誌目錄列表;該日誌列表內容實際上以標識FLAGS_log_dir建立; 類圖: std::streambuf A LogStreamBuf A’ std::ostream B LogStream B’ NullStream B’’ LogStreamBuf A* LogMessage C ErrnologMessage C’ LogMessageFatal C’’ LogMessageData D LogStream B’+ Logger E LogFileObject E’ LogDestionation F Logger E* LogSink G 說明:層次關係爲繼承,帶*爲引用,帶+爲包含; 事實上,針對類圖中的關係,基本上分爲三大塊,消息處理,消息分發,消息保存; raw_logging.h: 原始日誌記錄,可以使用宏RAW_LOG、RAW_VLOG、RAW_DLOG、RAW_CHECK、RAW_DCHECK等宏,其線程安全即內部使用了句柄消息棧以保證多線程安全; RAW_LOG:宏內部經過參數嚴重級別肯定調用相應的RAW_LOG_INFO、RAW_LOG_WARNING、RAW_LOG_ERROR、RAW_LOG_FATAL宏(事實上這些紅也是根據截斷宏的值實現調用RawLog__或RawLogStub__); STRIP_LOG:截斷宏,經過該宏實現原始日誌的瘦身;   RAW_VLOG:條件宏根據截斷宏值,調用相應的宏RAW_LOG_INFO或RawLogStub__;   RawLogStub__:原始日誌樁,空操做;   RAW_CHECK:檢驗宏,內部調用RAW_LOG(FATAL,…);   RAW_DLOG/ RAW_DCHECK:調試宏(調用RAW_LOG)、調試檢驗宏(調用RAW_CHECK); 再次說明宏的運用:   RawLog__:在RAW_LOG和RAW_VLOG宏中調用的函數,原始日誌記錄的格式化等操做;   RawLog__SetLastTime:設置保存最近一次原始日誌記錄系統時間;   必要的靜態變量或全局變量:     kLogBufSize:原始日誌記錄最大長度(3000);     crashed:是否已crash;     crash_reason:crash緣由;   crash_buf:crash緩衝區(kLogBufSize大小); stl_logging.h: 支持STL標準模板庫輸出至流對象,使用實例:list<string> x; LOG(INFO)<< "data: "<<x; vector<int>v1,v2; CHECK_EQ(v1,v2); PrintSequence:模板函數,打印序列至流對象,至多打印100個元素並以空格隔開,對於剩下的元素以「…」結束; 重載了多個版本的std::ostream& operator<<(std::ostream& out,…);以支持不一樣的參數時對應的STL容器對象,該內部調用PrintSequence做爲實際的打印操做;此外聲明瞭OUTPUT_TWO_ARG_CONTAINER、OUTPUT_THREE_ARG_CONTAINER、OUTPUT_FOUR_ARG_CONTAINER宏分別用以支持std::vector、std::deque、std::list;std::set、std::multiset;std::map、std::multimap; 此外還有一個特化版本std::ostream& operator<<(std::ostream&out,const std::pair<First,Second>&p)以支持std::pair; 大多數宏均會建立LogMessage對象實例,並根據嚴重級別調用相應的構造函數和初始化接口,此外還有數據處理方式最後因該實例爲局部對象將被析構,在析構時調用相應的輸出函數進行處理;部分宏只是做爲測試判斷條件;另外在InitGoogleLogging前也能夠執行一些基本的測試、日誌記錄; 打印日誌格式: 級別第一個字符月日 時:分:秒.微秒 線程ID 文件名稱:所在行] 信息 日誌文件名保存格式: 可執行應用程序名.計算機名.用戶名.log.級別.年月日-時分秒.進程ID 日誌文件內容保存格式: 文件頭示例: Log file created at: 2015/12/23 09:38:12 Running on machine: haomiao Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg 文件信息內容:同打印日誌格式; 基本上爲每一個級別生成一個log文件,當達到了最大文件大小時將從新生成新的對應級別的log文件以保存日誌; 項目總結: 總體上GLog開源日誌庫並不複雜,其提供了許多流操做和宏助手,支持向控制檯輸出、文件輸出、email發送輸出、Sink(用戶自定義輸出控制操做),實際上用戶能夠利用Sink自定義實現socket網絡輸出或是其餘的方式;提供多種嚴重級別的日誌輸出和靈活的log標識控制設置;此外還有條件和偶然、調試、檢驗、詳細日誌記錄宏、原始日誌記錄,支持STL容器數據至流;  此外內部靜態變量一部分用以保存數據信息另外一些用以做爲數據交換,減小內存申請開銷和碎片化的可能、合理的控制輸出信息至文件;不過不支持從配置文件進行控制log行爲以及網絡輸出、不支持unicode,也不支持自定義log文件名和任意log文件保存生成,相對Log4plus等開源日誌庫,就顯得不夠那麼靈活;