[转] GLOG 使用


0 下载及编译

从网络上搜索即可得到下载链接。然后编译(本人编译的是静态链接库libglog_static),编译过程中可能会报出如下错误。

(0)”min ” 不是std成员;

#include <algorithm>;

(1)函数snprintf已经被定义

可注释,或者将所有snprintf替换为其它名称如“glog_snprintf”(原因在于VS2015中已经集成C11,而C11中已经将该函数列入了标准的库函数);

(2)warning va_copy 宏重定义

修改文件port.h line117为

#undef va_copy

#defineva_copy(dst, src) (dst) = (src)

(3)一些编译中的错误可以尝试在port.h或者config.h这种系统配置文件中寻找解决办法;

1 集成测试

编译成功后会在glog-0.3.3/Debug下生成libglog_static.lib文件,供后续集成。同时还需要将glog-0.3.3\src\windows\glog下的所有文件拷贝到待测试工程中,如下图所示。

然后修改工程配置属性。如下所述。

(0)VC++目录,修改“包含目录”和“库目录”,分别添加GLOG头文件所在目录和生成的静态库拷贝所在目录;如下图所示。

(1)在“C/C++ 预处理器”->“预处理定义”中添加_CONSOLE宏和_STL_DEBUG宏和GOOGLE_GLOG_DLL_DECL=宏;如下图所示

(2)“链接器”->“常规”中“附加库目录”添加静态库所在目录,如下图所示。

(3)“链接器”->“输入”中“附加依赖项”添加libglog_static.lib;如下图所示。

(4)最后正常编写测试使用程序即可。

3 说明(转)

(0)严重性分级

Glog可根据指定的严重性等级,通过LOG宏来选择性记录日志。默认的等级是按INFO,WARNING,ERROR,ERROR和FATAL四级。另外,FATAL等级的日志会在纪录以后终止程序的运行。

stderrthreshold参数,即用来控制输出至stderr的阈值设置,严重性级别在该值以上的除了写入日志以外,还会输出至stderr。默认值2,对应ERROR。各严重性等级分别为INFO-0,WARNING-1,ERROR-2和FATAL-3。如果是代码中,则是通过修改FLAG_stderrthreshold完成,而如果是命令行参数则需要添加前缀GLOG完成。

       miloglevel参数,严重级级别在此阈值之上的才会被记录。

(1)VLOG

LOG是由google定义的日志等级信息,而vlog则是提供一个用户接口,由用户自定义日志等级。如下所示。

#define VLOG(verboselevel)LOG_IF(INFO, VLOG_IS_ON(verboselevel))

#define VLOG_IS_ON(verboselevel)(FLAGS_v>= (verboselevel))

       由上可知,需要设置FLAGS_v控制阈值输出,而且它也是作为INFO级别输出。

v (int, default= 0 )对于使用“VLOG(m)”,m为int型,表达式进行输出日志信息,只有m值小于FLGAS_v的值时,才能输出。

(2)log_dir

       FLAGS_log_dir,日志信息记录路径,默认为空。

如果没有指定信息输出到stderr则信息保存在“/tmp/<program name>.<hostname>.<username>.log.<severity level>.<date>.<time>.<pid>”文件中。

(3)有条件地记录日志信息

       LOG_IF(INFO,num > 10) << “num larger than 10”。表示num大于10,才会输出日志。

       LOG_EVERY_N(INFO,10)<<”aaa”。表示在该语句执行的第1次,11次,21次执行的时候,才会记录日志信息。

       LOG_IF_EVERY_N(INFO,condition, times),当condition满足且被执行times之后才会执行。即上述两者的结合。

       LOG_FIRST_N(INFO,20),语句执行20次以后记录的日志信息。

(4)有条件地终止程序

       CHECK,CHECK_EQ,当条件不满足时,会直接终止退出。

(5)debug日志

       GLOG考虑到了在调试过程中产生的日志,所以提供宏只在debug模式生效。宏有:DLOG,DLOG_IF,DLOG_EVERY_N,用法和意义与GLOG普通日志相同。

(6)去除日志信息

日志信息的字符串会占用比较大的内存空间,另外还带来隐私泄露的问题。glog提供了GOOGLE_STRIP_LOG宏在编译时候去除日志的字符串信息。

