最简单的基于VC的日志文件类库实现

来源:互联网 发布:dos下运行java程序 编辑:程序博客网 时间:2024/04/29 04:13

日志文件应具备基本功能< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />

Log4j据说是最闻名的日志文件类库,有针对于C++或者.NET的移植版本。一直不明白日志文件有什么特殊之处,也没有研究其功能强大在何处。

1.       理想中的日志文件类库功能应该具备:一个中心、两项基本功能、三个补充要求

2.       一个中心点:    使用简单
就是使用的时候可以感觉日志功能是随插随用,不用在代码层次上做太多前期的步骤。

3.       两个基本功能:日志类型管理日志文件管理
        
日志类型管理包括:格式化输出、日期时间标记等。前者可以考虑为日志分类,后者带上时间标记便于跟踪调试分析。
        
日志文件管理包括:日志文件的大小约定、按时间段整理等

4.       三点补充要求:多种类型信息输出多个进程输出到同一个日志文件多进程线程同时输出时互斥操作

以下是根据在实际过程中的运用,封装一个简单的日志文件功能模块。麻雀虽小,但是却满足以上所有要求。其中,对于日志文件管理这块简单点约定输出到指定文件名。

由于采用CString,因此仅适用于MFC!但是可以方便的改造为纯C|C++

//===============================================================
// LOG::
简单的日志工具
// 
日志功能包应该包括以下两块功能:
// 1. 
每个日志文本串
// 
目前日志文本串包括 [prefix][datetime][type][info...]
// a.
多个进程输出到同一个日志文件,可通过prefix来区分每个进程可以忽略
// b.datetime
可以用来测试时间
// c.
类型可以设定[error|warn|debug],
// 
由使用者任意使用,并不做明确标记也可以忽略
// d.info,
可以根据实际情况任意格式化输出,类似printf
// 2. 
日志文件
// a. 可将日志串保存到文本,或者自己处理
// b. 
支持并发写操作
// c. 
日志文件的管理
//===============================================================


.h文件

class LOG
{
public:
LOG();
virtual ~LOG();

public:
//-
日志文件-
//----
如果没有指定,则为exe所在路径下的log.log文件----
static CString GetLogFile();
static short SetLogFile(LPCTSTR strPath);
static short ViewLogFile();

//-
前缀-
//----
如果多个进程往同一个文件输出日志,可以为每个进程设置一个前缀----
//----
前缀出现在日期时间之前----
static short SetPrefix(LPCTSTR strPrefix);

//-
日志信息-
//-
获取日志字符串,可以另外-
static CString sOutV(LPCTSTR strType, LPCTSTR strFormat = NULL, va_list valist = NULL);
static CString sOut0(LPCTSTR strType, LPCTSTR strFormat = NULL,...);
static CString sOut ( LPCTSTR strFormat = NULL,...);

//-
将日志信息输出到
文件-
static short OutV(LPCTSTR strType, LPCTSTR strFormat = NULL, va_list valist = NULL);
static short Out0(LPCTSTR strType, LPCTSTR strFormat = NULL,...);
static short Out (LPCTSTR strFormat = NULL,...);

protected:
static CString s_strLogFile;
static CString s_strLogPrefix;
static HANDLE s_hWriteEvent;
};


.cpp文件

// 得到可执行程序所在目录
// BOOL bIncludeSep -- 
是否包含最后的分隔符"\"
CString GetExePath(BOOL bIncludeSep)
{
// 
得到当前的文件名
CString strFileName;
GetModuleFileName(AfxGetInstanceHandle(),strFileName.GetBuffer(_MAX_PATH),_MAX_PATH);
strFileName.ReleaseBuffer();
// 
得到当前目录
strFileName=strFileName.Left(strFileName.ReverseFind(_T('\\'))+1);

if(bIncludeSep)
return strFileName;
else
return strFileName.Left(strFileName.GetLength()-1);
}

