分享一个简易的程序日志记录C++类
2012-07-08 15:53
344 查看
最近一直在忙实验室的项目开发,很少上博客了,现在总算有一定时间空出来做些总结,今天起陆续更新博客,总结一下半年多来的学习心得。
今天先分享一个简易的程序日志记录类,参考自《一个简单又高效的日志系统》,针对项目本身做了一定的修改和补充,编程水平有限,仅供参考,呵呵 。
头文件:
实现代码:
今天先分享一个简易的程序日志记录类,参考自《一个简单又高效的日志系统》,针对项目本身做了一定的修改和补充,编程水平有限,仅供参考,呵呵 。
头文件:
#ifndef _INFO_LOGGER_H_ #define _INFO_LOGGER_H_ /******************************************************************** * created: 8/7/2012 13:41 * filename: CinfoLogger.h * author: ZouYuhua @ BUAA * * purpose: 这是一个简易的程序运行日志记录类 * 主要功能是 * 1. 将带参数的格式化字符串写入日志缓存字符串 * 2. 当缓存字符串长度大于阈值 或者 定时时间到 时,将缓存写入到本地log文件 * 3. 将带参数的格式化字符串转换为 std::string 字符串 * 4. 将当前系统时间转换为指定格式的字符串 * 5. 获取高精度(微秒级)的系统时间 * * sample: 使用示例 * * // 包含头文件,可以放在 stdafx.h 中 * * #include "CinfoLogger.h" * #define WRITE_LOG CinfoLogger::instance()->LogInfo * #define STRING_FORMAT CinfoLogger::instance()->LogInfo * #define ENTER_FUNC CinfoLogger::instance()->EnterFunction * #define LE***E_FUNC CinfoLogger::instance()->LeaveFunction * #define GET_TIME_STRING CinfoLogger::instance()->GetCurTimeToString * #define GET_TIME_ELAPSED CinfoLogger::instance()->GetTimeElapsed * #define GET_TIME_NOW CinfoLogger::instance()->GetSystemTimerCount() * #define LOG_LEVEL_FORMAT -1 * #define LOG_LEVEL_MAIN 0 * #define LOG_LEVEL_SUB_1 1 * #define LOG_LEVEL_SUB_2 2 * #define LOG_LEVEL_SUB_3 3 * * //具体调用方式 * * //1.写入日志 * WRITE_LOG(LOG_LEVEL_MAIN, "正在获取数据。"); * WRITE_LOG(LOG_LEVEL_SUB_1, "The value is %d", value); * cout << WRITE_LOG(LOG_LEVEL_MAIN, "写入日志缓存,并在控制台窗口显示信息。") << endl; * * //2.格式化字符串转换 * std::string info = "The "; * info += STRING_FORMAT(LOG_LEVEL_FORMAT, "value is %d", value); * * //3.将当前时间转换为字符串,作为文件名的一部分 * std::string imgFileName = "img_" + GET_TIME_STRING() + ".jpg"; * * //4.程序运行时间计时 * LONGLONG t_start = GET_TIME_NOW; * // do something ... * double t_elapsed = GET_TIME_ELAPSED( t_start ); * WRITE_LOG(LOG_LEVEL_MAIN, "[Main Process] 用时: %.3f ms", t_elapsed); * * //5.记录函数进出事件 * function func * { * ENTER_FUNC("func"); * ... * LE***E_FUNC("func"); * } ********************************************************************/ #pragma once //------------------------------------------------------------------------- // Includes //------------------------------------------------------------------------- /*** * 在 stdafx.h 还包含了其它的头文件,也可能在本类中用到 * #include "targetver.h" #include <stdio.h> #include <tchar.h> // TODO: 在此处引用程序需要的其他头文件 #include <Windows.h> #include <iostream> #include <vector> #include <time.h> #include <stdlib.h> #include <conio.h> */ #include <fstream> //------------------------------------------------------------------------- // 本类使用 boost 库的 thread 类进行线程管理 // 其在 VC6 中的应用和设置请参考以下资料: // 《Boost 1_37_0 的安装以及在VC6.0中的使用》http://www.cnblogs.com/cy163/archive/2010/03/27/1698156.html // 另外一种C++多线程方法,是利用 _beginthreadex,参考以下资料: // 《C/C++ Runtime 多线程函数》http://www.cppblog.com/mzty/archive/2007/07/25/28756.html //------------------------------------------------------------------------- #include <boost/thread.hpp> //------------------------------------------------------------------------- // Defines //------------------------------------------------------------------------- #define MAX_STR_BUF_LEN 30000 //日志缓存最大长度,超过则将日志缓存写入到本地文件 #define TIME_TO_WRITE_LOG 5000 //定时时间(毫秒),超过则将日志缓存写入到本地文件 using namespace std; //------------------------------------------------------------------------- // Class //------------------------------------------------------------------------- class CinfoLogger { public: /*---------------------------- * 功能 : 获取类实例静态指针 *---------------------------- * 函数 : CinfoLogger::instance * 访问 : public static * 返回 : CinfoLogger* */ static CinfoLogger* instance(); /*---------------------------- * 功能 : 将 带参数的日志信息 输出到 IDE 输出窗口,并保存到 日志文件缓存 中 *---------------------------- * 函数 : CinfoLogger::LogInfo * 访问 : public * 返回 : string [ret] 格式化后的字符串 * * 参数 : int level [in] 日志级别 * 按照程序分支级别定义,主程序 Kinect_NI 的级别为 0 * 当 level < 0 时,功能相当于 sprintf 函数 * 仅生成 string 字符串,不在输出窗口显示、也不写入缓存 * 参数 : char * fmt [in] 格式化字符串 * 参数 : ... [in] 具体参数 */ string LogInfo(int level, char *fmt, ...); /*** * LogInfo 重载,日志信息 为 字符串常量 * * 参数 : int level [in] 日志级别 * 参数 : string info [in] 字符串常量 */ string LogInfo(int level, string info); /*---------------------------- * 功能 : 记录进入某一功能函数的事件 *---------------------------- * 函数 : CinfoLogger::EnterFunction * 访问 : public * 返回 : void * * 参数 : string funcName [in] 函数名称 * 或者 * 参数 : const char* funcName [in] 函数名称 */ void EnterFunction(string funcName) { LogInfo(1, "Enter function: " + funcName); } //重载1 void EnterFunction(const char* funcName) { LogInfo(1, "Enter function: %s", funcName); } /*---------------------------- * 功能 : 记录离开某一功能函数的事件 *---------------------------- * 函数 : CinfoLogger::LeaveFunction * 访问 : public * 返回 : void * * 参数 : string funcName [in] 函数名称 * 或者 * 参数 : const char* funcName [in] 函数名称 */ void LeaveFunction(string funcName) { LogInfo(1, "Leave function: " + funcName); } //重载1 void LeaveFunction(const char* funcName) { LogInfo(1, "Leave function: %s", funcName); } /*---------------------------- * 功能 : 将当前系统时间(年月日时分秒)转换为 string 字符串 *---------------------------- * 函数 : CinfoLogger::GetCurTimeToString * 访问 : public * 返回 : std::string [ret] 系统时间字符串 * * 参数 : TIME_STRING_MODE mode [in] 时间字符串的输出格式,分两种:文件名模式 和 文本模式 */ enum TIME_STRING_MODE { FOR_FILE_NAME, // 按 文件名格式 获取时间字符串 FOR_TEXT // 按 文本格式 获取时间字符串 }; string GetCurTimeToString(TIME_STRING_MODE mode = FOR_TEXT); /*---------------------------- * 功能 : 获取计算机内部定时器的当前值 *---------------------------- * 函数 : CinfoLogger::GetSystemTimerCount * 访问 : public * 返回 : LONGLONG [ret] 频率计数 * */ LONGLONG GetSystemTimerCount() { LARGE_INTEGER liTmp; QueryPerformanceCounter( &liTmp ); return liTmp.QuadPart; } /*---------------------------- * 功能 : 获取微秒级的精确时间 *---------------------------- * 函数 : CinfoLogger::GetTimeElapsed * 访问 : public * 返回 : double [ret] 整数位表示毫秒、小数位表示微秒的时间值 * * 参数 : LONGLONG tStart [in] 定时器计数 2 */ double GetTimeElapsed(LONGLONG tStart) { double dfTime, dfFreq, dfDiff; LARGE_INTEGER liTmp; LONGLONG tNow; QueryPerformanceCounter( &liTmp ); //获得当前计数值 tNow = liTmp.QuadPart; QueryPerformanceFrequency(&liTmp); //获得时钟频率 dfFreq = (double)liTmp.QuadPart; dfDiff = (double)(tNow - tStart); dfTime = dfDiff / dfFreq; //获得对应的时间值(秒) dfTime *= 1000; //转换为毫秒值 return dfTime; } /*---------------------------- * 功能 : 将内部变量 m_bRun 置为 false,以退出日志循环线程 *---------------------------- * 函数 : CinfoLogger::SetExit * 访问 : public * 返回 : void */ void SetExit() { m_bRun = false; } private: //------------------------------------------------------------------------- // 内部变量 //------------------------------------------------------------------------- static CinfoLogger* _instance; // 日志类实例静态指针,只创建一次,其它类通过此指针来访问类内函数 boost::thread m_hThread; // 线程指针 boost::mutex m_logMutex; // 线程对象 bool m_bRun; // 线程循环使能标志 string m_strWriteStrInfo; // 日志文件缓存字符串 string m_strLogFileName; // 日志文件名,每次启动时按照系统时间自动生成 //------------------------------------------------------------------------- // 内部函数 //------------------------------------------------------------------------- /*---------------------------- * 功能 : 类实例初始化 *---------------------------- * 函数 : CinfoLogger::CinfoLogger * 访问 : private * 返回 : */ CinfoLogger(void); /*---------------------------- * 功能 : 更新日志缓存 *---------------------------- * 函数 : CinfoLogger::WriteLog * 访问 : private * 返回 : void * * 参数 : string strLog [in] 日志信息 */ void WriteLog(string strLog); /*---------------------------- * 功能 : 日志循环线程 * 每隔五秒定时、或者 日志缓存字符串长度大于阈值时 * 将缓存的日志信息强制写入到本地文件 *---------------------------- * 函数 : CinfoLogger::LogProcStart * 访问 : private * 返回 : void */ void LogProcStart(); /*---------------------------- * 功能 : 将缓存的日志信息写入到本地日志文件 *---------------------------- * 函数 : CinfoLogger::WriteLogToFile * 访问 : private * 返回 : void */ void WriteLogToFile(); }; #endif
实现代码:
#include "StdAfx.h" #include "CinfoLogger.h" //------------------------------------------------------------------------- // // ------ 内部变量与函数 ------ // //------------------------------------------------------------------------- // 类实例静态指针(初始为空) CinfoLogger* CinfoLogger::_instance = NULL; /*---------------------------- * 功能 : 类实例初始化 *---------------------------- * 函数 : CinfoLogger::CinfoLogger * 访问 : private * 返回 : */ CinfoLogger::CinfoLogger(void) { // 启动信息 m_strWriteStrInfo = ""; // 日志文件名称 m_strLogFileName = "Run_" + GetCurTimeToString(FOR_FILE_NAME) + ".log"; // 创建日志线程 m_bRun = true; m_hThread = boost::thread( boost::bind( &CinfoLogger::LogProcStart, this )); } /*---------------------------- * 功能 : 日志循环线程 * 每隔五秒定时、或者 日志缓存字符串长度大于阈值时 * 将缓存的日志信息强制写入到本地文件 *---------------------------- * 函数 : CinfoLogger::LogProcStart * 访问 : private * 返回 : void */ void CinfoLogger::LogProcStart() { int nCount = 1; clock_t preSaveTime = clock(); do { Sleep(250); if ( (clock() - preSaveTime) > TIME_TO_WRITE_LOG ) { preSaveTime = clock(); WriteLogToFile(); // 每隔五秒写一次日志 } } while (m_bRun); if (!m_strWriteStrInfo.empty()) WriteLogToFile(); // 退出循环后如果缓存非空,则将缓存写入日志 再退出线程 cout << LogInfo(LOG_LEVEL_SUB_1, "[- Info Logger] 正在退出日志线程!") << endl; } /*---------------------------- * 功能 : 更新日志缓存 *---------------------------- * 函数 : CinfoLogger::WriteLog * 访问 : private * 返回 : void * * 参数 : string strLog [in] 日志信息 */ void CinfoLogger::WriteLog(string strLog) { if ( !strLog.empty() ) { m_strWriteStrInfo += "[" + GetCurTimeToString() + "] "; m_strWriteStrInfo += strLog; m_strWriteStrInfo += _T("\r\n"); } if ( m_strWriteStrInfo.length() > MAX_STR_BUF_LEN ) { WriteLogToFile(); // 达到一定量时才写入到文件中 } } /*---------------------------- * 功能 : 将缓存的日志信息写入到本地日志文件 *---------------------------- * 函数 : CinfoLogger::WriteLogToFile * 访问 : private * 返回 : void */ void CinfoLogger::WriteLogToFile() { if (m_logMutex.try_lock()) { try { // 以 Append 方式打开日志文件 ofstream osWriter( m_strLogFileName.c_str(), ios::out | ios_base::app ); if (osWriter.is_open()) { // 写入日志缓存 osWriter << m_strWriteStrInfo.c_str(); // 清空日志缓存 m_strWriteStrInfo = ""; // 关闭文件写入器 osWriter.close(); } } catch (std::exception e) { cout << LogInfo(LOG_LEVEL_FORMAT, "写入文件失败:%s", e.what()) << endl; } m_logMutex.unlock(); } } //------------------------------------------------------------------------- // // ------- 访问接口 ------ // //------------------------------------------------------------------------- /*---------------------------- * 功能 : 创建类实例静态指针 *---------------------------- * 函数 : CinfoLogger::instance * 访问 : public static * 返回 : CinfoLogger* */ CinfoLogger* CinfoLogger::instance() { // 若静态指针为空,则创建类实例,并获取指针 if (_instance == NULL) { _instance = new CinfoLogger(); } // 返回静态指针 return _instance; } /*---------------------------- * 功能 : 将 日志信息 输出到 IDE 输出窗口,并保存到 日志文件缓存 中 *---------------------------- * 函数 : CinfoLogger::LogInfo * 访问 : public * 返回 : string [ret] 格式化后的字符串 * * 参数 : int level [in] 日志级别 * 按照程序分支级别定义,主程序 Kinect_NI 的级别为 0 * 当 level < 0 时,功能相当于 sprintf 函数 * 仅生成 string 字符串,不在输出窗口显示、也不写入缓存 * 参数 : char * fmt [in] 格式化字符串 * 参数 : ... [in] 具体参数 */ string CinfoLogger::LogInfo(int level,char *fmt, ...) { // 格式化输入的字符串 fmt 到输出字符串 out char out[1024]; va_list body; va_start(body, fmt); vsprintf_s(out, fmt, body); va_end(body); // 将日志信息转换为 string 字符串,存入缓存变量中 string strTemp(out); //日志级别需要大于设定级别 或者 小于 0,则只返回字符串,不作记录 if(level > CparamServer::instance()->LogLevel() || level < 0) { return strTemp; } // 在输出窗口显示日志信息 OutputDebugStringA(out); OutputDebugStringA("\n"); // 将信息存入日志缓存中 WriteLog( strTemp ); return strTemp; } /*---------------------------- * LogInfo 重载,日志信息 为 字符串常量 *---------------------------- * 参数 : int level [in] 日志级别,按照程序分支级别定义,主程序 Kinect_NI 的级别为 0 * 参数 : string info [in] 字符串常量 */ string CinfoLogger::LogInfo(int level, string info) { //日志级别需要小于或等于设定级别,否则不记录 if(level > CparamServer::instance()->LogLevel()) { return info; } if (level >= 0) { // 在输出窗口显示日志信息 OutputDebugStringA(info.c_str()); // 将信息存入日志缓存中 WriteLog( info ); } return info; } /*---------------------------- * 功能 : 将当前系统时间转换为 string 字符串 *---------------------------- * 函数 : CinfoLogger::GetCurTimeStr * 访问 : public * 返回 : std::string [ret] 系统时间字符串 * * 参数 : TIME_STRING_MODE mode [in] 时间字符串的输出格式,分两种:文件名模式 和 文本模式 */ string CinfoLogger::GetCurTimeToString(TIME_STRING_MODE mode /* = FOR_TEXT */) { int strLen = 20; string retStr = "0"; if (mode == FOR_TEXT) { char *pszCurrTime1 = (char*)malloc(sizeof(char)*strLen); memset(pszCurrTime1, 0, sizeof(char)*strLen); time_t now; time(&now); strftime(pszCurrTime1, strLen , "%Y-%m-%d %H:%M:%S", localtime(&now)); retStr = pszCurrTime1; } else if (mode == FOR_FILE_NAME) { char *pszCurrTime2 = (char*)malloc(sizeof(char)*strLen); memset(pszCurrTime2, 0, sizeof(char)*strLen); time_t now; time(&now); strftime(pszCurrTime2, strLen , "%Y_%m_%d_%H_%M_%S", localtime(&now)); retStr = pszCurrTime2; } return retStr; }
相关文章推荐
- 分享一个简单的日志记录静态类
- [原创]自己写的一个简单的程序日志记录类
- 分享个C++日志记录类以及日志记录程序
- Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!
- 使用LOG4J记录程序日志的一个例子
- 分享一个记录日志的类,可多线程使用。
- 两个日志记录程序操作同一个log文件
- Python:通过自定义系统级快捷键来控制程序开始或停止记录日志(使用小技巧解决一个貌似无解的问题)
- 一个简易的C++日志记录类
- Python:通过自定义系统级快捷键来控制程序开始或停止记录日志(使用小技巧解决一个貌似无解的问题)
- 分享一个Android 分类打印,及日志记录工具
- 程序日志中自动记录所在函数名、文件名、行号,并定向输出到一个日志文件
- 一个简易的日志程序
- 程序那些事:日志记录的作用和方法
- 【转载】程序那些事:日志记录的作用和方法
- 分享一个用Xcode4实现基于Webservice用户登录的iphone程序
- 扔掉log4j、log4j2,自己动手实现一个多功能日志记录框架,包含文件,数据库日志写入,实测5W+/秒日志文件写入,2W+/秒数据库日志写入,虽然它现在还没有logback那么强大
- printf记录程序日志,彻底告别vsnprintf
- c++的一个程序源码记录
- 网站访客 简易日志记录