(7)日志风格

Glog提供了与LOG*和CHECK宏作用等价的PLOG()、PLOG_IF() 和PCHECK()宏,不同的是,后者在记录日志信息的时候,会将errno的状态及其描述附加到日志描述中。

如:PCHECK(write(1, NULL, 2) >= 0)<< "Write NULL failed";

当条件不成立时,会输出日志信息:

F0825 185142 test.cc:22] Check failed:write(1, NULL, 2) >= 0 Write NULL failed: Bad address [14]

4 GLOG调用追踪

glog一般使用VLOG(num)或者LOG(severity)两种形式的宏进行输出。就以LOG(severity)为例进行说明,VLOG(num)系列应该类似了。比如要输出一条日志信息,如 

  LOG(ERROR) << "helloworld"

LOG宏的定义是:

#define LOG(severity)COMPACT_GOOGLE_LOG_ ## severity.stream()

可以看到它将根据具体的名字展开为另一个宏,因为上面选择的输出级别是ERROR,所以展开的名称为COMPACT_GOOGLE_LOG_ERROR。

继续跟进这个宏的定义:

#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage(\

__FILE__, __LINE__, google::GLOG_ERROR)

可以看到这个宏的作用其实就是创建了一个名为LogMessage的类,构造函数的输入参数包括了:文件名,行号,日志级别。继续跟进LogMessage的构造函数:

   LogMessage::LogMessage(const char* file, int line, LogSeverity severity)

   : allocated_(NULL){

Init(file, line, severity,&LogMessage::SendToLog);

   }

这一次,多了一个参数,名为SendToLog的类成员函数指针。这里需要说明的是,其实这个函数指针参数的目的是进行日志输出的操作,但是是可以配置的,因为LogMessage还有另外重载的构造函数其中有这个参数的,只是这里说明的是最简单的情况,所以就考虑了这个函数指针默认为SendToLog的情况,从名字可以猜测到,该函数的作用是向磁盘进行日志输出操作,另外glog中还可以向标准输出进行输出,如果有必要,应该还可以通过网络对某个地址端口进行输出–这些情况我都没有进一步跟进了,只想说明该函数指针的作用是向不同的介质输出日志,而使用函数指针作为参数就是为了让这个行为可以配置。

继续往下走,看看LogMessage::Init函数做的事情。这里不贴代码了,有兴趣的可以自己跟进看看。简单来说做的事情是:初始化日志输入的流缓冲区,初始化该日志的时间,格式,找到日志打印的文件名等。

好了,至此,一个完整的LogMessage就创建完毕。可以看到,在glog中,任何的一条日志信息,最终都会对应到一个新创建的LogMessage对象。

上面的日志输出流程,其实还没有完,因为还要进行流输入操作呢,就是输入“helloworld”字符串。没错,退回头看看LOG宏的定义。

#define LOG(severity)COMPACT_GOOGLE_LOG_ ## severity.stream()

如果说,前面的COMPACT_GOOGLE_LOG_ ## severity创建了一个LogMessage类对象,那么其实这个宏最终的结果是返回这个LogMessage类对象的成员stream(),在提到LogMessage::Init函数的时候就提到过,该函数初始化了流输入缓冲区。来看LogMessage类中该流输入类的定义:

#ifdef _MSC_VER

# pragma warning(disable: 4275)

#endif

  class GOOGLE_GLOG_DLL_DECL LogStream :public std::ostream {

#ifdef _MSC_VER

# pragma warning(default:4275)

#endif

  public:

   LogStream(char *buf, int len, int ctr)

     : std::ostream(NULL),

     streambuf_(buf, len),

     ctr_(ctr),

     self_(this){

     rdbuf(&streambuf_);

   }

   int ctr()const { return ctr_;}

   void set_ctr(int ctr){ ctr_ = ctr;}

   LogStream* self()const { return self_;}

   // Legacy std::streambuf methods.

   size_t pcount()const { return streambuf_.pcount();}

   char* pbase()const { return streambuf_.pbase();}

   char* str()const { return pbase();}

  private:

   base_logging::LogStreamBuf streambuf_;

   int ctr_; //Counter hack (for the LOG_EVERY_X() macro)

   LogStream *self_; //Consistency check hack

 };

