experment: LogXML modify - A pure win32 XML Logging Class for Unicode

来源:互联网 发布:vb可视化数据管理器 编辑:程序博客网 时间:2024/05/16 06:57
原版下载点: LogXML - A XML Logging Class

修改版下载点:  LogXMLByUnicode_2013_0407_2347.rar

修改版效果


今天正好要用到Log类, 没有用以前写过的, 觉得写的不好.

去CodeProject逛了逛, 看见一个有新意的日志类, 将日志写成了XML文件.

好处是: 日志可以用市面上现有的优秀XML文件分析工具来浏览, 不用另外写日志查看工具了.

如果日志不大, 用网页浏览器打开即可, 用户体验不错.


原版工程是基于Ansi编码, 我的工程是Unicode编码的, 用的都是wchar_t.

于是修改了一版,  使其符合我的应用, 修改点如下:

* 全部改成Unicode操作, 使用宽字符.

* 建立日志文件时写入 Unicode1 6 Le Bom, 使形成的xml文件可以被网页浏览器正常打开.

* 改变xml文件中的编码标识为 <?xml version=\"1.0\" encoding=\"Unicode\"?>

* 加入日志宏, 使日志类的使用体验更好.

* 修正了原版显示取时间戳毫秒数的BUG.

* 整理代码, 符合我的编码习惯.

* 加入以前写好的CUnicodeFileHelper, 在原版类中作为一个成员使用, 辅助生成UTF16LEBOM的文件头.

* 修正了XML中的显示格式, 增加实际应用中需要的日志字段, 符合我的应用.


日志类的使用还算方便, 测试程序如下:

/**\file    LogXML_test.cpp\brief   LogCML Test\date    2003-05-12\author  Christian Richardt (cr@whizer.net)@note modify by LostSpeed on 2013-04-07**/#include <windows.h>#include <tchar.h>#include <stdio.h>#include "LogXmlUnicode.h"LOG_INIT(L"logAbc.xml", L"AppTest");int main(){    int i = 0;    LOG_INFO(L"Starting ...\n");    for(int i = 0; i<100; i++)    {        LOG_INFO(L"SampleFunction(%i), Writing log entry #%i and waiting for the next ...\n",            i, i);    }    LOG_INFO(L"\nAll sample log entries have been written ...\n");    LOG_INFO(L"\nMission finished ...\n\n\n");    return 0;}

修改后的日志类定义:

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~LogXML 1.0------------------LogXML is a simple and free logging class for all purposes.You can use it freely und unlimited but give me creditwhere it's due.Source code is ready for DoxyGen (http://www.doxygen.org/).Written by Christian Richardt (cr@whizer.net).Release history:Mai 12, 2003: Version 1.0. First release.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*//**\file    LogXML.h\brief   XML log class\date    2003-05-12\author  Christian Richardt (cr@whizer.net)@note     modify by LostSpeed on 2013-04-07, support unicode**/#ifndef LOGXML_H#define LOGXML_H#include <stdio.h>#include "UnicodeFileHelper.h"#ifndef __WFILE__#define WIDEN2(x) L ## x#define WIDEN(x) WIDEN2(x)#define __WFILE__ WIDEN(__FILE__)#define __WFUNCTION__ WIDEN(__FUNCTION__)#endif  // #ifndef __WFILE__#ifndef LOG_INIT/// 日志初始化宏#define LOG_INIT(LogFileName, LogAppName) \    LogXML  XmlLogGolobal(LogFileName, LogAppName);/// 日志记录宏#define LOG_INFO(...)\    XmlLogGolobal.LogEx(XmlLogGolobal.FileName(__WFILE__), __WFUNCTION__, __LINE__, __VA_ARGS__);#endif  // #ifndef LOG_INIT/**\brief   LogXML is a simple and free logging class for all purposes.\author  Christian Richardt (cr@whizer.net)**/class LogXML{public:    LogXML();    LogXML(wchar_t * pszFileName, wchar_t * pszAppName = L"None");    ~LogXML();    /// useage e.g.     calsslog.LogEx(FileName(__WFILE__), __WFUNCTION__, __LINE__, L"hello~");    bool  LogEx(wchar_t * pszFilename, wchar_t * pszFunctionName, size_t nLineSn, wchar_t * pszContentFormat, ...);    wchar_t * FileName(wchar_t * pszFile);private:    bool  goDown(wchar_t * pszMessage = NULL, wchar_t * pszFilename = NULL, wchar_t * pszFuncname = NULL);    void  goUp(void);    bool  Log(wchar_t * pszFilename, wchar_t * pszFunctionName, size_t nLineSn, wchar_t * pszContentFormat);    bool  WriteLine(wchar_t * pData);    bool  WriteLine(wchar_t * pszTagName, wchar_t* pszContents);    bool  WriteTimestamp(void);    bool  WriteDateTime(void);    bool  WriteData(wchar_t * pData);    double mtime(unsigned short & millitm); ///< UNIX timestamp: seconds from 1970-01-01 00:00:00 (UTC)    void memberInit();    BOOL GetModulePathPrefix(std::wstring & strPathW);  ///< @todo 放到工具代码中private:    wchar_t *   m_pszFileName; ///< log file name    FILE *      m_fileLog;     ///< file handle of log file    int         m_iDepth;      ///< current depth in document    BOOL                    m_bFileIsUTF16_LE;  ///< 文件是UTF16_LE? , 如果文件不是UTF16_LE, 无法再继续操作    CUnicodeFileHelper *    m_pFileHelper;};extern LogXML  XmlLogGolobal;#endif // LOGXML_H

