前面已经展示了内存循环日志系统中ModuleBuffer的实现,这里继续展示剩下的两个部分: ThreadBuffer 和 MemLogSystem, ThreadBuffer用来管理ModuleBuffer实现分模块日志记录, MemLogSystem 用来管理线程日志,模块管理和线程管理是一个类似的管理,类似一个工厂的经销存管理商,
不负责产品具体的创建和销毁,但提供接口查询,提领,回收。
下面看ThreadBuffer的具体实现:
//线程buffer, 用来管理线程中的 模块Buffer
template<int nMaxModuleNum = MEMLOGSYS_MAX_MODULE_NUM, int nMaxModuleBufferLen = MEMLOGSYS_MAX_BUFFE_LEN>
class IThreadBufferImp
{
public:
static const unsigned int m_snMaxModuleNum = nMaxModuleNum;
typedef unsigned int ThreadID;
typedef IModuleBufferImp<nMaxModuleBufferLen> IModuleBuffer;
typedef std::map<std::string, IModuleBuffer*> ModuleBufferMap;
typedef typename ModuleBufferMap::iterator ModuleBufferMapIterator;
typedef typename ModuleBufferMap::const_iterator ModuleBufferMapConstIterator;
static IThreadBufferImp* CreateThreadBuffer(ThreadID nThreadID)
{
IThreadBufferImp* pThreadBuffer = new IThreadBufferImp(nThreadID);
return pThreadBuffer;
}
static void DestroyThreadBuffer(IThreadBufferImp* pThreadBuffer)
{
SAFE_DELETE(pThreadBuffer);
}
bool WriteLog(const char* pszModuleName, const char* pszBufferCache) //写内存日志
{
IModuleBuffer* pModuleBuffer = FindModuleBuffer(pszModuleName);
if (!pModuleBuffer)
{
pModuleBuffer = AllocModuleBuffer(pszModuleName);
PTR_CHECK_RET(pModuleBuffer, false);
}
pModuleBuffer->WriteLog(pszBufferCache);
return true;
}
std::string GetThreadMemLog()
{
std::stringstream strOutPut;
int nModuleCount = m_BufferMap.size();
CON_CHECK_RET_F(nModuleCount > 0, NULL);
int nBufferSize = (nMaxModuleBufferLen + MEMLOGSYS_MAX_MODULENAME_LEN + 20) * nModuleCount;
int nCopyCount = 0;
ModuleBufferMapIterator ite = m_BufferMap.begin();
while(ite != m_BufferMap.end() && ite->second)
{
strOutPut << "[MODULE]: ";
strOutPut << ite->second->GetModuleName();
strOutPut << "\n";
strOutPut << ite->second->GetMemLog();
++ite;
}
return strOutPut.str();
}
IModuleBuffer* FindModuleBuffer(const char* pszModuleName)const
{
ModuleBufferMapConstIterator ite = m_BufferMap.find(std::string(pszModuleName));
if (ite != m_BufferMap.end())
{
return ite->second;
}
return NULL;
}
IModuleBuffer* AllocModuleBuffer(const char* pszModuleName)
{
if (m_BufferMap.size() > m_snMaxModuleNum || !pszModuleName) //限制一下最大模块数
{
return NULL;
}
IModuleBuffer* pModuleBuffer = IModuleBuffer::CreateModuleBuffer(pszModuleName);
PTR_CHECK_RET(pModuleBuffer, NULL);
m_BufferMap[std::string(pszModuleName)] = pModuleBuffer;
return pModuleBuffer;
}
bool FreeModuleBuffer(IModuleBuffer* pModuleBuffer)
{
IModuleBuffer::DestroyModuleBuffer(pModuleBuffer);
return true;
}
void Clear()
{
ModuleBufferMapIterator ite = m_BufferMap.begin();
while(ite != m_BufferMap.end())
{
FreeModuleBuffer(ite->second); //析构释放进程相应的模块日志
++ite;
}
m_BufferMap.clear();
}
ThreadID GetThreadID()const
{
return m_ThreadID;
}
protected:
explicit IThreadBufferImp(ThreadID nThreadID)
{
m_ThreadID = nThreadID;
}
~IThreadBufferImp()
{
Clear();
}
ThreadID m_ThreadID;
ModuleBufferMap m_BufferMap;
private:
IThreadBufferImp(const IThreadBufferImp& rstThreadBuffer){;};
IThreadBufferImp& operator = (const IThreadBufferImp& rstThreadBuffer){;};
};
如下的三个接口用来实现ThreadBuffer对ModuleBuffer的进销存管理商:
IModuleBuffer* FindModuleBuffer(const char* pszModuleName)const
IModuleBuffer* AllocModuleBuffer(const char* pszModuleName)
bool FreeModuleBuffer(IModuleBuffer* pModuleBuffer)
三个接口的实现都非常直观。创建和销毁完全是基于ModuleBuffer本身的接口,唯一的区别就是在创建的时候考虑了一个最大值,我们都不太喜欢在不可控的情况, 所以我们进场对一些创建的地方进行一些限制,对于后台程序这个更加常见,我们会定义在整个服最多多少个怪物同时存在,一个小时候里面全服最多生成多少个特定 的掉落物等等, 这里我们定义了ModuleBuffer 的最大长度,一个线程可以同时存在的ModuleBuffer的数量,以及程序中最多可以有多少个ThreadBuffer。线程Buffer 与ModuleBuffer的访问焦点就在 bool WriteLog(const char* pszModuleName, const char* pszBufferCache)//写内存日志。鉴于MemLogSys的管理功能类似于 ThreadBuffer对于ModuleBuffer,这里就不多说了,直接上实现代码:
#define p_in_ //输入
#define p_out_ //输出
#define p_in_out_ //输入 && 输出
typedef bool (*pfn_Encryption)( p_in_out_ char*, p_in_ int eWay); //加解密函数
//内存日志系统的接口类,
//用来管理线程buffer,
//并提供外部访问接口
//管理加解密
template<int nMaxThreadNum = MEMLOGSYS_MAX_THREAD_NUM, int nMaxModuleNum = MEMLOGSYS_MAX_MODULE_NUM, int nMaxModuleBufferLen = MEMLOGSYS_MAX_BUFFE_LEN>
class IMemLogSys
{
public:
static const unsigned int m_snMaxThreadNum = nMaxThreadNum;
typedef unsigned int ThreadID;
typedef IThreadBufferImp<nMaxModuleNum, nMaxModuleBufferLen> IThreadBuffer;
typedef std::map<ThreadID, IThreadBuffer*> ThreadBufferMap;
typedef typename ThreadBufferMap::iterator ThreadBufferMapIterator;
typedef typename ThreadBufferMap::const_iterator ThreadBufferMapConstIterator;
typedef enum E_IMEMLOGSYS_LEVEL
{
E_IMEMLOGSYS_LEVEL_MIN = 0,
E_IMEMLOGSYS_NORMAL = E_IMEMLOGSYS_LEVEL_MIN,
E_IMEMLOGSYS_WARING,
E_IMEMLOGSYS_ERROR,
E_IMEMLOGSYS_LEVEL_MAX,
}E_IMEMLOGSYS_LEVEL;
typedef enum E_IMEMLOGSYS_DEE{ E_IMEMLOGSYS_ENCRYPTION, E_IMEMLOGSYS_DEENCRYPTION, }E_IMEMLOGSYS_DEE;
bool WriteLog(E_IMEMLOGSYS_LEVEL msgLevel, const char* pszModuleName, const char* pszFormat, ...) //写内存日志
{
CON_CHECK_RET_F(msgLevel >= m_LogLevel && msgLevel >= E_IMEMLOGSYS_NORMAL && msgLevel < E_IMEMLOGSYS_LEVEL_MAX, false);
ThreadID nThreadID = IOSInterfaceImp::GetCurrentTreadID();
IThreadBuffer* pThreadBuffer = FindThreadBuffer(nThreadID);
if (!pThreadBuffer)
{
pThreadBuffer = AllocThreadBuffer(nThreadID);
PTR_CHECK_RET(pThreadBuffer, false);
}
char szBufferCache[IThreadBuffer::IModuleBuffer::m_snMaxBuffLen/MEMLOGSYS_MIN_MODULEBUF_LOG_NUM] = {0};
memset(szBufferCache, 0, nMaxModuleBufferLen/MEMLOGSYS_MIN_MODULEBUF_LOG_NUM);
va_list aptrlist;
va_start(aptrlist, pszFormat);
int nRet = _vsnprintf(szBufferCache, IThreadBuffer::IModuleBuffer::m_snMaxBuffLen/MEMLOGSYS_MIN_MODULEBUF_LOG_NUM, pszFormat, aptrlist);
va_end(aptrlist);
CON_CHECK_RET_F(nRet >0 && nRet < (IThreadBuffer::IModuleBuffer::m_snMaxBuffLen/MEMLOGSYS_MIN_MODULEBUF_LOG_NUM), false);
szBufferCache[IThreadBuffer::IModuleBuffer::m_snMaxBuffLen/MEMLOGSYS_MIN_MODULEBUF_LOG_NUM-1] = 0;
if (m_pfnEncryption)
{
m_pfnEncryption(szBufferCache, E_IMEMLOGSYS_ENCRYPTION);
}
return pThreadBuffer->WriteLog(pszModuleName, szBufferCache);
}
IThreadBuffer* FindThreadBuffer(ThreadID nThreadID)const
{
ThreadBufferMapConstIterator ite = m_BufferMap.find(nThreadID);
if (ite != m_BufferMap.end())
{
return ite->second;
}
return NULL;
}
IThreadBuffer* AllocThreadBuffer(ThreadID nThreadID)
{
if (m_BufferMap.size() > m_snMaxThreadNum) //限制一下最大线程数
{
return NULL;
}
IThreadBuffer* pThreadBuffer = IThreadBuffer::CreateThreadBuffer(nThreadID);
PTR_CHECK_RET(pThreadBuffer, NULL);
m_BufferMap[nThreadID] = pThreadBuffer;
return pThreadBuffer;
}
bool FreeThreadBuffer(IThreadBuffer* pThreadBuffer)
{
IThreadBuffer::DestroyThreadBuffer(pThreadBuffer);
return true;
}
void OutPutLogToFile(const char* pszFilePath) //输出内存日志
{
int nThreadCount = m_BufferMap.size();
if (nThreadCount < 0 || !pszFilePath)
{
return;
}
std::ofstream outPutFileStream;
outPutFileStream.open(pszFilePath);
if (!outPutFileStream.is_open())
{
return;
}
ThreadBufferMapConstIterator ite = m_BufferMap.begin();
while (ite != m_BufferMap.end())
{
if (ite->second )
{
std::string strThreadLog = ite->second->GetThreadMemLog();
if (strThreadLog.length() > 0)
{
outPutFileStream<<"-----------Thread ID:"<<ite->second->GetThreadID()<<" Log ("<<IThreadBuffer::IModuleBuffer::GetTimeSting()<<")----------------\n";
outPutFileStream<<strThreadLog.c_str();
outPutFileStream<<"\n\n";
}
}
++ite;
}
outPutFileStream.close();
outPutFileStream.clear();
}
void PrintLog()
{
ThreadBufferMapConstIterator ite = m_BufferMap.begin();
while (ite != m_BufferMap.end())
{
if (ite->second )
{
std::string strThreadLog = ite->second->GetThreadMemLog();
if (strThreadLog.length() > 0)
{
std::cout<<"-----------Thread ID:"<<ite->second->GetThreadID()<<" Log ("<<IThreadBuffer::IModuleBuffer::GetTimeSting()<<")---------------------\n";
std::cout<<strThreadLog.c_str();
std::cout<<"\n\n";
}
}
++ite;
}
}
void RegisterEncryption(pfn_Encryption pfnEncryFunc) //注册加解密
{
m_pfnEncryption = pfnEncryFunc;
}
void RegisterLogLevel(E_IMEMLOGSYS_LEVEL eLevel) //设置日志级别
{
m_LogLevel = eLevel;
}
void Clear()
{
ThreadBufferMapIterator ite = m_BufferMap.begin();
while(ite != m_BufferMap.end())
{
FreeThreadBuffer(ite->second); //析构释放进程相应的模块日志
++ite;
}
m_BufferMap.clear();
}
IMemLogSys()
{
m_pfnEncryption = NULL;
m_LogLevel = E_IMEMLOGSYS_NORMAL;
}
~IMemLogSys()
{
Clear();
}
private:
pfn_Encryption m_pfnEncryption;
E_IMEMLOGSYS_LEVEL m_LogLevel;
ThreadBufferMap m_BufferMap;
};
这里的实现也是很直观了。也是一个直接而单纯的进销存管理商,不夹杂一丝自私的商人铜臭。前面提到了可控性,这里再一 次进行一次强力控制,我们的日志是一个循环日志,也就是说,后面的日志有可能会覆盖前面的日志,猜想下,如果一条日志很 长,比最大缓冲区都长,那么会出现什么情况。我们写入日志的时候会出现,自己覆盖自己的情况,这是个很悲剧的情况 (前面 的ModuleBuffer的写入实现也没考虑这种超级长的写入,一旦正的传入了这个阐述,日志也就悲剧了),所以这里,我们再一次 产生一个限制,我们设置一条记录的最大长度为缓存区的1/MEMLOGSYS_MIN_MODULEBUF_LOG_NUM,也就是我们一个满的缓冲 区最少有MEMLOGSYS_MIN_MODULEBUF_LOG_NUM条临近的完整日志, 上面实现中有一个留白处,就是加密和解密,这个加解密 方法是每个项目真的秘密,也就不在这里多说了。在实现中提供了一个PrintLog()的调试方法。
关于内存循环日志的用户有一点 需要说明:
这种日志是一种重要的紧急,一般记录一些事后需要的节点信息,而且鉴于容量是有限的,所以不要再Update里面使 用这个日志,要不然循环日志也没意义了,估计里面就一条日志充斥整个缓冲区。
循环日志在何时输出,一般最好是两个途径输出,一个快捷键输出;一个是崩溃输出,崩溃输出最好是选择在系统析构或者程序exit的时候输出到文件。
Sign Clown 2010.7.7 23:09 HDPY,
[本文原创,转载请注明出处,在文章末尾提供原文链接http://www.cnblogs.com/JefferyZhou/,否则一旦发现,将按字节每人民币收费,绝不论价]