第二人生的源码分析(4)Log调试功能的实现

对于一个比较复杂的软件来说,没有 Log 调试系统,就像一个人没有眼睛一样,看不到任何东西。对于一个能稳健运行的软件来说, Log 调试系统是必须有的,否则这个软件是开发不成功的。如果在开发软件过程里,没有强调 Log 系统的实现,就等于这个软件运行的不稳定性已经存在其中,后期调试工作和源码维护都存在严重的问题。在《第二人生》的源码里已经开发一个非常容易使用的 Log 系统,这个 Log 系统具有如下特点:
1、             容易使用。
2、             分级调试信息输出。
3、             可重定向不同方式输出。
4、             可以运行时打开调试输出。
 
下面先来看看怎么使用 Log 系统,例子如下:
llinfos << "Saving settings to file: " << filename << llendl;
可以看出,它是跟 C++ 库里的 cout 是差不多的,第一个 << 操作符就是把字符串 "Saving settings to file: " 显示到 Log 里,第二个 << 操作符就是文件名称显示到 Log 里,最后一个 << 操作符紧跟着 llendl 宏定义,表示一行 Log 输出结束。 llinfos 接收后面所有字符串和对象,然后根据类型进行合适格式化输出到指定的目标文件或窗口里。
接着下来,仔细地分析 llinfos 是怎么样实现这么神奇的 Log 输出,满足上述的需求。先来看下面定义的几个宏:
#001 /*
#002  Error Logging Macros
#003  See top of file for common usage. 
#004 */
#005 
#006 #define lllog(level) /
#007  { /
#008         static LLError::CallSite _site( /
#009               level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);/
#010         if (_site.shouldLog()) /
#011         { /
#012               std::ostringstream* _out = LLError::Log::out(); /
#013               (*_out)
#014  
#015 #define llendl /
#016               LLError::End(); /
#017               LLError::Log::flush(_out, _site); /
#018         } /
#019  }
#020 
#021 #define llinfos           lllog(LLError::LEVEL_INFO)
#022 #define lldebugs lllog(LLError::LEVEL_DEBUG)
#023 #define llwarns         lllog(LLError::LEVEL_WARN)
#024 #define llerrs      lllog(LLError::LEVEL_ERROR)
#025 
#026 #define llcont           (*_out)
从上面的代码可以看到 llinfos 是一个宏定义,也就是定义为 lllog(LLError::LEVEL_INFO) ,通过宏定义展开就会生成如下的代码:
{
 static LLError::CallSite _site(
             LLError::LEVEL_INFO, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);
 if (_site.shouldLog())
 {
       std::ostringstream* _out = LLError::Log::out();
       (*_out)
在这里先构造一个对象 _site ,然后根据 shouldLog 里的返回值是否需要输出 Log ,接着从 LLError::Log::out() 里获取接收信息和格式化的对象 _out ,把后面 "Saving settings to file: " << filename 输出到 std::ostringstream 的对象里。至于“ << llendl ”的处理,就是通过 << 操作符重载来实现处理的。因此所有宏定义的展开代码如下:
{
 static LLError::CallSite _site(
             LLError::LEVEL_INFO, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);
 if (_site.shouldLog())
 {
       std::ostringstream* _out = LLError::Log::out();
       (*_out) << "Saving settings to file: " << filename <<
LLError::End();
LLError::Log::flush(_out, _site);
}
}
 
上面的代码主要使用到两个类: CallSite Log 。类 CallSite 主要实现调用输出 Log 位置的一些信息,比如当前函数的名称,或者当前源程序所有行号,又或者类的名称等等。类 Log 真正地实现 Log 的输出到文件,或者调试窗口。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值