由Google Log库glog循环打印到一行引发的C++知识点思考

原创 2016年08月29日 19:34:24

Google Log库glog

glog是Google的一个C++日志库,原文见http://google-glog.googlecode.com/svn/trunk/doc/glog.html。其使用方法类似于:

LOG(INFO) << "Found " << num_cookies << " cookies";

使用相当方便!输出会类似于:

xxxxxxxx] Found 123456 cookies

前面的前缀我偷懒了,实际会包含输出log的时间、文件,以及行号!

我遇到的问题

上面的一行代码可以输出一行日志,但是我有时候需要遍历一个数组然后把数组里的东西输出到一行里。

比如我期望输出一个学生的所有课程id:

xxxxxxxxxx] Classes for student 10086: 135 137 134

假设我这么写代码(请原谅我用了c++11,因为语法比较简洁啦!):

vector<int> classIds = findClasses(studentId);
LOG(INFO) << "Classes for student " << studentId << ": ";
for(int classId: classIds) {
    LOG(INFO) << classId << " ";
}

实际输出会是介个样纸:

xxxxxxxxxx]Classes for student 10086:
xxxxxxxxxx]135
xxxxxxxxxx]137
xxxxxxxxxx]134

啊,每个LOG(INFO)都会输出一个前缀,还有换行!肿么达到我期望的输出呢!

我的解决方案

先撇出我经过一番搜寻得到的解决方案:

{
    auto&& log = COMPACT_GOOGLE_LOG_INFO;

    vector<int> classIds = findClasses(studentId);
    log.stream() << "Classes for student " << studentId << ": ";
    for(int classId: classIds) {
        log.stream() << classId << " ";
    }
}

这是神马东东!?

这个要解释起来还不是那么好解释,因为问题太多了,涉及的知识点也太多了!

关于Google log库的问题:

  1. LOG(INFO) 到底是神马东东?为什么它可以像cout一样使用?
  2. 为什么LOG(INFO)自动输出了换行?我明明没有让他输出换行来的。

关于我的解决方案的问题:

  1. COMPACT_GOOGLE_LOG_INFO是神马东东?
  2. auto 是神马东东?
  3. auto 后面的 && 是神马东东?
  4. auto 后面的 & 又是神马东东?
  5. for(int classId: classIds) 为啥跟学过的c++语法不一样啊?
  6. 为什么要在最外面加一层花括号?

关于Google log的问题

LOG(INFO) 到底是神马东东?为什么它可以像cout一样使用?

经过一番搜寻,最终还是通过查看源码得到了答案:

LOG(INFO)做了两件事情:
1. 创建了google::LogMessage类的一个临时对象
2. 调用临时对象的stream()方法,返回std::ostream的对象

看到这里有些盆友应该已经知道了!我再来做进一步解释:

cout 其实是一个全局变量,它也是std::ostream类的对象。

所以它们的使用方法一样,都可以用<<来输出东东!

为什么LOG(INFO)自动输出了换行?

根据上面的分析,有两种猜测,而且似乎只有这两种可能的解释:

  1. LogMessage的临时对象析构时,会输出换行
  2. LogMessage里存的std::ostream析构时,会输出换行

如果第2种猜测是对的,那代码写起来就简单啦!

{
    std::ostream& logStream = LOG(INFO);
    vector<int> classIds = findClasses(studentId);
    logStream << "Classes for student " << studentId << ": ";
    for(int classId: classIds) {
        logStream << classId << " ";
    }
}

我们用一个引用保存了std::ostream对象,让它暂时不要被析构,等我们用完再让它析构。

那么输出如何呢?现实很骨感。。。什么都没输出TAT。

于是只剩下第1种猜测了!
那么,我们只要自己构造一个LogMessage对象,并在使用完后让它自动析构!

{
    google::LogMessage log(__FILE__, __LINE__);
    vector<int> classIds = findClasses(studentId);
    log.stream() << "Classes for student " << studentId << ": ";
    for(int classId: classIds) {
        log.stream() << classId << " ";
    }
}

结果很满意!!!!跟预想的完全一致!

然后,我高高兴兴地在很多很多地方都用上了这个方案!

程序效率突然降低,老板说暂时不要打Log了,看看效率如何,如果没有影响再恢复Log

我的天啊!
我的天啊!

这么多地方都用了,肿么办!!!总不能一个一个注释掉,然后又删掉注释吧!太麻烦了!以后要是有类似的要求,我就要去屎了!

为了和命运斗争,我决定再仔细研究一下Google log的源码!下载了glog源码,并进行./configure之后,我们就可以做做简单的分析啦!

搜索 #define LOG( 就能找到这个LOG的定义啦!其实它是个宏定义!

具体的定义如下:

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

好像。。。。看不懂啊!!! ##是几个意思?

再仔细一搜,发现宏定义里,## 用于拼接标识符,也就是说,你调用了LOG(INFO) 的地方,COMPACT_GOOGLE_LOG_ ## severity 都会被展开成COMPACT_GOOGLE_LOG_INFO 。哦!!看出来是怎么拼接的了吗?也就是说最后,整个表达式会被展开成:COMPACT_GOOGLE_LOG_INFO.stream()

