日志记录模块

日志记录模块


#include  < Windows.h >
#include 
" Log_msg.h "

int  TestWinerrReturn()
{
    LOG_WINERROR_MSG_RETURN(
105);
    
return -100;
}


int  TestErrmsgReturn()
{
    LOG_WINERROR_MSG_RETURN(
105);
    
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.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 *= _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 
*= 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 
*= 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);
    }

}

你可能感兴趣的:(日志记录模块)