2019.10.28C++学习笔记——简单日志类

C++学习笔记——简单日志类

最近工作中我发现工作项目与在学校中的课设有很大不同,其中非常重要的一点就是对于代码每次bug产生和修复的记录,以此来提醒自己代码的改进过程。但是对于工作项目来说,每次的错误记录都要手工记录有些麻烦,所以需要在代码中加入可以帮助我们自动调用和写入日志的日志类来简化错误记录过程。

Log日志需求:

我暂时对于日志需求不高,要求在运行程序时,如果有函数返回了错误信息的返回值,则调用日志类写入日志,写入信息包括时间,错误等级和错误信息。

CLogger轻量级日志类:

头文件:


```cpp

```cpp
//logger.h
/*
//类名:CLogger
//功能介绍:Win平台日志记录功能,多线程安全,支持写日志级别的设置,日志格式包含日志等级,日志时间,文件名,行号信息
//作者:sunflover 2016-1-15 14:31:27
//使用方法:
1:将logger.h,logger.cpp添加到项目中
2:设置logger.cpp的预编译头选项为“不使用预编译头”
3:使用代码示例:
#include "Logger.h"
using namespace LOGGER;
CLogger logger(LogLevel_Info,CLogger::GetAppPathA().append("log\\"));
void main()
{
logger.TraceFatal("TraceFatal %d", 1);
logger.TraceError("TraceError %s", "sun");
logger.TraceWarning("TraceWarning");
logger.TraceInfo("TraceInfo");
logger.ChangeLogLevel(LOGGER::LogLevel_Error);
logger.TraceFatal("TraceFatal %d", 2);
logger.TraceError("TraceError %s", "sun2");
logger.TraceWarning("TraceWarning");
logger.TraceInfo("TraceInfo");
}
执行结果:20160126_101329.log文件内容如下
Fatal	2016-01-26 10:13:29 TraceFatal 1
Error	2016-01-26 10:13:29 TraceError sun
Warning	2016-01-26 10:13:29 TraceWarning
Info	2016-01-26 10:13:29 TraceInfo
Fatal	2016-01-26 10:13:29 TraceFatal 2
Error	2016-01-26 10:13:29 TraceError sun2
*/
 
#ifndef _LOGGER_H_
#define _LOGGER_H_
#include <Windows.h>
#include <stdio.h>
#include <string>
 
namespace LOGGER
{
	//日志级别的提示信息
	static const std::string strFatalPrefix = "Fatal\t";
	static const std::string strErrorPrefix = "Error\t";
	static const std::string strWarningPrefix = "Warning\t";
	static const std::string strInfoPrefix = "Info\t";
 
	//日志级别枚举
	typedef enum EnumLogLevel
	{
		LogLevel_Stop = 0,	//什么都不记录
		LogLevel_Fatal,		//只记录严重错误
		LogLevel_Error,		//记录严重错误,普通错误
		LogLevel_Warning,	//记录严重错误,普通错误,警告
		LogLevel_Info		//记录严重错误,普通错误,警告,提示信息(也就是全部记录)
	};
 
	class CLogger
	{
	public:
		//nLogLevel:日志记录的等级,可空
		//strLogPath:日志目录,可空
		//strLogName:日志名称,可空
		CLogger(EnumLogLevel nLogLevel = EnumLogLevel::LogLevel_Info, const std::string strLogPath = "", const std::string strLogName = "");
		//析构函数
		virtual ~CLogger();
	public:
		//写严重错误信息
		void TraceFatal(const char *lpcszFormat, ...);
		//写错误信息
		void TraceError(const char *lpcszFormat, ...);
		//写警告信息
		void TraceWarning(const char *lpcszFormat, ...);
		//写提示信息
		void TraceInfo(const char *lpcszFormat, ...);
		//改变写日志级别
		void ChangeLogLevel(EnumLogLevel nLevel);
		//获取程序运行路径
		static std::string GetAppPathA();
		//格式化字符串
		static std::string FormatString(const char *lpcszFormat, ...);
	private:
		//写文件操作
		void Trace(const std::string &strLog);
		//获取当前系统时间
		std::string GetTime();
		//文件全路径得到文件名
		const char *path_file(const char *path, char splitter);
	private:
		//写日志文件流
		FILE * m_pFileStream;
		//写日志级别
		EnumLogLevel m_nLogLevel;
		//日志目录
		std::string m_strLogPath;
		//日志的名称
		std::string m_strLogName;
		//日志文件全路径
		std::string m_strLogFilePath;
		//线程同步的临界区变量
		CRITICAL_SECTION m_cs;
	};
}
 
