日志记录模块
#include
<
Windows.h
>
#include " Log_msg.h "
int TestWinerrReturn()
{
LOG_WINERROR_MSG_RETURN(10, 5);
return -100;
}
int TestErrmsgReturn()
{
LOG_WINERROR_MSG_RETURN(10, 5);
return -100;
}
int TestCombine()
{
LOG_MSG_ERROR_RETURN(10, _T("ERRORNO:%d, description: %s, return val:%d"), 5, LOG_WIN32ERROR_TO_MSG_WRAPPER(5), 10);
return 1;
}
int TestWrapper()
{
LOG_MSG_ERROR(LOG_WIN32ERROR_TO_MSG_WRAPPER(5));
return 0;
}
int _tmain( int argc, _TCHAR * argv[])
{
LOG_CONFIGURATION conf = {true, Log_entity::LL_INFO, Log_entity::LO_FILE, _T("c:\\987.log")};
LOG_MSG_INITIALIZE(conf);
LOG_MSG_INFO(_T("LOG_MSG_INFO1"));
LOG_MSG_INFO(_T("LOG_MSG_INFO1:%s"), _T("info2"));
LOG_MSG_WARNING((_T("LOG_MSG_WARNING")));
LOG_MSG_WARNING(_T("LOG_MSG_WARNING1:%s"), _T("warning"));
LOG_MSG_ERROR((_T("LOG_MSG_ERROR")));
LOG_MSG_ERROR(_T("LOG_MSG_ERROR1:%s"), _T("Error"));
if(TestWinerrReturn() != 10)
{
printf("TestWinerrReturn failed");
}
if(TestErrmsgReturn() != 10)
{
printf("TestErrmsgReturn failed");
}
LOG_WINERROR_MSG((5));
if(TestCombine() != 10)
{
printf("TestCombine failed");
}
system("pause");
return 0;
}
#include " Log_msg.h "
int TestWinerrReturn()
{
LOG_WINERROR_MSG_RETURN(10, 5);
return -100;
}
int TestErrmsgReturn()
{
LOG_WINERROR_MSG_RETURN(10, 5);
return -100;
}
int TestCombine()
{
LOG_MSG_ERROR_RETURN(10, _T("ERRORNO:%d, description: %s, return val:%d"), 5, LOG_WIN32ERROR_TO_MSG_WRAPPER(5), 10);
return 1;
}
int TestWrapper()
{
LOG_MSG_ERROR(LOG_WIN32ERROR_TO_MSG_WRAPPER(5));
return 0;
}
int _tmain( int argc, _TCHAR * argv[])
{
LOG_CONFIGURATION conf = {true, Log_entity::LL_INFO, Log_entity::LO_FILE, _T("c:\\987.log")};
LOG_MSG_INITIALIZE(conf);
LOG_MSG_INFO(_T("LOG_MSG_INFO1"));
LOG_MSG_INFO(_T("LOG_MSG_INFO1:%s"), _T("info2"));
LOG_MSG_WARNING((_T("LOG_MSG_WARNING")));
LOG_MSG_WARNING(_T("LOG_MSG_WARNING1:%s"), _T("warning"));
LOG_MSG_ERROR((_T("LOG_MSG_ERROR")));
LOG_MSG_ERROR(_T("LOG_MSG_ERROR1:%s"), _T("Error"));
if(TestWinerrReturn() != 10)
{
printf("TestWinerrReturn failed");
}
if(TestErrmsgReturn() != 10)
{
printf("TestErrmsgReturn failed");
}
LOG_WINERROR_MSG((5));
if(TestCombine() != 10)
{
printf("TestCombine failed");
}
system("pause");
return 0;
}
/**/
//////////////////////////////////////////////////////////////////////////
// file Log_msg.h
//
// Copyright (c) 2010 robert xiao. All Rights Reserved. [email protected]
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
// agreement, is hereby granted, provided that the above copyright notice,
// this paragraph and the following two paragraphs appear in all copies,
// modifications, and distributions.
//
//
// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
//
/**/ //////////////////////////////////////////////////////////////////////////
/**/ /**
* @file: Log_msg.h
*
* @brief: provide write log message function, macro, and assistant class.
*
* @author: Robert xiao
*
*/
#pragma once
#if !defined (__TFILE__)
#define __TFILE__ _T(__FILE__)
#endif
/**/ /* get description from a windows error. */
#if !defined LOG_WIN32ERROR_TO_MSG_WRAPPER
#define LOG_WIN32ERROR_TO_MSG_WRAPPER(x) \
Log_winErrorMsg(x)
#endif
/**/ /* Intend to initialize the logger instance */
#if !defined (LOG_MSG_INITIALIZE)
#define LOG_MSG_INITIALIZE(conf) \
{ Log_entity::Initialize(conf);}
#endif
/**/ /* Intend to print information */
#if !defined (LOG_MSG_INFO)
#define LOG_MSG_INFO(x, ) \
do { \
Log_entity::GetInstance()->Log(Log_entity::LL_INFO, __TFILE__, __LINE__, x, __VA_ARGS__);\
} while ( 0 )
#endif
/**/ /* print warning message */
#if !defined (LOG_MSG_WARNING)
#define LOG_MSG_WARNING(x,) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_WARNING, __TFILE__, __LINE__, x, __VA_ARGS__); \
} while ( 0 )
#endif
/**/ /* print error message */
#if !defined (LOG_MSG_ERROR)
#define LOG_MSG_ERROR(x,) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, x, __VA_ARGS__); \
} while ( 0 )
#endif
/**/ /* print error message and return y */
#if !defined (LOG_MSG_ERROR_RETURN)
#define LOG_MSG_ERROR_RETURN(y, x,) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, x, __VA_ARGS__); \
return y;\
} while ( 0 )
#endif
/**/ /* print fatal message */
#if !defined (LOG_MSG_FATAL)
#define LOG_MSG_FATAL(x,) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_FATAL, __TFILE__, __LINE__, x, __VA_ARGS__); \
} while ( 0 )
#endif
/**/ /* print fatal message and return */
#if !defined (LOG_MSG_FATAL_RETURN)
#define LOG_MSG_FATAL_RETURN(y, x, ) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_FATAL, __TFILE__, __LINE__, x , __VA_ARGS__); \
return y;\
} while ( 0 )
#endif
/**/ /* print error no. description */
#if !defined (LOG_WINERROR_MSG)
#define LOG_WINERROR_MSG(x)\
do { \
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, Log_winErrorMsg(x));\
} while ( 0 )
#endif
/**/ /* print error no. description and return */
#if !defined (LOG_WINERROR_MSG_RETURN)
#define LOG_WINERROR_MSG_RETURN(y, x)\
do { \
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, Log_winErrorMsg(x));\
return y; \
} while ( 0 )
#endif
/**/ /* print COM result description */
#if !defined (LOG_HRESULT_MSG)
#define LOG_HRESULT_MSG(x) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, Log_winErrorMsg(x & 0x0000ffff));\
} while ( 0 )
#endif
/**/ /* print COM result description and return */
#if !defined (LOG_HRESULT_MSG_RETURN)
#define LOG_HRESULT_MSG_RETURN(y, x) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, Log_winErrorMsg(x & 0x0000ffff));\
return y; \
} while ( 0 )
#endif
#include < Windows.h >
#define LOG_API
class LOG_API Log_critical {
public:
Log_critical(){
m_lEntered = 0;
::InitializeCriticalSection(&m_sec);
}
~Log_critical(){
::DeleteCriticalSection(&m_sec);
}
void Lock(DWORD){
::EnterCriticalSection(&m_sec);
++m_lEntered;
}
void UnLock(){
if(m_lEntered > 0)
{
--m_lEntered;
::LeaveCriticalSection(&m_sec);
}
}
private:
CRITICAL_SECTION m_sec;
LONG m_lEntered;
} ;
template < typename T, DWORD dwWaitTime = INFINITE >
class LOG_API Log_manualLock {
public:
Log_manualLock(T& t, bool bLock)
:m_lock(t)
,m_bLocked(false){
m_lock = t;
if(bLock){
Lock();
}
}
~Log_manualLock(){
if(m_bLocked){
UnLock();
}
}
void Lock(){
m_lock->Lock(dwWaitTime);
m_bLocked = true;
}
void UnLock(){
if(m_bLocked){
m_lock->UnLock();
m_bLocked = false;
}
}
private:
T &m_lock;
bool m_bLocked;
} ;
template < typename T, DWORD dwWaitTimeOut = INFINITE >
class LOG_API Log_autoLock {
public:
Log_autoLock(T &t)
:m_lock(t){
m_lock.Lock(dwWaitTimeOut);
}
~Log_autoLock(){
m_lock.UnLock();
}
private:
T &m_lock;
} ;
class LOG_API Log_winErrorMsg {
typedef TCHAR _character_type;
typedef _character_type* _p_character_type;
typedef const TCHAR* _pc_character_type;
public:
Log_winErrorMsg(int nError)
:_szBuf(NULL){
::FormatMessage (
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
nError,
MAKELANGID (LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR ) &_szBuf,
0,
NULL);
}
~Log_winErrorMsg(){
if(_szBuf)
LocalFree(_szBuf);
}
operator _pc_character_type(){
return _szBuf;
};
_pc_character_type c_str(){
return _szBuf;
}
private:
_p_character_type _szBuf;
} ;
struct _LOG_CONFIGURATION;
/**/ /**
* @class Log_entity
*
* @brief provide a variable length argument message logging
*
* @This class is liable for write the log message to standard output,
* DebugView tool , File.
*
*
*/
class LOG_API Log_entity
{
typedef Log_autoLock< Log_critical > _AutoCritical;
public: // embed custom type
enum LOG_LEVEL{
LL_INFO = 0,
LL_WARNING,
LL_ERROR,
LL_FATAL
};
enum LOG_OUTPUT{
LO_NONE = 0x0,
LO_DEBUG = 0x2,
LO_STANDARD = 0x4,
LO_STANDARD_DEBUG = 0X6,
LO_FILE = 0x8,
LO_FILE_DEBUG = 0X0A,
LO_FILE_STANDARD =0X0C,
};
public:
static Log_entity* GetInstance();
static void Initialize(struct _LOG_CONFIGURATION& con);
void Log(LOG_LEVEL le, LPCTSTR szMsg, );
void Log(LOG_LEVEL le, LPCTSTR szFile, int nLine, LPCTSTR szMsg, );
static void Dumb(LPCTSTR szMsg, ){}
private:
void _write(LPCTSTR szMsg);
/**//* Do nothing */
void _writeNone( LPCTSTR){}
/**//* Write the message to DebugView */
void _writeDebug( LPCTSTR szMsg);
/**//* Write the message to stderr */
void _writeStandard( LPCTSTR szMsg);
/**//* Write the message to the file */
void _writeFile( LPCTSTR szMsg);
bool CanLog(LOG_LEVEL le);
private:
static Log_critical m_sCritical;
} ;
typedef struct _LOG_CONFIGURATION {
bool _bNeedTime;
Log_entity::LOG_LEVEL _lowerLevel;
Log_entity::LOG_OUTPUT _output;
TCHAR _szLogFile[MAX_PATH];
} LOG_CONFIGURATION, * LPLOG_CONFIGURATION;
// file Log_msg.h
//
// Copyright (c) 2010 robert xiao. All Rights Reserved. [email protected]
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
// agreement, is hereby granted, provided that the above copyright notice,
// this paragraph and the following two paragraphs appear in all copies,
// modifications, and distributions.
//
//
// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
//
/**/ //////////////////////////////////////////////////////////////////////////
/**/ /**
* @file: Log_msg.h
*
* @brief: provide write log message function, macro, and assistant class.
*
* @author: Robert xiao
*
*/
#pragma once
#if !defined (__TFILE__)
#define __TFILE__ _T(__FILE__)
#endif
/**/ /* get description from a windows error. */
#if !defined LOG_WIN32ERROR_TO_MSG_WRAPPER
#define LOG_WIN32ERROR_TO_MSG_WRAPPER(x) \
Log_winErrorMsg(x)
#endif
/**/ /* Intend to initialize the logger instance */
#if !defined (LOG_MSG_INITIALIZE)
#define LOG_MSG_INITIALIZE(conf) \
{ Log_entity::Initialize(conf);}
#endif
/**/ /* Intend to print information */
#if !defined (LOG_MSG_INFO)
#define LOG_MSG_INFO(x, ) \
do { \
Log_entity::GetInstance()->Log(Log_entity::LL_INFO, __TFILE__, __LINE__, x, __VA_ARGS__);\
} while ( 0 )
#endif
/**/ /* print warning message */
#if !defined (LOG_MSG_WARNING)
#define LOG_MSG_WARNING(x,) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_WARNING, __TFILE__, __LINE__, x, __VA_ARGS__); \
} while ( 0 )
#endif
/**/ /* print error message */
#if !defined (LOG_MSG_ERROR)
#define LOG_MSG_ERROR(x,) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, x, __VA_ARGS__); \
} while ( 0 )
#endif
/**/ /* print error message and return y */
#if !defined (LOG_MSG_ERROR_RETURN)
#define LOG_MSG_ERROR_RETURN(y, x,) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, x, __VA_ARGS__); \
return y;\
} while ( 0 )
#endif
/**/ /* print fatal message */
#if !defined (LOG_MSG_FATAL)
#define LOG_MSG_FATAL(x,) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_FATAL, __TFILE__, __LINE__, x, __VA_ARGS__); \
} while ( 0 )
#endif
/**/ /* print fatal message and return */
#if !defined (LOG_MSG_FATAL_RETURN)
#define LOG_MSG_FATAL_RETURN(y, x, ) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_FATAL, __TFILE__, __LINE__, x , __VA_ARGS__); \
return y;\
} while ( 0 )
#endif
/**/ /* print error no. description */
#if !defined (LOG_WINERROR_MSG)
#define LOG_WINERROR_MSG(x)\
do { \
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, Log_winErrorMsg(x));\
} while ( 0 )
#endif
/**/ /* print error no. description and return */
#if !defined (LOG_WINERROR_MSG_RETURN)
#define LOG_WINERROR_MSG_RETURN(y, x)\
do { \
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, Log_winErrorMsg(x));\
return y; \
} while ( 0 )
#endif
/**/ /* print COM result description */
#if !defined (LOG_HRESULT_MSG)
#define LOG_HRESULT_MSG(x) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, Log_winErrorMsg(x & 0x0000ffff));\
} while ( 0 )
#endif
/**/ /* print COM result description and return */
#if !defined (LOG_HRESULT_MSG_RETURN)
#define LOG_HRESULT_MSG_RETURN(y, x) \
do {\
Log_entity::GetInstance()->Log(Log_entity::LL_ERROR, __TFILE__, __LINE__, Log_winErrorMsg(x & 0x0000ffff));\
return y; \
} while ( 0 )
#endif
#include < Windows.h >
#define LOG_API
class LOG_API Log_critical {
public:
Log_critical(){
m_lEntered = 0;
::InitializeCriticalSection(&m_sec);
}
~Log_critical(){
::DeleteCriticalSection(&m_sec);
}
void Lock(DWORD){
::EnterCriticalSection(&m_sec);
++m_lEntered;
}
void UnLock(){
if(m_lEntered > 0)
{
--m_lEntered;
::LeaveCriticalSection(&m_sec);
}
}
private:
CRITICAL_SECTION m_sec;
LONG m_lEntered;
} ;
template < typename T, DWORD dwWaitTime = INFINITE >
class LOG_API Log_manualLock {
public:
Log_manualLock(T& t, bool bLock)
:m_lock(t)
,m_bLocked(false){
m_lock = t;
if(bLock){
Lock();
}
}
~Log_manualLock(){
if(m_bLocked){
UnLock();
}
}
void Lock(){
m_lock->Lock(dwWaitTime);
m_bLocked = true;
}
void UnLock(){
if(m_bLocked){
m_lock->UnLock();
m_bLocked = false;
}
}
private:
T &m_lock;
bool m_bLocked;
} ;
template < typename T, DWORD dwWaitTimeOut = INFINITE >
class LOG_API Log_autoLock {
public:
Log_autoLock(T &t)
:m_lock(t){
m_lock.Lock(dwWaitTimeOut);
}
~Log_autoLock(){
m_lock.UnLock();
}
private:
T &m_lock;
} ;
class LOG_API Log_winErrorMsg {
typedef TCHAR _character_type;
typedef _character_type* _p_character_type;
typedef const TCHAR* _pc_character_type;
public:
Log_winErrorMsg(int nError)
:_szBuf(NULL){
::FormatMessage (
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
nError,
MAKELANGID (LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR ) &_szBuf,
0,
NULL);
}
~Log_winErrorMsg(){
if(_szBuf)
LocalFree(_szBuf);
}
operator _pc_character_type(){
return _szBuf;
};
_pc_character_type c_str(){
return _szBuf;
}
private:
_p_character_type _szBuf;
} ;
struct _LOG_CONFIGURATION;
/**/ /**
* @class Log_entity
*
* @brief provide a variable length argument message logging
*
* @This class is liable for write the log message to standard output,
* DebugView tool , File.
*
*
*/
class LOG_API Log_entity
{
typedef Log_autoLock< Log_critical > _AutoCritical;
public: // embed custom type
enum LOG_LEVEL{
LL_INFO = 0,
LL_WARNING,
LL_ERROR,
LL_FATAL
};
enum LOG_OUTPUT{
LO_NONE = 0x0,
LO_DEBUG = 0x2,
LO_STANDARD = 0x4,
LO_STANDARD_DEBUG = 0X6,
LO_FILE = 0x8,
LO_FILE_DEBUG = 0X0A,
LO_FILE_STANDARD =0X0C,
};
public:
static Log_entity* GetInstance();
static void Initialize(struct _LOG_CONFIGURATION& con);
void Log(LOG_LEVEL le, LPCTSTR szMsg, );
void Log(LOG_LEVEL le, LPCTSTR szFile, int nLine, LPCTSTR szMsg, );
static void Dumb(LPCTSTR szMsg, ){}
private:
void _write(LPCTSTR szMsg);
/**//* Do nothing */
void _writeNone( LPCTSTR){}
/**//* Write the message to DebugView */
void _writeDebug( LPCTSTR szMsg);
/**//* Write the message to stderr */
void _writeStandard( LPCTSTR szMsg);
/**//* Write the message to the file */
void _writeFile( LPCTSTR szMsg);
bool CanLog(LOG_LEVEL le);
private:
static Log_critical m_sCritical;
} ;
typedef struct _LOG_CONFIGURATION {
bool _bNeedTime;
Log_entity::LOG_LEVEL _lowerLevel;
Log_entity::LOG_OUTPUT _output;
TCHAR _szLogFile[MAX_PATH];
} LOG_CONFIGURATION, * LPLOG_CONFIGURATION;
/**/
//////////////////////////////////////////////////////////////////////////
// file Log_msg.cpp
//
// Copyright (c) 2010 robert xiao. All Rights Reserved. [email protected]
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
// agreement, is hereby granted, provided that the above copyright notice,
// this paragraph and the following two paragraphs appear in all copies,
// modifications, and distributions.
//
//
// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
//
/**/ //////////////////////////////////////////////////////////////////////////
/**/ /**
* @file: Log_msg.cpp
*
* @author: Robert xiao
*
*/
#include " stdafx.h "
#include < io.h >
#include " Log_msg.h "
/**/ /**
* @global variable
*
* Log_entity g_logger
*
* g_config
*
* DEBUGFUFFERLEN
*/
static Log_entity g_logger;
static LOG_CONFIGURATION g_config = {true, Log_entity::LL_ERROR, Log_entity::LO_NONE, _T('\0')} ;
const USHORT DEBUGFUFFERLEN = 4096 ;
#define LOG_MSG_SECTION "log_msg"
#define LOG_LEVEL_CAPTION "log_level"
#define LOG_OUTPUT_CAPTION "log_output"
#define LOG_FILE_CAPTION "log_file"
namespace {
/**//* if szPath is file name, then convert it to full path name */
bool _ValidateLogFilePath(LPTSTR szPath){
if(!_tcslen(szPath)){
return false;
}
if(TCHAR *p = _tcsrchr(szPath, _T('\\'))){
TCHAR szDirectory[MAX_PATH] = {_T('\0')};
_tcsncpy_s(szDirectory, MAX_PATH, szPath, p - szPath);
WIN32_FIND_DATA data;
HANDLE h;
if((h = FindFirstFile(szDirectory, &data)) != INVALID_HANDLE_VALUE){
FindClose(h);
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
return true;
}
}
return false;
}
TCHAR szDirectory[MAX_PATH] = {_T('\0')};
GetModuleFileName(NULL, szDirectory, MAX_PATH);
_tcscat_s(szDirectory, MAX_PATH, szPath);
_tcscpy_s(szPath, MAX_PATH, szDirectory);
return true;
}
int PrintCurrentTimeString(LPTSTR szTime, int nBufferLen)
{
SYSTEMTIME stLocalTime;
FILETIME ftLocalTime;
GetSystemTime(&stLocalTime);
GetSystemTimeAsFileTime(&ftLocalTime);
return _stprintf_s(szTime,
nBufferLen,
_T("thread--0x%04x %02d:%02d:%02d.%03d%s %02d-%02d-%4d: "),
GetCurrentThreadId(),
(stLocalTime.wHour <= 12)?stLocalTime.wHour:stLocalTime.wHour-12,
stLocalTime.wMinute,
stLocalTime.wSecond,
stLocalTime.wMilliseconds,
(stLocalTime.wHour <= 12)?_T("AM"):_T("PM"),
stLocalTime.wMonth,
stLocalTime.wDay,
stLocalTime.wYear);
}
int PrintMsgTypeString(Log_entity::LOG_LEVEL le, LPTSTR szBuf){
if(!szBuf){
return 0;
}
static TCHAR msgTopics[][20] = {
_T("INFO: "),
_T("WARNING: "),
_T("ERROR: "),
_T("FATAL: ")
};
_tcscpy_s(szBuf, 20, msgTopics[le]);
return static_cast<int>(_tcslen(szBuf));
}
class Log_file{
public:
Log_file(){
pf = 0;
}
int Open(LPCTSTR szFileName){
if(!szFileName){
return EXIT_FAILURE;
}
LPCTSTR szParams = _T("a+,ccs=UTF-8");
#if defined (_MSC_VER) && (_MSC_VER >= 1500)
int err = _tfopen_s(&pf, szFileName, szParams);
#else
pf = _tfopen(szFileName, szParams);
#endif
if(pf){
return EXIT_SUCCESS;
}
else
{
//File IO failed - complain - not using error macros since we may not have debug output here
TCHAR szErr[256];
DWORD dwErr = GetLastError();
HRESULT hRes = HRESULT_FROM_WIN32(dwErr);
LPTSTR szSysErr = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
0,
dwErr,
0,
(LPTSTR)&szSysErr,
0,
0);
_stprintf_s(szErr,sizeof(szErr) / sizeof(TCHAR),
_T("_tfopen failed, hRes = 0x%08X, dwErr = 0x%08X = \"%s\"\n"),
HRESULT_FROM_WIN32(dwErr),
dwErr,
szSysErr);
OutputDebugString(szErr);
LocalFree(szSysErr);
return NULL;
}
return EXIT_FAILURE;
}
int WriteLine(LPCTSTR szMsg){
if(pf && szMsg){
if(_fputts(szMsg, pf) >= 0){
_fputts(_T("\n"), pf);
return EXIT_SUCCESS;
}
}
return EXIT_FAILURE;
}
~Log_file()
{
if(pf){
fclose(pf);
}
}
private:
FILE *pf;
};
}
Log_critical Log_entity::m_sCritical;
Log_entity * Log_entity::GetInstance() {
return &g_logger;
}
void Log_entity::Initialize( struct _LOG_CONFIGURATION & con ) {
if(con._output & LO_FILE){
TCHAR szTemp[MAX_PATH];
_tcscpy_s(szTemp, MAX_PATH, con._szLogFile);
if(!_ValidateLogFilePath(szTemp)){
return ;
}
_tcscpy_s(g_config._szLogFile, MAX_PATH, szTemp);
}
g_config._lowerLevel = con._lowerLevel;
g_config._output = con._output;
g_config._bNeedTime = con._bNeedTime;
}
void Log_entity::Log( LOG_LEVEL le, LPCTSTR szMsg, ) {
if(!CanLog(le)){
return;
}
if(!szMsg){
return;
}
TCHAR szDebugBuffer[DEBUGFUFFERLEN] = {_T('\0')};
TCHAR *p = szDebugBuffer;
int nRemainBuffer = DEBUGFUFFERLEN;
int nUse = PrintMsgTypeString(le, p);
p += nUse;
if(g_config._bNeedTime){
nUse = PrintCurrentTimeString(p, DEBUGFUFFERLEN - (p -szDebugBuffer));
if(nUse >= 0){
p += nUse;
}
}
nRemainBuffer = DEBUGFUFFERLEN - (p - szDebugBuffer);
if(_tcsrchr(szMsg, _T('%'))){
va_list argList = NULL;
va_start(argList, szMsg);
int nWrite = _vsntprintf_s(p,
nRemainBuffer - 1,
nRemainBuffer,
szMsg,
argList);
if(nWrite >= nRemainBuffer){
szDebugBuffer[DEBUGFUFFERLEN - 1] = _T('\0');
}
va_end(argList);
}
else{
_tcscat_s(p, nRemainBuffer, szMsg);
}
_write(szDebugBuffer);
}
void Log_entity::Log( LOG_LEVEL le, LPCTSTR szFile, int nLine, LPCTSTR szMsg, ) {
if(!CanLog(le)){
return;
}
if(!szMsg){
return;
}
TCHAR szDebugBuffer[DEBUGFUFFERLEN] = {_T('\0')};
TCHAR *p = szDebugBuffer;
int nRemainBuffer = DEBUGFUFFERLEN;
int nUse = PrintMsgTypeString(le, p);
p += nUse;
if(szFile){
TCHAR szSourceBuffer[MAX_PATH * 2];
_stprintf_s(szSourceBuffer,
MAX_PATH * 2,
_T("File:'%s' Line: %d; "),
szFile,
nLine);
_tcscat_s(szDebugBuffer, nRemainBuffer, szSourceBuffer);
p += _tcslen(szSourceBuffer);
}
if(g_config._bNeedTime){
nUse = PrintCurrentTimeString(p, DEBUGFUFFERLEN - (p - szDebugBuffer));
if(nUse >= 0){
p += nUse;
}
}
nRemainBuffer = DEBUGFUFFERLEN - (p - szDebugBuffer);
if(_tcsrchr(szMsg, _T('%'))){
va_list argList;
va_start(argList, szMsg);
int nWrite = _vsntprintf_s(p,
nRemainBuffer - 1,
nRemainBuffer,
szMsg,
argList);
if(nWrite >= nRemainBuffer){
szDebugBuffer[DEBUGFUFFERLEN - 1] = _T('\0');
}
va_end(argList);
}
else{
_tcscat_s(p, nRemainBuffer, szMsg);
}
_write(szDebugBuffer);
}
void Log_entity::_write(LPCTSTR szMsg ) {
if(g_config._output & LO_FILE){
_writeFile(szMsg);
}
if(g_config._output & LO_STANDARD){
_writeStandard(szMsg);
}
if(g_config._output & LO_DEBUG){
_writeDebug(szMsg);
}
}
bool Log_entity::CanLog( LOG_LEVEL le ) {
return le >= g_config._lowerLevel && g_config._output != LO_NONE;
}
void Log_entity::_writeDebug( LPCTSTR szMsg ) {
OutputDebugString(szMsg);
}
void Log_entity::_writeStandard( LPCTSTR szMsg ) {
_tprintf(szMsg);
_tprintf(_T("\n"));
}
void Log_entity::_writeFile( LPCTSTR szMsg ) {
_AutoCritical singleLock(m_sCritical);
Log_file logFile;
if(logFile.Open(g_config._szLogFile) == EXIT_SUCCESS){
logFile.WriteLine(szMsg);
}
}
// file Log_msg.cpp
//
// Copyright (c) 2010 robert xiao. All Rights Reserved. [email protected]
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
// agreement, is hereby granted, provided that the above copyright notice,
// this paragraph and the following two paragraphs appear in all copies,
// modifications, and distributions.
//
//
// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
//
/**/ //////////////////////////////////////////////////////////////////////////
/**/ /**
* @file: Log_msg.cpp
*
* @author: Robert xiao
*
*/
#include " stdafx.h "
#include < io.h >
#include " Log_msg.h "
/**/ /**
* @global variable
*
* Log_entity g_logger
*
* g_config
*
* DEBUGFUFFERLEN
*/
static Log_entity g_logger;
static LOG_CONFIGURATION g_config = {true, Log_entity::LL_ERROR, Log_entity::LO_NONE, _T('\0')} ;
const USHORT DEBUGFUFFERLEN = 4096 ;
#define LOG_MSG_SECTION "log_msg"
#define LOG_LEVEL_CAPTION "log_level"
#define LOG_OUTPUT_CAPTION "log_output"
#define LOG_FILE_CAPTION "log_file"
namespace {
/**//* if szPath is file name, then convert it to full path name */
bool _ValidateLogFilePath(LPTSTR szPath){
if(!_tcslen(szPath)){
return false;
}
if(TCHAR *p = _tcsrchr(szPath, _T('\\'))){
TCHAR szDirectory[MAX_PATH] = {_T('\0')};
_tcsncpy_s(szDirectory, MAX_PATH, szPath, p - szPath);
WIN32_FIND_DATA data;
HANDLE h;
if((h = FindFirstFile(szDirectory, &data)) != INVALID_HANDLE_VALUE){
FindClose(h);
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
return true;
}
}
return false;
}
TCHAR szDirectory[MAX_PATH] = {_T('\0')};
GetModuleFileName(NULL, szDirectory, MAX_PATH);
_tcscat_s(szDirectory, MAX_PATH, szPath);
_tcscpy_s(szPath, MAX_PATH, szDirectory);
return true;
}
int PrintCurrentTimeString(LPTSTR szTime, int nBufferLen)
{
SYSTEMTIME stLocalTime;
FILETIME ftLocalTime;
GetSystemTime(&stLocalTime);
GetSystemTimeAsFileTime(&ftLocalTime);
return _stprintf_s(szTime,
nBufferLen,
_T("thread--0x%04x %02d:%02d:%02d.%03d%s %02d-%02d-%4d: "),
GetCurrentThreadId(),
(stLocalTime.wHour <= 12)?stLocalTime.wHour:stLocalTime.wHour-12,
stLocalTime.wMinute,
stLocalTime.wSecond,
stLocalTime.wMilliseconds,
(stLocalTime.wHour <= 12)?_T("AM"):_T("PM"),
stLocalTime.wMonth,
stLocalTime.wDay,
stLocalTime.wYear);
}
int PrintMsgTypeString(Log_entity::LOG_LEVEL le, LPTSTR szBuf){
if(!szBuf){
return 0;
}
static TCHAR msgTopics[][20] = {
_T("INFO: "),
_T("WARNING: "),
_T("ERROR: "),
_T("FATAL: ")
};
_tcscpy_s(szBuf, 20, msgTopics[le]);
return static_cast<int>(_tcslen(szBuf));
}
class Log_file{
public:
Log_file(){
pf = 0;
}
int Open(LPCTSTR szFileName){
if(!szFileName){
return EXIT_FAILURE;
}
LPCTSTR szParams = _T("a+,ccs=UTF-8");
#if defined (_MSC_VER) && (_MSC_VER >= 1500)
int err = _tfopen_s(&pf, szFileName, szParams);
#else
pf = _tfopen(szFileName, szParams);
#endif
if(pf){
return EXIT_SUCCESS;
}
else
{
//File IO failed - complain - not using error macros since we may not have debug output here
TCHAR szErr[256];
DWORD dwErr = GetLastError();
HRESULT hRes = HRESULT_FROM_WIN32(dwErr);
LPTSTR szSysErr = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
0,
dwErr,
0,
(LPTSTR)&szSysErr,
0,
0);
_stprintf_s(szErr,sizeof(szErr) / sizeof(TCHAR),
_T("_tfopen failed, hRes = 0x%08X, dwErr = 0x%08X = \"%s\"\n"),
HRESULT_FROM_WIN32(dwErr),
dwErr,
szSysErr);
OutputDebugString(szErr);
LocalFree(szSysErr);
return NULL;
}
return EXIT_FAILURE;
}
int WriteLine(LPCTSTR szMsg){
if(pf && szMsg){
if(_fputts(szMsg, pf) >= 0){
_fputts(_T("\n"), pf);
return EXIT_SUCCESS;
}
}
return EXIT_FAILURE;
}
~Log_file()
{
if(pf){
fclose(pf);
}
}
private:
FILE *pf;
};
}
Log_critical Log_entity::m_sCritical;
Log_entity * Log_entity::GetInstance() {
return &g_logger;
}
void Log_entity::Initialize( struct _LOG_CONFIGURATION & con ) {
if(con._output & LO_FILE){
TCHAR szTemp[MAX_PATH];
_tcscpy_s(szTemp, MAX_PATH, con._szLogFile);
if(!_ValidateLogFilePath(szTemp)){
return ;
}
_tcscpy_s(g_config._szLogFile, MAX_PATH, szTemp);
}
g_config._lowerLevel = con._lowerLevel;
g_config._output = con._output;
g_config._bNeedTime = con._bNeedTime;
}
void Log_entity::Log( LOG_LEVEL le, LPCTSTR szMsg, ) {
if(!CanLog(le)){
return;
}
if(!szMsg){
return;
}
TCHAR szDebugBuffer[DEBUGFUFFERLEN] = {_T('\0')};
TCHAR *p = szDebugBuffer;
int nRemainBuffer = DEBUGFUFFERLEN;
int nUse = PrintMsgTypeString(le, p);
p += nUse;
if(g_config._bNeedTime){
nUse = PrintCurrentTimeString(p, DEBUGFUFFERLEN - (p -szDebugBuffer));
if(nUse >= 0){
p += nUse;
}
}
nRemainBuffer = DEBUGFUFFERLEN - (p - szDebugBuffer);
if(_tcsrchr(szMsg, _T('%'))){
va_list argList = NULL;
va_start(argList, szMsg);
int nWrite = _vsntprintf_s(p,
nRemainBuffer - 1,
nRemainBuffer,
szMsg,
argList);
if(nWrite >= nRemainBuffer){
szDebugBuffer[DEBUGFUFFERLEN - 1] = _T('\0');
}
va_end(argList);
}
else{
_tcscat_s(p, nRemainBuffer, szMsg);
}
_write(szDebugBuffer);
}
void Log_entity::Log( LOG_LEVEL le, LPCTSTR szFile, int nLine, LPCTSTR szMsg, ) {
if(!CanLog(le)){
return;
}
if(!szMsg){
return;
}
TCHAR szDebugBuffer[DEBUGFUFFERLEN] = {_T('\0')};
TCHAR *p = szDebugBuffer;
int nRemainBuffer = DEBUGFUFFERLEN;
int nUse = PrintMsgTypeString(le, p);
p += nUse;
if(szFile){
TCHAR szSourceBuffer[MAX_PATH * 2];
_stprintf_s(szSourceBuffer,
MAX_PATH * 2,
_T("File:'%s' Line: %d; "),
szFile,
nLine);
_tcscat_s(szDebugBuffer, nRemainBuffer, szSourceBuffer);
p += _tcslen(szSourceBuffer);
}
if(g_config._bNeedTime){
nUse = PrintCurrentTimeString(p, DEBUGFUFFERLEN - (p - szDebugBuffer));
if(nUse >= 0){
p += nUse;
}
}
nRemainBuffer = DEBUGFUFFERLEN - (p - szDebugBuffer);
if(_tcsrchr(szMsg, _T('%'))){
va_list argList;
va_start(argList, szMsg);
int nWrite = _vsntprintf_s(p,
nRemainBuffer - 1,
nRemainBuffer,
szMsg,
argList);
if(nWrite >= nRemainBuffer){
szDebugBuffer[DEBUGFUFFERLEN - 1] = _T('\0');
}
va_end(argList);
}
else{
_tcscat_s(p, nRemainBuffer, szMsg);
}
_write(szDebugBuffer);
}
void Log_entity::_write(LPCTSTR szMsg ) {
if(g_config._output & LO_FILE){
_writeFile(szMsg);
}
if(g_config._output & LO_STANDARD){
_writeStandard(szMsg);
}
if(g_config._output & LO_DEBUG){
_writeDebug(szMsg);
}
}
bool Log_entity::CanLog( LOG_LEVEL le ) {
return le >= g_config._lowerLevel && g_config._output != LO_NONE;
}
void Log_entity::_writeDebug( LPCTSTR szMsg ) {
OutputDebugString(szMsg);
}
void Log_entity::_writeStandard( LPCTSTR szMsg ) {
_tprintf(szMsg);
_tprintf(_T("\n"));
}
void Log_entity::_writeFile( LPCTSTR szMsg ) {
_AutoCritical singleLock(m_sCritical);
Log_file logFile;
if(logFile.Open(g_config._szLogFile) == EXIT_SUCCESS){
logFile.WriteLine(szMsg);
}
}