讲到log4j,现在国外基本是没有开发者用这个框架了,原因大致有几点,1、功能太少;2、效率低下;3、线程锁bug等等等各种莫名其妙的bug一直都没解决。
其实最重要的是log4j的作者自己也放弃了log4j,该作者现在在维护logback项目(现在主流的日志记录框架,彻底推翻了log4j的架构重写了,功能很强大),所以log4j以后基本不会再用了。
讲到这里,还是要研究一下要怎么实现的日志记录框架,那么要写个日志记录框架,得要熟悉日志记录系统的整体设计思路。于是自己构思了一晚上,花了一上午时间写了一个简单的日志记录系统(就是logGuide0.1.1),姑且称为一个简单框架吧。
由于后面又继续对logGuide进行开发更新,所以现在的版本有这些:
如果有兴趣研究这一块的话,源码在这里:
logGuide 0.1.1比较简陋就不在提供了。
老核心源码(logGuide 0.2.1):http://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>