#endif

cpp文件:

//logger.cpp
#include "logger.h"
#include <time.h>
#include <stdarg.h>
#include <direct.h>
#include <vector>
#include <Dbghelp.h>
#pragma comment(lib,"Dbghelp.lib")
 
using std::string;
using std::vector;
 
namespace LOGGER
{
	CLogger::CLogger(EnumLogLevel nLogLevel, const std::string strLogPath, const std::string strLogName)
		:m_nLogLevel(nLogLevel),
		m_strLogPath(strLogPath),
		m_strLogName(strLogName)
	{
		//初始化
		m_pFileStream = NULL;
		if (m_strLogPath.empty())
		{
			m_strLogPath = GetAppPathA();
		}
		if (m_strLogPath[m_strLogPath.length()-1] != '\\')
		{
			m_strLogPath.append("\\");
		}
		//创建文件夹
		MakeSureDirectoryPathExists(m_strLogPath.c_str());
		//创建日志文件
		if (m_strLogName.empty())
		{
			time_t curTime;
			time(&curTime);
			tm tm1;
			localtime_s(&tm1, &curTime);
			//日志的名称如:201601012130.log
			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);
		}
		m_strLogFilePath = m_strLogPath.append(m_strLogName);
 
		//以追加的方式打开文件流
		fopen_s(&m_pFileStream, m_strLogFilePath.c_str(), "a+");
 
