第二人生的源码分析(5)类Log的实现

来源:互联网 发布:铺货软件 编辑:程序博客网 时间:2024/05/20 17:24
Log定义如下:
#001 class Log
#002  {
#003  public:
#004         static bool shouldLog(CallSite&);
#005         static std::ostringstream* out();
#006         static void flush(std::ostringstream*, const CallSite&);
#007  };
在类Log里的函数shouldLog是先获取全局的Log对象和全局设置参数,然后检查是否需要保存这条Log信息,同时把这条Log保存起来。它的代码如下:
#001 bool Log::shouldLog(CallSite& site)
#002  {
#003         LogLock lock;
#004         if (!lock.ok())
#005         {
#006               return false;
#007         }
#008        
#009         Globals& g = Globals::get();
#010         Settings& s = Settings::get();
#011        
#012         s.shouldLogCallCounter += 1;
#013        
#014         std::string class_name = className(site.mClassInfo);
#015         std::string function_name = functionName(site.mFunction);
#016         if (site.mClassInfo != typeid(NoClassInfo))
#017         {
#018               function_name = class_name + "::" + function_name;
#019         }
#020 
#021         ELevel compareLevel = s.defaultLevel;
#022 
#023         checkLevelMap(s.functionLevelMap, function_name, compareLevel)
#024         || checkLevelMap(s.classLevelMap, class_name, compareLevel)
#025         || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel);
#026 
#027         site.mCached = true;
#028          g.addCallSite(site);
#029         return site.mShouldLog = site.mLevel >= compareLevel;
#030  }
 
在类Log里的函数out是获取保存字符串的输出对象std::ostringstream,由它来格式化所有输出的字符串。它的代码如下:
#001 std::ostringstream* Log::out()
#002  {
#003         LogLock lock;
#004         if (lock.ok())
#005         {
#006               Globals& g = Globals::get();
#007 
#008               if (!g.messageStreamInUse)
#009               {
#010                     g.messageStreamInUse = true;
#011                    return &g.messageStream;
#012               }
#013         }
#014        
#015         return new std::ostringstream;
#016  }
 
在类Log里的函数flush是把保存在Log缓存里字符串输出到合适的地方,比如把一条Log输出到文件里。
#001 void Log::flush(std::ostringstream* out, const CallSite& site)
#002  {
#003         LogLock lock;
#004         if (!lock.ok())
#005         {
#006               return;
#007         }
#008        
这里进行加锁操作。
 
#009         Globals& g = Globals::get();
#010         Settings& s = Settings::get();
#011 
获取全局保存LOG的对象和LOG参数对象。
 
#012         std::string message = out->str();
#013         if (out == &g.messageStream)
#014         {
#015                g.messageStream.clear();
#016                g.messageStream.str("");
#017                g.messageStreamInUse = false;
#018         }
#019         else
#020         {
#021               delete out;
#022         }
#023 
#024         if (site.mLevel == LEVEL_ERROR)
#025         {
#026               std::ostringstream fatalMessage;
#027               fatalMessage << abbreviateFile(site.mFile)
#028                               << "(" << site.mLine << ") : error";
#029              
#030               writeToRecorders(site.mLevel, fatalMessage.str());
#031         }
#032        
写出错的LOG处理。
 
#033        
#034         std::ostringstream prefix;
#035 
#036         switch (site.mLevel)
#037         {
#038               case LEVEL_DEBUG:          prefix << "DEBUG: ";   break;
#039               case LEVEL_INFO:        prefix << "INFO: ";       break;
#040               case LEVEL_WARN:           prefix << "WARNING: ";     break;
#041               case LEVEL_ERROR:          prefix << "ERROR: ";   break;
#042               default:                 prefix << "XXX: ";       break;
#043         };
#044  
输出LOG的前缀提示。
 
#045         if (s.printLocation)
#046         {
#047               prefix << abbreviateFile(site.mFile)
#048                          << "(" << site.mLine << ") : ";
#049         }
#050        
#051         if (message.find(functionName(site.mFunction)) == std::string::npos)
#052         {
#053  #if LL_WINDOWS
#054               // DevStudio: __FUNCTION__ already includes the full class name
#055  #else
#056               if (site.mClassInfo != typeid(NoClassInfo))
#057               {
#058                    prefix << className(site.mClassInfo) << "::";
#059               }
#060  #endif
#061               prefix << site.mFunction << ": ";
#062         }
#063        
#064         prefix << message;
#065         message = prefix.str();
#066        
#067         writeToRecorders(site.mLevel, message);
#068        
写调试、提示、警告、错误的LOG到文件或者显示窗口。
 
 
#069         if (site.mLevel == LEVEL_ERROR && s.crashFunction)
#070         {
#071               s.crashFunction(message);
#072         }
#073  }
最后处理出错LOG的情况。
Log通过上面三个函数来检查是否可以输出LOG,怎么样保存LOG信息,然后怎么样输出LOG到文件或者窗口里。到这里就分析完成类Log了,下面再来分析类CallSite的代码。