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