		InitializeCriticalSection(&m_cs);
	}
 
 
	//析构函数
	CLogger::~CLogger()
	{
		//释放临界区
		DeleteCriticalSection(&m_cs);
		//关闭文件流
		if (m_pFileStream)
		{
			fclose(m_pFileStream);
			m_pFileStream = NULL;
		}
	}
 
	//文件全路径得到文件名
	const char *CLogger::path_file(const char *path, char splitter)
	{
		return strrchr(path, splitter) ? strrchr(path, splitter) + 1 : path;
	}
 
	//写严重错误信息
	void CLogger::TraceFatal(const char *lpcszFormat, ...)
	{
		//判断当前的写日志级别
		if (EnumLogLevel::LogLevel_Fatal > m_nLogLevel)
			return;
		string strResult;
		if (NULL != lpcszFormat)
		{
			va_list marker = NULL;
			va_start(marker, lpcszFormat); //初始化变量参数
			size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度
			std::vector<char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
			int nWritten = _vsnprintf_s(&vBuffer[0], vBuffer.size(), nLength, lpcszFormat, marker);
			if (nWritten > 0)
			{
				strResult = &vBuffer[0];
			}
			va_end(marker); //重置变量参数
		}
		if (strResult.empty())
		{
			return;
		}
		string strLog = strFatalPrefix;
		strLog.append(GetTime()).append(strResult);
 
		//写日志文件
		Trace(strLog);
	}
 
	//写错误信息
	void CLogger::TraceError(const char *lpcszFormat, ...)
	{
		//判断当前的写日志级别
		if (EnumLogLevel::LogLevel_Error > m_nLogLevel)
			return;
		string strResult;
		if (NULL != lpcszFormat)
		{
			va_list marker = NULL;
			va_start(marker, lpcszFormat); //初始化变量参数
			size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度
			std::vector<char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
			int nWritten = _vsnprintf_s(&vBuffer[0], vBuffer.size(), nLength, lpcszFormat, marker);
			if (nWritten > 0)
			{
				strResult = &vBuffer[0];
			}
			va_end(marker); //重置变量参数
		}
		if (strResult.empty())
		{
			return;
		}
		string strLog = strErrorPrefix;
		strLog.append(GetTime()).append(strResult);
 
		//写日志文件
		Trace(strLog);
	}
 
	//写警告信息
	void CLogger::TraceWarning(const char *lpcszFormat, ...)
	{
		//判断当前的写日志级别
		if (EnumLogLevel::LogLevel_Warning > m_nLogLevel)
			return;
		string strResult;
		if (NULL != lpcszFormat)
		{
			va_list marker = NULL;
			va_start(marker, lpcszFormat); //初始化变量参数
			size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度
			std::vector<char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
			int nWritten = _vsnprintf_s(&vBuffer[0], vBuffer.size(), nLength, lpcszFormat, marker);
			if (nWritten > 0)
			{
				strResult = &vBuffer[0];
			}
			va_end(marker); //重置变量参数
		}
		if (strResult.empty())
		{
			return;
		}
		string strLog = strWarningPrefix;
		strLog.append(GetTime()).append(strResult);
 
		//写日志文件
		Trace(strLog);
	}
 
 
	//写一般信息
	void CLogger::TraceInfo(const char *lpcszFormat, ...)
	{
		//判断当前的写日志级别
		if (EnumLogLevel::LogLevel_Info > m_nLogLevel)
			return;
		string strResult;
		if (NULL != lpcszFormat)
		{
			va_list marker = NULL;
			va_start(marker, lpcszFormat); //初始化变量参数
			size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度
			std::vector<char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
			int nWritten = _vsnprintf_s(&vBuffer[0], vBuffer.size(), nLength, lpcszFormat, marker);
			if (nWritten > 0)
			{
				strResult = &vBuffer[0];
			}
			va_end(marker); //重置变量参数
		}
		if (strResult.empty())
		{
			return;
		}
		string strLog = strInfoPrefix;
		strLog.append(GetTime()).append(strResult);
 
		//写日志文件
		Trace(strLog);
	}
 
	//获取系统当前时间
	string CLogger::GetTime()
	{
		time_t curTime;
		time(&curTime);
		tm tm1;
		localtime_s(&tm1, &curTime);
		//2016-01-01 21:30:00
		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);
 
		return strTime;
	}
 
	//改变写日志级别
	void CLogger::ChangeLogLevel(EnumLogLevel nLevel)
	{
		m_nLogLevel = nLevel;
	}
 
	//写文件操作
	void CLogger::Trace(const string &strLog)
	{
		try
		{
			//进入临界区
			EnterCriticalSection(&m_cs);
			//若文件流没有打开,则重新打开
			if (NULL == m_pFileStream)
			{
				fopen_s(&m_pFileStream, m_strLogFilePath.c_str(), "a+");
				if (!m_pFileStream)
				{
					return;
				}
			}
			//写日志信息到文件流
			fprintf(m_pFileStream, "%s\n", strLog.c_str());
			fflush(m_pFileStream);
			//离开临界区
			LeaveCriticalSection(&m_cs);
		}
		//若发生异常,则先离开临界区,防止死锁
		catch (...)
		{
			LeaveCriticalSection(&m_cs);
		}
	}
 
	string CLogger::GetAppPathA()
	{
		char szFilePath[MAX_PATH] = { 0 }, szDrive[MAX_PATH] = { 0 }, szDir[MAX_PATH] = { 0 }, szFileName[MAX_PATH] = { 0 }, szExt[MAX_PATH] = { 0 };
		GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath));
		_splitpath_s(szFilePath, szDrive, szDir, szFileName, szExt);
 
		string str(szDrive);
		str.append(szDir);
		return str;
	}
 
	string CLogger::FormatString(const char *lpcszFormat, ...)
	{
		string strResult;
		if (NULL != lpcszFormat)
		{
			va_list marker = NULL;
			va_start(marker, lpcszFormat); //初始化变量参数
			size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度
			std::vector<char> vBuffer(nLength, '\0'); //创建用于存储格式化字符串的字符数组
			int nWritten = _vsnprintf_s(&vBuffer[0], vBuffer.size(), nLength, lpcszFormat, marker);
			if (nWritten > 0)
			{
				strResult = &vBuffer[0];
			}
			va_end(marker); //重置变量参数
		}
		return strResult;
	}
}

参考:
CLogger轻量级日志类


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值