glog使用与功能修改

在写代码的过程中,打log肯定是少不了的,毕竟不能总靠调试来发现问题。log库的选用就很纠结了,成熟的log库非常多,log4cpp、log4cxx、poco.log、boost.log、glog等等,以前我用过log4cxx,觉得配置巨麻烦,一大段看着好纠结,不过用起来很舒服。这次我决定使用比较轻量的glog。

glog来自于google,google提供给大家不少好东西,所以功能和质量上都是可以保证的。而且很轻量,用起来很灵活。

glog项目地址:https://code.google.com/p/google-glog/

glog的文档:英文 http://google-glog.googlecode.com/svn/trunk/doc/glog.html

glog入门代码就不多写了,在文档中也有,网上也是一大片,大家请自行搜索。他提供了vs工程和configure文件,编译方法见文档。

 

我修改的部分

1.增加文件按天区分

glog是根据进程ID来区分文件的,如果你重新启动了程序,则log文件的名字就会变,这样似乎不太满足我的需求,我还要求它可以每天生成文件,方便我整理和分析log,其实也有办法,自己增加一个按天滚文件的函数就可以了。

在utilities.cc中增加函数如下,(因为PidHasChanged()在这个文件里)

static int32 g_main_day = 0;
bool DayHasChanged()
{
    time_t raw_time;
    struct tm* tm_info;

    time(&raw_time);
    tm_info = localtime(&raw_time);

    if (tm_info->tm_mday != g_main_day)
    {
        g_main_day = tm_info->tm_mday;
        return true;
    }

    return false;
}

在logging.cc的LogFileObject::Write函数中将

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

改成

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

这样就会按照天来输出log了。

 

2.glog默认有四种log级别,高级别的log中会包含低级别的log,这个我也是不需要的,我希望每一个分级一个文件。

我增加了一个宏来控制这个开关,以免影响到原来的功能。

在glog/src/windows/glog/logging.h (我在windows上用的,linux的请自己查找)

DECLARE_bool(servitysinglelog);

然后修改 logging.cc中的LogDestination::LogToAllLogfiles为如下

inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
 time_t timestamp,
 const char* message,
 size_t len) {
     if ( FLAGS_logtostderr ) { // global flag: never log to file
         ColoredWriteToStderr(severity, message, len);
     } else {
         if (FLAGS_servitysinglelog)
         {
             LogDestination::MaybeLogToLogfile(severity, timestamp, message, len);
         }
         else
         {
             for (int i = severity; i >= 0; --i)
                 LogDestination::MaybeLogToLogfile(i, timestamp, message, len);
         }
    }
 }

我整体的初始化函数如下:

bool Init()
{
    google::InitGoogleLogging("");
    #ifdef DEBUG_MODE
        google::SetStderrLogging(google::GLOG_INFO); //设置级别高于 google::INFO 的日志同时输出到屏幕
    #else
        google::SetStderrLogging(google::GLOG_FATAL);//设置级别高于 google::FATAL 的日志同时输出到屏幕
    #endif
    FLAGS_colorlogtostderr = true; //设置输出到屏幕的日志显示相应颜色
    FLAGS_servitysinglelog = true;// 用来按照等级区分log文件
    google::SetLogDestination(google::GLOG_FATAL, "./log/log_fatal_"); // 设置 google::FATAL 级别的日志存储路径和文件名前缀
    google::SetLogDestination(google::GLOG_ERROR, "./log/log_error_"); //设置 google::ERROR 级别的日志存储路径和文件名前缀
    google::SetLogDestination(google::GLOG_WARNING, "./log/log_warning_"); //设置 google::WARNING 级别的日志存储路径和文件名前缀
    google::SetLogDestination(google::GLOG_INFO, "./log/log_info_"); //设置 google::INFO 级别的日志存储路径和文件名前缀
    FLAGS_logbufsecs = 0; //缓冲日志输出,默认为30秒,此处改为立即输出
    FLAGS_max_log_size = 100; //最大日志大小为 100MB
    FLAGS_stop_logging_if_full_disk = true; //当磁盘被写满时,停止日志输出
    //google::SetLogFilenameExtension("91_"); //设置文件名扩展,如平台?或其它需要区分的信息
    //google::InstallFailureSignalHandler(); //捕捉 core dumped (linux)
    //google::InstallFailureWriter(&Log); //默认捕捉 SIGSEGV 信号信息输出会输出到 stderr (linux)

    return true;
}

