添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

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>
  4 class A
  6 public:
  7     A() { }
  9     ~A()
 11         std::cout << m_ss.str() << std::endl;
 14     template<typename T>
 15     A& operator << (const T& t)
 17         m_ss << t;
 18         return *this;
 21 private:
 22     std::ostringstream m_ss;
 23 };  
 25 #define SLOG() LOG(A)
 27 #define LOG(a) \
 28     a()
 30 class B
 32 public:
 33     B() {}
 34     ~B()
 36         std::cout << "~B()" << std::endl;
 38 };  
 40 int main()
 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;

以上代码编译输出结果如下:

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

begin和middle之间两次单独调用构造函数的地方产生的临时对象,都在语句结束后被析构了,在middle和end之间,47行处,调用了构造函数构造出一个临时变量,然后通过赋值构造函数赋值给变量b,随即临时变量被析构,而变量b直到main函数结束才被析构掉。

总而言之,要对easylogging++做一层封装并保持其流式日志的特性,可以通过同样的方式,在析构函数上做手脚。