您的位置:首页 > 其它

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

2008-05-10 09:21 656 查看
对于一个比较复杂的软件来说,没有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的输出到文件,或者调试窗口。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