首页 > 其他分享 >1.日志系统

1.日志系统

时间:2023-02-09 22:33:29浏览次数:37  
标签:std void 系统 event LogEvent 日志 ptr

#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())
			{

			}
		}
	}
}



}

标签:std,void,系统,event,LogEvent,日志,ptr
From: https://www.cnblogs.com/Epiephany/p/17107378.html

相关文章

  • Ubuntu系统挂载iso作为本地源
    1、创建挂载点mkdir/mnt/cdrom//创建挂载点umount/dev/sr0mount-tiso9660/dev/sr0/cdrom或sudomount-tiso9660-oloop/xxx/yyy/zzz.iso/mnt/cdrom///x......
  • Linux系统怎么配置静态IP?
    使用虚拟机学习Linux可能对新手来说是最简单有效的方式,这里使用的软件是VirtualBox,对新手来说也是比较容易上手的一款软件。如何使用VirtualBox以及如何在VirtualBox......
  • 力扣---1797. 设计一个验证系统
    你需要设计一个包含验证码的验证系统。每一次验证中,用户会收到一个新的验证码,这个验证码在currentTime时刻之后timeToLive秒过期。如果验证码被更新了,那么它会在curre......
  • 3.5正则表达式和EXCESS系统
       尾数部分使用正则表达式,可以将表现形式多样的浮点数统一为一种表现型时。例如,十进制数0.75就有很多中表现形式,如图3-5所示。     单精度浮点数的正则......
  • ASP.NET Core+Element+SQL Server开发校园图书管理系统(完)
    随着技术的进步,跨平台开发已经成为了标配,在此大背景下,ASP.NETCore也应运而生。本文主要基于ASP.NETCore+Element+SqlServer开发一个校园图书管理系统为例,简述基于MVC三......
  • 操作系统
    操作系统操作系统的概念操作系统:控制和管理整个计算机系统的硬件和软件资源,并合理组织调度计算机的工作和资源分配,以提供给用户和其他软件方便的接口和环境,是计算机系统......
  • 【操作系统】05-虚拟存储器
    计算机操作系统——虚拟存储器目录计算机操作系统——虚拟存储器第五章虚拟存储器5.1虚拟存储器概述5.1.1常规存储器管理方式的特征和局部性原理5.1.2虚拟存储器的定......
  • C/C++单项选择题标准化考试系统[2023-02-09]
    C/C++单项选择题标准化考试系统[2023-02-09](C)3.17单项选择题标准化考试系统【难度系数】5级【任务描述】设计一个单项选择题的考试系统,可实现试题维护、自动组卷等......
  • proc 文件系统
    1、简介proc是一个虚拟文件系统,通常作为进程信息的伪文件系统,里面没有真正的文件,但是却包含系统运行信息(系统内存、设备mount、硬件配置)。proc文件系统可以认为是内核的......
  • 基于QT实现的影院订票系统[2023-02-09]
    基于QT实现的影院订票系统[2023-02-09](1)订票模块:用户选择影院影片和场次,进行选座购票的操作等。(2)用户模块:用户的登录,修改信息等。(3)影院管理模块:影院负责人对自己影院的......