随笔 - 64, 文章 - 11, 评论 - 12, 引用 - 0
数据加载中……

日志记录模块


#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. robert.xiao2010@gmail.com
// 
// 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. robert.xiao2010@gmail.com
// 
// 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);
    }

}

posted on 2010-02-04 20:19 Robertxiao 阅读(664) 评论(0)  编辑 收藏 引用 所属分类: C++


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理