在第一篇中主要由讨论日志的需求以及接口设计,这里阐述一下各个部分的实现过程。在设计过程中我们把整个系统分为三个部分:模块buffer, 线程buffer, 和内存日志系统接口。
首先我们需要明确的是我们的写入是正对线程来说,不同线程需要在不同的内存段进行写入操作,而线程内的写入操作是针对模块而来的。所以正在的写入操作在模块buffer里面,这里我们直接实现 一个前面设计的模块buffer:
//模块buffer
template <int nMaxBuffLen = MEMLOGSYS_MAX_BUFFE_LEN>
class IModuleBufferImp
{
public:
typedef unsigned int size_t;
static const unsigned int m_snMaxBuffLen = nMaxBuffLen;
void WriteLog( const char* szBufferCache) //写日志
{
WriteLog_Imp(GetTimeSting().c_str());
WriteLog_Imp(szBufferCache);
WriteLog_Imp("\n");
}
const char* GetMemLog() //获取当前模块的日志信息
{
m_Buffer[m_snMaxBuffLen] = 0;
return m_Buffer;
}
const char* GetModuleName()const
{
return m_szModuleName;
}
static IModuleBufferImp* CreateModuleBuffer(const char* pszModuleName)
{
IModuleBufferImp* pModuleBuffer = new IModuleBufferImp(pszModuleName);
return pModuleBuffer;
}
static void DestroyModuleBuffer(IModuleBufferImp* pModuleBuffer)
{
SAFE_DELETE(pModuleBuffer);
}
static std::string GetTimeSting()
{
tm* pTimeStruct = Time::GetLOCALTime();
char szTempBuffer[128] = {0};
sprintf_s(szTempBuffer,"%.2d.%.2d.%.2d:%.2d:%.2d:%.10d ",pTimeStruct->tm_mon,pTimeStruct->tm_mday,pTimeStruct->tm_hour,pTimeStruct->tm_min,pTimeStruct->tm_sec, GetTickCount());
return std::string(szTempBuffer);
}
protected:
explicit IModuleBufferImp(const char* pszModuleName)
{
if (pszModuleName)
{
sprintf_s(m_szModuleName, MEMLOGSYS_MAX_MODULENAME_LEN-1, "%s", pszModuleName);
m_szModuleName[MEMLOGSYS_MAX_MODULENAME_LEN-1] = 0;
}else
{
memset(m_szModuleName, 0, MEMLOGSYS_MAX_MODULENAME_LEN);
sprintf_s(m_szModuleName, MEMLOGSYS_MAX_MODULENAME_LEN-1, "%s", MEMLOGSYS_DEFAULT_MODULENAME);
}
m_WriteOffSet = 0;
memset(m_Buffer, 0, m_snMaxBuffLen);
}
~IModuleBufferImp()
{
;
}
bool WriteLog_Imp(const char* pszLog)
{
if (pszLog)
{
int len = strlen(pszLog);
if (len >= m_snMaxBuffLen) //超过最大值了
{
return false;
}
if (m_WriteOffSet + len > m_snMaxBuffLen)
{
memcpy(m_Buffer+m_WriteOffSet, pszLog, m_snMaxBuffLen - m_WriteOffSet);
memcpy(m_Buffer,pszLog + (m_snMaxBuffLen - m_WriteOffSet), len-m_snMaxBuffLen + m_WriteOffSet);
}else
{
memcpy(m_Buffer+m_WriteOffSet, pszLog, len);
}
m_WriteOffSet += len;
if (m_WriteOffSet >= m_snMaxBuffLen)
{
m_WriteOffSet -= m_snMaxBuffLen;
}
return true;
}
return false;
}
private:
IModuleBufferImp(const IModuleBufferImp& rstIModuleBuffer){;}; //禁用
IModuleBufferImp& operator = (const IModuleBufferImp& rstIModuleBuffer) {;};//禁用
char m_szModuleName[MEMLOGSYS_MAX_MODULENAME_LEN];
int m_WriteOffSet;
char m_Buffer[m_snMaxBuffLen + 1];
};
上面我们提供了一个简单的工厂函数来创建模块buffer, 并置拷贝构造函数和赋值构造函数为私有防止恶意拷贝。
在上面的实现过程中,有几个小细节需要注意:
1。 我们是需要一个线程安全的写入类,所以在类的实现中不能出现任何多线程共享的可写字段。
2。 线程Buffer 是一个循环日志,必须保证最后记录的完整性,以及记录的循环可读性,
必须在写入记录的时候保证字符串结尾的0不屏蔽,数组中的有效内容。也就是在Write_Imp()里面用的是memcpy, 当然也可以使用 sprintf 系列,
(读者也可以自行改为使用sprintf系列,如果使用sprintf系列需要仔细阅读相关文档, 比如 sprintf_s 保证最后给你加一个 0, 超过缓冲区会报错获设置错误标志位 : 这里有一个小tips,sprintf_s ,不仅在你的缓冲区里面输入内容,而且在后面加一个0,不仅加一个0,还会对0后面的有效缓冲区拿来做其他用途)
3。 为了保证不破坏任何有效的完整记录,以及循环可读性,申请的缓冲区必须比可写缓冲区多一个字节用来存字符串结束符.
4。 把构造函数定义为保护,提供一个简单工厂函数,这里把缓冲区定义为一个数组,而不是一个动态申请的空间,然后,这个时候工厂函数全部是new出的模块buff,所有你定义任何大小的缓冲区,只要不操作当前系统最大可申请内存数量就不会出现错误。
Sign Clown 2010.7.6 0:59 HDPY
大概实现就是上面了。后面另外两个部分,线程buff,系统管理接口的具体实现,会陆续展示。
[本文原创,转载请注明出处,在文章末尾提供原文链接http://www.cnblogs.com/JefferyZhou/,否则一旦发现,将按字节每人民币收费,绝不论价]

浙公网安备 33010602011771号