最近閒來無事寫了一個簡單的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;
... ...