其实很简单,从std::ostrstream中继承过来,构造函数中有一个缓冲区就好了。在LogMessage::Init类中,定义该缓冲区的大小为:

data_->buf_= new char[kMaxLogMessageLen +1]

其中

    const size_t LogMessage::kMaxLogMessageLen =30000;

这里可以看到glog限制的一条日志长度大小为30000 byte。

好了,到此为止,流输入也有了,尽管往里面写数据就好。那么什么时候进行输出呢?glog采用的是在这个创建的临时LogMessage对象(说它是”临时对象”是因为它是匿名的,因此不会保存,创建了就会被释放)被释放的时候,在析构函数中做输出操作:

  LogMessage::~LogMessage(){

   Flush();

   delete allocated_;

  }

Flush函数不详细分析了,主要做的事情就是将日志和之前得到的日期等进行格式化,最后调用注册的输出日志用的函数指针进行输出操作。到此为止,一条glog日志就输出完成了。

再回头看看,实际上这里应该还有一些东西是需要全局使用的,比如有多条日志同时向一个文件进行输出的时候,需要对文件进行加锁,还比如要更新一些统计的数据,如每个级别的日志都有多少条了。这些在glog中都是全局变量:

static Mutex log_mutex;

// Number of messages sent at eachseverity. Under log_mutex.

int64LogMessage::num_messages_[NUM_SEVERITIES] = {0, 0, 0, 0};

当然,这里的num_messages_数组准确的说是LogMessage的静态成员变量,但是大体理解为全局变量也不为错,因为这个数据全局都只有一份了。

5 常用API

0)void google::InitGoogleLogging(const char* argv0)

初始化glog库,参数是第一个命令行参数即程序名。

1)void google::ShutdownGoogleLogging()

关闭glog库。

3)void google::FlushLogFiles(LoSeveritymin_severity)

    [Thread - safe]指定级别以上的所有日志消息都立即写入到日志文件中。

4)void google::FlushLogFilesUnsafe(LogSeverity min_severity)

    非线程安全的输出指定级别以上的日志消息,用于灾难性程序问题时输出必要的日志消息。

5)void google::SetLogDestination(LogSeverity severity, const char* basefilename)

    [Thread - safe]设置指定级别的日志输出的日志文件,如果basefilename为""则表示该级别日志不输出。

6)void google::SetLogSymlink(LogSeverity severity, const char* symlinkbasename)

    [Thread - safe]设置置顶级别的日志文件的软连接,symlikbasename为空表示不设置软连接。如果不调用该函数,系统默认连接名称是程序名。

7)void google::AddLogSink(LogSink *destination)

   void google::RemoveLogSink(LogSink *destination)

   [Thread - safe]添加和删除日志输出渠道。

8)void google::SetLogFilenameExtension(const char* filename_extension)

   [Thread - safe]为所有日志文件添加文件扩展名,特别用于SetLogDestination()设置的日志文件。通常做法是将监听的端口号作为日志文件扩展名。

9)void google::SetStderrLogging(LogSeverity min_severity)

   [Thread - safe]确定除了输出到日志文件同时还输出到STDERR的日志最小级别。

10)void google::LogToStderr()

   [Thread - safe]设置只只将日志输出到STDERR而不输出到日志文件。

11)void google::SetEmailLogging(LogSeverity min_severity, const char* address)

    [Thread - safe]设置发送邮件的日志最小级别。

12)bool google::SendEmail(const char *dest, const char *subject, const char *body)

    [Thread - safe]发送邮件。

13)const std::vector& google::GetLoggingDirectories()

    获取日志输出目录集合。

14)void google::InstallFailureSignalHandler()

    信号处理函数,处理的主要信号有SIGSEGV / SIGILL / SIGFPE / SIGBRT / SIGBUS/SIGTERM

15)void google::InstallFailureWriter(void(*writer)(const char *data, int size))

    设置系统崩溃时的输出函数,data数据不一定是以'\0'结尾。

16)void google::InstallFailureFunction(void(*fail_func)())

    设置LOG(FATAL)在输出日志消息后调用的函。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值