1.日志系统

image

#ifndef __SYLAR_LOG_H__
#define __SYLAR_LOG_H__

#include<iostream>
#include<string>
#include<stdint.h>//为了使用int32_t
#include<memory>//为了使用shared_ptr
#include<list>
#include<vector>
#include<sstream>
#include<fstream>//为了使用std::ofstream  m_filestream;


namespace sylar//为了区分和别人的代码里有重名的一些内容
{
//每个日志在生成出来的时候,把它定义成LogEvent,这样的话,把它里面所要用的属性、字段等,都放里面。
//日志事件
class LogEvent
{
public:
	//使用了C++11中的智能指针,方便内存管理
	typedef std::shared_ptr<LogEvent> ptr;
	LogEvent();
private:
	const char *m_file = nullptr;//文件名 //nullptr:C++11内容
	int32_t m_line = 0;			 //行号
	uint32_t m_elapse = 0;		 //程序启动开始到现在的毫秒数		
	int m_threadId = 0;			 //线程号
	uint32_t m_fiberId = 0;		 //协程号 //因为是协程库,所以还要有一个协程
	uint64_t m_time;			 //时间戳
	std::string m_content;		 //消息内容
};

//日志级别
class LogLevel
{
public:
	//定义日志级别
	//弹幕:日志级别完全可以用策略模式?为了以后的多种功能
	enum Level
	{
		DEBUG = 1,
		INFO = 2,
		WARN = 3,
		ERROR = 4,
		FATAL = 5
	};
};

//日志格式器
//目前只有一种Formatter,那么先只有一个Formatter
class LogFormatter
{
public:
	typedef std::shared_ptr<LogFormatter> ptr;

	//当pattern赋值的狮虎,我们会根据pattern的格式来解析出它里面的item的信息
	LogFormatter(const std::string& pattern);

	//格式示例:%t	%thread_id	%m%n
	std::string format(LogEvent::ptr event);//把formatter的一个string提供给Appender输出
	
	//创建一个日志解析的子模块,定义成一个FormatItem的抽象类,再定义它的子类用来实现
private:
	class FormatItem
	{
	public:
		typedef std::shared_ptr<FormatItem> ptr;
		virtual ~FormatItem(){}
		//使用ostream作为输出,不再使用std::string 来作为返回值,因为它会多个组合起来
		//这样性能会更好一点
		virtual void format(std::ostream os,LogEvent::ptr event) = 0;
	};

	void init();//init方法来做pattern的解析
	//定义很多种具体的子类,每个子类负责输出一部分
private:
	std::string m_pattern;//输出formatter结构
	std::vector<FormatItem> m_items;

private:

};


//日志输出的地址
//可以输出到控制台、文件、网络等...
//这里实现文控制台(STD)、文件的....
//先定义一个基类,里面只有一个纯虚函数log,这样它的子类就必须实现这个方法
class LogAppender
{
public:
	typedef std::shared_ptr<LogAppender> ptr;
	//因为日志输出地址有很多,所以把它定义成一个虚类
	//定义一个虚析构函数,让子类在继承的时候继承它,
	//如果不写成虚析构函数,那么它的子类在释放的时候,可能会产生释放的问题
	virtual ~LogAppender(){};
	virtual void log(LogLevel::Level level, LogEvent::ptr event) = 0;

	//设置formatter的方法
	void setFormatter(LogFormatter::ptr val){ m_formatter = val; }
	//获取formatter的方法
	LogFormatter::ptr getFormatter()const{ return m_formatter; }
protected://由于是虚拟的基类,有可能要用到它的level,所以基类中的属性应该是个protected,这样的话,子类就可以使用到
	LogLevel::Level m_level;//主要针对哪些日志来定义的级别
	//Appender里面还有一个Formatter对象,这个formatter是定义要输出的格式
	//可能有的输出格式要把线程、文件都输出出来,而有的不需要输出这些
	//以及时间格式是如何定义的都可能不一样
	//所以在这里定义一个LogFormatter
	LogFormatter::ptr m_formatter;
};

//日志(输出)器
//只有满足了日志级别的日志才会被输出
class Logger
{
public:
	typedef std::shared_ptr<Logger> ptr;//

	//弹幕:成员函数能够直接初始化是C++11开始就支持的特性,
	Logger(const std::string &name = "root");
	void log(LogLevel::Level level, LogEvent::ptr event);

	//定义五种级别的日志
	void debug(LogEvent::ptr event);
	void info(LogEvent::ptr event);
	void warn(LogEvent::ptr event);
	void error(LogEvent::ptr event);
	void fatal(LogEvent::ptr event);

