|
实现了简易的log打印,有以下的特点: 1) 支持向标准输出或者文件打印log 2) 向文件打印log时限制log文件的大小, 同时, 如果在文件大小超出范围的时候, 可以选择下一个文件进行打印.在这里, 文件大小和文件的数量都是可以配置的. 3) 支持分级别打印, 目前分的级别有DEBUG,ERROR,WARN,INFO这几种, 在打印时, 也可以通过宏来开启DEBUG,WARN的log. 4) 在向文件打印log时, 支持多线程, 同样的, 这个也是可以配置的. 分为三个文件,log.h是对外的接口, 提供对文件打印log和对标准输出打印log的简易封装, 具体使用哪种方式, 可以通过宏进行配置;logger.h和logger.cpp是对文件进行打印的类封装, 是一个单件类, 因此继承自前面提过的singleton类. log.h:
/******************************************************************** created: 2008/08/02 filename: log.h author: Lichuang purpose: log模块的对外接口, 可以根据宏将log打印到文件或者标准 输出 *********************************************************************/
#ifndef __LOG_H__ #define __LOG_H__
#ifdef __USE_LOG_FILE__
#include "logger.h"
#define LOG(runlevel, file, lineno, args) \ do \ { \ CLogger::GetInstance()->Log( \ runlevel, file, \ lineno, args); \ } while (0)
#define RUN_MSG_LOG() LOG(INFO, __FILE__, __LINE__, __VA_ARGS__); #define ERROR_MSG_LOG() LOG(ERROR, __FILE__, __LINE__, __VA_ARGS__);
#ifdef LOG_DEBUG_MSG #define DEBUG_MSG_LOG() LOG(DEBUG, __FILE__, __LINE__, __VA_ARGS__); #else #define DEBUG_MSG_LOG() #endif
#ifdef LOG_WARN_MSG #define WARN_MSG_LOG() LOG(WARN, __FILE__, __LINE__, __VA_ARGS__); #else #define WARN_MSG_LOG() #endif
#else
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <stdarg.h> #include <sys/time.h>
#define LOG(runlevel, file, lineno, args) \ do{ \ struct timeval now;\ gettimeofday(&now,0); \ struct tm *ptm=localtime(&(now.tv_sec)); \ fprintf(runlevel, "[%d:%d] [%s:%d]",ptm->tm_hour,ptm->tm_min, file,lineno); \ fprintf(runlevel, args); \ fprintf(runlevel, "\n"); \ }while(0)
#define RUN_MSG_LOG() LOG(stdout, __FILE__, __LINE__, __VA_ARGS__); #define ERROR_MSG_LOG() LOG(stderr, __FILE__, __LINE__, __VA_ARGS__);
#ifdef LOG_DEBUG_MSG #define DEBUG_MSG_LOG() LOG(stdout, __FILE__, __LINE__, __VA_ARGS__); #else #define DEBUG_MSG_LOG() #endif
#ifdef LOG_WARN_MSG #define WARN_MSG_LOG() LOG(stdout, __FILE__, __LINE__, __VA_ARGS__); #else #define WARN_MSG_LOG() #endif
#endif
#endif /* __LOG_H__ */
logger.h
/******************************************************************** created: 2008/08/02 filename: logger.h author: Lichuang purpose: 实现简易的log打印 *********************************************************************/
#ifndef __LOGGER_H__ #define __LOGGER_H__
#include "defines.h" #include "singleton.h" #include "threadmutex.h" #include <string>
using namespace std;
struct LogInfo { int nFileNum; string strFileSuffix; string strFileName; };
enum { DEBUG = 0, WARN, ERROR, INFO, NUM_OF_LOG_LEVEL };
class CLogger : public CSingleton<CLogger> { public:
public: int Init(const string& strLogPath, const string& strFileName); int Log(int nLogLevel, const char* pFileName, int nLine, const char *szFormat, );
private: DECLARE_SINGLETON_CLASS(CLogger) CLogger(); virtual ~CLogger();
int GetFileName(int nLogLevel); int CheckFileSize(const string& strFileName); void GenerateFileName(string& strFileName, int nFileNum, int nLogLevel);
private: string m_strLogPath; string m_strFileName; LogInfo m_szLogInfo[NUM_OF_LOG_LEVEL]; CThreadMutex m_tThreadMutex; };
#endif /* __LOGGER_H__ */
logger.cpp
/******************************************************************** created: 2008/08/02 filename: logger.h author: Lichuang purpose: 实现简易的log打印 *********************************************************************/
#include "logger.h" #include <sys/stat.h>
static const char* g_szLogSuffix[] = { ".debug", ".warn", ".error", ".info", NULL };
CLogger::CLogger() { }
CLogger::~CLogger() { }
int CLogger::Init(const string& strLogPath, const string& strFileName) { m_strLogPath = strLogPath; m_strFileName = strFileName;
for (int i = DEBUG; i < NUM_OF_LOG_LEVEL; ++i) { m_szLogInfo[i].strFileSuffix = g_szLogSuffix[i]; if (0 > GetFileName(i)) return -1; }
return 0; }
int CLogger::GetFileName(int nLogLevel) { int i; string strFileName; for (i = 0; i < MAX_FILE_NUM; ++i) { GenerateFileName(strFileName, i, nLogLevel); if (!CheckFileSize(strFileName)) { break; } }
if (MAX_FILE_NUM == i) { return -1; }
m_szLogInfo[nLogLevel].nFileNum = i; m_szLogInfo[nLogLevel].strFileName = strFileName;
return 0; }
int CLogger::CheckFileSize(const string& strFileName) { struct stat tStat; int nRet = ::stat(strFileName.c_str(), &tStat); if (0 == nRet && tStat.st_size > MAX_FILE_SIZE) { return -1; } else { return 0; } }
void CLogger::GenerateFileName(string& strFileName, int nFileNum, int nLogLevel) { char szFileNum[10]; ::snprintf(szFileNum, sizeof(szFileNum), "_%02d", nFileNum); strFileName = m_strLogPath + m_strFileName + m_szLogInfo[nLogLevel].strFileSuffix + szFileNum; }
int CLogger::Log(int nLogLevel, const char* pFileName, int nLine, const char *szFormat, ) { va_list ap; FILE *pFile; char szTime[32]; time_t nCurrTime; struct tm stCurrTime;
THREAD_LOCK(m_tThreadMutex);
if (0 > CheckFileSize(m_szLogInfo[nLogLevel].strFileName)) { m_szLogInfo[nLogLevel].nFileNum = (m_szLogInfo[nLogLevel].nFileNum + 1) % MAX_FILE_NUM; GenerateFileName(m_szLogInfo[nLogLevel].strFileName, m_szLogInfo[nLogLevel].nFileNum, nLogLevel); }
if(NULL == (pFile = ::fopen(m_szLogInfo[nLogLevel].strFileName.c_str(), "a+"))) { return -1; }
::time(&nCurrTime); ::localtime_r(&nCurrTime, &stCurrTime); ::snprintf(szTime, sizeof(szTime), "%d%02d%02d %02d:%02d:%02d", stCurrTime.tm_year+1900, stCurrTime.tm_mon+1, stCurrTime.tm_mday, stCurrTime.tm_hour, stCurrTime.tm_min, stCurrTime.tm_sec); ::fprintf(pFile, "[%s]:[%s][%d] ", szTime, pFileName, nLine);
::va_start(ap, szFormat); ::vfprintf(pFile, szFormat, ap); ::va_end(ap);
::fprintf(pFile, "\n"); ::fclose(pFile);
THREAD_UNLOCK(m_tThreadMutex);
return 0; }
|