C++轻量级日志类

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/sunflover454/article/details/49758801
         <!--一个博主专栏付费入口结束-->
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-d284373521.css">
                                    <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-d284373521.css">
            <div class="htmledit_views" id="content_views">


 
 
  1. //logger.h
  2. /*
  3. //类名:CLogger
  4. //功能介绍:Win平台日志记录功能,多线程安全,支持写日志级别的设置,日志格式包含日志等级,日志时间,文件名,行号信息
  5. //作者:sunflover 2016-1-15 14:31:27
  6. //使用方法:
  7. 1:将logger.h,logger.cpp添加到项目中
  8. 2:设置logger.cpp的预编译头选项为“不使用预编译头”
  9. 3:使用代码示例:
  10. #include "Logger.h"
  11. using namespace LOGGER;
  12. CLogger logger(LogLevel_Info,CLogger::GetAppPathA().append("log\\"));
  13. void main()
  14. {
  15. logger.TraceFatal("TraceFatal %d", 1);
  16. logger.TraceError("TraceError %s", "sun");
  17. logger.TraceWarning("TraceWarning");
  18. logger.TraceInfo("TraceInfo");
  19. logger.ChangeLogLevel(LOGGER::LogLevel_Error);
  20. logger.TraceFatal("TraceFatal %d", 2);
  21. logger.TraceError("TraceError %s", "sun2");
  22. logger.TraceWarning("TraceWarning");
  23. logger.TraceInfo("TraceInfo");
  24. }
  25. 执行结果:20160126_101329.log文件内容如下
  26. Fatal 2016-01-26 10:13:29 TraceFatal 1
  27. Error 2016-01-26 10:13:29 TraceError sun
  28. Warning 2016-01-26 10:13:29 TraceWarning
  29. Info 2016-01-26 10:13:29 TraceInfo
  30. Fatal 2016-01-26 10:13:29 TraceFatal 2
  31. Error 2016-01-26 10:13:29 TraceError sun2
  32. */
  33. #ifndef _LOGGER_H_
  34. #define _LOGGER_H_
  35. #include <Windows.h>
  36. #include <stdio.h>
  37. #include <string>
  38. namespace LOGGER
  39. {
  40. //日志级别的提示信息
  41. static const std:: string strFatalPrefix = "Fatal\t";
  42. static const std:: string strErrorPrefix = "Error\t";
  43. static const std:: string strWarningPrefix = "Warning\t";
  44. static const std:: string strInfoPrefix = "Info\t";
  45. //日志级别枚举
  46. typedef enum EnumLogLevel
  47. {
  48. LogLevel_Stop = 0, //什么都不记录
  49. LogLevel_Fatal, //只记录严重错误
  50. LogLevel_Error, //记录严重错误,普通错误
  51. LogLevel_Warning, //记录严重错误,普通错误,警告
  52. LogLevel_Info //记录严重错误,普通错误,警告,提示信息(也就是全部记录)
  53. };
  54. class CLogger
  55. {
  56. public:
  57. //nLogLevel:日志记录的等级,可空
  58. //strLogPath:日志目录,可空
  59. //strLogName:日志名称,可空
  60. CLogger(EnumLogLevel nLogLevel = EnumLogLevel::LogLevel_Info, const std:: string strLogPath = "", const std:: string strLogName = "");
  61. //析构函数
  62. virtual ~CLogger();
  63. public:
  64. //写严重错误信息
  65. void TraceFatal(const char *lpcszFormat, ...);
  66. //写错误信息
  67. void TraceError(const char *lpcszFormat, ...);
  68. //写警告信息
  69. void TraceWarning(const char *lpcszFormat, ...);
  70. //写提示信息
  71. void TraceInfo(const char *lpcszFormat, ...);
  72. //改变写日志级别
  73. void ChangeLogLevel(EnumLogLevel nLevel);
  74. //获取程序运行路径
  75. static std:: string GetAppPathA();
  76. //格式化字符串
  77. static std:: string FormatString(const char *lpcszFormat, ...);
  78. private:
  79. //写文件操作
  80. void Trace(const std::string &strLog);
  81. //获取当前系统时间
  82. std:: string GetTime();
  83. //文件全路径得到文件名
  84. const char *path_file(const char *path, char splitter);
  85. private:
  86. //写日志文件流
  87. FILE * m_pFileStream;
  88. //写日志级别
  89. EnumLogLevel m_nLogLevel;
  90. //日志目录
  91. std:: string m_strLogPath;
  92. //日志的名称
  93. std:: string m_strLogName;
  94. //日志文件全路径
  95. std:: string m_strLogFilePath;
  96. //线程同步的临界区变量
  97. CRITICAL_SECTION m_cs;
  98. };
  99. }
  100. #endif


 
 
  1. //logger.cpp
  2. #include "logger.h"
  3. #include <time.h>
  4. #include <stdarg.h>
  5. #include <direct.h>
  6. #include <vector>
  7. #include <Dbghelp.h>
  8. #pragma comment(lib,"Dbghelp.lib")
  9. using std:: string;
  10. using std:: vector;
  11. namespace LOGGER
  12. {
  13. CLogger::CLogger(EnumLogLevel nLogLevel, const std:: string strLogPath, const std:: string strLogName)
  14. :m_nLogLevel(nLogLevel),
  15. m_strLogPath(strLogPath),
  16. m_strLogName(strLogName)
  17. {
  18. //初始化
  19. m_pFileStream = NULL;
  20. if (m_strLogPath.empty())
  21. {
  22. m_strLogPath = GetAppPathA();
  23. }
  24. if (m_strLogPath[m_strLogPath.length() -1] != '\\')
  25. {
  26. m_strLogPath.append( "\\");
  27. }
  28. //创建文件夹
  29. MakeSureDirectoryPathExists(m_strLogPath.c_str());
  30. //创建日志文件
  31. if (m_strLogName.empty())
  32. {
  33. time_t curTime;
  34. time(&curTime);
  35. tm tm1;
  36. localtime_s(&tm1, &curTime);
  37. //日志的名称如:201601012130.log
  38. m_strLogName = FormatString( "%04d%02d%02d_%02d%02d%02d.log", tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday, tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
  39. }
  40. m_strLogFilePath = m_strLogPath.append(m_strLogName);
  41. //以追加的方式打开文件流
  42. fopen_s(&m_pFileStream, m_strLogFilePath.c_str(), "a+");
  43. InitializeCriticalSection(&m_cs);
  44. }
  45. //析构函数
  46. CLogger::~CLogger()
  47. {
  48. //释放临界区
  49. DeleteCriticalSection(&m_cs);
  50. //关闭文件流
  51. if (m_pFileStream)
  52. {
  53. fclose(m_pFileStream);
  54. m_pFileStream = NULL;
  55. }
  56. }
  57. //文件全路径得到文件名
  58. const char *CLogger::path_file( const char *path, char splitter)
  59. {
  60. return strrchr(path, splitter) ? strrchr(path, splitter) + 1 : path;
  61. }
  62. //写严重错误信息
  63. void CLogger::TraceFatal( const char *lpcszFormat, ...)
  64. {
  65. //判断当前的写日志级别
  66. if (EnumLogLevel::LogLevel_Fatal > m_nLogLevel)
  67. return;
  68. string strResult;
  69. if ( NULL != lpcszFormat)
  70. {
  71. va_list marker = NULL;
  72. va_start(marker, lpcszFormat); //初始化变量参数
  73. size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度
  74. std:: vector< char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
  75. int nWritten = _vsnprintf_s(&vBuffer[ 0], vBuffer.size(), nLength, lpcszFormat, marker);
  76. if (nWritten > 0)
  77. {
  78. strResult = &vBuffer[ 0];
  79. }
  80. va_end(marker); //重置变量参数
  81. }
  82. if (strResult.empty())
  83. {
  84. return;
  85. }
  86. string strLog = strFatalPrefix;
  87. strLog.append(GetTime()).append(strResult);
  88. //写日志文件
  89. Trace(strLog);
  90. }
  91. //写错误信息
  92. void CLogger::TraceError( const char *lpcszFormat, ...)
  93. {
  94. //判断当前的写日志级别
  95. if (EnumLogLevel::LogLevel_Error > m_nLogLevel)
  96. return;
  97. string strResult;
  98. if ( NULL != lpcszFormat)
  99. {
  100. va_list marker = NULL;
  101. va_start(marker, lpcszFormat); //初始化变量参数
  102. size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度
  103. std:: vector< char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
  104. int nWritten = _vsnprintf_s(&vBuffer[ 0], vBuffer.size(), nLength, lpcszFormat, marker);
  105. if (nWritten > 0)
  106. {
  107. strResult = &vBuffer[ 0];
  108. }
  109. va_end(marker); //重置变量参数
  110. }
  111. if (strResult.empty())
  112. {
  113. return;
  114. }
  115. string strLog = strErrorPrefix;
  116. strLog.append(GetTime()).append(strResult);
  117. //写日志文件
  118. Trace(strLog);
  119. }
  120. //写警告信息
  121. void CLogger::TraceWarning( const char *lpcszFormat, ...)
  122. {
  123. //判断当前的写日志级别
  124. if (EnumLogLevel::LogLevel_Warning > m_nLogLevel)
  125. return;
  126. string strResult;
  127. if ( NULL != lpcszFormat)
  128. {
  129. va_list marker = NULL;
  130. va_start(marker, lpcszFormat); //初始化变量参数
  131. size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度
  132. std:: vector< char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
  133. int nWritten = _vsnprintf_s(&vBuffer[ 0], vBuffer.size(), nLength, lpcszFormat, marker);
  134. if (nWritten > 0)
  135. {
  136. strResult = &vBuffer[ 0];
  137. }
  138. va_end(marker); //重置变量参数
  139. }
  140. if (strResult.empty())
  141. {
  142. return;
  143. }
  144. string strLog = strWarningPrefix;
  145. strLog.append(GetTime()).append(strResult);
  146. //写日志文件
  147. Trace(strLog);
  148. }
  149. //写一般信息
  150. void CLogger::TraceInfo( const char *lpcszFormat, ...)
  151. {
  152. //判断当前的写日志级别
  153. if (EnumLogLevel::LogLevel_Info > m_nLogLevel)
  154. return;
  155. string strResult;
  156. if ( NULL != lpcszFormat)
  157. {
  158. va_list marker = NULL;
  159. va_start(marker, lpcszFormat); //初始化变量参数
  160. size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度
  161. std:: vector< char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
  162. int nWritten = _vsnprintf_s(&vBuffer[ 0], vBuffer.size(), nLength, lpcszFormat, marker);
  163. if (nWritten > 0)
  164. {
  165. strResult = &vBuffer[ 0];
  166. }
  167. va_end(marker); //重置变量参数
  168. }
  169. if (strResult.empty())
  170. {
  171. return;
  172. }
  173. string strLog = strInfoPrefix;
  174. strLog.append(GetTime()).append(strResult);
  175. //写日志文件
  176. Trace(strLog);
  177. }
  178. //获取系统当前时间
  179. string CLogger::GetTime()
  180. {
  181. time_t curTime;
  182. time(&curTime);
  183. tm tm1;
  184. localtime_s(&tm1, &curTime);
  185. //2016-01-01 21:30:00
  186. string strTime = FormatString( "%04d-%02d-%02d %02d:%02d:%02d ", tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday, tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
  187. return strTime;
  188. }
  189. //改变写日志级别
  190. void CLogger::ChangeLogLevel(EnumLogLevel nLevel)
  191. {
  192. m_nLogLevel = nLevel;
  193. }
  194. //写文件操作
  195. void CLogger::Trace( const string &strLog)
  196. {
  197. try
  198. {
  199. //进入临界区
  200. EnterCriticalSection(&m_cs);
  201. //若文件流没有打开,则重新打开
  202. if ( NULL == m_pFileStream)
  203. {
  204. fopen_s(&m_pFileStream, m_strLogFilePath.c_str(), "a+");
  205. if (!m_pFileStream)
  206. {
  207. return;
  208. }
  209. }
  210. //写日志信息到文件流
  211. fprintf(m_pFileStream, "%s\n", strLog.c_str());
  212. fflush(m_pFileStream);
  213. //离开临界区
  214. LeaveCriticalSection(&m_cs);
  215. }
  216. //若发生异常,则先离开临界区,防止死锁
  217. catch (...)
  218. {
  219. LeaveCriticalSection(&m_cs);
  220. }
  221. }
  222. string CLogger::GetAppPathA()
  223. {
  224. char szFilePath[MAX_PATH] = { 0 }, szDrive[MAX_PATH] = { 0 }, szDir[MAX_PATH] = { 0 }, szFileName[MAX_PATH] = { 0 }, szExt[MAX_PATH] = { 0 };
  225. GetModuleFileNameA( NULL, szFilePath, sizeof(szFilePath));
  226. _splitpath_s(szFilePath, szDrive, szDir, szFileName, szExt);
  227. string str(szDrive);
  228. str.append(szDir);
  229. return str;
  230. }
  231. string CLogger::FormatString( const char *lpcszFormat, ...)
  232. {
  233. string strResult;
  234. if ( NULL != lpcszFormat)
  235. {
  236. va_list marker = NULL;
  237. va_start(marker, lpcszFormat); //初始化变量参数
  238. size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度
  239. std:: vector< char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
  240. int nWritten = _vsnprintf_s(&vBuffer[ 0], vBuffer.size(), nLength, lpcszFormat, marker);
  241. if (nWritten > 0)
  242. {
  243. strResult = &vBuffer[ 0];
  244. }
  245. va_end(marker); //重置变量参数
  246. }
  247. return strResult;
  248. }
  249. }


有图有真相:


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值