IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 基于log4J模式的日志系统 -> 正文阅读

[Java知识库]基于log4J模式的日志系统

开发环境

Centos 7.6
vim
Visual Studio 2022
Makefile
gdb
g++ 9

系统思想

仿照log4j的模式进行开发

格式如下:

	 %m--->消息体
	 %p--->日志级别
	 %r--->启动的时间
	 %c--->日志名称
	 %t--->进程id
	 %n--->回车
	 %d--->时间
	 %f--->文件名
	 %l--->行号

将日志抽象成Logger(日志器),LogAppender(输出落地点),LogFormat(日志格式器)三大模块。
Logger, 对外使用的类,输入的日志级别大于等于Logger的日志,才会被真正写入。可以有多个Logger,不同的logger,记录不同类型的日志,比如将系统框架日志和业务逻辑日志分离。
LogAppender, 定义日志的输出落地点,目前实现了控制台日志(StdoutLogAppender),文件日志(FileLogAppender).两种类型。拥有自己的日志级别和日志格式,可以灵活定义不同的输出。主要用于区分日志级别,将error日志,单独输出到一个文件,以防被其他类型的日志淹没
Formater,日志格式,通过字符串自定义日志的格式,仿printf格式。可以灵活定义日志格式

系统介绍

系统最大特点就是具有独立性,可以作为不同模块的日志系统,之间互不影响。可以实现不同模块之间的日志分离,系统还支持流式日志风格写日志和格式化风格写日志,支持日志格式自定义,日志级别,多日志分离等等功能 流式日志使用:LOG_INFO(logger) << “this is a log”; 格式化日志使用:LOG_FMT_INFO(logger, “%s”, “hello log”); 支持时间,线程id,线程名称,日志级别,日志名称,文件名,行号等内容的自由配置

系统主体框架

在这里插入图片描述

系统日志展示

控制台流式日志输出
在这里插入图片描述
文件格式日志输出
在这里插入图片描述

核心代码展示

日志系统最为核心的就是解析用户输出的日志格式,其算法和C标准库中printf的算法相似

void Formattor::Init() {
	string nstr;
	for (size_t i = 0;i < m_pattern.size();i++) {
		if (m_pattern[i] != '%') {
			nstr.append(1, m_pattern[i]);
			continue;
		}
		//其实还是一个%
		if ((i + 1) < m_pattern.size()) {
			if (m_pattern[i + 1] == '%') {
				nstr.append(1, '%');
				continue;
			}
		}
		size_t n = i + 1;
		int fmt_staus = 0;
		int fmt_beign = 0;
		string str;
		string fmt;
		while (n < m_pattern.size()) {
			//遇见空格
			if (!isalpha(m_pattern[n]) && m_pattern[n] != '}' && m_pattern[n] != '{') {
				str = m_pattern.substr(i + 1, n - i - 1);
				break;
			}
			if (fmt_staus == 0) {
				if (m_pattern[n] == '{') {
					//字符串分割
					str = m_pattern.substr(i + 1, n - i - 1);
					fmt_staus = 1;
					fmt_beign = n;
					n++;
					continue;
				}
			}
			else if (fmt_staus == 1) {
				if (m_pattern[n] == '}') {
					//字符串分割
					fmt = m_pattern.substr(fmt_beign + 1, n - fmt_beign - 1);
					//	cout << "#" << fmt << endl;
					fmt_staus = 0;
					++n;
					break;
				}
			}
			++n;
			if (n == m_pattern.size()) {
				if (str.empty()) {
					str = m_pattern.substr(i - 1);
				}
			}
		}
		if (fmt_staus == 0) {
			if (!nstr.empty()) {
				vec.push_back(make_tuple(nstr, string(), 0));
				nstr.clear();
			}
			str = m_pattern.substr(i + 1, n - i - 1);
			//解析日志将日志存储在数组中
			vec.push_back(make_tuple(str, fmt, 1));
			i = n - 1;
		}
		else if (fmt_staus == 1) {
			cout << "pattern parse error" << m_pattern << "-" << m_pattern.substr(i) << endl;
			//格式错误
			vec.push_back(make_tuple("<<pattern_error>>", fmt, 0));
		}
	}
	if (!nstr.empty()) {
		vec.push_back(make_tuple(nstr, "", 0));

	}
	for (auto& i : vec) {
		if (get<2>(i) == 0) {
			m_items.push_back(Formattor::Item::ptr(new stringitemforma(get<0>(i))));
		}
		else {
			auto it = formar_item.find(get<0>(i));
			if (it == formar_item.end()) {
				m_items.push_back(Formattor::Item::ptr(new stringitemforma("<<error_format %" + get<0>(i) + ">>")));
			}
			else {
				m_items.push_back(it->second(get<1>(i)));

			}

		}
		//cout << "(" << get<0>(i) << ")-(" << get<1>(i) << ")-(" << get<2>(i)<<")" << endl;
	}
	//	cout << m_items.size() << endl;
}

管理所有的日志器,并且可以通过解析类模板,动态创建或修改日志器相关的内容(日志级别,日志格式,输出落地点等等)