	//添加和删除日志级别
	void addAppender(LogAppender::ptr appender);	//添加Appender
	void delAppender(LogAppender::ptr appender);	//删除Appender
	LogLevel::Level getLevel()const{ return m_level;} //获取日志级别
	void setLevel(LogLevel::Level val){ m_level = val; }//设置日志级别
private:
	std::string m_name;								//日志名称
	LogLevel::Level m_level;						//日志级别,只有满足了日志级别的日志才会被输出
	std::list<LogAppender::ptr> m_appenders;		//Appender是输出到目的地的集合,这里用一个链来实现表
};

//输出到控制台(Std)的Appender
class StdoutLogAppender : public LogAppender
{
public:
	//1.先定义出智能指针,后面很多时候,都是用智能指针来操作的
	typedef std::shared_ptr<StdoutLogAppender> ptr;
	//2.实现基类的抽象函数log
	//从父类继承的函数的实现,可以用override来描述
	void log(LogLevel::Level level, LogEvent::ptr event) override;
private:

};

//定义输出到文件的Appender
class FileLogAppender : public LogAppender
{
	//1.先定义智能指针
	typedef std::shared_ptr<FileLogAppender> ptr;
	//2.实现基类的抽象函数log
	//从父类继承的函数的实现,可以用override来描述
	FileLogAppender(const std::string& filename);//FileLog跟StdLog不一样,因为它要输出到文件里,因此它需要一个文件名
	void log(LogLevel::Level level, LogEvent::ptr event) override;

	//重新打开文件,重新打开成功返回true
	bool reopen();
private:
	std::string m_filename;
	std::ofstream  m_filestream;//用流的方式去输出
};

}

#endif //__SYLAR_LOG_H__


、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
#include"Log.h"

namespace sylar
{
Logger::Logger(const std::string &name = "root") : m_name(name)
{

}


void Logger::addAppender(LogAppender::ptr appender)	//添加Appender
{
	m_appenders.push_back(appender);//这里先不考虑线程安全,等后面线程库做出来之后再考虑
}

void Logger::delAppender(LogAppender::ptr appender)	//删除Appender
{
	//利用遍历的方式删除日志输出地址
	for (auto it = m_appenders.begin();//auto 是C++11 的内容
		it != m_appenders.end();++it)
	{
		if (*it == appender)
		{
			m_appenders.erase(it);
			break;
		}
	}
}



void Logger::log(LogLevel::Level level, LogEvent::ptr & event)
{
	if (level >= m_level)//就开始输出
	{
		//输出就是要输出到每个appender里去
		//因此,就遍历每个appenders,然后再用appender把它输出出来
		for (auto & i : m_appenders)
		{
			i->log(level, event);
		}
	}
	else
	{

	}
}

//定义五种级别的日志
//下面的这几个方法,都是利用上面的Logger::log方法来实现的,只是为了便捷
//就像有的人喜欢用相应日志级别的函数输出,而不喜欢加 LogLevel
void Logger::debug(LogEvent::ptr event)
{
	debug(LogLevel::DEBUG, event);
}
void Logger::info(LogEvent::ptr event)
{
	debug(LogLevel::INFO event);
}
void Logger::warn(LogEvent::ptr event)
{
	debug(LogLevel::WARN, event);
}
void Logger::error(LogEvent::ptr event)
{
	debug(LogLevel::ERROR, event);
}
void fatal(LogEvent::ptr event)
{
	debug(LogLevel::FATAL, event);
}

FileLogAppender::FileLogAppender(const std::string& filename)
	:m_filename(filename)
{

}

void FileLogAppender::log(LogLevel::Level level, LogEvent::ptr event)
{
	if (level >= m_level)
	{
		m_filestream << m_formatter.format(event);//把文件按照我们需要的方式输出出来
	}
}

bool FileLogAppender::reopen()
{
	if (m_filestream)//如果为true,就说明是已经打开的状态
	{
		m_filestream.close();//先关闭
	}
	m_filestream.open(m_filename);//再打开
	return !!m_filestream;
}

void StdoutLogAppender::log(LogLevel::Level level, LogEvent::ptr event)
{
	
	if (level >= m_level)
	{
		//初始化完成后,一定会有一个formatter
		//使用formatter把日志序列化
		if (level >= m_level)
		{
			std::cout << m_formatter.format(event);
		}
	}
}

LogFormatter::LogFormatter(const std::string &pattern)
	:m_pattern(pattern)
{

}

std::string LogFormatter::format(LogEvent::ptr event)
{
	std::stringstream ss;
	for (auto& i :m_items)
	{
		i->format(ss, event);
	}
	return ss.str();
}


//两种格式:
//1.%xxx
//2.%xxx{xxx}
//3. %%
void LogFormatter::init()
{
	std::vector<std::pair<std::string, int>> vec;
	size_t last_pos = 0;
	for (size_t i = 0; i < m_pattern.size();++i)
	{
		if (m_pattern[i] == '%')
		{
			if ((i + 1) < m_pattern.size())
			{

			}
		}
	}
}



}
posted @ 2023-02-09 22:27  nullptrException  阅读(57)  评论(0编辑  收藏  举报