1. 程式人生 > >easylogging++學習記錄(二):流式日誌

easylogging++學習記錄(二):流式日誌

析構 log middle 方式 pat eas _id stream 流式

easylogging++日誌庫流式日誌的寫入,依賴於el::base::Writer類的析構,以debug日誌為例:具體代碼如下:

#define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
#define CLOG(LEVEL, ...)\
    C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__)
#if ELPP_DEBUG_LOG
#   define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__)

#define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \ writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)

宏替換之後就是調用了Writer類的一個構造函數和一個construct()成員函數,等同於下面代碼:

el::base::Writer(...).construct(...)

單獨調用一個構造函數的話,會產生一個臨時對象,在語句結束後,這個臨時對象會被析構,進而觸發析構函數中的日誌寫入邏輯,可以通過下列代碼進行驗證:

  1 #include <iostream>
  2 #include <sstream>
  3 
  4 class A
  5 {
  6 public:
  7     A() { }
  8     
  9     ~A()
 10     {
 11         std::cout << m_ss.str() << std::endl;
 12     }   
 13     
 14     template<typename T>
 15     A& operator << (const
T& t) 16 { 17 m_ss << t; 18 return *this; 19 } 20 21 private: 22 std::ostringstream m_ss; 23 }; 24 25 #define SLOG() LOG(A) 26 27 #define LOG(a) 28 a() 29 30 class B 31 { 32 public: 33 B() {} 34 ~B() 35 { 36 std::cout << "~B()" << std::endl; 37 } 38 }; 39 40 int main() 41 { 42 std::cout << ".........begin........." << std::endl; 43 SLOG() << "first...."; 44 B(); 45 std::cout << "..........middle......." << std::endl; 46 B b; 47 b = B(); 48 std::cout << ".........end.........." << std::endl; 49 return 0; 50 }

以上代碼編譯輸出結果如下:

$ g++ macro.cpp -o main
$ ./main 
.........begin.........
first....
~B()
..........middle.......
~B()
.........end..........
~B()

begin和middle之間兩次單獨調用構造函數的地方產生的臨時對象,都在語句結束後被析構了,在middle和end之間,47行處,調用了構造函數構造出一個臨時變量,然後通過賦值構造函數賦值給變量b,隨即臨時變量被析構,而變量b直到main函數結束才被析構掉。

總而言之,要對easylogging++做一層封裝並保持其流式日誌的特性,可以通過同樣的方式,在析構函數上做手腳。

easylogging++學習記錄(二):流式日誌