zoukankan      html  css  js  c++  java
  • 初次使用glog

    一、安装配置

    1、简单介绍

      google 出的一个C++轻量级日志库,支持下面功能:

    复制代码
    ◆ 參数设置,以命令行參数的方式设置标志參数来控制日志记录行为;
    ◆ 严重性分级,依据日志严重性分级记录日志;
    ◆ 可有条件地记录日志信息。
    ◆ 条件中止程序。丰富的条件判定宏,可预设程序终止条件。
    ◆ 异常信号处理。程序异常情况。可自己定义异常处理过程。
    ◆ 支持debug功能;
    ◆ 自己定义日志信息;
    ◆ 线程安全日志记录方式。
    ◆ 系统级日志记录;
    ◆ google perror风格日志信息。
    ◆ 精简日志字符串信息
    复制代码

     

    2、安装

      下载地址:https://code.google.com/p/google-glog/downloads/list (假设不能訪问则点击这里下载)

      解压安装:

    tar zxvf glog-0.3.3.tar.gz && cd glog-0.3.3 && ./configure && make

      头文件目录为 /src/glog 。链接库为 .libs/libglog.{a,so}

      帮助文档为 doc/glog.html 或直接訪问下面 URL: http://google-glog.googlecode.com/svn/trunk/doc/glog.html

     

    3、简单 Demo 

    #include <glog/logging.h>
    
    int main(int argc,char* argv[])
    {
        LOG(INFO) << "Hello,GLOG!";
    }

      链接时,须要 -lglog ,也可能会须要 -lunwind -lpthread (有一次遇到的,记不起来了,一般不须要)

      运行时,可使用 ./glogdemo 将日志输出到 stderr,可使用 valgrind 检測。未发现内存泄漏。

     

     

    二、用法

    1、错误级别

      GLOG 有四个错误级别,枚举例如以下:

    复制代码
    enum SeverityLevel
    {
      google::INFO = 0,
      google::WARNING = 1,
      google::ERROR = 2,
      google::FATAL = 3,
    };
    复制代码

     

    2、Flags 设置:

      在上面的简单 Demo 中,仅仅能将日志输出到 stderr ,假设想将日志重定向到文件,须要:

    google::InitGoogleLogging(argv[0]);
    /*
    GLOG代码
    */
    google::ShutdownGoogleLogging();

      则默认执行会将日志输出到 /tmp 文件夹下(格式为 "<program name>.<hostname>.<user name>.log.<severity level>.<date>.<time>.<pid>")。也能够使用设置暂时环境变量的方式(给命令行參数加上 GLOG_ 前缀),如 GLOG_logtostderr=1 ./your_application 将日志输出到 stderr。

      另外,glog 使用了 gflags 库,假设已经安装好了 gflags 库(./configure && make && make install 然后再配置编译GLOG库)还能够通过 ./your_application --logtostderr=1 来指定执行參数。但须要在使用时加上例如以下代码:(详见 http://www.cnblogs.com/tianyajuanke/p/3467572.html

    google::ParseCommandLineFlags(&argc, &argv, true);
    /*
    GLOG代码
    */
    google::ShutDownCommandLineFlags();

      但此方法会使 valgrind 检測有内存泄漏(截止 valgrind 3.9.0 依旧如此)。这是因为使用 gflags 库造成的。(即使不使用此方法,但仅仅要在编译 glog 库之前安装好了 gflags 库,就会使 libglog.so 有内存泄漏,介意者可进入 gflags 文件夹 make uninstall 之后,再对 glog 进行 ./configure && make )。

      经常使用的执行參数例如以下:

    复制代码
    logtostderr (bool, default=false)    //是否将全部日志输出到 stderr,而非文件
    alsologtostderr(bool,default=false)  //是否同一时候将日志输出到文件和stderr
    minloglevel (int, default=google::INFO)  //限制输出到 stderr 的部分信息,包含此错误级别和更高错误级别的日志信息 
    stderrthreshold (int, default=google::ERROR)  //除了将日志输出到文件之外,还将此错误级别和更高错误级别的日志同一时候输出到 stderr,这个仅仅能使用 -stderrthreshold=1 或代码中设置,而不能使用环境变量的形式。(这个參数能够替代上面两个參数)
    colorlogtostderr(bool, default=false)  //将输出到 stderr 上的错误日志显示对应的颜色 
    v (int, default=0)  //仅仅记录此错误级别和更高错误级别的 VLOG 日志信息
    log_dir (string, default="")  //设置日志文件输出文件夹 
    v (int, default=0)  //仅仅有当自己定义日志(VLOG)级别值小于此值时,才进行输出,默觉得0(注:自己定义日志的优先级与GLOG内置日志优级相反,值越小优先级越高。!。)。

    vmodule (string, default="")  //分文件(不包含文件名称后缀,支持通配符)设置自己定义日志的可输出级别,如:GLOG_vmodule=server=2,client=3 表示文件名称为server.* 的仅仅输出小于 2 的日志,文件名称为 client.* 的仅仅输出小于 3 的日志。

    假设同一时候使用 GLOG_v 选项,将覆盖 GLOG_v 选项。

    复制代码

      很多其它执行參数见 logging.cc 中的 DEFINE_ 开头的定义。

      执行參数设置的第三种方法是,能够在代码里通过加上 FLAGS_ 前缀来设置,如:

    FLAGS_stderrthreshold=google::INFO;
    FLAGS_colorlogtostderr=true;

     

    3、条件输出:

    LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";   //当条件满足时输出日志
    LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";  //google::COUNTER 记录该语句被运行次数。从1開始。在第一次运行输出日志之后,每隔 10 次再输出一次日志信息
    LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER << "th big cookie";  //上述两者的结合,只是要注意,是先每隔 10 次去推断条件是否满足,假设滞则输出日志;而不是当满足某条件的情况下,每隔 10 次输出一次日志信息。

    LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";  //当此语句运行的前 20 次都输出日志。然后不再输出

      演示代码例如以下:

    复制代码
    #include <glog/logging.h>
    
    int main(int argc,char* argv[])
    {
        google::InitGoogleLogging(argv[0]);
        FLAGS_stderrthreshold=google::INFO;
        FLAGS_colorlogtostderr=true;
        for(int i = 1; i <= 100;i++)
        {
            LOG_IF(INFO,i==100)<<"LOG_IF(INFO,i==100)  google::COUNTER="<<google::COUNTER<<"  i="<<i;
            LOG_EVERY_N(INFO,10)<<"LOG_EVERY_N(INFO,10)  google::COUNTER="<<google::COUNTER<<"  i="<<i;
            LOG_IF_EVERY_N(WARNING,(i>50),10)<<"LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER="<<google::COUNTER<<"  i="<<i;
            LOG_FIRST_N(ERROR,5)<<"LOG_FIRST_N(INFO,5)  google::COUNTER="<<google::COUNTER<<"  i="<<i;
        }
        google::ShutdownGoogleLogging();
    }
    复制代码

       输出结果例如以下:

    复制代码
    I1210 13:23:20.059790  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=1  i=1
    E1210 13:23:20.060670  6322 test01.cpp:13] LOG_FIRST_N(INFO,5)  google::COUNTER=1  i=1
    E1210 13:23:20.061272  6322 test01.cpp:13] LOG_FIRST_N(INFO,5)  google::COUNTER=2  i=2
    E1210 13:23:20.061337  6322 test01.cpp:13] LOG_FIRST_N(INFO,5)  google::COUNTER=3  i=3
    E1210 13:23:20.061393  6322 test01.cpp:13] LOG_FIRST_N(INFO,5)  google::COUNTER=4  i=4
    E1210 13:23:20.061450  6322 test01.cpp:13] LOG_FIRST_N(INFO,5)  google::COUNTER=5  i=5
    I1210 13:23:20.061506  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=11  i=11
    I1210 13:23:20.061529  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=21  i=21
    I1210 13:23:20.061553  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=31  i=31
    I1210 13:23:20.061575  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=41  i=41
    I1210 13:23:20.061599  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=51  i=51
    W1210 13:23:20.061621  6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER=51  i=51
    I1210 13:23:20.061667  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=61  i=61
    W1210 13:23:20.061691  6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER=61  i=61
    I1210 13:23:20.061738  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=71  i=71
    W1210 13:23:20.061761  6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER=71  i=71
    I1210 13:23:20.061807  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=81  i=81
    W1210 13:23:20.061831  6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER=81  i=81
    I1210 13:23:20.061877  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=91  i=91
    W1210 13:23:20.061902  6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER=91  i=91
    I1210 13:23:20.062140  6322 test01.cpp:10] LOG_IF(INFO,i==100)  google::COUNTER=0  i=100
    复制代码

     

    4、日志类型

    复制代码
    LOG    //内置日志
    VLOG    //自己定义日志
    DLOG    //DEBUG模式可输出的日志
    DVLOG    //DEBUG模式可输出的自己定义日志
    SYSLOG    //系统日志。同一时候通过 syslog() 函数写入到 /var/log/message 文件
    PLOG    //perror风格日志,设置errno状态并输出到日志中
    RAW_LOG        //线程安全的日志,须要#include <glog/raw_logging.h>
    复制代码

      前六种的日志用法全然同样(包含条件日志输出),而 RAW_LOG 用法比較特殊,且不支持条件日志输出。另外不接受  colorlogtostderr 的颜色设置。自己定义日志也不接受 colorlogtostderr 的颜色设置,另外其日志严重级别也为自己定义数字。且与默认日志严重级别相反。数字越小严重级别越高。如:

    复制代码
     1 #include <glog/logging.h>
     2 #include <glog/raw_logging.h>
     3 
     4 class GLogHelper
     5 {
     6 public:
     7     GLogHelper(char* program)
     8     {
     9         google::InitGoogleLogging(program);
    10         FLAGS_stderrthreshold=google::INFO;
    11         FLAGS_colorlogtostderr=true;
    12         FLAGS_v = 3;
    13     }
    14     ~GLogHelper()
    15     {
    16         google::ShutdownGoogleLogging();
    17     }
    18 };
    19 
    20 int main(int argc,char* argv[])
    21 {
    22     GLogHelper gh(argv[0]);
    23     LOG(ERROR)<<"LOG";
    24     VLOG(3)<<"VLOG";
    25     DLOG(ERROR)<<"DLOG";
    26     DVLOG(3)<<"DVLOG";
    27     SYSLOG(ERROR)<<"SYSLOG";
    28     PLOG(ERROR)<<"PLOG";
    29     RAW_LOG(ERROR,"RAW_LOG");
    30 }
    复制代码

      输出结果例如以下:

    复制代码
    E1211 03:04:22.718116 13083 test01.cpp:23] LOG
    I1211 03:04:22.719225 13083 test01.cpp:24] VLOG
    E1211 03:04:22.719297 13083 test01.cpp:25] DLOG
    I1211 03:04:22.719365 13083 test01.cpp:26] DVLOG
    E1211 03:04:22.719391 13083 test01.cpp:27] SYSLOG
    E1211 03:04:22.719650 13083 test01.cpp:28] PLOG: Success [0]
    E1211 03:04:22.719650 13083 test01.cpp:29] RAW: RAW_LOG
    复制代码

     

    5、CHECK 宏

      当通过该宏指定的条件不成立的时候,程序会中止,而且记录相应的日志信息。功能类似于ASSERT,差别是 CHECK 宏不受 NDEBUG 约束,在 release 版中相同有效。

      眼下这个功能我临时不须要,就不实践了,简介下,如:

    CHECK(port == 80)<<"HTTP port 80 is not exit.";

      其他还有:CHECK_EQ、 CHECK_NOTNULL、CHECK_STREQ、CHECK_DOUBLE_EQ 等推断数字、空指针。字符串。浮点数的 CHECK 宏。须要使用时能够搜索 glog/logging.h 文件里以 CHECK_ 开头的宏定义。

      此外。类似的。还有 PCHECK 和 RAW_CHECK 版本号,用法类似。仅仅是 RAW_CHECK 用法特殊。形如 RAW_CHECK(i<3,"RAW_CHECK");

     

    6、core dumped 

      通过 google::InstallFailureSignalHandler(); 就可以注冊。将 core dumped 信息输出到 stderr,如:

    复制代码
    #include <glog/logging.h>
    #include <string>
    #include <fstream>
    
    //将信息输出到单独的文件和 LOG(ERROR)
    void SignalHandle(const char* data, int size)
    {
        std::ofstream fs("glog_dump.log",std::ios::app);
        std::string str = std::string(data,size);
        fs<<str;
        fs.close();
        LOG(ERROR)<<str;
    }
    
    class GLogHelper
    {
    public:
        GLogHelper(char* program)
        {
            google::InitGoogleLogging(program);
            FLAGS_colorlogtostderr=true;
            google::InstallFailureSignalHandler();
            //默认捕捉 SIGSEGV 信号信息输出会输出到 stderr,能够通过以下的方法自己定义输出方式:
            google::InstallFailureWriter(&SignalHandle);
        }
        ~GLogHelper()
        {
            google::ShutdownGoogleLogging();
        }
    };
    
    void fun()
    {
        int* pi = new int;
        delete pi;
        pi = 0;
        int j = *pi;
    }
    
    int main(int argc,char* argv[])
    {
        GLogHelper gh(argv[0]);
        fun();
    }
    复制代码

      输出的错误报告例如以下,可定位错误于 fun() 函数内:

    复制代码

    E1211 06:07:04.787719 15444 test01.cpp:11] *** Aborted at 1386742024 (unix time) try "date -d @1386742024" if you are using GNU date ***
    E1211 06:07:04.789120 15444 test01.cpp:11] PC: @ 0x401227 fun()
    E1211 06:07:04.789481 15444 test01.cpp:11] *** SIGSEGV (@0x0) received by PID 15444 (TID 0x7f03ce478720) from PID 0; stack trace: ***
    E1211 06:07:04.791168 15444 test01.cpp:11] @ 0x7f03cd505960 (unknown)
    E1211 06:07:04.791453 15444 test01.cpp:11] @ 0x401227 fun()
    E1211 06:07:04.791712 15444 test01.cpp:11] @ 0x40125b main
    E1211 06:07:04.792908 15444 test01.cpp:11] @ 0x7f03cd4f1cdd __libc_start_main
    E1211 06:07:04.793227 15444 test01.cpp:11] @ 0x400fc9 (unknown)
    段错误 (core dumped)

    复制代码

      假设不使用  google::InstallFailureSignalHandler();  则仅仅会输出 “段错误” 三个字,难于排查。

     

    7、其他经常使用配置

    google::SetLogDestination(google::ERROR,"log/prefix_");   //第一个參数为日志级别。第二个參数表示输出文件夹及日志文件名称前缀。
    google::SetStderrLogging(google::INFO);   //输出到标准输出的时候大于 INFO 级别的都输出;等同于 FLAGS_stderrthreshold=google::INFO;
    FLAGS_logbufsecs =0;  //实时输出日志
    FLAGS_max_log_size =100;  //最大日志大小(MB)
    #define GOOGLE_STRIP_LOG 3    // 小于此级别的日志语句将在编译时清除。以减小编译后的文件大小,必须放在 #include 前面才有效。

     

    8、日志文件说明

      假设可运行文件名称为 "test",则将日志输出到文件后。还会生成 test.ERROR,test.WARNING,test.INFO 三个链接文件。分别链接到相应级别的日志文件。假设日志输出超过 FLAGS_max_log_size 设置的大小,则会分为多个文件存储。链接文件就会指向当中最新的相应级别的日志文件。

    所以当日志文件较多时,查看链接文件来查看最新日志挺方便的。

     

    三、有用封装

      GLogHelper.h 例如以下:

    复制代码
    #include <glog/logging.h>
    #include <glog/raw_logging.h>
    
    //将信息输出到单独的文件和 LOG(ERROR)
    void SignalHandle(const char* data, int size);
    
    class GLogHelper
    {
    public:
        //GLOG配置:
        GLogHelper(char* program);
        //GLOG内存清理:
        ~GLogHelper();
    };
    复制代码

      GlogHelper.cpp 例如以下:

    复制代码
    #include <stdlib.h>
    #include "GLogHelper.h"
    
    //配置输出日志的文件夹:
    #define LOGDIR "log"
    #define MKDIR "mkdir -p "LOGDIR
    
    //将信息输出到单独的文件和 LOG(ERROR)
    void SignalHandle(const char* data, int size)
    {
        std::string str = std::string(data,size);
        /*
        std::ofstream fs("glog_dump.log",std::ios::app);
        fs<<str;
        fs.close();
        */
        LOG(ERROR)<<str;
        //也能够直接在这里发送邮件或短信通知。只是这种方法是被回调多次的(每次回调仅仅输出一行错误信息,所以如上面的记录到文件,也须要>以追加模式方可)。所以这里发邮件或短信不是非常适合。只是倒是能够调用一个 SHELL 或 PYTHON 脚本,而此脚本会先 sleep 3秒左右,然后将错
    误信息通过邮件或短信发送出去,这样就不须要监控脚本定时高频率运行,浪费效率了。
    }
    
    //GLOG配置:
    GLogHelper::GLogHelper(char* program)
    {
        system(MKDIR);
        google::InitGoogleLogging(program);
    
        google::SetStderrLogging(google::INFO); //设置级别高于 google::INFO 的日志同一时候输出到屏幕
        FLAGS_colorlogtostderr=true;    //设置输出到屏幕的日志显示对应颜色
        //google::SetLogDestination(google::ERROR,"log/error_");    //设置 google::ERROR 级别的日志存储路径和文件名称前缀
        google::SetLogDestination(google::INFO,LOGDIR"/INFO_"); //设置 google::INFO 级别的日志存储路径和文件名称前缀
        google::SetLogDestination(google::WARNING,LOGDIR"/WARNING_");   //设置 google::WARNING 级别的日志存储路径和文件名称前缀
        google::SetLogDestination(google::ERROR,LOGDIR"/ERROR_");   //设置 google::ERROR 级别的日志存储路径和文件名称前缀
        FLAGS_logbufsecs =0;        //缓冲日志输出,默觉得30秒。此处改为马上输出
        FLAGS_max_log_size =100;  //最大日志大小为 100MB
        FLAGS_stop_logging_if_full_disk = true;     //当磁盘被写满时,停止日志输出
        google::SetLogFilenameExtension("91_");     //设置文件名称扩展。如平台?或其他须要区分的信息
        google::InstallFailureSignalHandler();      //捕捉 core dumped
        google::InstallFailureWriter(&SignalHandle);    //默认捕捉 SIGSEGV 信号信息输出会输出到 stderr,能够通过以下的方法自己定义输出>方式:
    }
    //GLOG内存清理:
    GLogHelper::~GLogHelper()
    {
        google::ShutdownGoogleLogging();
    }
    复制代码

      測试文件 test.cpp 例如以下:

    复制代码
    #include "GLogHelper.h"
    
    int main(int argc,char* argv[])
    {
        //要使用 GLOG ,仅仅须要在 main 函数開始处加入这句就可以
        GLogHelper gh(argv[0]);
    
        LOG(INFO)<<"INFO";
        LOG(ERROR)<<"ERROR";
    }
    复制代码

     

    三、自己定义改动

    參考:http://www.cppfans.org/1566.html

    1、添加日志按天输出

    glog默认是依据进程ID是否改变和文件大小是否超过预定值来确定是否须要新建日志文件的。此处能够參考glog源代码 logging.cc 文件里的 void LogFileObject::Write 函数中

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

     

    我们仅仅须要在此处加一个日期推断就能够了,PidHasChanged() 定义于 utilities.cc 文件里,能够加一个类似的 DayHasChanged() 函数(注意 utilities.h 文件里加上函数声明):

    复制代码
    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;
    }
    复制代码

     

    再改动 void LogFileObject::Write 函数中的推断条件就可以:

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

     

    (注:參考 http://www.cppfans.org/1566.html)

    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    Linux中磁盘mbr分区——实践篇
    Linux中磁盘分区——理论篇
    Linux中常用压缩打包工具
    自动化(脚本)安装httpd服务
    CentOS6.8环境下搭建yum网络仓库
    CentOS下rpm命令详解
    CentOS下yum命令详解
    CentOS7.3环境下源码安装httpd
    js对url进行编码和解码(三种方式区别)
    前端paging分页,前端设置每页多少条和当前页面的索引,传给后端,数据显示出来
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4690114.html
Copyright © 2011-2022 走看看