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

原版下载点: LogXML - A XML Logging Class

修改版下载点:  LogXMLByUnicode_2013_0407_2347.rar

修改版效果

experment: LogXML modify - A pure win32 XML Logging Class for Unicode_第1张图片

今天正好要用到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 ([email protected])

@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 credit
where it's due.

Source code is ready for DoxyGen (http://www.doxygen.org/).

Written by Christian Richardt ([email protected]).

Release history:
Mai 12, 2003: Version 1.0. First release.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

*/

/**
\file    LogXML.h
\brief   XML log class
\date    2003-05-12
\author  Christian Richardt ([email protected])

@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 ([email protected])
**/
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 是0xFEFF
	static 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日志记录.


以后想好了, 再来改.




你可能感兴趣的:(experment: LogXML modify - A pure win32 XML Logging Class for Unicode)