tinylog

本文介绍了一款名为tinylog的简单日志库,该库支持Unix和Windows平台。作者在工程中直接整合了tinyxml,并提供了功能函数的头文件、实现、宏定义及错误信息。此外,还给出了log配置文件模板和使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近闲来无事写了一个简单的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;
... ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值