头文件:
#ifndef LOG4CPP #define LOG4CPP #include <log4cpp/Category.hh> #include <log4cpp/FileAppender.hh> #include <log4cpp/BasicLayout.hh> #include <log4cpp/RollingFileAppender.hh> #include <log4cpp/PatternLayout.hh> namespace niiwoo { namespace util { namespace log { enum LOG_LEVEL { LOG_LEVEL_NONE = 0, // 不打日志 LOG_LEVEL_ERROR = 1, LOG_LEVEL_WARN = 2, LOG_LEVEL_INFO = 3, LOG_LEVEL_DEBUG = 4, LOG_LEVEL_MAX = 5 }; enum ERR_CODE { ERR_CODE_OK = 0, ERR_CODE_PATH = -1, OTHER_ERR = -2 }; // 调用NiiwooLog* GetInstance()->Init() 初始化之后,即可使用以下宏打印日志 // DEBUG级别日志会同时打印到屏幕一份 #define LOG4_DEBUG(...) NiiwooLog::GetInstance()->Log(LOG_LEVEL_DEBUG, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) #define LOG4_WARN(...) NiiwooLog::GetInstance()->Log(LOG_LEVEL_WARN, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) #define LOG4_INFO(...) NiiwooLog::GetInstance()->Log(LOG_LEVEL_INFO, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) #define LOG4_ERROR(...) NiiwooLog::GetInstance()->Log(LOG_LEVEL_ERROR, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) class NiiwooLog { public: ERR_CODE Init(std::string strLogPath, std::string strModName, LOG_LEVEL lev, long iLogFileSize, long iLogPathSize);//ilogFileSize:size of per log file:Byte,iLogPathSize:Maxsize of LogPath:Byte private: NiiwooLog(); virtual ~NiiwooLog(); public: <span style="white-space:pre"> </span>static NiiwooLog* GetInstance(); <span style="white-space:pre"> </span>int Log(LOG_LEVEL lev, char const *file, int line, char const *func, char const *format, ...); <span style="white-space:pre"> </span>int SetFileName(std::string& FileName, std::string strModName); <span style="white-space:pre"> </span>ERR_CODE CheckPath(std::string &strLogPath); <span style="white-space:pre"> </span>int SetLev(LOG_LEVEL lev); <span style="white-space:pre"> </span>int RebuildCurLog(); <span style="white-space:pre"> </span>void LogClearTimer(std::string strLogPath, long lPathSize); <span style="white-space:pre"> </span>private: <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>LOG_LEVEL m_lev; <span style="white-space:pre"> </span>log4cpp::Category *m_pTotal; <span style="white-space:pre"> </span>log4cpp::PatternLayout *m_pLayout; <span style="white-space:pre"> </span>log4cpp::RollingFileAppender *m_pAppender; <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>bool m_isRunning;<span style="white-space:pre"> </span> <span style="white-space:pre"> </span>std::string m_strLogPath; <span style="white-space:pre"> </span>std::string m_strCurLog; <span style="white-space:pre"> </span>std::string m_strModName; <span style="white-space:pre"> </span>unsigned long m_lMaxFileSize; <span style="white-space:pre"> </span>}; } } } #endif
实现程序
#include <boost/format.hpp> #include <boost/thread.hpp> #include <boost/filesystem.hpp> #include <iostream> #include <fstream> #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <time.h> #include <sys/time.h> #include <sys/stat.h> #include "log4.h" #define MAX_PATH_LEN 1024 #define MAX_LOG_LEN 1024 using namespace std; namespace fs = boost::filesystem; namespace niiwoo { namespace util { namespace log { NiiwooLog::NiiwooLog() { m_isRunning = false; m_strLogPath = "/usr/local/var/NiiwooLog/"; m_strCurLog = "/usr/local/var/NiiwooLog/NiiwoLog.log"; m_lMaxFileSize = 2*1024; } NiiwooLog* NiiwooLog::GetInstance() { static NiiwooLog log; return &log; } int NiiwooLog::Log(LOG_LEVEL lev, char const *file, int line, char const *func, char const *format, ...) { if(m_isRunning == false) { return -1; } if(lev>m_lev||m_lev == LOG_LEVEL_NONE) { return -1; } char buf[MAX_LOG_LEN]={0}; char buff[MAX_LOG_LEN]={0}; char *p1; snprintf(buf,1024, "%s:%d@%s@", file, line, func); va_list argptr; va_start(argptr, format); vsnprintf(buf+strlen(buf), MAX_LOG_LEN, format, argptr); va_end(argptr); p1 = buf; for(int i=0;i<(int)(strlen(buf));i++) { if(buf[i]==':') break; if(buf[i]=='/') { p1 = buf+i; } } memcpy(buff,p1+1,strlen(p1)-1); switch(lev) { case LOG_LEVEL_ERROR: m_pTotal->error(buff); break; case LOG_LEVEL_WARN: m_pTotal->warn(buff); break; case LOG_LEVEL_INFO: m_pTotal->info(buff); break; case LOG_LEVEL_DEBUG: std::cout<<buff<<std::endl; m_pTotal->debug(buff); break; default: break; } return 0; } ERR_CODE NiiwooLog::CheckPath(std::string &strLogPath) { if(strLogPath.empty()) { return ERR_CODE_PATH; } if(strLogPath.at(strLogPath.size()-1)!='/') { strLogPath += '/'; } if (!fs::exists(strLogPath)) { fs::create_directory(strLogPath); } return ERR_CODE_OK; } int NiiwooLog::SetFileName(std::string& strFileFullPath, std::string strModName) { struct timeval tv; struct timezone tz; struct tm *tm_now; gettimeofday(&tv, &tz); tm_now = localtime(&tv.tv_sec); int us = tv.tv_usec/1000; strFileFullPath += (boost::format("%s_%04d-%02d-%02d_%02d.%02d.%02d.%02d.log")%strModName %(tm_now->tm_year+1900) %(tm_now->tm_mon+1) %tm_now->tm_mday %tm_now->tm_hour %tm_now->tm_min %tm_now->tm_sec %us).str(); return 0; } unsigned long get_file_size(const char *path) { unsigned long filesize = -1; struct stat statbuff; if(stat(path, &statbuff) < 0) { return filesize; } else { filesize = statbuff.st_size; } return filesize; } void NiiwooLog::LogClearTimer(std::string strLogPath, long lPathSize) { while(1) { fs::path RootPath(strLogPath); long lTotalSize=0; vector<std::string> FileVector; fs::path CurLogFullPath(m_strCurLog); if (!fs::exists(CurLogFullPath)) { //fs::create_directory(CurLogFullPath); RebuildCurLog(); } if(get_file_size(m_strCurLog.c_str()) > m_lMaxFileSize) { RebuildCurLog(); } fs::directory_iterator end_iter; for (fs::directory_iterator iter(RootPath); iter!=end_iter; ++iter) { if (fs::is_regular_file(iter->status())) { FileVector.push_back(iter->path().string()); fs::path PathIter = iter->path(); if(fs::exists(PathIter)) lTotalSize += fs::file_size(PathIter); } } if(lTotalSize > lPathSize) { std::sort(FileVector.begin(),FileVector.end()); vector<std::string>::iterator it; for(it=FileVector.begin(); it!=FileVector.end();) { fs::path PathIter(*it); cout<<*it<<endl; if(fs::exists(PathIter)) { lTotalSize -= fs::file_size(PathIter); fs::remove(PathIter); } FileVector.erase(it); if(lTotalSize <= lPathSize) break; } } boost::this_thread::sleep(boost::posix_time::seconds(1800)); } } int NiiwooLog::RebuildCurLog() { if(m_isRunning == false) { std::cout<<"log module need init"<<std::endl; return -1; } std::string strNewLogFileFullPath; strNewLogFileFullPath = (boost::format("%s")%m_strLogPath).str(); SetFileName(strNewLogFileFullPath, m_strModName); m_pTotal->shutdown(); log4cpp::PatternLayout* DebugLo = new log4cpp::PatternLayout(); DebugLo->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l}[%p]%m%n"); //log4cpp::RollingFileAppender* Debug_Appender = new log4cpp::RollingFileAppender("Debug_Appender",strNewLogFileFullPath.c_str(), m_lMaxFileSize, 0); log4cpp::Appender* Debug_Appender = new log4cpp::FileAppender("Debug_Appender",strNewLogFileFullPath.c_str(),true,0666); Debug_Appender->setLayout(DebugLo); m_pLayout = DebugLo; //m_pAppender = Debug_Appender; m_pTotal->setAdditivity(false); m_pTotal->setAppender(Debug_Appender); m_strCurLog.clear(); m_strCurLog = strNewLogFileFullPath; return 0; } ERR_CODE NiiwooLog::Init(std::string strLogPath, std::string strModName, LOG_LEVEL iLogLevel, long iLogFileSize, long iLogPathSize) { if(m_isRunning) { std::cout<<"log module has been init"<<std::endl; return OTHER_ERR; } iLogPathSize *= 1024*1024; iLogFileSize *= 1024*1024; std::string strFileFullPath; ERR_CODE errCode; if((errCode = CheckPath(strLogPath)) != ERR_CODE_OK) { return errCode; } strFileFullPath = str(boost::format("%s")%strLogPath); SetFileName(strFileFullPath, strModName); m_lev = iLogLevel; m_strLogPath.clear(); m_strLogPath = strLogPath; m_strCurLog = strFileFullPath; m_lMaxFileSize = (iLogFileSize>1*1024*1024)?iLogFileSize:1*1024*1024; iLogPathSize = (iLogPathSize/m_lMaxFileSize>=100)?iLogPathSize:m_lMaxFileSize*100; m_strModName = strModName; log4cpp::Category& total = log4cpp::Category::getInstance("total"); m_pTotal = &total; log4cpp::PatternLayout* DebugLo = new log4cpp::PatternLayout(); DebugLo->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l}[%p]%m%n"); //log4cpp::RollingFileAppender* Debug_Appender = new log4cpp::RollingFileAppender("Debug_Appender", strFileFullPath.c_str(), m_lMaxFileSize,100); log4cpp::Appender* Debug_Appender = new log4cpp::FileAppender("Debug_Appender",strFileFullPath.c_str(),true,0666); Debug_Appender->setLayout(DebugLo); m_pLayout = DebugLo; //m_pAppender = Debug_Appender; m_pTotal->setAdditivity(false); m_pTotal->setAppender(Debug_Appender); switch(m_lev) { case LOG_LEVEL_ERROR: m_pTotal->setPriority(log4cpp::Priority::ERROR); break; case LOG_LEVEL_WARN: m_pTotal->setPriority(log4cpp::Priority::WARN); break; case LOG_LEVEL_INFO: m_pTotal->setPriority(log4cpp::Priority::INFO); break; case LOG_LEVEL_DEBUG: m_pTotal->setPriority(log4cpp::Priority::DEBUG); break; default: m_pTotal->setPriority(log4cpp::Priority::DEBUG); break; } m_isRunning = true; boost::thread ThreadLogClearTimer(boost::bind(&NiiwooLog::LogClearTimer, this, strLogPath, iLogPathSize)); return ERR_CODE_OK; } int NiiwooLog::SetLev(LOG_LEVEL lev) { m_lev=lev; switch(m_lev) { case LOG_LEVEL_ERROR: m_pTotal->setPriority(log4cpp::Priority::ERROR); break; case LOG_LEVEL_WARN: m_pTotal->setPriority(log4cpp::Priority::WARN); break; case LOG_LEVEL_INFO: m_pTotal->setPriority(log4cpp::Priority::INFO); break; case LOG_LEVEL_DEBUG: m_pTotal->setPriority(log4cpp::Priority::DEBUG); break; default: m_pTotal->setPriority(log4cpp::Priority::DEBUG); break; } return lev; } NiiwooLog::~NiiwooLog() { //log4cpp::Category::shutdown(); } } } }
测试程序:
#include <log4cpp/Category.hh> #include <log4cpp/FileAppender.hh> #include <log4cpp/BasicLayout.hh> #include <string.h> #include <stdio.h> #include <stdlib.h> #include "log4.h" using namespace niiwoo::util::log; int main(int argc, char *argv[]) { if(argc<2) { printf("please input debug level,0:none,1:error,2:warn,3:info,other:debug\n"); return 0; } int lev = atoi(argv[1]); std::string name("yanglei"); std::string module=("log4cpp"); std::string path("/opt/LogPath"); LOG_LEVEL level; switch(lev) { case 0: level = LOG_LEVEL_NONE; break; case 1: level = LOG_LEVEL_ERROR; break; case 2: level = LOG_LEVEL_WARN; break; case 3: level = LOG_LEVEL_INFO; break; default: level = LOG_LEVEL_DEBUG; } NiiwooLog *pLog; pLog = NiiwooLog::GetInstance(); pLog->Init(path, module, level, 0, 100); for(int i=0; i<=500000; i++) { LOG4_DEBUG("//debug log test,//%s-%s-%d//", name.c_str(), module.c_str(), 2014); LOG4_INFO("//error log test,//%s-%s-%d//",name.c_str(), module.c_str(),2014); LOG4_WARN("//warn log test,//%s-%s-%d//",name.c_str(), module.c_str(),2014); LOG4_ERROR("//info log test,//%s-%s-%d//",name.c_str(), module.c_str(),2014); } /* pLog->RebuildCurLog(); LOG4_DEBUG("debug log test,%s-%s-%d", name.c_str(), module.c_str(), 2014); LOG4_INFO("error log test,%s-%s-%d",name.c_str(), module.c_str(),2014); LOG4_WARN("warn log test,%s-%s-%d",name.c_str(), module.c_str(),2014); LOG4_ERROR("info log test,%s-%s-%d",name.c_str(), module.c_str(),2014); //在不使用log4cpp时可调用log4cpp::Category::shutdown(),其功能如同HierarchyMaintainer的内存清理。但如果不手动调用,在程序结束时HierarchyMaintainer会调用Category的析构函数来释放所有Appender。 */ return 0; }
依赖库:
liblog4cpp.a
libboost_filesystem.a
libboost_thread.a