c++ windows下的简单的日志输出DebugPrintf
2014-12-12 01:20
267 查看
这是本人实现的一个简单的软件调试日志。论功能肯定不能和glog、log4cplus等日志相提并论,但是我也觉得这个两个日志库太强大,也有点庞大,个人想法。
实现的这个日志只包含一个头文件和一个cpp文件。
日志使用平台为windows,主要测试环境为win32和MFC。
是将日志直接输出到标准输出stdout和stderr。通过宏实现可变参数以及输出日志时间和文件名函数名行号。要输出什么内容可以通过_PRINTF_LOCATION_自行配置。当然很多是将日志写入文件中的,这里通过重导向标准输出流(__iob_func()[1]、__iob_func()[2])的方式输出到文件,重导向了标准输出流有个意外的收获,就是有时同时把程序中一些其他库的错误输出也保存了下来。通过_fsopen()函数实现日志文件的读共享写独占。通过_snprintf_s()格式化字符串在信息长度超过buff大小时会自动截断而不会像其他格式化函数会崩溃。
这里贴出部分源码
使用方法如下:
<span style="font-size:18px;">InfoPrintf("日志普通输出,数字:%d", 12345678);
WarnPrintf("日志警告输出,数字:%d", 12345678);
ErrPrintf("日志错误信息输出,数字:%d", 12345678);</span>效果如下图:
实现比较简单通道也造成了一些问题。比如长时间运行后会有造成日志文件过大。
实现的这个日志只包含一个头文件和一个cpp文件。
日志使用平台为windows,主要测试环境为win32和MFC。
是将日志直接输出到标准输出stdout和stderr。通过宏实现可变参数以及输出日志时间和文件名函数名行号。要输出什么内容可以通过_PRINTF_LOCATION_自行配置。当然很多是将日志写入文件中的,这里通过重导向标准输出流(__iob_func()[1]、__iob_func()[2])的方式输出到文件,重导向了标准输出流有个意外的收获,就是有时同时把程序中一些其他库的错误输出也保存了下来。通过_fsopen()函数实现日志文件的读共享写独占。通过_snprintf_s()格式化字符串在信息长度超过buff大小时会自动截断而不会像其他格式化函数会崩溃。
这里贴出部分源码
namespace NamespaceKun { // 创建并打开日志文件,当文件名为空,表示关闭对应的日志文件,两个日志文件名最好不相同 // infoOutFileName替换的是标准输出流stdout // errOutFileName替换的标准错误输出流stderr bool LogInit( const char *infoOutFileName, const char * errOutFileName, const char * infoOutFileMode = "w+", const char * errOutFileMode = "w+" ); //打开控制台 void OpenConsole(); }; //信息输出 #define _INFO_PRINTF_ //警告输出 #define _WARNING_PRINTF_ //错误输出 #define _ERROR_PRINTF_ //输出方式: //0: //是否显示输出的位置,无附加信息 //1://是否显示输出的位置,行号 //2://是否显示输出的位置,函数,行号 //3://是否显示输出的位置,包括文件,函数,行号 #ifdef _DEBUG #define _PRINTF_LOCATION_ 0 #else #define _PRINTF_LOCATION_ 3 #endif //---------------------------------------------------------------------------------- //是否显示输出的位置 #if _PRINTF_LOCATION_ == 0 #define _FPRINTF_PARAMETERS_ "%s %s %s\n",datetimebuff,pszLevel,szOutBuff #elif _PRINTF_LOCATION_ == 1 #define _FPRINTF_PARAMETERS_ "%s %s %s\tLine:%d\n",datetimebuff,pszLevel,szOutBuff,__LINE__ #elif _PRINTF_LOCATION_ == 2 #define _FPRINTF_PARAMETERS_ "%s %s %s\tFunction:%s, Line:%d\n",datetimebuff,pszLevel,szOutBuff,__FUNCTION__,__LINE__ #elif _PRINTF_LOCATION_ == 3 #define _FPRINTF_PARAMETERS_ "%s %s %s\tFilePath:%s, Function:%s, Line:%d\n",datetimebuff,pszLevel,szOutBuff,__FILE__,__FUNCTION__,__LINE__ #else #define _FPRINTF_PARAMETERS_ "%s %s %-500s\tFilePath:%s, Function:%s, Line:%d\n",datetimebuff,pszLevel,szOutBuff,__FILE__,__FUNCTION__,__LINE__ #endif //---------------------------------------------------------------------------------- //构造输出字数串 #define _PRINTF_FORMATE_CONTENT_(szLevel, format, ...) char datetimebuff[32] = {0};\ const char *pszLevel = szLevel;\ time_t nowtime = time(NULL);\ tm tmdatetime;\ localtime_s(&tmdatetime, &nowtime);\ strftime(datetimebuff,sizeof(datetimebuff),"%Y-%m-%d %H:%M:%S",&tmdatetime);\ char szOutBuff[10240] = {0};\ _snprintf_s(szOutBuff, sizeof(szOutBuff)-1, _TRUNCATE, format, ##__VA_ARGS__); //调试输出---------------------------------------------------------------------------------- #ifdef _INFO_PRINTF_ #define InfoPrintf(format, ...); {\ _PRINTF_FORMATE_CONTENT_("INFO ", format, ##__VA_ARGS__) \ fprintf(stdout, _FPRINTF_PARAMETERS_);\ fflush(stdout);\ }; #else #define InfoPrintf(...); do{ }while(0); #endif //---------------------------------------------------------------------------------- //调试输出---------------------------------------------------------------------------------- #ifdef _WARNING_PRINTF_ #define WarnPrintf(format, ...); {\ _PRINTF_FORMATE_CONTENT_("WARN ", format, ##__VA_ARGS__) \ fprintf(stdout, _FPRINTF_PARAMETERS_);\ fflush(stdout);\ }; #else #define WarnPrintf(...); do{ }while(0); #endif //---------------------------------------------------------------------------------- //错误输出---------------------------------------------------------------------------------- #ifdef _ERROR_PRINTF_ #define ErrPrintf(format, ...); {\ _PRINTF_FORMATE_CONTENT_("ERROR", format, ##__VA_ARGS__) \ fprintf(stderr, _FPRINTF_PARAMETERS_);\ fflush(stderr);\ }; #else #define ErrPrintf(...); do{ }while(0); #endif //----------------------------------------------------------------------------------打开控制台和重导向日志到文件函数的实现
<span style="font-size:18px;">namespace NamespaceKun { // bool LogInit( const char *infoOutFileName, const char * errOutFileName, const char * infoOutFileMode, const char * errOutFileMode ) { //保存stdout,stderr句柄 static FILE stdoutHandle = __iob_func()[1]; static FILE stderrHandle = __iob_func()[2]; static FILE * logInfoFile = NULL; static FILE * logErrFile = NULL; bool bRet = true; //返回值 if ( NULL != logInfoFile ) {//关闭文件句柄 if (logErrFile == logInfoFile) {//上次打开的是同一个文件 logErrFile = NULL; __iob_func()[2] = stderrHandle; } fclose(logInfoFile); logInfoFile = NULL; __iob_func()[1] = stdoutHandle; } if ( NULL != logErrFile ) {//关闭文件句柄 fclose(logErrFile); logErrFile = NULL; __iob_func()[2] = stderrHandle; } //替换标准输出流 if ( infoOutFileName ) { //打开文件 logInfoFile = _fsopen(infoOutFileName, infoOutFileMode, _SH_DENYWR); if (NULL != logInfoFile) { __iob_func()[1] = *logInfoFile; //stdout } else { char errbuff[1024] = {0}; strerror_s(errbuff, sizeof(errbuff), errno); fprintf(stderr, "%s\n", errbuff); bRet = false; } } //错误输出流 if (errOutFileName) { if ( 0 == strcmp(errOutFileName, infoOutFileName) ) {//当错误和信息文件是同一个文件,则错误输出也使用信息输出的句柄 if (NULL != logInfoFile) { __iob_func()[2] = *logInfoFile; //stderr logErrFile = logInfoFile; } } else { //打开文件 logErrFile = _fsopen(errOutFileName, errOutFileMode, _SH_DENYWR); if (NULL != logErrFile) { __iob_func()[2] = *logErrFile; //stderr } else { char errbuff[1024] = {0}; strerror_s(errbuff, sizeof(errbuff), errno); fprintf(stderr, "%s\n", errbuff); bRet = false; } } } return bRet; } void OpenConsole() {//开启控制台 BOOL re = ::AllocConsole(); FILE *consoleStdout, *consoleStderr, *consoleStdin; freopen_s(&consoleStdout,"CONOUT$","w+t", stdout); freopen_s(&consoleStderr, "CONOUT$","w+t", stderr); freopen_s(&consoleStdin, "CONIN$", "r+t", stdin); } };//namespace NamespaceKun</span>
使用方法如下:
<span style="font-size:18px;">//例子 #ifdef _DEBUG NamespaceKun::OpenConsole();<span style="white-space: pre;"> </ 8dd3 span>//debug模式下MFC程序打开控制台显示 #else <span style="white-space: pre;"> </span>//release模式下直接将日志输出到文件 time_t nowtime = time(NULL); tm tmdatetime; localtime_s(&tmdatetime, &nowtime); char szInfoLogNameBuff[256] = {0}; char szErrLogNameBuff[256] = {0}; strftime(szInfoLogNameBuff,sizeof(szInfoLogNameBuff),"%Y-%m-%d_%H:%M:%S日志INFO.txt",&tmdatetime); strftime(szErrLogNameBuff,sizeof(szErrLogNameBuff),"%Y-%m-%d_%H:%M:%S日志ERR.txt",&tmdatetime); NamespaceKun::LogInit(szInfoLogNameBuff, szErrLogNameBuff);//stdout和stderr可以输出到同一个文件 #endif</span>
<span style="font-size:18px;">InfoPrintf("日志普通输出,数字:%d", 12345678);
WarnPrintf("日志警告输出,数字:%d", 12345678);
ErrPrintf("日志错误信息输出,数字:%d", 12345678);</span>效果如下图:
实现比较简单通道也造成了一些问题。比如长时间运行后会有造成日志文件过大。
相关文章推荐
- 简单的C++加载jvm实现--简单的日志输出
- 简单的C++加载jvm实现--简单的日志输出--JAVA端程序
- Web 事件--向SQL Server 数据库、Windows 事件日志、WMI 命名空间或电子邮件输出事件
- 简单易用的日志c++版本
- 一个基于Loki::SingletonHolder的Windows线程安全的C++日志类实现
- Windows C++ 应用程序通用日志组件(组件及测试程序下载)
- windows下使用gvim搭建简单的IDE编译环境(支持C/C++/Python等)
- 一个关于C++简单递归的奇怪输出结果的不解??
- chklib0.2 release notes——windows平台的c++日志系统
- Windows下C++多线程同步与互斥简单运用
- C++ 控制台彩色输出(windows)
- Windows Store apps开发[26]C++/CX Part 1 of [n]: 一个简单的类
- windows下tomcat输出日志
- Windows下简单配置VIM写C++程序
- WINDOWS下构建简单日志服务器
- C++简单例子 分别用 数组 和 指针来输出单个字符
- 查看Windows 2003系统日志的简单办法
- UCS-2与UTF8之间的选择(3)--windows中各编码字符串的C/C++输出支持及方式比较
- 查看Windows 2003系统日志的简单办法
- windows下输出tomcat应用日志到文件