C++跨平台基于log4cpp二次单例封装

项目因为切换日志库,选型log4cpp,为了使用方便,进行了二次封装

 log4cpp.h

#ifndef __LOG_4_CPP__
#define __LOG_4_CPP__

#include<iostream>
#include <string.h> //strrchr()函数所需头文件
#include <stdio.h>
#include <stdarg.h>
#include<log4cpp/Category.hh>
#include<log4cpp/PatternLayout.hh>
#include<log4cpp/OstreamAppender.hh>
#include<log4cpp/FileAppender.hh>
#include<log4cpp/RollingFileAppender.hh>
#include<log4cpp/Priority.hh>

#ifdef _WIN32
#include <direct.h>
#include <io.h>
#else 
#include <stdarg.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/stat.h>
#include <cstdlib>
#endif

//日志优先级
enum Priority {
	LOG_LEVEL_ERROR = 0,
	LOG_LEVEL_WARN = 1,
	LOG_LEVEL_INFO = 2,
	LOG_LEVEL_DEBUG = 3
};


#define MAX_LOG_RECORD_LEN    1024*4	//每条日志大小
#define MAX_LOGSIZE 1024*1024*10		//日志文件大小,默认10M   1024*1024*10
#define LOGFILE_SIZE 30					//文件日志数量

//用单例模式封装log4cpp
class CCVLog {
public:
	static CCVLog& getInstance();
	~CCVLog();
	
	// 设置日志输出文件名 [10/16/2019 none]
	bool SetLogFileName(const std::string& fileName = "log4cpp.log");

	// 设置日志级别 [10/16/2019 none]
	void SetPriority(Priority priority);

	// 日志打印 [10/16/2019 none]
	void Info(const char* pchFormat, ...);
	void Debug(const char* pchFormat, ...);
	void Error(const char* pchFormat, ...);
	void Warn(const char* pchFormat, ...);
	//void Warn(const char* szFileName, const int nLineNo, const char* pchFormat, ...);

	// 释放 [10/16/2019 none]
	void Destory();

private:
	//单例模式:构造函数私有化
	CCVLog(); 

	//设置终端不显示,只打印日志文件 [10/16/2019 none]
	void SetLogOnMonitor(const char* pszCfgFileName);

	//读取日志配置文件 [10/16/2019 none]
	void SetConfigureFile(const char* pszCfgFileName);

	//创建日志文件夹 [10/16/2019 none]
	bool CreatLogDir(int nPos, std::string strFileName);
private:
	std::string					m_strLogFileName;
	log4cpp::Category&			m_Category_Ref;
	static CCVLog*				m_pLog;
	static char					m_szLogBuf[MAX_LOG_RECORD_LEN];
	log4cpp::OstreamAppender*	m_pOs_Appender;
	log4cpp::FileAppender*		m_pFile_Appender;
};

#ifdef WIN32
#define FILENAME(x) strrchr(x,'\\')?strrchr(x,'\\')+1:x
#else
#define FILENAME(x) strrchr(x,'/')?strrchr(x,'/')+1:x
#endif

static CCVLog &CVLog = CCVLog::getInstance();	//实例化单例

#define LOG_E(format, ...)		CVLog.Error(format, ##__VA_ARGS__)
#define LOG_W(format, ...)		CVLog.Warn(format, ##__VA_ARGS__)
#define LOG_I(format, ...)		CVLog.Info(format, ##__VA_ARGS__)
#define LOG_D(format, ...)		CVLog.Debug(format, ##__VA_ARGS__)

//#define LOG_I(format, ...)		CVLog.Info(FILENAME(__FILE__), __LINE__, format, ##__VA_ARGS__)



#endif // !__LOG_4_CPP__

log4cpp.cpp

#include "stdafx.h"
#include "log4cpp.h"
#include<iostream>

using namespace std;

