对于日志 , 一般在工业24小时执行的程序很多见, 通常的用就是法记录文本信息.。这次提供的C++类命名为CxLog, 提供文本记录, 多参数格式化文本纪录, 二进制数据参照常见16进制编辑器纪录,对常见编译器的异常提供便捷的记录接口。本次提供的类支持多线程,本身也是依赖守护线程执行,也采用了简单的单件模式,一个程序只会有一个实例,且不需要用户定义。同时支持UNICODE,支持常见的编译器,记录文件时同时会向控制台输出,也会向调试窗口输出, 主要目的就是为了方便,其实程序难度很低,高手莫要见笑。
下载地址http://download.csdn.net/source/408048
本文末提供源代码
文本纪录: LOG(text);
多参数格式化文本纪录:
GNU C++ :LOGN(format, p1, p2...);
VC6等不支持多参数宏采用LOG1(format, p1); LOG2(format, p1, p2); .....
CException: LOGE(e);
_com_error: LOGE(e);
std::exception: LOGE(e);
日志内容:
2008-04-10 15:05:26.469 Exception BaseTestLog.cpp(func, 44): test of c ++ exception.
二进制数据: LOG_BIN(pData, uDataSize);
日志内容:
2008-04-10 15:05:26.469 Exception BaseTestLog.cpp(func, 44):
00000060: 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F `abcdefghijklmno
对于ASCII的控制字符默认替换成_T('.'),你可以定义宏CX_LOG_REPLACE_ASCII来改变他,也可以定义宏CX_LOG_REPLACE_CONTROL选择是否替换
总的来说功能也就是记录文件名、函数名、行号、内容,并提供对常见异常自动扩展,
你可以通过定义宏来改变日志文件名
比如你定义
#define CX_LOG_FILE_NAME _T("d:/mylog.log")
日志就会记录在该文件中
系统默认记录在./log下,文件名为程序启动当天日期
提供按一定时间记录的功能
通过宏CX_LOG_BY_DAY、CX_LOG_BY_WEEK、CX_LOG_BY_MONTH、CX_LOG_BY_YEAR
改变记录的文件名
初步遗留问题:
1 听说VC2005支持多参数宏 没有安装测试
2 __FUNCTION__ 的UNICODE扩展在GCC中没有成功但是__FILE__成功了,我都有点糊涂了 ,所以UNICODE下不支持__FUNCTION__
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
#define __WFUNCTION__ WIDEN(__FUNCTION__)//GCC失败
3 对于不支持多参数宏的采用LOG1~9的扩展宏支持,尽管很难看,暂时我也不会了
4 只支持WIN32 希望有时间考虑开发移植
以下是一个测试用例, 在VC6(sp6)、VC2003、BCB6、GCC3.4.4、GCC4.4.1、Intel C++9下分别在UNICODE和非UNICODE下编译通过
输出内容:
2008-04-10 15:05:26.468 Message BaseTestLog.cpp(14): Test Log
2008-04-10 15:05:26.468 Message BaseTestLog.cpp(15): Arg:1
2008-04-10 15:05:26.468 Message BaseTestLog.cpp(16): Arg:1, 2
2008-04-10 15:05:26.468 Message BaseTestLog.cpp(17): Arg:1, 2, 3
2008-04-10 15:05:26.468 Message BaseTestLog.cpp(18): Arg:1, 2, 3, 4
2008-04-10 15:05:26.468 Message BaseTestLog.cpp(19): Arg:1, 2, 3, 4, 5
2008-04-10 15:05:26.468 Message BaseTestLog.cpp(20): Arg:1, 2, 3, 4, 5, 6
2008-04-10 15:05:26.468 Message BaseTestLog.cpp(21): Arg:1, 2, 3, 4, 5, 6, 7
2008-04-10 15:05:26.468 Message BaseTestLog.cpp(22): Arg:1, 2, 3, 4, 5, 6, 7, 8
2008-04-10 15:05:26.468 Message BaseTestLog.cpp(23): Arg:1, 2, 3, 4, 5, 6, 7, 8, 9
2008-04-10 15:05:26.468 Warning BaseTestLog.cpp(25): Test Log
2008-04-10 15:05:26.468 Warning BaseTestLog.cpp(26): Arg:1
2008-04-10 15:05:26.468 Warning BaseTestLog.cpp(27): Arg:1, 2
2008-04-10 15:05:26.468 Warning BaseTestLog.cpp(28): Arg:1, 2, 3
2008-04-10 15:05:26.468 Warning BaseTestLog.cpp(29): Arg:1, 2, 3, 4
2008-04-10 15:05:26.468 Warning BaseTestLog.cpp(30): Arg:1, 2, 3, 4, 5
2008-04-10 15:05:26.468 Warning BaseTestLog.cpp(31): Arg:1, 2, 3, 4, 5, 6
2008-04-10 15:05:26.468 Warning BaseTestLog.cpp(32): Arg:1, 2, 3, 4, 5, 6, 7
2008-04-10 15:05:26.468 Warning BaseTestLog.cpp(33): Arg:1, 2, 3, 4, 5, 6, 7, 8
2008-04-10 15:05:26.468 Warning BaseTestLog.cpp(34): Arg:1, 2, 3, 4, 5, 6, 7, 8, 9
2008-04-10 15:05:26.469 Error BaseTestLog.cpp(36): (0):操作成功完成。
2008-04-10 15:05:26.469 Exception BaseTestLog.cpp(44): test of c ++ exception.
2008-04-10 15:05:26.469 Message BaseTestLog.cpp(52):
00000000: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000010: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
00000020: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F !"#$&'()*+,-./
00000030: 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 0123456789:;<=>?
00000040: 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F @ABCDEFGHIJKLMNO
00000050: 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F PQRSTUVWXYZ[/]^_
00000060: 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F `abcdefghijklmno
00000070: 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F pqrstuvwxyz{|}~
00000080: 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F €亗儎厗噲墛媽崕?
00000090: 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F 悜挀敃枟槞殯湞灍
000000A0: A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF 牎ⅲぅΗī
000000B0: B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF 氨渤吹斗腹夯冀究
000000C0: C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF 懒旅呐魄壬仕掏蜗
000000D0: D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF 醒矣哉肿刭谯茌捱
000000E0: E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF 噌忏溴骁栝觌祉铒
000000F0: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF 瘃蝮趱鲼?
头文件CxLog.h 下载地址 http://download.csdn.net/source/408048
直接拷贝也行,只要一个头文件就好
/*
CxLog (WIN32) free version 0.1
Compiled by: C++ BUILDER 6, X; VC++ 6, 7, 8; GCC 3.4.5, 4.2.1; Intel C++ 9
Writer: llbird
Mail : [email protected]
Blog : http:///blog.csdn.net/wujian53
Copyright(c) 2005.5 - 2008.3
void Test()
{
LOG(_T("Test Log"));
LOG1(_T("Arg:%d"), 1);
LOG2(_T("Arg:%d, %d"), 1, 2);
LOG_WARN(_T("Test Log"));
LOG_WARN1(_T("Arg:%d"), 1);
LOG_LAST_ERROR();
try
{
throw std::runtime_error("test of c ++ exception.");
}
catch (const std::exception &e)
{
LOGE(e);
}
BYTE bin[256];
for(int i = 0; i < 256; i++)
bin[i] = i;
LOG_BIN(bin, 256);
#ifdef __GNUC__
LOGN(_T("test for LogN :%d, %d, %d"), 1, 2, 3);
#endif
}
*/
#ifndef _CX_LOG_H_
#define _CX_LOG_H_
#if defined(_MSC_VER)
#pragma warning(disable: 4530)
#endif
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include <list>
#include <iterator>
#include <stdexcept>
#include <exception>
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
#include <comdef.h>
#endif
#include <tchar.h>
#include <process.h>
#include <windows.h>
//////////////////////////////////////////////////////////////////////////
///文件型多线程日志类 class for log file
#ifndef CX_LOG_DEFAULT_FORMAT
#if (defined(_MSC_VER) && _MSC_VER<=1310) || defined(__BORLANDC__) || (defined(__GNUC__) && defined(_UNICODE))
#define CX_LOG_DEFAULT_FORMAT _T("%s %s %s(%d): %s/r/n")
#else
#define CX_LOG_DEFAULT_FORMAT _T("%s %s %s(%s, %d): %s/r/n")
#endif
#endif
#ifndef CX_LOG_DEFAULT_FORMAT_SIZE
#define CX_LOG_DEFAULT_FORMAT_SIZE 1024
#endif
#ifndef CX_LOG_REPLACE_CONTROL
#define CX_LOG_REPLACE_CONTROL true
#endif
#ifndef CX_LOG_REPLACE_ASCII
#define CX_LOG_REPLACE_ASCII _T(' ')
#endif
class CxLog
{
public:
enum EnumType{
CX_LOG_MESSAGE = 0,
CX_LOG_WARNING,
CX_LOG_EXCEPTION,
CX_LOG_ERROR
};
static CxLog& Instance()
{
static bool alive = false;
static CxLog log(alive);
if(!alive)
{
OutputDebugString(_T("CxLog has destroy!"));
throw std::runtime_error("CxLog has destroy!");
}
return log;
}
struct Item
{
SYSTEMTIME _Time;//>time stamp
TCHAR _szTime[24];
LPTSTR _szSrc;//>source file name
LPTSTR _szFunc;//>founction name
ULONG _uLine;//>line number
EnumType _eType;//
LPTSTR _szDesc;//>content
LPBYTE _pBin;//>binary data szBuffer
ULONG _uBinSize;//>the size of binary data szBuffer
Item()
{
InitItem(NULL, NULL, 0, CX_LOG_MESSAGE, NULL, NULL, 0);
}
Item(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, EnumType eType,
LPCTSTR szDesc, LPVOID pBin = NULL, ULONG uSize = 0)
{
InitItem(szSrc, szFunc, uLine, eType, szDesc, pBin, uSize);
}
~Item()
{
ReleaseStringBuffer(_szSrc);
ReleaseStringBuffer(_szFunc);
ReleaseStringBuffer(_szDesc);
if(_pBin)
{
delete []_pBin;
_pBin = NULL;
}
}
VOID InitItem(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, EnumType eType,
LPCTSTR szDesc, LPVOID pBin, ULONG uSize)
{
GetLocalTime(&_Time);
wsprintf(_szTime, _T("%04d-%02d-%02d %02d:%02d:%02d.%03d"),
_Time.wYear,
_Time.wMonth,
_Time.wDay,
_Time.wHour,
_Time.wMinute,
_Time.wSecond,
_Time.wMilliseconds
);
_eType = eType;
_uBinSize = _uLine = 0;
_szSrc = _szFunc = _szDesc = NULL;
_pBin = NULL;
if(szSrc)
{
LPCTSTR p = szSrc;
#ifndef CX_LOG_FULL_SOURCE_NAME
p = szSrc + _tcslen(szSrc);
while(p>szSrc && *p!=_T('//'))
p--;
if(*p == _T('//'))
p++;
#endif
AllocStringBuffer(_szSrc, p);
_uLine = uLine;
}
AllocStringBuffer(_szFunc, szFunc);
AllocStringBuffer(_szDesc, szDesc);
if(pBin && uSize)
{
_pBin = new BYTE[uSize];
assert(_pBin);
memcpy(_pBin, pBin, uSize);
_uBinSize = uSize;
}
}
VOID AllocStringBuffer(LPTSTR& szDest, LPCTSTR& szSrc)
{
if(szSrc)
{
ULONG uSize = _tcslen(szSrc) + 1;
szDest = new TCHAR[uSize];
assert(szDest);
memcpy(szDest, szSrc, uSize*sizeof(TCHAR));
}
}
VOID ReleaseStringBuffer(LPTSTR& lpDest)
{
if(lpDest)
{
delete []lpDest;
lpDest = NULL;
}
}
LPTSTR Format(LPTSTR szBuffer, ULONG uSize, ULONG* pSize = NULL)
{
static LPCTSTR szType[] = {_T("Message"), _T("Warning"), _T("Exception"), _T("Error")};
if(!szBuffer)
return szBuffer;
int iLen;
#if (defined(_MSC_VER) && _MSC_VER<=1310) || defined(__BORLANDC__) || (defined(__GNUC__) && defined(_UNICODE))
iLen = _sntprintf(szBuffer, uSize,
CX_LOG_DEFAULT_FORMAT,
_szTime, szType[_eType],
_szSrc?_szSrc:_T(""), _uLine,
_szDesc?_szDesc:_T(""));
#else
iLen = _sntprintf(szBuffer, uSize,
CX_LOG_DEFAULT_FORMAT,
_szTime, szType[_eType],
_szSrc?_szSrc:_T(""), _szFunc?_szFunc:_T(""), _uLine,
_szDesc?_szDesc:_T(""));
#endif
if(iLen>4 && !_tcsncmp(szBuffer+iLen-4, _T("/r/n"), 2))
*(szBuffer+iLen-2) = TCHAR(NULL), iLen -= 2;
if(pSize)
*pSize = iLen;
return szBuffer;
}
LPTSTR FormatBinary(LPTSTR szBuffer, ULONG uSize, ULONG* pSize = NULL,
bool bReplace = CX_LOG_REPLACE_CONTROL,
TCHAR chReplaceAscii = CX_LOG_REPLACE_ASCII)
{
return FormatBinary(_pBin, _uBinSize, szBuffer, uSize, pSize,
bReplace, chReplaceAscii);
}
LPTSTR FormatBinary(LPVOID lpBin, ULONG uBinSize,
LPTSTR szBuffer, ULONG uSize, ULONG* pSize = NULL,
bool bReplace = CX_LOG_REPLACE_CONTROL,
TCHAR chReplaceAscii = CX_LOG_REPLACE_ASCII)
{
TCHAR temp[8+2+3*16+16+2+1];
ULONG uActualSize = 0;
if(!_pBin)
{
if(pSize)
*pSize = uActualSize;
return szBuffer;
}
if(!szBuffer)
{
uSize = ((_uBinSize>>4)+1)*(8+2+3*16+16+2)+1;
szBuffer = new TCHAR[uSize];
assert(szBuffer);
}
for(ULONG p = 0; p<_uBinSize && uActualSize<uSize-1; p += 16)
{
wsprintf(temp, _T("%08X: "), p);
int i;
for(i = 0; i < 16; i++)
{
if(p+i<_uBinSize)
{
BYTE x = *(_pBin+p+i), t;
t = (x&0xF0) >> 4;
*(temp+8+2+3*i) = t>9 ? _T('A')+t-10 : _T('0')+t;
t = x&0x0F;
*(temp+8+2+3*i+1) = t>9 ? _T('A')+t-10 : _T('0')+t;
*(temp+8+2+3*i+2) = _T(' ');
}
else
_tcscpy(temp+8+2+3*i, _T(" "));
}
for(i = 0; i < 16; i++)
{
if(p+i<_uBinSize)
*(temp+8+2+3*16+i) = (bReplace&&_istcntrl(TCHAR(*(_pBin+p+i)))) ? chReplaceAscii : *(_pBin+p+i);
else
*(temp+8+2+3*16+i) = _T(' ');
}
_tcscpy(temp+8+2+3*16+16, _T("/r/n"));
ULONG uLen = uSize-uActualSize-1>8+2+3*16+16+2? 8+2+3*16+16+2 : uSize-uActualSize-1;
memcpy(szBuffer+uActualSize, temp, uLen*sizeof(TCHAR));
uActualSize += uLen;
}
if(pSize)
*pSize = uActualSize;
szBuffer[uActualSize] = TCHAR(NULL);
return szBuffer;
}
};
LPTSTR GetLogFileName()
{
#if defined(CX_LOG_BY_DAY) || defined(CX_LOG_BY_WEEK) || defined(CX_LOG_BY_MONTH) || defined(CX_LOG_BY_YEAR)
time_t now = time(NULL);
#if defined(CX_LOG_BY_DAY)
_tcsftime(_szFileName, MAX_PATH, _T(".//Log//%Y%m%d.log"), localtime(&now));
#elif defined(CX_LOG_BY_WEEK)
_tcsftime(_szFileName, MAX_PATH, _T(".//Log//%Y%W.log"), localtime(&now));
#elif defined(CX_LOG_BY_MONTH)
_tcsftime(_szFileName, MAX_PATH, _T(".//Log//%Y%m.log"), localtime(&now));
#elif defined(CX_LOG_BY_YEAR)
_tcsftime(_szFileName, MAX_PATH, _T(".//Log//%Y.log"), localtime(&now));
#endif
#endif
return _szFileName;
}
public:
CxLog(bool &alive) : _bAlive(alive)
{
_bAlive = true;
#ifdef CX_LOG_FILE_NAME
ULONG uSize = _tcslen(CX_LOG_FILE_NAME) + 1;
uSize = uSize>MAX_PATH ? MAX_PATH : uSize;
memcpy(_szFileName, CX_LOG_FILE_NAME, uSize*sizeof(TCHAR));
#else
CreateDirectory(_T(".//Log"), NULL); //>create log sub dir
#if !defined(CX_LOG_BY_DAY) && !defined(CX_LOG_BY_WEEK) && !defined(CX_LOG_BY_MONTH) && !defined(CX_LOG_BY_YEAR)
time_t now = time(NULL);
_tcsftime(_szFileName, MAX_PATH, _T(".//Log//%Y%m%d.log"), localtime(&now));
#endif
#endif
_TerminateEvent = CreateEvent(0, TRUE, FALSE, NULL);
_LogHandle = CreateEvent(0, FALSE, FALSE, NULL);
::InitializeCriticalSection(&_LogMutex);
#ifdef _MT
unsigned int id;
_hThreadHandle = (HANDLE)::_beginthreadex(NULL, 0, StaticThreadProc, this, 0, &id);
#else
DWORD id;
_hThreadHandle = ::CreateThread(NULL, 0, StaticThreadProc, this, 0, &id);
#endif
}
~CxLog()
{
Destroy();
}
VOID Destroy()
{
_bAlive = false;
if(_hThreadHandle)
{
SetEvent(_TerminateEvent);
if(::WaitForSingleObject(_hThreadHandle, 500) != WAIT_OBJECT_0)
::TerminateThread(_hThreadHandle, 0);
CloseHandle(_hThreadHandle);
}
::DeleteCriticalSection(&_LogMutex);
}
VOID Lock()
{
::EnterCriticalSection(&_LogMutex);
}
VOID Unlock()
{
::LeaveCriticalSection(&_LogMutex);
}
VOID Log(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, EnumType eType,
LPCTSTR szDesc, LPVOID pBin = NULL, ULONG uSize = 0)
{
Item* p = new Item(szSrc, szFunc, uLine, eType, szDesc, pBin, uSize);
#if defined(_CONSOLE) || defined(_DEBUG)
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE];
p->Format(szBuffer, CX_LOG_DEFAULT_FORMAT_SIZE);
LPTSTR pBinStr = p->FormatBinary(p->_pBin, p->_uBinSize, NULL, 0, &uSize);
#ifdef _CONSOLE
if(szBuffer)
_tprintf(szBuffer);
if(pBinStr)
_tprintf(pBinStr);
#endif
#ifdef _DEBUG
OutputDebugString(szBuffer);
OutputDebugString(pBinStr);
#endif
delete []pBinStr;
#endif
Lock();
_ItemList.push_back(p);
Unlock();
SetEvent(_LogHandle);
}
VOID LogBin(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, EnumType eType, LPVOID pBin, ULONG uSize)
{
Log(szSrc, szFunc, uLine, eType, NULL, pBin, uSize);
}
VOID LogN(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, EnumType eType, LPCTSTR szFormat, ...)
{
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE] = {0};
va_list va;
va_start(va, szFormat);
_vsntprintf(szBuffer, 1024-1, szFormat, va);
va_end(va);
Log(szSrc, szFunc, uLine, eType, szBuffer);
}
#ifdef _INC_COMDEF
VOID Log(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, _com_error &e)
{
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE] = {0};
_sntprintf(szBuffer, 1024, _T("_com_error Code=%08X Meaning=%s Source=%s Description=%s"),
e.Error(),
(LPCSTR)_bstr_t(e.ErrorMessage()),
(LPCSTR)e.Source(),
(LPCSTR)e.Description());
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, szBuffer);
}
#endif
VOID LogLastError(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, DWORD dwError)
{
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE] = {0};
int iLen = _stprintf(szBuffer, _T("(%d):"), dwError);
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
szBuffer + iLen,
CX_LOG_DEFAULT_FORMAT_SIZE - iLen - 3,
NULL
);
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_ERROR, szBuffer);
}
#if defined(INC_VCL) && defined(__BORLANDC__)
VOID Log(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, const Exception *e)
{
#ifdef _UNICODE
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE];
e->Message.WideChar(szBuffer, CX_LOG_DEFAULT_FORMAT_SIZE);
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, szBuffer);
#else
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, e->Message.c_str());
#endif
}
VOID Log(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, const Exception &e)
{
#ifdef _UNICODE
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE];
e.Message.WideChar(szBuffer, CX_LOG_DEFAULT_FORMAT_SIZE);
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, szBuffer);
#else
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, e.Message.c_str());
#endif
}
#endif
#if (defined(_MFC_VER) && defined(__AFX_H__))
VOID Log(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, const CException *e)
{
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE];
e->GetErrorMessage(szBuffer, CX_LOG_DEFAULT_FORMAT_SIZE, NULL);
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, szBuffer);
}
VOID Log(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, const CException &e)
{
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE];
e.GetErrorMessage(szBuffer, CX_LOG_DEFAULT_FORMAT_SIZE, NULL);
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, szBuffer);
}
#endif
VOID Log(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, const std::exception *e)
{
#ifdef _UNICODE
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE];
MultiByteToWideChar(CP_ACP, 0, e->what(), -1, szBuffer, CX_LOG_DEFAULT_FORMAT_SIZE);
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, szBuffer);
#else
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, e->what());
#endif
}
VOID Log(LPCTSTR szSrc, LPCTSTR szFunc, ULONG uLine, const std::exception &e)
{
#ifdef _UNICODE
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE];
MultiByteToWideChar(CP_ACP, 0, e.what(), -1, szBuffer, CX_LOG_DEFAULT_FORMAT_SIZE);
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, szBuffer);
#else
Log(szSrc, szFunc, uLine, CxLog::CX_LOG_EXCEPTION, e.what());
#endif
}
protected:
bool& _bAlive;
CRITICAL_SECTION _LogMutex;
std::list<Item*> _ItemList;
TCHAR _szFileName[MAX_PATH];
HANDLE _hThreadHandle, _LogHandle, _TerminateEvent;
virtual VOID Run()
{
HANDLE HandleArray[2];
HandleArray[0] = _LogHandle;
HandleArray[1] = _TerminateEvent;
for(;;)
{
DWORD ret = ::WaitForMultipleObjects(2, HandleArray, false, INFINITE);
if(ret == WAIT_OBJECT_0)
{
HANDLE hHandle = ::CreateFile(
GetLogFileName(),
GENERIC_READ | GENERIC_WRITE ,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if(!hHandle)
return;
DWORD NumberOfBytesWritten;
SetFilePointer(hHandle, 0, 0, FILE_END);
try
{
Lock();
while(_ItemList.size())
{
Item *p = _ItemList.front();
TCHAR szBuffer[CX_LOG_DEFAULT_FORMAT_SIZE];
ULONG uSize = 0;
p->Format(szBuffer, CX_LOG_DEFAULT_FORMAT_SIZE, &uSize);
WriteFile(hHandle, szBuffer, uSize*sizeof(TCHAR), &NumberOfBytesWritten, NULL);
if(p->_pBin && p->_uBinSize)
{
ULONG uSize = 0;
LPTSTR t = p->FormatBinary(p->_pBin, p->_uBinSize, NULL, 0, &uSize);
WriteFile(hHandle, t, uSize*sizeof(TCHAR), &NumberOfBytesWritten, NULL);
delete []t;
}
_ItemList.pop_front();
delete p;
}
Unlock();
}
catch (...)
{
Unlock();
}
SetEndOfFile(hHandle);
CloseHandle(hHandle);
}
if(ret == WAIT_OBJECT_0 + 1)
break;
}
}
private:
CxLog(const CxLog&);
CxLog& operator=(CxLog&);
#ifdef _MT
static UINT APIENTRY StaticThreadProc(LPVOID lpPara) //允许C多线程运行库
#else
static DWORD WINAPI StaticThreadProc(LPVOID lpPara)
#endif
{
((CxLog*)(lpPara))->Run();
#ifdef _MT
::_endthreadex(0);
#endif
return 0;
}
};
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
#ifdef _UNICODE
#define __TFILE__ __WFILE__
#else
#define __TFILE__ __FILE__
#endif
#if (_MSC_VER && _MSC_VER<=1200) || (__BORLANDC__)
#define __FUNCTION__ NULL
#define __WFUNCTION__ NULL
#else //_MSC_VER>1200 __GNUC__ __INTEL_COMPILER
#define __WFUNCTION__ WIDEN(__FUNCTION__)
#endif
#ifdef _UNICODE
#ifdef __GNUC__
#define __TFUNCTION__ NULL
#else
#define __TFUNCTION__ __WFUNCTION__
#endif
#else
#define __TFUNCTION__ __FUNCTION__
#endif
#define BASE_LOG(type, msg) CxLog::Instance().Log(__TFILE__, __TFUNCTION__, __LINE__, (type), (msg))
#define LOG(msg) BASE_LOG(CxLog::CX_LOG_MESSAGE, (msg))
#define LOG_WARN(msg) BASE_LOG(CxLog::CX_LOG_WARNING, (msg))
#define LOGE(e) CxLog::Instance().Log(__TFILE__, __TFUNCTION__, __LINE__, (e))
#define LOG_ERR(msg) BASE_LOG(CxLog::CX_LOG_ERROR, (msg))
#define BASE_LOG_BIN(type, bin, size) CxLog::Instance().LogBin(__TFILE__, __TFUNCTION__, __LINE__, (type), (bin), (size))
#define LOG_BIN(bin, size) BASE_LOG_BIN(CxLog::CX_LOG_MESSAGE, (bin), (size))
#define LOG_WARN_BIN(bin, size) BASE_LOG_BIN(CxLog::CX_LOG_WARNING, (bin), (size))
#define LOG_ERR_BIN(bin, size) BASE_LOG_BIN(CxLog::CX_LOG_ERROR, (bin), (size))
#if __GNUC__ || __INTEL_COMPILER || _MSC_VER>1310
#define BASE_LOGN(type, msg, ...) CxLog::Instance().LogN(__TFILE__, __TFUNCTION__, __LINE__, (type), (msg), ##__VA_ARGS__)
#define LOGN(msg, ...) BASE_LOGN(CxLog::CX_LOG_MESSAGE, (msg), ##__VA_ARGS__)
#define LOGN_WARNN(msg, ...) BASE_LOGN(CxLog::CX_LOG_WARNING, (msg), ##__VA_ARGS__)
#define LOGN_ERRN(msg, ...) BASE_LOGN(CxLog::CX_LOG_ERROR, (msg), ##__VA_ARGS__)
#endif
#define PRE_LOG CxLog::Instance().LogN(__TFILE__, __TFUNCTION__, __LINE__, CxLog::CX_LOG_MESSAGE,
#define LOG1(str, p1) PRE_LOG (str), (p1))
#define LOG2(str, p1, p2) PRE_LOG (str), (p1), (p2))
#define LOG3(str, p1, p2, p3) PRE_LOG (str), (p1), (p2), (p3))
#define LOG4(str, p1, p2, p3, p4) PRE_LOG (str), (p1), (p2), (p3), (p4))
#define LOG5(str, p1, p2, p3, p4, p5) PRE_LOG (str), (p1), (p2), (p3), (p4), (p5))
#define LOG6(str, p1, p2, p3, p4, p5, p6) PRE_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6))
#define LOG7(str, p1, p2, p3, p4, p5, p6, p7) PRE_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7))
#define LOG8(str, p1, p2, p3, p4, p5, p6, p7, p8) PRE_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7), (p8))
#define LOG9(str, p1, p2, p3, p4, p5, p6, p7, p8, p9) PRE_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7), (p8), (p9))
#define PRE_T_LOG CxLog::Instance().LogN(__TFILE__, __TFUNCTION__, __LINE__,
#define LOG_T1(t, str, p1) PRE_T_LOG (t), (str), (p1))
#define LOG_T2(t, str, p1, p2) PRE_T_LOG (t), (str), (p1), (p2))
#define LOG_T3(t, str, p1, p2, p3) PRE_T_LOG (t), (str), (p1), (p2), (p3))
#define LOG_T4(t, str, p1, p2, p3, p4) PRE_T_LOG (t), (str), (p1), (p2), (p3), (p4))
#define LOG_T5(t, str, p1, p2, p3, p4, p5) PRE_T_LOG (t), (str), (p1), (p2), (p3), (p4), (p5))
#define LOG_T6(t, str, p1, p2, p3, p4, p5, p6) PRE_T_LOG (t), (str), (p1), (p2), (p3), (p4), (p5), (p6))
#define LOG_T7(t, str, p1, p2, p3, p4, p5, p6, p7) PRE_T_LOG (t), (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7))
#define LOG_T8(t, str, p1, p2, p3, p4, p5, p6, p7, p8) PRE_T_LOG (t), (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7), (p8))
#define LOG_T9(t, str, p1, p2, p3, p4, p5, p6, p7, p8, p9) PRE_T_LOG (t), (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7), (p8), (p9))
#define PRE_WARN_LOG CxLog::Instance().LogN(__TFILE__, __TFUNCTION__, __LINE__, CxLog::CX_LOG_WARNING,
#define LOG_WARN1(str, p1) PRE_WARN_LOG (str), (p1))
#define LOG_WARN2(str, p1, p2) PRE_WARN_LOG (str), (p1), (p2))
#define LOG_WARN3(str, p1, p2, p3) PRE_WARN_LOG (str), (p1), (p2), (p3))
#define LOG_WARN4(str, p1, p2, p3, p4) PRE_WARN_LOG (str), (p1), (p2), (p3), (p4))
#define LOG_WARN5(str, p1, p2, p3, p4, p5) PRE_WARN_LOG (str), (p1), (p2), (p3), (p4), (p5))
#define LOG_WARN6(str, p1, p2, p3, p4, p5, p6) PRE_WARN_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6))
#define LOG_WARN7(str, p1, p2, p3, p4, p5, p6, p7) PRE_WARN_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7))
#define LOG_WARN8(str, p1, p2, p3, p4, p5, p6, p7, p8) PRE_WARN_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7), (p8))
#define LOG_WARN9(str, p1, p2, p3, p4, p5, p6, p7, p8, p9) PRE_WARN_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7), (p8), (p9))
#define PRE_EXCEPTION_LOG CxLog::Instance().LogN(__TFILE__, __TFUNCTION__, __LINE__, CxLog::CX_LOG_EXCEPTION,
#define LOG_EXCEPTION1(str, p1) PRE_EXCEPTION_LOG (str), (p1))
#define LOG_EXCEPTION2(str, p1, p2) PRE_EXCEPTION_LOG (str), (p1), (p2))
#define LOG_EXCEPTION3(str, p1, p2, p3) PRE_EXCEPTION_LOG (str), (p1), (p2), (p3))
#define LOG_EXCEPTION4(str, p1, p2, p3, p4) PRE_EXCEPTION_LOG (str), (p1), (p2), (p3), (p4))
#define LOG_EXCEPTION5(str, p1, p2, p3, p4, p5) PRE_EXCEPTION_LOG (str), (p1), (p2), (p3), (p4), (p5))
#define LOG_EXCEPTION6(str, p1, p2, p3, p4, p5, p6) PRE_EXCEPTION_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6))
#define LOG_EXCEPTION7(str, p1, p2, p3, p4, p5, p6, p7) PRE_EXCEPTION_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7))
#define LOG_EXCEPTION8(str, p1, p2, p3, p4, p5, p6, p7, p8) PRE_EXCEPTION_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7), (p8))
#define LOG_EXCEPTION9(str, p1, p2, p3, p4, p5, p6, p7, p8, p9) PRE_EXCEPTION_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7), (p8), (p9))
#define PRE_ERR_LOG CxLog::Instance().LogN(__TFILE__, __TFUNCTION__, __LINE__, CxLog::CX_LOG_ERROR,
#define LOG_ERR1(str, p1) PRE_ERR_LOG (str), (p1))
#define LOG_ERR2(str, p1, p2) PRE_ERR_LOG (str), (p1), (p2))
#define LOG_ERR3(str, p1, p2, p3) PRE_ERR_LOG (str), (p1), (p2), (p3))
#define LOG_ERR4(str, p1, p2, p3, p4) PRE_ERR_LOG (str), (p1), (p2), (p3), (p4))
#define LOG_ERR5(str, p1, p2, p3, p4, p5) PRE_ERR_LOG (str), (p1), (p2), (p3), (p4), (p5))
#define LOG_ERR6(str, p1, p2, p3, p4, p5, p6) PRE_ERR_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6))
#define LOG_ERR7(str, p1, p2, p3, p4, p5, p6, p7) PRE_ERR_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7))
#define LOG_ERR8(str, p1, p2, p3, p4, p5, p6, p7, p8) PRE_ERR_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7), (p8))
#define LOG_ERR9(str, p1, p2, p3, p4, p5, p6, p7, p8, p9) PRE_ERR_LOG (str), (p1), (p2), (p3), (p4), (p5), (p6), (p7), (p8), (p9))
#define LOG_LAST_ERROR() CxLog::Instance().LogLastError(__TFILE__, __TFUNCTION__, __LINE__, GetLastError())
#endif //_CX_LOG_H_