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>


  • 相关阅读:
    linux驱动开发学习一:创建一个字符设备
    如何高效的对有序数组去重
    找到缺失的第一个正整数
    .NET不可变集合已经正式发布
    中国人唯一不认可的成功——就是家庭的和睦,人生的平淡【转】
    自己动手搭建 MongoDB 环境,并建立一个 .NET HelloWorld 程序测试
    ASP.NET MVC 中如何用自定义 Handler 来处理来自 AJAX 请求的 HttpRequestValidationException 错误
    自己动手搭建 Redis 环境,并建立一个 .NET HelloWorld 程序测试
    ServiceStack 介绍
    一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL
  • 原文地址:https://www.cnblogs.com/eguid/p/6821626.html
Copyright © 2011-2022 走看看