最近闲来无事写了一个简单的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;
... ...