zoukankan      html  css  js  c++  java
  • 简单的日志系统

    參考glog写了现有的Logging系统。

    直接有

    enum LoggingEnum{
    LOG_INFO,
    LOG_DBBUG,
    LOG_ERROR,
    LOG_WARNNING,
    LOG_END
    };

    几种等级的日志,实时刷到console上,异步延迟写到日志上,建立队列缓存日志,时间一到一起刷到file,好了,看下Logging实现:

    class Active;
    struct Buffer;
    
    enum LoggingEnum{
    	LOG_INFO,
    	LOG_DBBUG,
    	LOG_ERROR,
    	LOG_WARNNING,
    	LOG_END
    };
    
    enum GLogColor {
    	COLOR_DEFAULT,
    	COLOR_RED,
    	COLOR_GREEN,
    	COLOR_YELLOW
    };
    
    class Logging
    {
    public:
    	Logging();
    	~Logging();
    	void	WriteWithFunLine(LoggingEnum eLoggingEnum, char* fun, int line, char* msg, ...);	
    	void	WriteBuffer(Buffer*& pBuffer);
    
    private:
    	INT32	CreateLogFile(LoggingEnum aLoggingEnum);
    	void	Write(LoggingEnum eLoggingEnum, char* msg, int msgLen);
    
    private:
    	FILE*					m_File[LOG_END];
    	Active*					m_pActive;
    	typedef boost::posix_time::ptime PTIME;
    	boost::atomic<BOOLEAN>	m_IfCanFlush[LOG_END];
    	PTIME					m_PrelushTime[LOG_END];
    	std::queue<Buffer*>		m_BufferQueue[LOG_END];
    };
    

    Logging g_Logging;
    string LOGPreStr[LOG_END] = {"LOG_INFO", "LOG_DBBUG", "LOG_ERROR", "LOG_WARNNING"};
    
    #ifdef _WINDOWS
    // Returns the character attribute for the given color.
    WORD GetColorAttribute(GLogColor color) {
    	switch (color) {
    	case COLOR_RED:    return FOREGROUND_RED;
    	case COLOR_GREEN:  return FOREGROUND_GREEN;
    	case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
    	default:           return 0;
    	}
    }
    #else
    // Returns the ANSI color code for the given color.
    const char* GetAnsiColorCode(GLogColor color) {
    	switch (color) {
    	case COLOR_RED:     return "1";
    	case COLOR_GREEN:   return "2";
    	case COLOR_YELLOW:  return "3";
    	case COLOR_DEFAULT:  return "";
    	};
    	return NULL; // stop warning about return type.
    }
    
    #endif  // OS_WINDOWS
    
    GLogColor GLogColorVec[LOG_END] = {COLOR_GREEN, COLOR_DEFAULT, COLOR_RED, COLOR_YELLOW};
    
    Logging::Logging(){
    	PTIME nowTime = boost::posix_time::microsec_clock::local_time();
    
    	INT32 n32Res = eNormal;
    	for (INT32 i = LOG_INFO; i < LOG_END; ++i){
    		m_File[i] = NULL;
    		m_IfCanFlush[i] = FALSE;
    		m_PrelushTime[i] = nowTime;
    		n32Res = CreateLogFile((LoggingEnum)i);
    		if (n32Res != eNormal){
    			printf("Createfile(i) failed", i);
    		}
    	}
    	
    	m_pActive = Active::CreateActive(std::bind(&Logging::WriteBuffer, this, std::placeholders::_1));
    }
    
    void Logging::Write(LoggingEnum eLoggingEnum, char* msg, int msgLen){
    	Buffer* pBuffer = m_pActive->GetBuffer();
    	pBuffer->m_LogLevel = eLoggingEnum;
    	char* curData = pBuffer->m_pMsg;
    	pBuffer->m_Len = msgLen;
    	memcpy(curData, msg, msgLen);
    
    	m_pActive->Send(pBuffer);
    }
    
    void Logging::WriteBuffer(Buffer*& pBuffer){
    	char* pContent = pBuffer->m_pMsg;
    	pContent[pBuffer->m_Len] = '';
    
    	const GLogColor color = GLogColorVec[pBuffer->m_LogLevel];
    #ifdef _WINDOWS
    	const HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
    	CONSOLE_SCREEN_BUFFER_INFO buffer_info;
    	GetConsoleScreenBufferInfo(stderr_handle, &buffer_info);
    	const WORD old_color_attrs = buffer_info.wAttributes;
    	fflush(stderr);
    	SetConsoleTextAttribute(stderr_handle,
    		GetColorAttribute(color) | FOREGROUND_INTENSITY);
    	fwrite(pContent, pBuffer->m_Len+1, 1, stderr);
    	fflush(stderr);
    	SetConsoleTextAttribute(stderr_handle, old_color_attrs);
    #else
    	fprintf(stderr, "33[0;3%sm", GetAnsiColorCode(color));
    	fwrite(message, len, 1, stderr);
    	fprintf(stderr, "33[m");  // Resets the terminal to default.
    #endif
    
    	FILE* pNowFile = m_File[pBuffer->m_LogLevel];
    	if (pNowFile == NULL){
    		return;
    	}
    
    	std::queue<Buffer*>& bufferQueue = m_BufferQueue[pBuffer->m_LogLevel];
    
    	if (FALSE == m_IfCanFlush[pBuffer->m_LogLevel]){
    		bufferQueue.push(pBuffer);
    		pBuffer = NULL;
    	}
    	else{
    		while (FALSE == bufferQueue.empty()){
    			Buffer* pPreBuffer = bufferQueue.front();
    			bufferQueue.pop();
    
    			fwrite(pPreBuffer->m_pMsg, 1, pPreBuffer->m_Len, pNowFile);
    			fflush(pNowFile);
    
    			m_pActive->ReleaseBuffer(pPreBuffer);
    		}
    
    		fwrite(pContent, 1, pBuffer->m_Len, pNowFile);
    		fflush(pNowFile);
    
    		m_IfCanFlush[pBuffer->m_LogLevel] = FALSE;
    		m_PrelushTime[pBuffer->m_LogLevel] = boost::posix_time::microsec_clock::local_time();
    	} 
    }
    
    void Logging::WriteWithFunLine(LoggingEnum eLoggingEnum, char* fun, int line, char* msg, ...){
    	if (eLoggingEnum < LOG_INFO || eLoggingEnum > LOG_WARNNING){
    		eLoggingEnum = eLoggingEnum;
    	}
    
    	char tmp[1024] = {0};
    	PTIME nowTime = boost::posix_time::microsec_clock::local_time();
    	boost::posix_time::time_duration timeFidd = nowTime - m_PrelushTime[eLoggingEnum];
    	if (timeFidd.total_microseconds() > 1000){
    		m_IfCanFlush[eLoggingEnum] = TRUE;
    	}
    
    	sprintf(tmp, "%s.%d %s:%d ", boost::posix_time::to_iso_string(nowTime).c_str(), boost::this_thread::get_id(), fun, line);
    	int curPos = strlen(tmp);
    
    	va_list pArg = NULL;
    	va_start(pArg, msg);
    	vsprintf(tmp+curPos, msg, pArg);
    	va_end(pArg);
    
    	curPos = strlen(tmp);
    	char end[] = "
    ";
    	sprintf(tmp + curPos, "%s", end);
    
    	Write(eLoggingEnum, tmp, strlen(tmp));
    }
    
    Logging::~Logging(){
    	for (INT32 i = 0; i < 4; ++i){
    		if (NULL != m_File[i]){
    			fclose(m_File[i]);
    		}
    	}
    
    	delete m_pActive;
    }
    
    
    INT32 Logging::CreateLogFile(LoggingEnum aLoggingEnum){
    	string strPre;
    	switch (aLoggingEnum){
    	case LOG_DBBUG:
    		strPre = "LOG_DBBUG";
    		break;
    	case LOG_INFO:
    		strPre = "LOG_INFO";
    		break;
    	case LOG_WARNNING:
    		strPre = "LOG_WARNNING";
    		break;
    	case LOG_ERROR:
    		strPre = "LOG_ERROR";
    		break;
    	}
    	char str[128];
    	sprintf(str, "./Log/%s-%d-%s", strPre.c_str() ,boost::this_thread::get_id(), boost::posix_time::to_iso_string(boost::posix_time::microsec_clock::local_time()).c_str());
    	string fileName(str);
    	fileName += ".log";
    	int fd = open(fileName.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0664);
    	if (fd == -1){
    		printf("%s create(%d) file error
    ", __FUNCTION__, aLoggingEnum);
    		return -1;
    	}
    
    	m_File[aLoggingEnum] = fdopen(fd, "a");
    	if (NULL == m_File[aLoggingEnum]){
    		printf("%s open file(%d) failed
    ", __FUNCTION__, aLoggingEnum);
    		return -1;
    	}
    
    	return 0;
    }

    当中用到的Active就是简单的生产者消费者模型:

    struct  Buffer
    {
    	Buffer():m_LogLevel(0), m_Len(1024), m_pMsg(new char[m_Len]){}
    	~Buffer(){
    		if (NULL != m_pMsg)
    			delete []m_pMsg;
    	}
    	Buffer(int size):m_LogLevel(0), m_Len(size)
    		, m_pMsg(new char[m_Len]){
    
    	}
    	int		m_LogLevel;
    	int		m_Len;
    	char*	m_pMsg;
    };
    
    typedef std::function<void(Buffer*&)> Callback;
    
    class Active {
    private:
    	Active(const Active&);
    	Active& operator=(const Active&);
    	Active(); 
    	void doDone(){m_IfDone = true;}
    	void Run();
    	void setCallBack(Callback aCallBack);
    	bool IfEmpty();
    	int Consume(Buffer*& apBuffer);
    
    	std::queue<Buffer*> m_Queue;
    	boost::thread	m_Thread;
    	volatile bool	m_IfDone;
    	Callback		m_Callback;
    	boost::mutex	m_Mutex;
    	boost::mutex	m_ObjectMutex;
    	CSSObejctPool<Buffer> m_pBufferPool;
    	boost::condition_variable m_ConditionVar; 
    
    public:
    	~Active();
    	Buffer*			GetBuffer();
    	void			ReleaseBuffer(Buffer*& pBuffer);
    	void			Send(Buffer* apBuffer);
    	void			Stop();
    	static Active*	CreateActive(Callback aCallBack);
    };

    Active::Active(): m_IfDone(false){}
    
    Active::~Active() {
    	Stop();
    }
    
    void Active::Send( Buffer* apBuffer ){
    	if (NULL != apBuffer){
    		boost::mutex::scoped_lock lock(m_Mutex);
    		bool bNeedSig = m_Queue.empty();
    		m_Queue.push(apBuffer);
    		if (bNeedSig){
    			m_ConditionVar.notify_one();
    		}
    	}
    }
    
    void Active::Run() {
    	Buffer* pBuffer = NULL;
    	while (!m_IfDone && 0 == Consume(pBuffer)){
    		m_Callback(pBuffer);
    		if (NULL != pBuffer){
    			boost::mutex::scoped_lock lock(m_ObjectMutex);
    			m_pBufferPool.ReleaseObejct(pBuffer);
    		}
    	}
    }
    
    Active* Active::CreateActive(Callback aCallBack){
    	Active* aPtr = new Active();
    	aPtr->m_Thread = boost::thread(&Active::Run, aPtr);
    	aPtr->m_Callback = aCallBack;
    	return aPtr;
    }
    
    void Active::setCallBack(Callback aCallBack){
    	m_Callback = aCallBack;
    }
    
    Buffer* Active::GetBuffer(){
    	boost::mutex::scoped_lock lock(m_ObjectMutex);
    	return m_pBufferPool.AcquireObject();
    }
    
    bool Active::IfEmpty(){
    	return m_Queue.empty();  
    }
    
    int Active::Consume(Buffer*& apBuffer){
    	boost::mutex::scoped_lock lock(m_Mutex);
    	while (m_Queue.empty()){
    		if (m_IfDone){
    			return 1;
    		}
    		m_ConditionVar.wait(lock);
    	}
    
    	if (m_IfDone){
    		return 1;
    	}
    
    	apBuffer = m_Queue.front();
    	m_Queue.pop();
    
    	return 0;
    }
    
    void Active::Stop(){
    	m_IfDone = true;
    	m_ConditionVar.notify_one();
    }
    
    void Active::ReleaseBuffer(Buffer*& pBuffer){
    	if (NULL != pBuffer){
    		boost::mutex::scoped_lock lock(m_ObjectMutex);
    		m_pBufferPool.ReleaseObejct(pBuffer);
    		pBuffer = NULL;
    	}
    }

    ok!仅仅有4个文件,仅仅要有boost库就能够编译使用了。用到的objectpool是之前博客介绍过的内存池。

  • 相关阅读:
    sqlite
    c++primer
    c++ std find_last_of
    c语言
    boost serialization
    ssh autologin
    c/c++文件相关
    AndroidTreeView等例子
    and
    解决Gradle 依赖下载慢以及android开发释放c盘空间及android虚拟机访问网络--以及访问本机
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/3902703.html
Copyright © 2011-2022 走看看