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等开源日志库,就显得不够那么灵活;

猜你喜欢

转载自www.cnblogs.com/haomiao/p/11647340.html