tinylog

最近閒來無事寫了一個簡單的log庫,支持Unix和Windows兩個版本;
裏面調用了tinyxml,本人比較懶,直接把它加載到了工程裏面;
廢話不過說直接上代碼:
第一部分:是功能函數的頭文件,文件名(CLogEx.h)

#ifdef CTLOGEX_EXPORTS
#define CTLOGEX_API __declspec(dllexport)
#else
#define CTLOGEX_API __declspec(dllimport)
#endif

#ifndef __CTLOGEX_H__
#define __CTLOGEX_H__

#include "custom.h"

#ifndef __cplusplus
extern "C"{
#endif

/*<載入XML配置文件;>*/
CTLOGEX_API int LoadConfig(const char* xmlfile);

/*<初始化log環境;>*/
CTLOGEX_API int Init();

/*<釋放log資源;>*/
CTLOGEX_API void Release();

/*<功能函數:warn
    @param:
    [in]警告等級,從0~6,錯誤爲0級警告;
    [in]輸入的日誌,可變參數組
    @result:
    返回錯誤類型
>*/
CTLOGEX_API int cwarn(unsigned short level, const char *format, ...);

/*<功能函數:trace
    @param:
    [in]輸入的日誌,可變參數組
    @result:
    [out]返回錯誤類型
>*/
CTLOGEX_API int ctrace(const char *format, ...);

/*<獲取錯誤信息>*/
CTLOGEX_API extern const TCHAR* GetLogErrorInfo(int code);

#ifndef __cplusplus
};
#endif

#endif // !__CTLOGEX_H__

第二部分:功能函數的實現

// CTLogEx.cpp : 定義 DLL 應用程序的導出函數。
//

#include "CTLogEx.h"
#include <stdarg.h>
#include "tinyxml2.h"
#include <sys/stat.h>
#include <io.h>
#include <fcntl.h>
#include <string.h>

using namespace tinyxml2;

static FILE* _swarn,* _strace; /*<日誌輸出位置,當輸出到控制檯時,_swarn = stderr而_strace = stdout;>*/

static bool  _default = false;/*<是否爲默認配置,默認不輸出日誌;>*/

static int   _type;/*<輸出類型,0表示不輸出,1表示輸出到控制檯,2表示輸出到文件;>*/

static int   _level; /*<警告等級,總計劃分爲0~6級別,錯誤爲0級;>*/

static bool _traceIsActive = true; /*<是否開啓TRCE>*/

static long size_log; /*<文件的大小,以M爲單位>*/

static char _pwarn[256];

static char _ptrace[256];

/*<log函數;>*/
int  cwarn(unsigned short level, const char *format, ...)
{
    int _ret;
    va_list arglist;
    char buffer[2048] = { 0 };

    if (!_default && _type == 0)
    {
        return __CLOG_CLOSE__;
    }

    //IO是否正常
    if (&_swarn == NULL)
    {
        return __CLOG_ERR_IO__;
    }

    //警告等級是否正常
    if (level < 0 || level > _level)
    {
        return __CLOG_ERR_EX__;
    }

    //輸出警告日誌
    va_start(arglist, format);
    _ret = vsprintf(buffer, format, arglist);
    va_end(arglist);

    if (_ret < 0)
    {
        return __CLOG_ERR_VF__;
    }

    return __CLOG_SUCCESS__;
}

int ctrace(const char *format, ...)
{
    int _ret;
    va_list arglist;
    char buffer[2048] = { 0 };

    //在不是默認情況下,日誌類型爲0
    if (!_default && _type == 0)
    {
        return __CLOG_CLOSE__;
    }

    //判斷記錄功能是否開啓
    if (!_traceIsActive)
    {
        return __CLOG_UNACTIVE__;
    }

    //輸出記錄日誌
    va_start(arglist, format);
    _ret = vsprintf(buffer, format, arglist);
    va_end(arglist);

    if (_ret < 0)
    {
        return __CLOG_ERR_VF__;
    }

    return __CLOG_SUCCESS__;
}



/*<配置函數>*/
#define MAX_SIZE (1024L*1024L) 

long getfilesize(const char* path)
{
    int fp;
    long len;
    fp = _open(path, _O_RDONLY);
    if (fp == -1)
    {
        return -1;
    }

    len = _filelength(fp);
    close(fp);
    return len;
}

int renamefile(const char* path)
{
    char _rename[256] = { 0 };
    char* sub = strstr((char*)path, ".log");

    if (sub == NULL)
    {
        return -1;
    }

    memcpy(_rename, path, (sub - path) / sizeof(char));
    printf_s(_rename, "%s%s%s.log", _rename,__DATE__, __TIME__);
    return rename(path, _rename);
}

