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、int32、string的聲明和定義專用於glog內部,分別為DECLARE_bool、DECLARE_int32、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等開源日志庫,就顯得不夠那么靈活;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM