简单的日志系统

参考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] = '\0';

	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, "\033[0;3%sm", GetAnsiColorCode(color));
	fwrite(message, len, 1, stderr);
	fprintf(stderr, "\033[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[] = "\n";
	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\n", __FUNCTION__, aLoggingEnum);
		return -1;
	}

	m_File[aLoggingEnum] = fdopen(fd, "a");
	if (NULL == m_File[aLoggingEnum]){
		printf("%s open file(%d) failed\n", __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是之前博客介绍过的内存池。

简单的日志系统

时间: 2024-10-05 04:25:06

简单的日志系统的相关文章

Linux下一个简单的日志系统的设计及其C代码实现

1.概述 在大型软件系统中,为了监测软件运行状况及排查软件故障,一般都会要求软件程序在运行的过程中产生日志文件.在日志文件中存放程序流程中的一些重要信息, 包括:变量名称及其值.消息结构定义.函数返回值及其执行情况.脚本执行及调用情况等.通过阅读日志文件,我们能够较快地跟踪程序流程,并发现程序问题. 因此,熟练掌握日志系统的编写方法并快速地阅读日志文件,是对一个软件开发工程师的基本要求. 本文详细地介绍了Linux下一个简单的日志系统的设计方法,并给出了其C代码实现.本文为相关开发项目Linux

Java日志系统框架的设计与实现

推荐一篇好的文章介绍java日志系统框架的设计的文章:http://soft.chinabyte.com/database/438/11321938.shtml 文章内容总结: 日志系统对跟踪调试.程序状态记录.数据恢复等功能有重要作用 日志系统一般作为服务进程或者系统调用存在,我们一般程序中使用系统调用 常用日志系统包括log4j的简单介绍 日志系统的系统架构 日志系统的信息分级 日志输出的设计 下面是全文的引用: 在Java领域,存在大量的日志组件,open-open收录了21个日志组件.日

python 标准日志模块loging 及日志系统实例

本文出处:https://www.cnblogs.com/goodhacker/p/3355660.html#undefined python的标准库里的日志系统从Python2.3开始支持.只要import logging这个模块即可使用.如果你想开发一个日志系统, 既要把日志输出到控制台, 还要写入日志文件,只要这样使用: 1 import logging 2 3 # 创建一个logger 4 logger = logging.getLogger('mylogger') 5 logger.s

Java日志系统---Logger之简单入门

Java 中自带的日志系统,今天抽空了解了一点,算是入了门,所以将自己的一些心得记录下来,以备日后查看,有兴趣的朋友,看到此文章,觉得有错误或需要添加的地方,请在下方评论留言,大家可以共同进步,谢谢:) Java中关于日志系统的API,在 java.util.logging 包中,在这个包中,Logger类很重要. Logger类是用来记录 某个级别的日志消息: 级别共分为以下几类,从上倒下,级别依次下降: SEVERE(严重)------级别最高 WARNING(警告) INFO CONFIG

slf4j简单日志门面与各种日志系统

SLF4J是为各种loging APIs提供一个简单统一的接口,从而使得最终用户能够在部署的时候配置自己希望的loging APIs实现. 准确的说,slf4j并不是一种具体的日志系统,而是一个用户日志系统的facade,允许用户在部署最终应用时方便的变更其日志系统.在系统开发中,统一按照slf4j的API进行开发,在部署时,选择不同的日志系统包,即可自动转换到不同的日志系统上.比如:选择JDK自带的日志系统,则只需要将slf4j-api-1.5.10.jar和slf4j-jdk14-1.5.1

日志系统之Flume采集加morphline解析

概述 这段时间花了部分时间在处理消息总线跟日志的对接上.这里分享一下在日志采集和日志解析中遇到的一些问题和处理方案. 日志采集-flume logstash VS flume 首先谈谈我们在日志采集器上的选型.由于我们选择采用ElasticSearch作为日志的存储与搜索引擎.而基于ELK(ElasticSearch,Logstash,Kibana)的技术栈在日志系统方向又是如此流行,所以把Logstash列入考察对象也是顺理成章,Logstash在几大主流的日志收集器里算是后起之秀,被Elas

【Yii系列】错误处理和日志系统

缘起 跟随上一章的脚步,上一章中,我们主要讲解了在用户发起请求,解析请求,服务器反馈请求以及session的一些知识点,这过程中,难免会遇到一些问题,比方说数据库查询失败,用户输入导致脚本出错,网络问题等等突发情况,对于突发情况,做过软件的一般都知道,会有错误处理和日志去记录下这个过程,同样的,Yii也提供了类似的功能帮助我们去抓住错误,记录错误,并且对相应错误做出对应处理. 错误处理 Yii 内置了一个error handler错误处理器. 所有非致命PHP错误(如,警告,提示)会转换成可获取

DNS的视图功能以及日志系统

实验环境:RHEL5.8 32Bit DNS的视图功能以及日志系统详解 DNS的主配置文件中的allow-recursion参数用来定义能够和DNS服务器进行递归的客户端来源,allow-query参数用来定义允许到DNS服务器上面发起查询请求的客户端,allow-transfer参数用来定义允许和DNS服务器进行区域传送的客户端,区域传送主要有两种方式,axfr和ixfr,使用dig命令也可以模拟实现区域传送: 如果我们的DNS服务器允许进行递归.发起查询请求以及进行区域传送的客户端比较多的话

日志系统之基于flume收集docker容器日志

最近我在日志收集的功能中加入了对docker容器日志的支持.这篇文章简单谈谈策略选择和处理方式. 关于docker的容器日志 docker 我就不多说了,这两年火得发烫.最近我也正在把日志系统的一些组件往docker里部署.很显然,组件跑在容器里之后很多东西都会受到容器的制约,比如日志文件就是其中之一. 当一个组件部署到docker中时,你可以通过如下命令在标准输出流(命令行)中查看这个组件的日志: docker logs ${containerName} 日志形如: 但这种方式并不能让你实时获