那么,这个COMPACT_GOOGLE_LOG_INFO 又是神马东东咧!?

我们搜索一下它,立马就出来啦!

#if GOOGLE_STRIP_LOG == 0
#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \
      __FILE__, __LINE__)
#define LOG_TO_STRING_INFO(message) google::LogMessage( \
      __FILE__, __LINE__, google::GLOG_INFO, message)
#else
#define COMPACT_GOOGLE_LOG_INFO google::NullStream()
#define LOG_TO_STRING_INFO(message) google::NullStream()
#endif

原来如此哦!这个COMPACT_GOOGLE_LOG_INFO 会根据GOOGLE_STRIP_LOG的不同而不同。如果这个GOOGLE_STRIP_LOG不是0,那么COMPACT_GOOGLE_LOG_INFO就会被定义成google::NullStream哦!根据语义,它什么都不会输出!如果是0,那就被定义成google::LogMessage(__FILE__, __LINE)!这样就会正常输出log!

所以解决方案来啦!我们不要自己构造google::LogMessage,而是使用COMPACT_GOOGLE_LOG_INFO来进行构造!

可是它构造的东西我们怎么用变量存起来呢!?毕竟

// 这是不行的啦!LogMessage里把复制构造函数屏蔽了,我们不能进行对象的复制
auto a = COMPACT_GOOGLE_LOG_INFO;
// 这也是不行的啦!引用必需指向一个有效的对象!当然不能引用一个立马就要消失的对象啦!
auto& b = COMPACT_GOOGLE_LOG_INFO;
// 这是可行的哦(仅c++11和c++14)!那么,这是什么东东呢?
auto&& c = COMPACT_GOOGLE_LOG_INFO;

&&是右值引用操作符,专门用来解决接受一个临时对象的问题!关于右值引用,我就先不多说太多啦!

总之c是一个新的对象,而不是临时对象的别名或者克隆人!它偷偷地把临时对象里的所有内容挪为己用,注意!不是复制!而是直接拿过来了!就好像shell里不是cp而是mv一样!然后临时对象里就就可以悄悄地离开,不带走一片云彩~

google-glog:开源c++轻量级日志库

Google glog is a library that implements application-level logging. This library provides logging AP...
  • u010443572
  • u010443572
  • 2015年02月18日 13:33
  • 1840

GOOGLE GLOG 日志使用心得

c++项目中想尝试些新的东西,google glog日志中间件功能挺全面,测试的效率也比较OK, 测试数据未作记录。 google glog官方网站  https://code.google.com/...
  • willability
  • willability
  • 2013年07月19日 15:12
  • 10553

Glog剖析之DLOG

首先来看看Glog文档上是如何介绍DLOG的: Debug Mode Support Special "debug mode" logging macros only have an effe...
  • zx_Cplusplus
  • zx_Cplusplus
  • 2014年03月18日 20:07
  • 2309

glog日志打印

在写代码的过程中,有些是时候只能用打日志的方法来看问题。比较常用的日志库也很多,log4cpp,boost.log,pcoc.log,glog。最近用了下glog日志库,比较轻量级,功能也比较齐全。G...
  • WEI_YANG_JU
  • WEI_YANG_JU
  • 2017年10月10日 15:13
  • 184

【神经网络与深度学习】【C/C++】C++日志操作开源函数库之Google-glog

今天想给我的C++项目找一个开源的日志类,用于记录系统日志,结果浪费了半个下午的时间。从网上搜索相关资料,找到以下几个备选方案: 1、log4cplus  下载地址:http://sourcef...
  • LG1259156776
  • LG1259156776
  • 2016年10月03日 20:32
  • 1097

几种C/C++ log库的比较

尝试了几种C/C++ log库,简单记录如下: Google glog 使用最方便,功能完善,基本上能想到的功能都有了。配合gflag一起使用,功能更强大。 log4c 现已不再有人维护了。不...
  • yasi_xi
  • yasi_xi
  • 2014年01月16日 13:57
  • 12219

GoogleLog(GLog)源码分析

本文分析和介绍了GLog实现的原理。
  • breaksoftware
  • breaksoftware
  • 2016年05月10日 19:18
  • 6156

glog简单分析

项目组一直使用google的glog开源库进行日志输出, 花时间研究了一下, 做些分享. 这里就不分析它的使用方式了, 还是比较简单的, 几乎可以不用配置就直接使用了.另外, 如果真的需要配置的...
  • langb2014
  • langb2014
  • 2016年04月10日 23:04
  • 2699

google glog 简单使用小结

glog 是 google 的一个 c++ 开源日志系统,轻巧灵活,入门简单,而且功能也比较完善。...
  • jcjc918
  • jcjc918
  • 2016年07月03日 23:37
  • 9819

如何使用google的日志库(glog)

简介 glog是google的一个应用级的日志库
  • u014161864
  • u014161864
  • 2014年05月05日 16:30
  • 2690
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:由Google Log库glog循环打印到一行引发的C++知识点思考
举报原因:
原因补充:

(最多只允许输入30个字)