Glog官方文檔翻譯

Glog使用文檔

參考鏈接:http://www.yeolar.com/note/2014/12/20/glog/

來自Google的Glog是一個應用程序的日誌庫。它提供基於C++風格的流的日誌API,以及各種輔助的宏。打印日誌只需以流的形式傳給 LOG(level) ,例如:

#include <glog/logging.h>

int main(int argc, char* argv[]) {
  // Initialize Google's logging library.
  google::InitGoogleLogging(argv[0]);

  // ...
  LOG(INFO) << "Found " << num_cookies << " cookies";
}

Glog定義了一系列的宏來簡化記錄日誌的工作。你可以:按級別打印日誌,通過命令行控制日誌行爲,按條件打印日誌,不滿足條件時終止程序,引入自定義的日誌級別,等等。

目錄

日誌級別

可以指定下面這些級別(按嚴重性遞增排序): INFO, WARNING, ERROR, and FATAL 。打印 FATAL 消息會在打印完成後終止程序。和其他日誌庫類似,級別更高的日誌會在同級別和所有低級別的日誌文件中打印。

DFATAL 級別會在調試模式(沒有定義 NDEBUG 宏)中打印 FATAL 日誌,但是會自動降級爲 ERROR 級別,而不終止程序。

如果不指定的話,Glog輸出到文件 /tmp/...log..-

設置flag

一些flag會影響Glog的輸出行爲。如果安裝了GFlags庫,編譯時會默認使用它,這樣就可以在命令行傳遞flag(別忘了調用 ParseCommandLineFlags 初始化)。比如你想打開 --logtostderr flag,可以這麼用:

./your_application --logtostderr=1

如果沒有安裝GFlags,那可以通過環境變量來設置,在flag名前面加上前綴 GLOG_ 。比如:

GLOG_logtostderr=1 ./your_application

常用的flag有:

  • logtostderrbool ,默認爲 false

    日誌輸出到stderr,不輸出到日誌文件。

  • colorlogtostderrbool ,默認爲 false

    輸出彩色日誌到stderr。

  • stderrthresholdint ,默認爲2,即 ERROR

    將大於等於該級別的日誌同時輸出到stderr。日誌級別 INFO, WARNING, ERROR, FATAL 的值分別爲0、1、2、3。

  • minloglevelint ,默認爲0,即 INFO

    打印大於等於該級別的日誌。日誌級別的值同上。

  • log_dirstring ,默認爲 ""

    指定輸出日誌文件的目錄。

  • vint ,默認爲0)

    顯示所有 VLOG(m) 的日誌, m 小於等於該flag的值。會被 --vmodule 覆蓋。

  • vmodulestring ,默認爲 ""

    每個模塊的詳細日誌的級別。參數爲逗號分隔的一組 <module name>=<log level><module name> 支持通配(即gfs*代表所有gfs開頭的名字),匹配不包含擴展名的文件名(忽略 .cc/.h./-inl.h 等)。 <log level> 會覆蓋 --v 指定的值。

logging.cc 中還定義了其他一些flag。grep一下 DEFINE_ 可以看到全部。

也可以通過修改 FLAGS_* 全局變量來改變flag的值。

LOG(INFO) << "file";
// Most flags work immediately after updating values.
FLAGS_logtostderr = 1;
LOG(INFO) << "stderr";
FLAGS_logtostderr = 0;
// This won't change the log destination. If you want to set this
// value, you should do this before google::InitGoogleLogging .
FLAGS_log_dir = "/some/log/directory";
LOG(INFO) << "the same file";

按條件/次數打印日誌

有時你可能只想在滿足一定條件的時候打印日誌。可以使用下面的宏來按條件打印日誌:

LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";

上面的日誌只有在滿足 num_cookies > 10 時纔會打印。

另一種情況,如果代碼被執行多次,可能只想對其中某幾次打印日誌。

LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";

上面的代碼會在執行的第1、11、21、…次時打印日誌。 google::COUNTER 用來表示是哪一次執行。

可以將這兩種日誌用下面的宏合併起來。

LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
                                        << "th big cookie";

不只是每隔幾次打印日誌,也可以限制在前n次打印日誌:

LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";

上面會在執行的前20次打印日誌。

調試模式

調試模式的日誌宏只在調試模式下有效,在非調試模式會被清除。可以避免生產環境的程序由於大量的日誌而變慢。

DLOG(INFO) << "Found cookies";

DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";

DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";

CHECK宏

常做狀態檢查以儘早發現錯誤是一個很好的編程習慣。 CHECK 宏和標準庫中的 assert 宏類似,可以在給定的條件不滿足時終止程序。

CHECKassert 不同的是,它不由 NDEBUG 控制,所以一直有效。因此下面的 fp->Write(x) 會一直執行:

