前面已经展示了内存循环日志系统中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/,否则一旦发现,将按字节每人民币收费,绝不论价]

相关文章:

  • 2022-02-06
  • 2021-09-15
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-29
  • 2022-12-23
  • 2021-12-03
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-07-28
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-09-01
相关资源
相似解决方案