//日志管理器
class LogMessage {
public:
	LogMessage() {
		//默认为stdout
		root.reset(new Logger());
		root->AddAppender(LogAppender::ptr(new stdoutAppender()));
	}
	map<string, Logger::ptr> mp;
	Logger::ptr root;
public:
	//获取日志器
	Logger::ptr getlogger(string name);
	void Init();
}

日志落地点抽象。目前只实现了输出到控制台(StdoutAppender)和输出到文件(FileAppender),LogAppender可以拥有自己的LogFormat。
一个日志器,可以对应多个LogAppender。也就是说写一条日志,可以落到多个输出,并且每个输出的格式都可以不一样。
Appender有单独的日志级别,可以自定义不同级别的日志,输出到不同的Appender,常用于将错误日志统一输出到一个地方。

//日志输出器
class LogAppender {
public:
	typedef shared_ptr<LogAppender> ptr;
	virtual~LogAppender() {}
	virtual void Log(shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event) = 0;
	//设置日志格式
	void setformattor(Formattor::ptr val) ;
	//返回日志格式
	Formattor::ptr getformattor() { return m_forattor; }
	void setlevel(LogLevel::Level level);
	LogLevel::Level getlevel();

protected:
	LogLevel::Level m_level;//日志级别
	Formattor::ptr m_forattor;//输出日志格式//将用于输出日志
};
//控制台输出器
class stdoutAppender :public LogAppender {
public:
	typedef shared_ptr<stdoutAppender> ptr;
	virtual void Log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event);
};
//文件输出器
class FileAppender :public LogAppender {
public:
	FileAppender(string filename);
	typedef shared_ptr<FileAppender> ptr;
	void Log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event);
   //重新打开文件,打开文件成功返回true
	bool repoen();
private:
	string m_file_name;//日志文件
	ofstream m_filestream;//文件流
};

日志器,包含一个日志格式器,一个root Logger,N个LogAppender提供日志写入方法。根据日志器的配置格式和内容。将日志写到对应的地方

//日志器
class Logger :public enable_shared_from_this<Logger> {
public:
	typedef shared_ptr<Logger> ptr;
	Logger(string _name = "root");
	void Log(LogLevel::Level level, LogEvent::ptr event);
	void AddAppender(LogAppender::ptr appender);//添加日志
	void DelAppendrt(LogAppender::ptr appender);//删除日志

	//日志级别
	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);
	LogLevel::Level getlevel() { return m_level; }//获取leve
	void setleve(LogLevel::Level level) { m_level = level; }
	void setformat(Formattor::ptr fmt) { format = fmt; }
	string getname()const { return m_name; }

private:
	string m_name;             //日志名称
	LogLevel::Level m_level;	  //日志级别(满足这各级别就会输出)
	list<LogAppender::ptr> m_appender;  //日志列表
	Formattor::ptr format;
};

日志格式器,执行日志格式化,负责日志格式的初始化。
解析日志格式,将用户自定义的日志格式,解析为对应的Item。
格式解析:
%t : 线程id ThreadIdFormatItem
%N : 线程名称 ThreadNameFormatItem
%F : 协程id FiberIdFormatItem
%p : 日志级别 LevelFormatItem
%c : 日志名称 NameFormatItem
%f : 文件名 FilenameFormatItem
%l : 行号 LineFormatItem
%m : 日志内容 MessageFormatItem

//日志格式控制
class Forater{
public:
	typedef shared_ptr<Formattor> ptr;
	Forater(string pattern) ;
	//通过pattern解析出item中的信息

	//日志解析
	string format(shared_ptr<Logger> logger, LogLevel::Level leve, LogEvent::ptr event);
public:
	//日志解析子模块
	class Item {
	public:
		typedef shared_ptr<Item> ptr;
		virtual ~Item() {}
		//日志解析
		virtual void format(ostream& os, shared_ptr<Logger> logger, LogLevel::Level leve, LogEvent::ptr event) = 0;
	};
	//对pattern解析
	void Init();
private:
	string m_pattern;//输出的是日志得一部分
	vector<Item::ptr> m_items;
};

日志事件的封装,将要写的日志,填充到LogEvent中。填充完毕之后,写入到对应的logger中

//日志事件
class LogEvent {
public:
	//默认构造函数
	LogEvent() {};
	typedef shared_ptr<LogEvent> ptr;
	void format(const char* fmt, ...);
	void format(const char* fmt, va_list al);
	//获取日志器
	shared_ptr<Logger> GetLogger() { return logger; }
	stringstream& getSS() { return m_ss; }

	//获取日志级别
	LogLevel::Level GetLevel() { return level; }

private:
	//日志器
	shared_ptr<Logger> logger;
	//日志级别
	LogLevel::Level level;

	const char* m_file = NULL;     		 //文件名
	int32_t m_line = 0;				 	 //行号
	uint32_t m_please = 0;           	  //程序运行时间(毫秒)
	uint32_t m_threadid = 0;           //线程id
	uint64_t m_time = 0;               //时间戳
	stringstream m_ss;				  //格式流	

};
日志级别
enum Level {
		UNKNOW = 0,
		DEBUG = 1,
		INFO = 2,
		WARN = 3,
		ERROR = 4,
		FATAL = 5
	};
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-13 11:38:35  更:2022-05-13 11:39:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:09:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码