CHECK(fp->Write(x) == 4) << "Write failed!";

有各種用於相等/不等檢查的宏: CHECK_EQ, CHECK_NE, CHECK_LE, CHECK_LT, CHECK_GE, CHECK_GT 。它們比較兩個值,在不滿足期望時打印包括這兩個值的 FATAL 日誌。注意這裏的值需要定義了 operator<<(ostream, ...)

比如:

CHECK_NE(1, 2) << ": The world must be ending!";

每個參數都可以保證只用一次,所以任何可以做爲函數參數的都可以傳給它。參數也可以是臨時的表達式,比如:

CHECK_EQ(string("abc")[1], 'b');

如果一個參數是指針,另一個是 NULL ,編譯器會報錯。可以給 NULL 加上對應類型的 static_cast 來繞過。

CHECK_EQ(some_ptr, static_cast<SomeType*>(NULL));

更好的辦法是用 CHECK_NOTNULL 宏:

CHECK_NOTNULL(some_ptr);
some_ptr->DoSomething();

該宏會返回傳入的指針,因此在構造函數的初始化列表中非常有用。

struct S {
  S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}
  Something* ptr_;
};

因爲該特性,這個宏不能用作C++流。如果需要額外信息,請使用 CHECK_EQ

如果是需要比較C字符串( char* ),可以用 CHECK_STREQ, CHECK_STRNE, CHECK_STRCASEEQ, CHECK_STRCASENECASE 的版本是不區分大小寫的。這裏可以傳入 NULLNULL 和任何非 NULL 的字符串是不等的,兩個 NULL 是相等的。

這裏的參數都可以是臨時字符串,比如 CHECK_STREQ(Foo().c_str(), Bar().c_str())

CHECK_DOUBLE_EQ 宏可以用來檢查兩個浮點值是否等價,允許一點誤差。 CHECK_NEAR 還可以傳入第三個浮點參數,指定誤差。

細節日誌

當你在追比較複雜的bug的時候,詳細的日誌信息非常有用。但同時,在通常開發中需要忽略太詳細的信息。對這種細節日誌的需求,Glog提供了 VLOG 宏,使你可以自定義一些日誌級別。通過 --v 可以控制輸出的細節日誌:

VLOG(1) << "I'm printed when you run the program with --v=1 or higher";
VLOG(2) << "I'm printed when you run the program with --v=2 or higher";

和日誌級別相反,級別越低的 VLOG 越會打印。比如 --v=1 的話, VLOG(1) 會打印, VLOG(2) 則不會打印。對 VLOG 宏和 --v flag可以指定任何整數,但通常使用較小的正整數。 VLOG 的日誌級別是 INFO

細節日誌可以控制按模塊輸出:

--vmodule=mapreduce=2,file=1,gfs*=3 --v=0

會:

  1. 爲 mapreduce.{h,cc} 打印 VLOG(2) 和更低級別的日誌
  2. 爲 file.{h,cc} 打印 VLOG(1) 和更低級別的日誌
  3. 爲前綴爲gfs的文件打印 VLOG(3) 和更低級別的日誌
  4. 其他的打印 VLOG(0) 和更低級別的日誌

其中 © 給出的通配功能支持 * (0或多個字符)和 ? (單字符)通配符。

細節級別的條件判斷宏 VLOG_IS_ON(n)--v 大於等於n時返回true。比如:

if (VLOG_IS_ON(2)) {
  // do some logging preparation and logging
  // that can't be accomplished with just VLOG(2) << ...;
}

此外還有 VLOG_IF, VLOG_EVERY_N, VLOG_IF_EVERY_N ,和 LOG_IF, LOG_EVERY_N, LOF_IF_EVERY 類似,但是它們傳入的是一個數字的細節級別。

VLOG_IF(1, (size > 1024))
   << "I'm printed when size is more than 1024 and when you run the "
      "program with --v=1 or more";
VLOG_EVERY_N(1, 10)
   << "I'm printed every 10th occurrence, and when you run the program "
      "with --v=1 or more. Present occurence is " << google::COUNTER;
VLOG_IF_EVERY_N(1, (size > 1024), 10)
   << "I'm printed on every 10th occurence of case when size is more "
      " than 1024, when you run the program with --v=1 or more. ";
      "Present occurence is " << google::COUNTER;

失敗信號處理

Glog庫還提供了一個信號處理器,能夠在 SIGSEGV 之類的信號導致的程序崩潰時導出有用的信息。使用 google::InstallFailureSignalHandler() 加載信號處理器。下面是它輸出的一個例子。