//-
获取最后的文件名 如果给定文件不是全路径,就是相对于exe-
CString GetFileForExePath(LPCTSTR strCurFileName)
{
CString strPath = strCurFileName;
if(!strPath.IsEmpty())
{
//-
相对路径-
if(strPath.Find(_T(":"))<=0) 

strPath.Format(_T("%s\\%s"), GetExePath(FALSE), strCurFileName); 


return strPath; 


#define LOG_EVENT _T("ChyLogWrite") 
CString LOG::s_strLogFile = _T(""); 
CString LOG::s_strLogPrefix = _T(""); 
HANDLE LOG::s_hWriteEvent = NULL; 

LOG::LOG() 
{


LOG::~LOG() 
{


short LOG::SetLogFile(LPCTSTR strPath)
{
if(strPath==NULL || strPath[0]==0)
s_strLogFile = GetFileForExePath("log.log");
else
s_strLogFile = GetFileForExePath(strPath);

return 1;
}

CString LOG::GetLogFile()
{
return s_strLogFile;
}

short LOG::ViewLogFile()
{
CString strLogFile = GetLogFile();
ShellExecute(NULL, _T("open"), strLogFile, NULL, NULL, SW_SHOW);
return strLogFile.IsEmpty()?0:1;
}

short LOG::SetPrefix(LPCTSTR strPrefix)
{
if(strPrefix && strPrefix[0])
{
s_strLogPrefix = strPrefix;
}

return 1;
}

CString LOG::sOutV(LPCTSTR strType, LPCTSTR strFormat, va_list valist)

CString strPart_Prefix;
if(!s_strLogPrefix.IsEmpty())
{
strPart_Prefix.Format(_T("[%s]"), s_strLogPrefix);
}

CString strPart_Time;
{
SYSTEMTIME sysTime = {0};
GetLocalTime(&sysTime);
strPart_Time.Format(_T("[%2d-%2d %2d:%2d:%2d_%3d]"), 
sysTime.wMonth, sysTime.wDay, 
sysTime.wHour, sysTime.wMinute, sysTime.wSecond, 
sysTime.wMilliseconds); 
}

CString strPart_Type;
if(strType && strType[0])
{
strPart_Type.Format(_T("[%s]"), strType);
}

CString strPart_Info;

strPart_Info.FormatV(strFormat, valist);
}

CString str = strPart_Prefix + strPart_Time + strPart_Type+ strPart_Info;

return str;
}

CString LOG::sOut0(LPCTSTR strType, LPCTSTR strFormat,...)
{
va_list valist;
va_start(valist, strFormat); 
CString strInfo = sOutV(strType, strFormat, valist);
va_end(valist); 

return strInfo;
}

CString LOG::sOut(LPCTSTR strFormat,...)
{
va_list valist;
va_start(valist, strFormat);
CString strInfo = sOutV(NULL, strFormat, valist);
va_end(valist);

return strInfo;
}


short LOG::OutV(LPCTSTR strType, LPCTSTR strFormat, va_list valist)
{
//--
if(s_hWriteEvent==NULL)
{
s_hWriteEvent = OpenEvent(0, FALSE,LOG_EVENT);
if(s_hWriteEvent==NULL)
s_hWriteEvent = CreateEvent(NULL, FALSE, TRUE, LOG_EVENT); 
}

WaitForSingleObject(s_hWriteEvent, INFINITE);

//-
打开关闭文件-
if(s_strLogFile.IsEmpty())
SetLogFile(NULL);
CStdioFile file;
if(file.Open(s_strLogFile, CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite))
{
CString strPart_NewLine = _T("\n");
CString strInfo = sOutV(strType, strFormat, valist); 
CString str = strPart_NewLine + strInfo;

file.SeekToEnd();
file.WriteString(str);
file.Close();
}

SetEvent(s_hWriteEvent);

return 1;
}

short LOG::Out0(LPCTSTR strType, LPCTSTR strFormat,...)
{
va_list valist;
va_start(valist, strFormat); 
short rtn = OutV(strType, strFormat, valist);
va_end(valist);

return rtn;
}

short LOG::Out(LPCTSTR strFormat,...)
{
va_list valist;
va_start(valist, strFormat);
short rtn = OutV(NULL, strFormat, valist);
va_end(valist);

return rtn;
}


使用说明



//-
设定日志文件,建议在Exe初始化时设定-
//-
设置相对路径则表示exe所在路径下-
//-
如果不设定则为exe所在路径下的log.log文件-
LOG::SetLogFile("bbb.log"); 

//-
获取日志文本串,可以自行处理,例如输出到界面-
CString str;
str = LOG::sOut0("debug", "hello");
str = LOG::sOut0("warn5", "hello %d", 25);
str = LOG::sOut0("warn3", "hello %s, you have %d apples!", "libai", 10);
str = LOG::sOut ("hello %s, you have %d apples!", "libai", 10);

//-
输出到文件-
LOG::Out0("debug", "hello");
LOG::Out0("warn5", "hello %d", 25);
LOG::Out0("warn3", "hello %s, you have %d apples!", "libai", 10);
LOG::Out ("hello %s, you have %d apples!", "libai", 10);

//-
查看日志文件-
LOG::ViewLogFile();


输出效果

[ 7-28 17:23:59_ 31][debug]hello
[ 7-28 17:24: 0_ 93][warn5]hello 25
[ 7-28 17:24: 0_343][warn3]hello libai, you have 10 apples!
[ 7-28 17:24: 0_593]hello libai, you have 10 apples!

0 0