#ifdef  WIN32

bool createstream(FILE* fp,const char* path)
{
    fp = fopen(path, "a+b");

    if (fp == NULL)
    {
        return FALSE;
    }

    return TRUE;
}

#endif //  

void checkfile(const char* path)
{
    if (getfilesize(path) > size_log*MAX_SIZE)
    {
        if (renamefile(path) < 0)
        {
            return;
        }
    }

    return;
}

int LoadConfig(const char* xmlfile)
{
    int i,j;
    char itoc[32] = {0};
    tinyxml2::XMLDocument     xml;
    XMLElement  *xRoot, *xNode, *xChild;

    if (xmlfile == NULL)
    {
        return __CLOG_ERR_CF__;
    }

    xml.LoadFile(xmlfile);
    xRoot = xml.RootElement();
    if (xRoot == NULL)
    {
        return __CLOG_ERR_CF__;
    }


    xNode = xRoot->FirstChildElement("default");
    if (xNode)
    {
        _default = *(xNode->GetText()) - '0';
    }
    else
    {
        return __CLOG_ERR_CF__;
    }

    xNode = xRoot->FirstChildElement("type");
    if (xNode)
    {
        _type = *(xNode->GetText()) - '0';
    }
    else
    {
        return __CLOG_ERR_CF__;
    }

    xNode = xRoot->FirstChildElement("level");
    if (xNode)
    {
        _level = *(xNode->GetText()) - '0';
    }
    else
    {
        return __CLOG_ERR_CF__;
    }

    xNode = xRoot->FirstChildElement("switch");;
    if (xNode)
    {
        _traceIsActive = *(xNode->GetText()) - '0';
    }
    else
    {
        return __CLOG_ERR_CF__;
    }

    xNode = xRoot->FirstChildElement("path");

    if (xNode)
    {
        xChild = xNode->FirstChildElement("warn");
        if (xChild)
        {
            memcpy(_pwarn, xChild->GetText(), strlen(xChild->GetText()));
        }
        else
        {
            return __CLOG_ERR_CF__;
        }

        xChild = xNode->FirstChildElement("trace");
        if (xChild)
        {
            memcpy(_ptrace, xChild->GetText(), strlen(xChild->GetText()));
        }
        else
        {
            return __CLOG_ERR_CF__;
        }
    }
    else
    {
        return __CLOG_ERR_CF__;
    }

    xNode = xRoot->FirstChildElement("size");
    if (xNode)
    {
        size_log = 0;

        memcpy(itoc, xNode->GetText(), strlen(xNode->GetText()));
        j = strlen(itoc);

        for (i = 0; i < j; i++)
        {
            size_log *= 10;
            size_log +=(itoc[i] - '0');
        }
    }
    else
    {
        return __CLOG_ERR_CF__;
    }

    return __CLOG_SUCCESS__;
}

int Init()
{
    if (_default)
    {
        //默認狀態下輸出到控制檯;
        _strace = stdout;
        _swarn = stderr;
        return __CLOG_DEFAULT__;
    }

    switch (_type)
    {
    case 0:
    {
        return __CLOG_CLOSE__;
    }
    case 1:
    {
        _strace = stdout;
        _swarn = stderr;
    }
    break;
    case 2:
    {
        checkfile(_pwarn);
        createstream(_swarn, _pwarn);
        if (!strcmp(_ptrace, _pwarn))
        {
            _strace = _swarn;
        }
        else
        {
            checkfile(_ptrace);
            createstream(_strace, _ptrace);
        }

    }
    break;
    default:
        return __CLOG_ERR_CF__;
    }

    return __CLOG_SUCCESS__;
}

void Release()
{
    if (_swarn != NULL)
    {
        fflush(_swarn);
        fclose(_swarn);
    }

    if (_strace != NULL && strcmp(_ptrace, _pwarn))
    {
        fflush(_strace);
        fclose(_strace);
    }

    return;
}

第三部分呢是我預定義的一些宏,文件名(log.h)

#ifndef __MACRO_H__
#define __MACRO_H__

#include "CTLogEx.h"

#ifndef _DEBUG //用戶日誌預編譯宏
#define TRACE
#define ERROR
#define WARN_1
#define WARN_2
#define WARN_3
#define WARN_4
#define WARN_5
#define WARN_6
#else

#define TRACE ctrace        

