标记选项
  • logtostderr 置位1 将log打印到stderr
  • stderrthreshold 将log 输出到stderr的最低门槛
  • log_dir 设置log文件的存储路径
  • minloglevel 最低输出log的级别,低于这个级别的log,即使在代码中有也不会输出出来
关于minloglevel

它的运用一般在于调试DEBUG,当我们的项目处于DEBUG时,可以打印很多调试log,把log级别定位为 INFO级别,当调试好后把minloglevel设置高于 INFO 级别后,程序关于调试的log就不会被打印出来了,这样十分便利。
虽然低于minloglevel级别的log不会打印出来,但是它们的相应级别文件也会被创建出来,并且低级别的日志文件也会包含高级log的信息,比如WANING的日志文件就会包含WANING及其以上级别的log。

初始化&善后
  • InitGoogleLogging(“程序名”) //如果不调初始化默认输出到stderr 即使后面设置了 dir
  • ShutdownGoogleLogging
glog 如何实现线程安全

我们知道iostream 是线程安全的,但是使用iostream很难实现线程安全,比如:

std::cerr << "hello" << "world";

其实都是调用了operator << 函数,虽然单个 operator << 是线程安全的,但是连着就不一定了,在多线程环境下可能因为调度的原因,就会出现日志错行线程不安全的事件。

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

#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage(  __FILE__, __LINE__, google::GLOG_WARNING)

#define COMPACT_GOOGLE_LOG_INFO google::LogMessage(__FILE__, __LINE__)

glog 使用以上方式实现线程安全,每次LOG(INFO)之类的日志输出,都会生成一个临时对象,因为这个对象是在栈上生成所以该对象是线程安全的。生成LogMessage 这个对象后,它的成员stream()函数会返回相应一个对象,这个对象继承了 ostream,所以就实现了 通过<<实现日志输出。

继续stream(),stream接受完用户的输入后保存到其内部,然后LogMessage临时对象生命周期到期,进行析构,析构了调用了Flush进行数据落地。

数据落地这里,首先glog 会构造不同级别的几个用于日志落地的全局对象。不同的log级别获取不同 日志落地的对象进行落地,如果是INFO级别就不会立即落地,而是缓存到这个静态对象的缓冲区中。

逻辑流

Flush-> 获取全局用于落地的对象 LogDestination -> LogToAllLogfiles -> write 落地

访问全局对象的时候加了锁,所以glog多线程下访问全局锁性能不是很高。
Flush 中会对minloglevel做判断,也就是即使当前日志级别低于minloglevel,它前面的构造这些开销也是需要的只是不会竞争锁进行数据落地。