C++轻量级日志类CLogger的使用(更新)

//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

//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;
	}
}


有图有真相:


阅读更多
版权声明:本文为博主原创文章,转载请注明原帖地址。 https://blog.csdn.net/sunflover454/article/details/49758801
个人分类: C++/MFC
想对作者说点什么? 我来说一句

C++高效日志类(库)

2014年07月03日 7KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