easylogging++學習記錄(二):流式日誌
阿新 • • 發佈:2018-06-08
析構 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 << (constT& 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++學習記錄(二):流式日誌