glog使用

一.簡單 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 目錄下(格式爲 “...log...

  另外,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();
}

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 的顏色設置,另外其日誌嚴重級別也爲自定義數字,且與默認日誌嚴重級別相反,數字越小嚴重級別越高。如:
 

#include <glog/logging.h>
#include <glog/raw_logging.h>

class GLogHelper
{
public:
    GLogHelper(char* program)
    {
        google::InitGoogleLogging(program);
        FLAGS_stderrthreshold=google::INFO;
        FLAGS_colorlogtostderr=true;
        FLAGS_v = 3;
    }
    ~GLogHelper()
    {
        google::ShutdownGoogleLogging();
    }
};

int main(int argc,char* argv[])
{
    GLogHelper gh(argv[0]);
    LOG(ERROR)<<"LOG";
    VLOG(3)<<"VLOG";
    DLOG(ERROR)<<"DLOG";
    DVLOG(3)<<"DVLOG";
    SYSLOG(ERROR)<<"SYSLOG";
    PLOG(ERROR)<<"PLOG";
    RAW_LOG(ERROR,"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 設置的大小,則會分爲多個文件存儲,鏈接文件就會指向其中最新的對應級別的日誌文件。所以當日志文件較多時,查看鏈接文件來查看最新日誌挺方便的。

三、實用封裝

#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

原文鏈接:
http://www.cnblogs.com/tianyajuanke/archive/2013/02/22/2921850.html

發佈了74 篇原創文章 · 獲贊 56 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章