利用XML文件写日志的类
利用XML文件写日志的类
作者:战鹰
对于程序执行期间的错误跟踪!相信大家都有自己的一套办法!!!但都是利用文件文件,我这次利用的是XML&XSL,可产生报表格式的日志,轻松生成报表!!!
我参考了Emilio Guijarro Cameros的CXMLProfile写XML配置文件的思想!!!利用XML 接口IXMLDOMDocument
、IXMLDOMNode 、IXMLDOMElement和 MFC相结合,写成了一个CXMLLogfile类,只暴露了两个公共方法
void Log(LPCTSTR lpszFilName,LPCTSTR s,...);
bool ClearAll()
Log是添加一条日志,ClearAll是清除所有日志!!!当大家需要查看日值时,只需要打开相应的XML文件Log.XML就可以看到一个日志表格了,为此我专门写了一个XSL样式文件(XML样式XSL文件必须在XML文件同一目录下)!
XSL样式文件代码:<?xml version="1.0" encoding="GB2312"?
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
<xsl:template match="/"
<html
<head
<title<xsl:value-of select="LogFile/AppName" / 日志文件</title
</head
<body
<h1<xsl:value-of select="LogFile/AppName" / 运行日志文件</h1
<table border="0" cellspacing="1" cellpadding="0"
<tr
<td bgcolor="#dddddd"
<table border="0" cellpadding="3" cellspacing="1"
<tr
<td bgcolor="#ffffff" </td
<td width="140" valign="center" bgcolor="#ffffff"<b日期-时间</b</td
<td bgcolor="#ffffff"<b错误信息</b</td
<td bgcolor="#ffffff"<b具体位置信息</b</td
</tr
<xsl:for-each select="LogFile/LogItem"
<tr onMouseover=""
<td bgcolor="#ffffff" valign="top"<xsl:number count="LogItem" /.</td
<td bgcolor="#ffffff" valign="top"<nobr<xsl:value-of select="Date" /</nobr<xsl:value-of select="Time" /</td
<td bgcolor="#ffffff" valign="top"<xsl:value-of select="comment" /</td
<td bgcolor="#ffffff" valign="top"<xsl:value-of select="Filename" /</td
</tr
</xsl:for-each
</table
</td
</tr
</table
<font style="font-size:5.0mm;"<br/
Log.xsl by force eagle <<a href="mailto:force_eagle@163.net"force_eagle@163.net</a></font
</body
</html
</xsl:template
</xsl:stylesheet
以下是一日志表格图:

以下是源代码,需要IE5.5以上支持!!!如果编译错误!请下载微软的最新XML SDK!!!!// XMLLogfile.h: interface for the CXMLLogfile class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_XMLLOGFILE_H__EA8ACC84_7139_49F6_9B8A_F69D9CF5C385__INCLUDED_)
#define AFX_XMLLOGFILE_H__EA8ACC84_7139_49F6_9B8A_F69D9CF5C385__INCLUDED_
#if _MSC_VER 1000
#pragma once
#endif // _MSC_VER 1000
#include <sys/timeb.h
#include <time.h
#include <atlbase.h
#include <msxml.h
#include <shlobj.h
#include <comdef.h
//Author : By force eagle
//Date time : 2003-5-26 17:08
//reference :
//CXMLProfile By Emilio Guijarro Cameros
//Christian Richardt
#pragma comment(lib,"msxml2.lib")
class CXMLLogfile : public CObject
{
CString m_strFileName;
IXMLDOMDocument *m_pXMLDoc;
IXMLDOMNode * GetChildNode(LPCTSTR lpszParent, LPCTSTR lpszChild,BOOL bCreate = TRUE);
IXMLDOMNode * GetFirstLevelNode(LPCTSTR lpszNodeName,BOOL bCreate = TRUE);
// UNIX timestamp: seconds from 1970-01-01 00:00:00 (UTC)
inline double TimeStamp(void)
{
_timeb ts;
_ftime( &ts );
return (int)ts.time + (ts.millitm/1000.0);
};
protected:
void AppendNode(IXMLDOMNode * pXMLItem, LPCTSTR lpszNodeName, LPCTSTR lpszValue);
void AppendItem(LPCTSTR lpszFileName,LPCTSTR lpszComment);
void Flush();
bool CreateLogFile(LPCTSTR lpszLogFilName);
void DumpComError(_com_error &e);
void Init();
public:
CXMLLogfile(LPCTSTR lpszFileName = NULL);
virtual ~CXMLLogfile();
void Log(LPCTSTR lpszFilName,LPCTSTR s,...);
bool ClearAll();
};
#endif // !defined(AFX_XMLLOGFILE_H__EA8ACC84_7139_49F6_9B8A_F69D9CF5C385__INCLUDED_)
// XMLLogfile.cpp: implementation of the CXMLLogfile class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "XMLLogfile.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
/*
static TCHAR *szLogOrig= {_T("<?xml version=\"1.0\" encoding=\"GB2312\"?\n"
"<?xml-stylesheet href=\"Log.xsl\" type=\"text/xsl\"?\n"
"<LogFile\n<AppNameXXXX</AppName\n<Timestamp1053925276.381</Timestamp\n"
"<Date2003-05-26</Date\n<Time13:01:16.861</Time\n</LogFile\n")};
//*/
static WCHAR *wszLogOrig = {L"<?xml version=\"1.0\" encoding=\"GB2312\"?\n<?xml-stylesheet href=\"Log.xsl\" type=\"text/xsl\"?\n<LogFile\n<AppNameXXXX</AppName\n<Timestamp1053925276.381</Timestamp\n<Date2003-05-26</Date\n<Time13:01:16.861</Time\n</LogFile\n"};
CXMLLogfile::CXMLLogfile(LPCTSTR lpszFileName)
{
VARIANT_BOOL bResult;
IXMLDOMElement *pRootNode;
HRESULT hr;
if (NULL == lpszFileName)
{
CString strHlpPath ,strAppName;
strHlpPath = AfxGetApp()-m_pszHelpFilePath;
strAppName = AfxGetAppName();
strHlpPath = strHlpPath.Left(strHlpPath.GetLength() - 4
- strAppName.GetLength());
m_strFileName = strHlpPath + _T("LOG.XML");
}
else
{
m_strFileName = lpszFileName;
}
hr = CoInitialize(NULL);
LoadLog:
if(SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument, (void**)&m_pXMLDoc);
if(SUCCEEDED(hr))
{
m_pXMLDoc-load(COleVariant(m_strFileName), &bResult);
}
}
//取得根节点
m_pXMLDoc-get_documentElement(&pRootNode);
if(pRootNode == NULL)//无根节点
{
m_pXMLDoc-Release();
m_pXMLDoc = NULL;
//重新创建XML日值文件
CreateLogFile(m_strFileName);
goto LoadLog; //重新载入
}
else
{
Init();
}
}
CXMLLogfile::~CXMLLogfile()
{
m_pXMLDoc-save(COleVariant(m_strFileName));
m_pXMLDoc-Release();
}
/*
*函数名称:Init()
*说明:初始化XML日志文件的工程信息
*参数:
*无
*返回:无
*/
void CXMLLogfile::Init()
{
IXMLDOMNode *pAppNameNode, *pTimestamp, *pDate, *pTime;;
TCHAR *szTemp = new TCHAR[MAX_PATH];
HRESULT hr ;
CTimetimeCur ;
timeCur = CTime::GetCurrentTime();
CString strDate, strTime;
strDate = timeCur.Format(_T("%Y-%m-%d"));
strTime = timeCur.Format(_T("%X"));
//更改工程名称
pAppNameNode = GetFirstLevelNode(_T("AppName"));
hr = pAppNameNode-put_text(CComBSTR(AfxGetAppName()));
pAppNameNode-Release();
//*
//时间戳
ZeroMemory(szTemp,MAX_PATH);
double timestamp = TimeStamp();
_stprintf(szTemp,_T("%.3f"),timestamp);
pTimestamp = GetFirstLevelNode(_T("Timestamp"));
hr = pTimestamp-put_text(CComBSTR(szTemp));
pTimestamp-Release();
//*/
//日期
pDate = GetFirstLevelNode(_T("Date"));
hr = pDate-put_text(CComBSTR(strDate));
pDate-Release();
//时间
pTime = GetFirstLevelNode(_T("Time"));
hr = pTime-put_text(CComBSTR(strTime));
pTime-Release();
delete szTemp;
Flush();
}
/*
*函数名称:DumpComError(_com_error &e)
*说明:输出COM错误信息
*参数:
*IN _com_error &eCOM错误信息对象
*返回:无
*/
void CXMLLogfile::DumpComError(_com_error &e)
{
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
TRACE("Error\n");
TRACE("\tCode = %08lx\n", e.Error());
TRACE("\tCode meaning = %s\n", e.ErrorMessage());
TRACE("\tSource = %s\n", (LPCSTR) bstrSource);
TRACE("\tDescription = %s\n", (LPCSTR) bstrDescription);
}
/*
*函数名称:CreateLogFile(LPCTSTR lpszLogFilName)
*说明:创建原始的XML日志文件
*参数:
*IN LPCTSTR lpszLogFileName 文件名称
*返回:true 成功
*/
bool CXMLLogfile::CreateLogFile(LPCTSTR lpszLogFilName)
{
IXMLDOMDocument *pXMLDoc = NULL;
BSTRbstr = NULL;
VARIANT_BOOLstatus;
HRESULT hr;
try
{
hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument, (void**)&pXMLDoc);
if (FAILED(hr))
_com_issue_error(hr);
bstr = ::SysAllocString(wszLogOrig);
ASSERT(NULL != bstr);
hr = pXMLDoc-loadXML(bstr,&status);
::SysFreeString(bstr);
if (FAILED(hr))
_com_issue_error(hr);
if(status != VARIANT_TRUE)
{
return false;
}
hr = pXMLDoc-save(COleVariant(lpszLogFilName));
if (FAILED(hr))
_com_issue_error(hr);
pXMLDoc-Release();
}
catch(_com_error &e)
{
DumpComError(e);
return false;
}
return true;
}
/*
*函数名称:GetFirstLevelNode(LPCTSTR lpszNodeName)
*说明:根据名称查找第一层子节点指针,没有则判断是否创建
*参数:
*IN LPCTSTR lpszNodeName 节点名称
*IN BOOLbCreate 是否创建
*返回:IXMLDOMNode *节点指针
*/
IXMLDOMNode * CXMLLogfile::GetFirstLevelNode(LPCTSTR lpszNodeName,BOOL bCreate)
{
IXMLDOMElement *pRootNode = NULL, *element = NULL;
IXMLDOMNode *pLogItem = NULL, *pResultNode = NULL;
CComBSTR szName;
bool bSecFound = false, bEntryFound = false;
//wchar_t *szTemp = new wchar_t[255];
m_pXMLDoc-get_documentElement(&pRootNode);
for(pRootNode-get_firstChild(&pLogItem); pLogItem != NULL; pLogItem-get_nextSibling(&pLogItem))
{
pLogItem-get_baseName(&szName);
if(szName == CComBSTR(lpszNodeName))
{
pResultNode = pLogItem;
break;
}
}
if(pLogItem == NULL && bCreate)
{
m_pXMLDoc-createElement(CComBSTR(lpszNodeName), &element);
pRootNode-appendChild(element, &pLogItem);
element-Release();
pResultNode = pLogItem;
}
pRootNode-Release();
return pResultNode;
}
/*
*函数名称:GetChildNode(LPCTSTR lpszParent, LPCTSTR lpszChild)
*说明:查找父节点下的某一子节点指针,没有则判断是否创建创建
*参数:
*IN LPCTSTR lpszParent 父节点名称
*INLPCTSTR lpszChild子节点名称
*IN BOOLbCreate 是否创建
*返回:IXMLDOMNode *子节点指针
*/
IXMLDOMNode * CXMLLogfile::GetChildNode(LPCTSTR lpszParent, LPCTSTR lpszChild,BOOL bCreate)
{
IXMLDOMElement *pRootNode= NULL, *element= NULL;
IXMLDOMNode *pLogItem= NULL, *pLogData= NULL, *pResultNode= NULL;
CComBSTR szName;
m_pXMLDoc-get_documentElement(&pRootNode);
for(pRootNode-get_firstChild(&pLogItem); pLogItem != NULL; pLogItem-get_nextSibling(&pLogItem))
{
pLogItem-get_baseName(&szName);
if(szName == CComBSTR(lpszParent))
{
for(pLogItem-get_firstChild(&pLogData); pLogData != NULL; pLogData-get_nextSibling(&pLogData))
{
pLogData-get_baseName(&szName);
if(szName == CComBSTR(lpszChild))
{
pResultNode = pLogData;
break;
}
}
if(pLogData == NULL && bCreate)
{
m_pXMLDoc-createElement(CComBSTR(lpszChild), &element);
pLogItem-appendChild(element, &pLogData);
element-Release();
pResultNode = pLogData;
}
pLogItem-Release();
break;
}
}
if(pLogItem == NULL && bCreate)
{
m_pXMLDoc-createElement(CComBSTR(lpszParent), &element);
pRootNode-appendChild(element, &pLogItem);
element-Release();
m_pXMLDoc-createElement(CComBSTR(lpszChild), &element);
pLogItem-appendChild(element, &pLogData);
element-Release();
pResultNode = pLogData;
}
pRootNode-Release();
return pResultNode;
}
/*
*函数名称:AppendNode(IXMLDOMNode * pXMLItem, LPCTSTR lpszNodeName, LPCTSTR lpszValue)
*说明:在XML中添加一节点,并赋值为 lpszValue
*参数:
*IN IXMLDOMNode *pXMLItem 要添加节点的节点指针
*INLPCTSTR lpszNodeName添加的节点名称
*IN LPCTSTR lpszComment值
*/
void CXMLLogfile::AppendNode(IXMLDOMNode * pXMLItem, LPCTSTR lpszNodeName, LPCTSTR lpszValue)
{
IXMLDOMElement *element;
IXMLDOMNode *pLogData;
m_pXMLDoc-createElement(CComBSTR(lpszNodeName),&element);
pXMLItem-appendChild(element,&pLogData);
element-Release();
pLogData-put_text(CComBSTR(lpszValue));
pLogData-Release();
}
/*
*函数名称:AppendItem(LPCTSTR lpszFileName,LPCTSTR lpszComment)
*说明:在XML中添加一条日志
*参数:
*INLPCTSTR lpszFileName文件信息
*IN LPCTSTR lpszComment错误信息
*/
void CXMLLogfile::AppendItem(LPCTSTR lpszFileName,LPCTSTR lpszComment)
{
IXMLDOMElement *pRootNode, *element;
IXMLDOMNode *nLogItem;
CComBSTR szName;
HRESULT hr;
CTime timeCur ;
timeCur = CTime::GetCurrentTime();
CString strDate, strTime;
strDate = timeCur.Format(_T("%Y-%m-%d"));
strTime = timeCur.Format(_T("%X"));
hr = m_pXMLDoc-get_documentElement(&pRootNode);
m_pXMLDoc-createElement(CComBSTR(_T("LogItem")),&element);
pRootNode-appendChild(element,&nLogItem);
element-Release();
AppendNode(nLogItem,_T("Date"),strDate);
AppendNode(nLogItem,_T("Time"),strTime);
AppendNode(nLogItem,_T("Filename"),lpszFileName);
AppendNode(nLogItem,_T("comment"),lpszComment);
pRootNode-Release();
}
/*
*函数名称:Flush()
*说明:将缓冲区内数据写到磁盘保存XML文件
*参数:
*无
*/
void CXMLLogfile::Flush()
{
m_pXMLDoc-save(COleVariant(m_strFileName));
}
/*
*函数名称:Log(LPCTSTR lpszFilName,LPCTSTR s,...)
*说明:添加一条日值记录
*参数:
*LPCTSTR lpszFileName文件信息
*LPCTSTRs其他错误信息
*EXAMPLE:
*Log(__FILE__,"%ld line error!!",__LINE__)
*/
void CXMLLogfile::Log(LPCTSTR lpszFilName,LPCTSTR s,...)
{
static TCHAR szBuff[1024];
va_list argptr;
int cnt;
va_start(argptr, s);
cnt = _vstprintf(szBuff, s, argptr);
va_end(argptr);
AppendItem(lpszFilName,szBuff);
Flush();
}
/*
*函数名称:ClearAll()
*说明:清除日值
*参数:
*无
*返回值: 成功 true
*/
bool CXMLLogfile::ClearAll()
{
IXMLDOMElement *pRootNode= NULL;
IXMLDOMNode *pLogItem= NULL, *pLogData= NULL, *pOldNode= NULL, *pNextNode ,*pPreviousNode;
CComBSTR szName;
HRESULThr ;
m_pXMLDoc-get_documentElement(&pRootNode);
try
{
pRootNode-get_lastChild(&pLogItem);
do
{
pLogItem-get_previousSibling(&pPreviousNode);
pLogItem-get_baseName(&szName);
if(szName == CComBSTR(_T("LogItem")))
{
pLogItem-get_firstChild(&pLogData);
do
{
pLogData-get_nextSibling(&pNextNode);
pLogData-get_baseName(&szName);
hr = pLogItem-removeChild(pLogData,&pOldNode);
if (FAILED(hr))
_com_issue_error(hr);
pOldNode-Release();
pOldNode = NULL;
pLogData = pNextNode;
}while(pLogData != NULL);
hr = pRootNode-removeChild(pLogItem,&pOldNode);
if (FAILED(hr))
_com_issue_error(hr);
}
pLogItem = pPreviousNode;
}while(pLogItem != NULL);
pRootNode-Release();
}
catch(_com_error &e)
{
pRootNode-Release();
DumpComError(e);
return false;
}
Flush();
return true;
}
(全文完)