#ifdef WIN32
#define ERROR(x, ...)   cwarn(0, x , ##__VA_ARGS__)     
#define WARN_1(x, ...)  cwarn(1, x , ##__VA_ARGS__)     
#define WARN_2(x, ...)  cwarn(2, x , ##__VA_ARGS__)     
#define WARN_3(x, ...)  cwarn(3, x , ##__VA_ARGS__)     
#define WARN_4(x, ...)  cwarn(4, x , ##__VA_ARGS__)     
#define WARN_5(x, ...)  cwarn(5, x , ##__VA_ARGS__)     
#define WARN_6(x, ...)  cwarn(6, x , ##__VA_ARGS__)

#else ifdef UNIX

#define ERROR(x, args...)   cwarn(0, x , ##args)    
#define WARN_1(x, args...)  cwarn(1, x , ##args)    
#define WARN_2(x, args...)  cwarn(2, x , ##args)    
#define WARN_3(x, args...)  cwarn(3, x , ##args)    
#define WARN_4(x, args...)  cwarn(4, x , ##args)    
#define WARN_5(x, args...)  cwarn(5, x , ##args)    
#define WARN_6(x, args...)  cwarn(6, x , ##args)

#endif

#endif

#endif

//#endif // !__OPERATION_H__

第四部分:是我定義的一些返回值和錯誤信息,文件名(custom.h)

#ifndef __COMMAND_H__
#define __COMMAND_H__

#ifdef WIN32
#include <tchar.h>
#else 
typedef char TCHAR;
#define _T
#endif

#define __CLOG_BASE_0       0x777
#define __CLOG_DEFAULT__    (__CLOG_BASE_0 + 0) /*<默認設置>*/
#define __CLOG_SUCCESS__    (__CLOG_BASE_0 + 1) /*<操作成功>*/
#define __CLOG_UNACTIVE__   (__CLOG_BASE_0 + 6)/*<trace功能未開啓>*/
#define __CLOG_CLOSE__      (__CLOG_BASE_0 + 7)/*<日誌類型爲0>*/
//錯誤宏定義;
#define __CLOG_ERR_EX__     (__CLOG_BASE_0 + 3) /*<異常錯誤>*/
#define __CLOG_ERR_IO__     (__CLOG_BASE_0 + 2) /*<IO錯誤>*/
#define __CLOG_ERR_VF__     (__CLOG_BASE_0 + 4) /*<調用vfprintf()出錯>*/
#define __CLOG_ERR_CF__     (__CLOG_BASE_0 + 5) /*<配置文件錯誤>*/

typedef struct err_msg
{
    int code;
    const TCHAR* msg;
}err_msg;

#endif 

第五部分:文件名(custom.cpp)

#include "custom.h"

err_msg ergv[] = {
    {__CLOG_SUCCESS__, _T("操作成功")},
    { __CLOG_ERR_IO__, _T("日誌IO錯誤")},
    { __CLOG_ERR_EX__, _T("日誌等級與設置不匹配")},
    { __CLOG_ERR_VF__, _T("寫入日誌時發生異常") },
    { __CLOG_DEFAULT__, _T("日誌設置爲默認") },
    { __CLOG_UNACTIVE__, _T("記錄功能設置爲不啓用") },
    {__CLOG_ERR_CF__, _T("配置文件錯誤")},
    { __CLOG_CLOSE__, _T("日誌類型爲0,功能被關閉") }
};

const TCHAR* GetLogErrorInfo(int code)
{
    int size = sizeof(ergv) / sizeof(err_msg);
    int i = 0;
    for (; i < size; i++)
    {
        if (ergv[i].code == code)
        {
            return ergv[i].msg;
        }
    }

    return _T("該錯誤信息未知");
}

最後給出我的log配置文件的模板:

<?xml version="1.0" encoding="UTF-8"?>
<receipt>
    <default>0</default> //0表示不是默認,1表示是默認, 默認狀態下輸出到控制檯;
    <type>2</type>       //0表示不輸出,1表示輸出到控制檯,2表示輸出到文件
    <level>6</level>     //警告等級1~6
    <switch>1</switch>   //是否開啓記錄日誌
    <path>
        <warn>warn.log</warn>  //警告和錯誤日誌收集路徑
        <trace>trace.log</trace> //記錄日誌收集路徑
    </path>
    <size>10</size>     //日誌文件的大小
</receipt>

恩恩,就是這樣了,下面是調用的實例:

#include<log.h>
#progam comment(lib, "CTLogEx.lib")

... ...
    LoadConfig("templete.xml");
    Init();
    TRACE("this is %d a test\n", 3);
    system("pause");
    return 0;
... ...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章