这些改动之后我的功能基本就满足了,修改下log输出的格式,原来的log格式大致是这样的 I1234 02/11 12:20:50.123456 xxx.cpp 12] 你的log内容,是 级别的首字母 线程ID 月/日 时分秒微秒 文件名 行号],我将它修改成为  [级别名 线程ID 年/月/日 时分秒毫秒 文件名 行号],在logging.cc的LogMessage::Init函数中修改

再加上一个log(severity_level, format, …)函数就可以打印log了。


NickYang

NickYang

无知一码农,现居住于上海,从事游戏服务器端开发
http://www.cppfans.org


Comments

  1. 您好。
      请问easylogging++有没有办法配置同一个日志支持多文件输出。
      例如:级别只控制DEBUG,INFO,WARNING,ERROR,高于INFO时同时输出到alarm和history目录下,文件名和日志内容相同。低于INFO时,只输出到history目录。
    LOG(DEBUG)<<“debug只输出到history目录日志文件”
      LOG(INFO)<<"INFO只输出到history目录日志文件"
    LOG(WARNING)<<“warning只输出到history目录日志文件”
      LOG(ERROR)<<"error只输出到history目录日志文件"
    或者其他日志库有没有支持该功能的?谢谢

    1. 这个可以通过创建多个conf来做,不过我没试过。你可以试试看,可能要修改一点点源码。你说的这种功能应该是所有log库都没有的,这属于业务需求,还有一个spdlog可以看看

      1. 谢谢指导。
        在boost.log里面我测试过,可以同时创建单个log source源,多个sink输出(输出到file/console等目标),独立且配置式管理。
        貌似其他日志库里面没有这个概念。我去分析下源码,再次感谢!

      2. 另外请教下,我下载glog源码,找不到google-glog.sln呢。
        如果您哪里有这个文件,能否转发我一份呢,谢谢!

        目前我在项目的服务器端(windows)采用的还是boost.log,并没有进行二次封装,客户端(linux)还是之前自己写的简易(按照指定格式分模块输出到file/console),水平不限,比较粗。
        现在想找一种合适的开源库进行二次封装,需要大概是:
        1、主要方法log_init() 加载配置及相应的初始化工作 log_uninit() 卸载 
        2、输出格式c++流式<<,而不是类printf
          MYLOG(LEVEL)<<"输出级别日志信息"。
          MYLOG_IF(LEVEL,condition)<<"满足condition条件输出日志信息"
        3、历史日志按日志级别输出控制,输出到history目录
        4、报警/错误日志强制输出,输出到alarm目录
        5、3和4是同一份日志源,且各级别输出到同一份日志文件,若支持core_dump功能,再独立输出dump目录的日志文件

        请问您有没有什么好的建议,多谢指导!

      3. 今天早上我下载了glog源码,自己建了工程按照文档已经编译过了
        我看了下源码,这个里面也有多sink的概念,我计划先测试glog是否能满足我的业务需求
        如果可以,服务端(windows)和客户端(linux)简单二次封装后使用。
        打扰了,多谢!

  2. 这个glog感觉不成熟啊,似乎只支持windows平台。
    其他日志库 log4系列,不是因为使用unicode崩溃,就是使用LGPL,GPL授权。
    有没有功能强大,简单易用,授权宽松的日志库推荐啊?

      1. 某次轮转之后,g_main_day 被更新,其他级别的LogFileObject就不会触发轮转了。bug的表现就是只会有某个级别的日志发生轮转

        1. 打点输出日志看下吧,这个值只有DayHasChanged会用到,而且是静态的,应该是没问题的,我这边用了半年,倒是没发现这个问题。如果你调试出来这个问题,麻烦留言说一下,谢谢

          1. 该反馈是对的,现象是只有一个级别(INFO)的日志会检测到DayHasChanged()。 g_main_day得改成数组g_main_day[NUM_SEVERITIES],调用DayHasChanged()时传入参数DayHasChanged(severity_)

发表评论

电子邮件地址不会被公开。 必填项已用*标注