zoukankan      html  css  js  c++  java
  • 扔掉log4j、log4j2,自己动手实现一个多功能日志记录框架,包含文件,数据库日志写入,实测5W+/秒日志文件写入,2W+/秒数据库日志写入,虽然它现在还没有logback那么强大

    讲到log4j,现在国外基本是没有开发者用这个框架了,原因大致有几点,1、功能太少;2、效率低下;3、线程锁bug等等等各种莫名其妙的bug一直都没解决。

    其实最重要的是log4j的作者自己也放弃了log4j,该作者现在在维护logback项目(现在主流的日志记录框架,彻底推翻了log4j的架构重写了,功能很强大),所以log4j以后基本不会再用了。

    讲到这里,还是要研究一下要怎么实现的日志记录框架,那么要写个日志记录框架,得要熟悉日志记录系统的整体设计思路。于是自己构思了一晚上,花了一上午时间写了一个简单的日志记录系统(就是logGuide0.1.1),姑且称为一个简单框架吧。

    由于后面又继续对logGuide进行开发更新,所以现在的版本有这些:

    如果有兴趣研究这一块的话,源码在这里:

    logGuide 0.1.1比较简陋就不在提供了。

    老核心源码logGuide 0.2.1http://download.csdn.net/detail/eguid_1/9491573

    最新logGuide 0.3.2.jar包(非源码)下载:http://download.csdn.net/detail/eguid_1/9532267

    最新logGuide 0.3.2(源码下载:http://download.csdn.net/detail/eguid_1/9532617


    新核心日志记录(logGuide 0.3.1)大致分为5层结构:

    1、写入区        ---> 传入消息,传入消息后交由分发器进行分发

    2、分发器        ---> 分发消息,缓冲消息数据(消息分为普通日志和异常错误日志),调用缓冲区缓冲消息日志

    3、缓冲区        ---> 缓冲消息日志,把所有消息缓冲到一个双缓冲队列中,交由缓冲分发器进行消息分发处理

    4、缓冲分发器 ---> 由一个后台保护线程调用持久层写出日志

    5、持久层        ---> 写出消息日志,缓冲区通过持久层实现写出日志,配置文件中配置可以实现文件和数据库同时写出


    当前最新版本:

    logGuide 0.3.2版本

    1、增加独立数据库缓存核心

    2、优化数据库写入效率

    3、优化文件写入逻辑


    logGuide 0.3.1版本(重大更新版本)

    1、源代码推翻重写

    2、优化代码结构,结构更加清晰,各功能模块分工更加明确

    3、优化NIO+BQ缓冲核心,占用资源更少,速度更快,实测 最高50822/每秒 日志文件写出速度

    4、增加数据库持久化功能,可通过配置文件配置

    5、消息格式可配置


    logGuide 0.2.1版本
    1、支持配置文件方式指定两种日志记录文件(infoPath=log.log,errorPath=error.log)在项目文件中的路径(注意:目前支持项目文件中的路径,其他路径会出现异常)
    2、支持读写顺序日志记录(先读后写)和读写同时两种方式记录(通过配置文件中的auto='false/true'来指定哪种方式,默认先读后写)
    3、优化代码结构,可读性更好


    logGuide 0.1.1版本
    1、实现第三方动态日志记录
    2、采用双缓冲队列,更好的多线程并发条件下的日志写入,安全与效率并重
    3、采用NIO文件底层操作,更快的读写效率
    4、采用读写同时日志记录(并发,写入为单独线程操作),提高组件运行效率


    logGuide 0.2.1文件写出核心代码:

    <span style="font-size:18px;">private static FileChannel infoChannel = null;
    	private static FileChannel errorChannel = null;
    
    	private static BlockingQueue<Object> bq = null;
    	private static ByteBuffer buffer = null;
    	private static int index = 0;// 用于控制是否开启自动写入
    	static {
    		Properties pro = new Properties();
    		File infoFile = null;
    		File errorFile = null;
    		try {
    			InputStream is = FileBuffer.class.getClassLoader()
    					.getResourceAsStream("logConf.properties");
    			pro.load(is);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		String infoFilePath = pro.getProperty("infoPath");
    		String errorFilePath = pro.getProperty("errorPath");
    		String status = pro.getProperty("auto");
    		if (status != null && status.equals("true")) {
    			index = 0;
    		} else {
    			index = 1;
    		}
    		String path = FileBuffer.class.getClassLoader().getResource("/")
    				.getPath();
    		if (infoFilePath != null) {
    			infoFile = new File(path + infoFilePath);
    			try {
    				createFile(infoFile);
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		if (errorFilePath != null) {
    			errorFile = new File(path + errorFilePath);
    			try {
    				createFile(errorFile);
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		bq = new LinkedBlockingQueue<Object>();
    		buffer = ByteBuffer.allocate(1024);
    		try {
    			infoChannel = new RandomAccessFile(infoFile, "rw").getChannel();
    			errorChannel = new RandomAccessFile(errorFile, "rw").getChannel();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		// 如果index=0则自动更新
    		if (index == 0) {
    			AutoWrite();
    		}
    	}
    
    	/**
    	 * 把消息存放进缓冲队列
    	 * 
    	 * @param msg
    	 * @param name
    	 * @throws Exception
    	 */
    	public static void addMsgToFile(StringBuilder msg, String name){
    
    		Map<String, Object> map = null;
    		map = new HashMap<String, Object>();
    		if (msg != null) {
    			map.put("fileName", name);
    			map.put("msg", msg);
    		}
    		bq.offer(map);
    		OneWrite();
    	}
    	/**
    	 *  index为1时为1次消息1次写入
    	 */
    	private static void OneWrite()
    	{
    		
    		if (index == 1) {
    			try {
    				writen();
    			} catch (Exception e) {
    				System.out.println("日志写入失败"+e.getMessage());
    			}
    		}
    	}
    	/**
    	 * 开启自动写入
    	 */
    	private static void AutoWrite() {
    		Thread t = new Thread() {
    			public void run() {
    				while (true) {
    					try {
    						writen();
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		};
    		//开启写入线程
    		t.start();
    	}
    
    	/**
    	 * 将缓冲队列中的文件写入到对应的文件中
    	 * 
    	 * @throws Exception
    	 */
    
    	private static void writen() throws Exception {
    
    		if (bq.peek() != null) {
    			Map map = (Map) bq.poll();
    			String name = (String) map.get("fileName");
    			StringBuilder msg = (StringBuilder) map.get("msg");
    			if (name != null && name.equals("info")) {
    				wirteInfo(msg);
    			} else if (name != null && name.equals("error")) {
    				writeError(msg);
    			}
    		} else {
    			Thread.sleep(200);
    		}
    	}
    
    	/**
    	 * 写入普通消息
    	 * 
    	 * @param msg
    	 */
    	private static void wirteInfo(StringBuilder msg) {
    		bufferWrite(buffer, infoChannel, msg);
    	}
    
    	// 写入错误消息
    	private static void writeError(StringBuilder msg) {
    		bufferWrite(buffer, errorChannel, msg);
    	}
    
    	/**
    	 * 使用NIO将消息缓冲进buffer,通过buffer写出到到指定通道
    	 * 
    	 * @param buffer
    	 * @param fc
    	 * @param msg
    	 */
    	private static void bufferWrite(ByteBuffer b, FileChannel fc,
    			StringBuilder msg) {
    		b.clear();
    		msg.append("
    ");
    		b.put(msg.toString().getBytes());
    		try {
    			b.flip();
    			fc.write(b, fc.size());
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    
    	/**
    	 * 是否存在文件,如果不存在则创建
    	 * 
    	 * @param file
    	 * @throws IOException
    	 */
    	private static void createFile(File file) throws IOException {
    		if (!file.exists()) {
    			try {
    				file.createNewFile();
    			} catch (IOException e) {
    				e.printStackTrace();
    				throw e;
    			}
    		}
    	}</span>


  • 相关阅读:
    Redis的特点什么是?
    Linux---用户和用户管理--用户配置文件
    python---模仿键盘
    Linux---脚本安装包
    python---创建句柄
    python---模仿鼠标悬停 move_to_element/perform/context_click
    python---总结所学元素及方法
    python---关闭 close,quit
    python---截屏
    python---前进和后退 back/forward
  • 原文地址:https://www.cnblogs.com/eguid/p/6821626.html
Copyright © 2011-2022 走看看