Post

开源项目--Glog

Glog的使用,以及一些本人定制过程

开源项目--Glog

简述 Glog

Glog 是 google 的开源日志系统,我自己接触的第一个日志库就是 Glog,习惯了,对于我一直以来的工作,我的应用程度上也没有什么缺点,反而有些我觉得很方便的地方,Glog 的特性官方的描述我就不粘贴了,百度一大把,下面会结合一点实际场景说明我觉好用的地方

  • 最简单的启用google::InitGoogleLogging("LogName");
  • 输出语句也很简单,自动补回车,自行加回车也不会输出一个空行,下面两句输出结果一致
1
2
   LOG(INFO) << "abc";
   LOG(INFO) << "abc\n";
  • 输出内容不需要调整的情况下,基本满足 DEBUG 需求,如带有文件名和行数:
    等级+日期 时间 PID 文件:行数
    I0514 15:52:26.102143 96944 [common.cpp:59] 1a 1d 65 94 1a e2 f3 31
  • 输出文件也方便,默认按照 PID 新建文件,携带新建时间,尤其方便的是会建立软链接到最新创建的日志,查看日志只需要查看软链接,免去了判断哪个文件才是当前最新的烦恼
  • 代码量不多(我没有对比过其他日志库的源码),对应不同场景,可以尝试修改源码适配不同工程,如本人修改了文件的命名格式,以及新建日志文件的条件增加按天新建功能(则 pid 或者日期改变都将新建一个日志文件)

Glog 使用示例

1
2
3
4
5
6
7
8
9
10
11
#include <glog/logging.h>
int main(){
    google::InitGoogleLogging("LogName");
    google::SetLogDestination(google::INFO, "/var/logs/LogName-");
    google::SetLogDestination(google::WARNING, "var/logs/LogName-");
    google::SetLogDestination(google::ERROR, "/var/logs/LogName-");
    FLAGS_logbufsecs = 0; //缓冲日志输出,默认为30秒,此处改为立即输出
    FLAGS_stop_logging_if_full_disk = true; //当磁盘被写满时,停止日志输出
    FLAGS_minloglevel = 0;//INFO=0,WARNING=1,ERROR=2
    LOG(INFO) << "Build time : " << __DATE__ << " - " << __TIME__;//输出编译时间
}

大多数设置有默认值,而更多设置可以直接查看头文件:

  • 搜索带”set”关键字的方法,如:SetLogDestination
  • 搜索”DECLARE_“,可以找到一系列 GFLAG 变量,如最小输出等级的定义:
    DECLARE_int32(minloglevel);
    那么我们可以用以下语句来修改(也可以运行程序时带参数指定):
    FLAGS_minloglevel = 0;
  • 另外查看头文件也能发现很多其他应用,如有一系列结合断言的 LOG 宏(如 LOG_ASSERT)等等,本人并未使用,比多做描述

根据需求定制自己的 Glog

例如,本人工作上希望日志能按天区分每一个文件,这样避免一个文件太大,以及查错方便等等

首先我们可以简单浏览以下源码,新建日志文件主要是每次 Write 时判断以下条件
src\logging.cc : LogFileObject::Write

1
2
if (static_cast<int>(file_length_ >> 20) >= MaxLogSize() ||
  PidHasChanged() )

src\utilities.cc : PidHasChanged

1
2
3
4
5
6
7
8
9
static int32 g_main_thread_pid = getpid();
bool PidHasChanged() {
  int32 pid = getpid();
  if (g_main_thread_pid == pid) {
    return false;
  }
  g_main_thread_pid = pid;
  return true;
}

可见,我们只需要仿照着写一个函数,加入到条件判断,即可符合我们的需求

src\logging.cc : LogFileObject::Write

1
2
if (static_cast<int>(file_length_ >> 20) >= MaxLogSize() ||
  PidHasChanged() || DayHasChanged())

src\utilities.cc : DayHasChanged

1
2
3
4
5
6
7
8
9
10
11
12
13
static int32 g_main_day = 0;
bool DayHasChanged()
{
  time_t raw_time;
  struct tm tm_info={0};
  time(&raw_time);
  localtime_r(&raw_time,&tm_info);
  if (tm_info.tm_mday == g_main_day){
    return false;
  }
  g_main_day = tm_info.tm_mday;
  return true;
}

再有,我当时觉得文件名时间去到了时分秒没必要,反而因为文件名太长在显示上觉得不舒服

同样,不难发现还是在 src\logging.cc : LogFileObject::Write 方法中,新建文件时构造了文件名的格式,主要涉及以下变量
ostringstream time_pid_stream; 找到了这个变量,接下来的几行代码,就可以随意修改成更适合当前工程上使用的版本了

1
2
3
4
5
6
7
8
9
10
11
12
ostringstream time_pid_stream;
time_pid_stream.fill('0');
time_pid_stream << 1900+tm_time.tm_year
                << setw(2) << 1+tm_time.tm_mon
                << setw(2) << tm_time.tm_mday
                // << '-'
                // << setw(2) << tm_time.tm_hour
                // << setw(2) << tm_time.tm_min
                // << setw(2) << tm_time.tm_sec
                << '-'
                << GetMainThreadPid()
                << ".log";
This post is licensed under CC BY 4.0 by the author.