*** Aborted at 1225095260 (unix time) try "date -d @1225095260" if you are using GNU date ***
*** SIGSEGV (@0x0) received by PID 17711 (TID 0x7f893090a6f0) from PID 0; stack trace: ***
PC: @           0x412eb1 TestWaitingLogSink::send()
    @     0x7f892fb417d0 (unknown)
    @           0x412eb1 TestWaitingLogSink::send()
    @     0x7f89304f7f06 google::LogMessage::SendToLog()
    @     0x7f89304f35af google::LogMessage::Flush()
    @     0x7f89304f3739 google::LogMessage::~LogMessage()
    @           0x408cf4 TestLogSinkWaitTillSent()
    @           0x4115de main
    @     0x7f892f7ef1c4 (unknown)
    @           0x4046f9 (unknown)

注意: InstallFailureSignalHandler() 在x86_64系統架構上可能會引發退棧的死鎖,導致遞歸地調用 malloc 。這是內置的退棧的bug,建議在安裝Glog之前安裝libunwind。更多解釋可以看Glog的 INSTALL 文件。

# apt-get install libunwind libunwind-dev

默認情況,信號處理器把失敗信息導出到stderr。可以用 InstallFailureWriter() 定製輸出位置。

其他

支持CMake

Glog並不自帶CMake支持,如果想在CMake腳本中使用它,可以把 FindGlog.cmake 添加到CMake的模塊目錄下。然後像下面這樣使用:

find_package (Glog REQUIRED)
include_directories (${GLOG_INCLUDE_DIR})

add_executable (foo main.cc)
target_link_libraries (foo glog)

性能

Glog提供的條件日誌宏(比如 CHECK, LOG_IF, VLOG, ... )在條件判斷失敗時,不會執行右邊表達式。因此像下面這樣的檢查不會犧牲程序的性能。

CHECK(obj.ok) << obj.CreatePrettyFormattedStringButVerySlow();

自定義失敗處理函數

FATAL 級別的日誌和 CHECK 條件失敗時會終止程序。可以用 InstallFailureFunction 改變該行爲。

void YourFailureFunction() {
  // Reports something...
  exit(1);
}

int main(int argc, char* argv[]) {
  google::InstallFailureFunction(&YourFailureFunction);
}

默認地,Glog會導出stacktrace,程序以狀態1退出。stacktrace只在Glog支持棧跟蹤的系統架構(x86和x86_64)上導出。

原始日誌

<glog/raw_logging.h> 可用於要求線程安全的日誌,它不分配任何內存,也不加鎖。因此,該頭文件中定義的宏可用於底層的內存分配和同步的代碼。

谷歌風格的perror()

PLOG(), PLOG_IF(), PCHECK() 和對應的 LOG*CHECK 類似,但它們會同時在輸出中加上當前 errno 的描述。如:

PCHECK(write(1, NULL, 2) >= 0) << "Write NULL failed";

下面是它的輸出:

F0825 185142 test.cc:22] Check failed: write(1, NULL, 2) >= 0 Write NULL failed: Bad address [14]

Syslog

SYSLOG, SYSLOG_IF, SYSLOG_EVERY_N 宏會在正常日誌輸出的同時輸出到syslog。注意輸出日誌到syslog會大幅影響性能,特別是如果syslog配置爲遠程日誌輸出。所以在用它們之前一定要確定影響,一般來說很少使用。

跳過日誌

打印日誌的代碼中的字符串會增加可執行文件的大小,而且也會帶來泄密的風險。可以通過使用 GOOGLE_STRIP_LOG 宏來刪除所有低於特定級別的日誌:

比如使用下面的代碼:

#define GOOGLE_STRIP_LOG 1    // this must go before the #include!
#include <glog/logging.h>

編譯器會刪除所有級別低於該值的日誌。因爲 VLOG 的日誌級別是 INFO (等於0),設置 GOOGLE_STRIP_LOG 大於等於1會刪除所有 VLOGINFO 日誌。

Windows用戶的注意事項

Glog定義的 ERROR 日誌級別,和 windows.h 中的定義有衝突。可以在引入 glog/logging.h 之前定義 GLOG_NO_ABBREVIATED_SEVERITIES ,這樣Glog就不會定義 INFO, WARNING, ERROR, FATAL 。不過你仍然可以使用原來的宏:

#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>

// ...

LOG(ERROR) << "This should work";
LOG_IF(ERROR, x > y) << "This should be also OK";

但是你不能再在 glog/logging.h 中的函數中使用 INFO, WARNING, ERROR, FATAL 了。

#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>

// ...

// This won't work.
// google::FlushLogFiles(google::ERROR);

// Use this instead.
google::FlushLogFiles(google::GLOG_ERROR);

如果不需要使用 windows.h 中定義的 ERROR ,那麼也可以嘗試下面的方法:

  • 在引入 windows.h 之前 #define WIN32_LEAN_AND_MEANNOGDI
  • 在引入 windows.h 之後 #undef ERROR

參考文獻

http://www.yeolar.com/note/2014/12/20/glog/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章