#ifdef _WIN32
#define ACCESS _access
#define MKDIR(a) _mkdir((a))
int CreatDir(char *pDir)
{
	int i = 0;
	int iRet = 0;
	int iLen;
	char* pszDir;
	if (NULL == pDir)
	{
		return 0;
	}
	pszDir = strdup(pDir);
	iLen = strlen(pszDir);
	// 创建中间目录
	for (i = 0; i < iLen; i++)
	{
		if (pszDir[i] == '\\' || pszDir[i] == '/')
		{
			pszDir[i] = '\0';
			iRet = ACCESS(pszDir, 0);	//如果不存在,创建
			if (iRet != 0)
			{
				iRet = MKDIR(pszDir);
				if (iRet != 0)
				{
					return -1;
				}
			}
			pszDir[i] = '/';	//支持linux,将所有\换成/
		}
	}

	iRet = MKDIR(pszDir);
	free(pszDir);
	printf("-----%d---\n", iLen);
	return iRet;
}
#else 
#define ACCESS access
#define MKDIR(a) mkdir((a),0755)
//创建多级目录
int CreatDir(char* sPathName)
{
	char szCmd[128] = { 0 };	//system("mkdir -p path");
	sprintf(szCmd, "mkdir -p  %s", sPathName);
	system(szCmd);
	return 0;
}
#endif

// 静态成员初始化
char CCVLog::m_szLogBuf[MAX_LOG_RECORD_LEN] = { 0 };
CCVLog* CCVLog::m_pLog = NULL;

//获取log指针
CCVLog& CCVLog::getInstance() 
{
	if (m_pLog == NULL) {
		m_pLog = new CCVLog;
	}
	return *m_pLog;
}

//销毁
CCVLog::~CCVLog() { }


//销毁
void CCVLog::Destory()
{
	if (m_pLog) {
		m_pLog->m_Category_Ref.info("log4cpp destroy :%s", m_strLogFileName.c_str());
		m_pLog->m_Category_Ref.shutdown();
		delete m_pLog;
		m_pLog = NULL;
	}
}

//构造函数
CCVLog::CCVLog() : m_Category_Ref(log4cpp::Category::getRoot()), m_strLogFileName(std::string("log4cpp.log"))
{

}

void CCVLog::SetLogOnMonitor(const char* pszCfgFileName)
{

}

void CCVLog::SetConfigureFile(const char* pszCfgFileName)
{

}

//创建日志文件夹 [10/16/2019 none]
bool CCVLog::CreatLogDir(int nPos, std::string strFileName)
{
	char szpath[128] = { 0 };
	memset(szpath, 0, 128);
	std::string strPath = strFileName.substr(0, nPos + 1);
	sprintf(szpath, "%s", strPath.c_str());
#ifdef _WIN32
	if (0 == CreatDir(szpath))
	{
		printf("创建日志文件夹失败");
		return false;
	}
#else 
	CreatDir(szpath);
#endif
	return true;
}

// 设置日志级别 [10/16/2019 none]
void CCVLog::SetPriority(Priority priority) {
	switch (priority) {
	case (LOG_LEVEL_ERROR):
		m_Category_Ref.setPriority(log4cpp::Priority::ERROR);
		break;

	case (LOG_LEVEL_WARN):
		m_Category_Ref.setPriority(log4cpp::Priority::WARN);
		break;

	case (LOG_LEVEL_INFO):
		m_Category_Ref.setPriority(log4cpp::Priority::INFO);
		break;
	default:
		m_Category_Ref.setPriority(log4cpp::Priority::DEBUG);
		break;
	}
}

// 设置日志输出文件名 [10/16/2019 none]
bool CCVLog::SetLogFileName(const std::string& fileName /*= "log4cpp.log"*/)
{
	m_strLogFileName = fileName;

#ifdef _WIN32
	int nPos = fileName.rfind("\\");
#else 
	int nPos = fileName.rfind("/");
#endif
	if (nPos != string::npos)
	{
		if (!CreatLogDir(nPos, fileName))
		{
			return false;
		}
	}
	else
	{
		nPos = fileName.rfind("//");
		if (nPos != string::npos)
		{
			if (!CreatLogDir(nPos, fileName))
			{
				return false;
			}
		}
	}
	

	//自定义日志的输出格式 1  
	/*%c->category, %d->日期, %m->消息,, %n->换行, %p->优先级  %x-->NDC
		举例: %d: %p %c %x:%m%n   时间: 优先级 Category NDC: 消息换行
	*/

	log4cpp::PatternLayout *pattern_one = new log4cpp::PatternLayout;
	pattern_one->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p]%c%x %m%n");

	//自定义日志的输出格式 2  
	log4cpp::PatternLayout *pattern_two = new log4cpp::PatternLayout;
	pattern_two->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p]%c%x %m%n");

	//获取屏幕输出
	log4cpp::OstreamAppender *os_appender = new log4cpp::OstreamAppender("osAppender", &std::cout);
	os_appender->setLayout(pattern_one);

	m_pOs_Appender = os_appender;
	//获取文件日志输出  http://blog.csdn.net/wyb19890515/article/details/7187057

	log4cpp::FileAppender *file_appender = new log4cpp::RollingFileAppender("RollingFileAppender", m_strLogFileName, MAX_LOGSIZE, LOGFILE_SIZE);
	file_appender->setLayout(pattern_two);
	m_pFile_Appender = file_appender;

	m_Category_Ref.setPriority(log4cpp::Priority::DEBUG);	//设置优先级  注意:取值越小,优先级越
	m_Category_Ref.addAppender(os_appender);
	m_Category_Ref.addAppender(file_appender);

	//log4cpp::Appender.TESTAppender.fileName

	//log4cpp::Category::getRoot().getInstance("LOG").addAppender(file_appender); //使用滚动的方式记录日志
	return true;
}