Unicode文件辅助类定义:

#ifndef __UNICODE_FILE_HELPER_H__#define __UNICODE_FILE_HELPER_H__#include <windows.h>#include <tchar.h>#include <string>class CUnicodeFileHelper{public:CUnicodeFileHelper(CONST TCHAR * lpcFilePathName);virtual ~CUnicodeFileHelper(void);public:BOOL IsFileExist();BOOL IsUTF16_LE();///< 文件是否是UTF16_LE格式BOOL CreateFileAsUTF16_LE();///< 按照UTF16_LE建立一个新文件CONST TCHAR * GetIniPathName();private:BOOL IsValidFileHandle();BOOL OpenFileForRead();/// @fn BOOL OpenFileForWrite(BOOL bOpenExist)/// @brief 打开文件去写/// @param BOOL bOpenExist, 被操作的文件是否是已经存在的文件///bOpenExist = TRUE, 指定打开的文件是已经存在的, 如果文件不存在, 打开文件失败///bOpenExist = FALSE, 新建文件, 如果文件存在, 会清空原文件内容BOOL OpenFileForWrite(BOOL bOpenExist);VOID CloseFile();private:std::wstring m_strFilePathName;///< 文件全路径HANDLE m_hFile;///< 文件句柄DWORD m_dwLastError;///< 最近的系统错误码/// 用UltraEdit观察到 Windows记事本保存成Unicode格式后, BOM 是0xFEFFstatic CONST WORD m_wUnicode16LeBom = 0xFEFF; ///< UTF16-little endian byte order mark};#endif

写完后, 才发现, 工程中有些单词拼错了...

bug list:

* 还不支持转移字符,  参考资料: http://blog.csdn.net/High_Mount/article/details/2953335

使用DTD文件的方法试过了, 不好使.

需要搞一个转义符处理, 写进文件之前进行处理.  这样日志效率很低啊.


也可以等文件关闭后, 做一次处理. 如果文件是海量日志, 这么搞行不通.

最好的方法是不使用XML日志, 还是用传统的行日志~


可以将日志处理发给后台处理, 后台在写入日志前, 进行转义.

这样日志形式就变成接口, 需要开一个日志后台处理程序.


还可以直接用支持unicode的xml类来处理, 直接将xml内容写成文件. 不过效率有问题.

还是要调用接口, 让后台程序慢慢去写日志.


让后台写日志, 就涉及到多线程的问题, 每个日志写入者有自己的PID, TID. 文件名, AppName.

需要后台日志处理程序都记住, 细节也挺多.


先将就用, 写完日志后, 用文本编辑器来浏览日志, 比看传统的行日志, 还是清晰很多.

还有一个临时措施, 写日志时, 不写入转义字符.

如果要记录的是第三方给的数据, 不可避免的会有转义字符,  那就一定要转义了或者不使用xml日志记录.


以后想好了, 再来改.




原创粉丝点击