对于程序执行期间的错误跟踪!相信大家都有自己的一套办法!!!但都是利用文件文件,我这次利用的是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:[email protected]">[email protected]</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>
//Author : By force eagle //Date time : 2003-5-26 17:08 //reference : // CXMLProfile By Emilio Guijarro Cameros
#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<AppName>XXXX</AppName>\n<Timestamp>1053925276.381</Timestamp>\n" "<Date>2003-05-26</Date>\n<Time>13: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<AppName>XXXX</AppName>\n<Timestamp>1053925276.381</Timestamp>\n<Date>2003-05-26</Date>\n<Time>13: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 ;
CTime timeCur ; 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 &e COM错误信息对象 * 返回: 无 */ 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;
BSTR bstr = NULL; VARIANT_BOOL status; 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 BOOL bCreate 是否创建 * 返回: 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 父节点名称 * IN LPCTSTR lpszChild 子节点名称 * IN BOOL bCreate 是否创建 * 返回: 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 要添加节点的节点指针 * IN LPCTSTR 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中添加一条日志 * 参数: * IN LPCTSTR 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 文件信息 * LPCTSTR s 其他错误信息 * 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; HRESULT hr ; 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; } 
|