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

mac2025-04-02  3

项目因为切换日志库,选型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,分别设置自定义路径日志目录即可!

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

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

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

最新回复(0)