void CCVLog::Error(const char* pchFormat, ...)
{
	memset(m_szLogBuf, 0, MAX_LOG_RECORD_LEN);
	int nLen = 0;
	//nLen += sprintf(m_szLogBuf + nLen, "[%s:%d] ", FILENAME(__FILE__), __LINE__);
	// 日志信息
	va_list list;
	va_start(list, pchFormat);
	nLen += vsprintf(m_szLogBuf + nLen, pchFormat, list);
	va_end(list);
	m_Category_Ref.error(m_szLogBuf);
}

// 日志打印 [10/16/2019 none]
void CCVLog::Info(const char* pchFormat, ...)
{
	//日志格式 2019-10-16 20:25:23.495 [INFO]  [VS2015.cpp:12]set log begin
	memset(m_szLogBuf, 0, MAX_LOG_RECORD_LEN);
	int nLen = 0;
	//nLen += sprintf(m_szLogBuf + nLen, "[%s:%d] ", szFileName, nLineNo);
	
	va_list list;				// 日志信息
	va_start(list, pchFormat);	//C 不定参宏
	nLen += vsprintf(m_szLogBuf + nLen, pchFormat, list);
	va_end(list);
	//nLen += sprintf(m_szLogBuf + nLen, "  (%s:%d)", szFilename, nLineNo);
	m_Category_Ref.info(m_szLogBuf);
}

void CCVLog::Debug(const char* pchFormat, ...)
{
	memset(m_szLogBuf, 0, MAX_LOG_RECORD_LEN);
	int nLen = 0;
	//nLen += sprintf(m_szLogBuf + nLen, "[%s:%d] ", FILENAME(__FILE__), __LINE__);
	va_list list;	// 日志信息
	va_start(list, pchFormat);
	nLen += vsprintf(m_szLogBuf + nLen, pchFormat, list);
	va_end(list);
	m_Category_Ref.debug(m_szLogBuf);
}

void CCVLog::Warn(const char* pchFormat, ...)
{
	memset(m_szLogBuf, 0, MAX_LOG_RECORD_LEN);
	int nLen = 0;
	//nLen += sprintf(m_szLogBuf + nLen, "[%s:%d] ", FILENAME(__FILE__), __LINE__);
	va_list list;	// 日志信息
	va_start(list, pchFormat);
	nLen += vsprintf(m_szLogBuf + nLen, pchFormat, list);
	va_end(list);
	m_Category_Ref.warn(m_szLogBuf);
}

main.cpp

#include "stdafx.h"
#include "log4cpp.h"
#include <iostream>
using namespace std;

int main()
{	
	
	CVLog.SetLogFileName("/opt/logs/test/test.log");
	int cnt = 1;
	
	while (true)
	{
		CVLog.Debug("printf log debug");
		CVLog.Error("printf log error");
		CVLog.Warn("[%s %d]printf log warn, %d",FILENAME(__FILE__), __LINE__, cnt++);
		LOG_I("printf INFO log :%d", FILENAME(__FILE__), __LINE__, cnt++);
		LOG_W("printf WARN logn");
		LOG_D("printf DEBUG log");
		LOG_E("printf ERROR log");
	}
	
	CVLog.Destory();
	system("pause");
	return 0;
}

window或linux调用SetLogFileName,分别设置自定义路径日志目录即可!

如果想通过加载日志配置文件设定日志属性,自行发挥!

-------------------------------------------------------------------------------------------------

这个世界是被精心设计过的!

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值