扔掉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.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("\r\n");
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>
扔掉log4j、log4j2,自己动手实现一个多功能日志记录框架,包含文件,数据库日志写入,实测5W+/秒日志文件写入,2W+/秒数据库日志写入,虽然它现在还没有logback那么强大的更多相关文章
- (网页)Java日志记录框架Logback配置详解(企业级应用解决方案)(转)
转自CSDN: 前言 Logback是现在比较流行的一个日志记录框架,它的配置比较简单学习成本相对较低,所以刚刚接触该框架的朋友不要畏惧,多花点耐心很快就能灵活应用了.本篇博文不会具体介绍Logbac ...
- 在android中配置 slf4j + log4j 日志记录框架
需求: 在项目开发中,需要记录 操作日志 .起初自己写了个简单的日志记录文本写入到文本的方法,后来随着项目的膨胀,需要考虑更多的操作,开始考虑性能问题. 实现: 考虑使用 slf4j + log4j ...
- SLF4J - 一个允许你统一日志记录API的抽象层
一.什么是SLF4J 我们在做Java开发时,如果需要记录日志,有很多日志API可供选择,如: java.util.logging Apache log4j logback SLF4J又是个什么东东呢 ...
- Serilog 是 ASP.NET Core 的一个插件,可以简化日志记录
[翻译] ASP.NET Core 利用 Docker.ElasticSearch.Kibana 来记录日志 原文: Logging with ElasticSearch, Kibana, ASP.N ...
- 一个小时搭建一个全栈 Web 应用框架
把想法变为现实的能力是空想家与实干家的区别.不管你是在一家跨国公司工作,还是正在为自己的创业公司而努力,那些有能力将创意转化为真正产品的人,都具有宝贵的技能并拥有明显的实力.如果你能在不到一个小时的时 ...
- logback log4j log4j2 性能实测
logback log4j log4j2 性能实测 转载: https://blog.souche.com/logback-log4j-log4j2shi-ce/ 日志已经成为系统开发中不可或缺的一部 ...
- Log4j,Log4j2,logback,slf4j日志学习
日志学习笔记 Log4j Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.数据库等:我们也可以控制每一条日志的输出格式:通过定义每一条 ...
- Log4j,Log4j2,logback,slf4j日志学习(转)
日志学习笔记Log4jLog4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.数据库等:我们也可以控制每一条日志的输出格式:通过定义每一条日志 ...
- 常见java日志系统的搭配详解:关于slf4j log4j log4j2 logback jul jcl commons-logging jdk-logging
先看一张图: 是不是有点晕, 晕就对了.这个仅仅是 slf4j 的情况,实际上, 我们不仅要接触到 slf4j ,有时候还会接触其他的日志系统.且看下文分解. 1 直接使用各个日志系统 1.1 直接使 ...
随机推荐
- glup/grunt,browserify / webpack等的比较
gulp/grunt的比较: Gulp / Grunt 是一种工具,能够优化前端工作流程.比如自动刷新页面.combo.压缩css.js.编译less等等.简单来说,就是使用Gulp/Grunt,然后 ...
- Eclipse导入Android签名
本篇主要参照http://blog.csdn.net/wuxy_shenzhen/article/details/20946839 在安装安卓apk时经常会出现类似INSTALL_FAILED_SHA ...
- EZChart - 在线图表生成器
朋友写材料时,需要用到一些分析图表,嫌Excel的太丑,就为他写了一个在线图表生成器. 纯静态实现,基于:H5 + Bootstrap + FusionCharts 本地存储使用H5的localSto ...
- HTTP长连接、短连接使用及测试
概念 HTTP短连接(非持久连接)是指,客户端和服务端进行一次HTTP请求/响应之后,就关闭连接.所以,下一次的HTTP请求/响应操作就需要重新建立连接. HTTP长连接(持久连接)是指,客户端和服务 ...
- phpcms后台管理
phpcms从网上下载就好了,记住这个要安装在Wamp中的www文件下 从网页输入网址进入后台控制 输入密码账号,即进入后台控制界面: 后台管理有自带的网页模板把他换成自己的模板: 修改站点: 把 ...
- 内存管理之slab分配器
基本思想 与传统的内存管理模式相比, slab 缓存分配器提供了很多优点.首先,内核通常依赖于对小对象的分配,它们会在系统生命周期内进行无数次分配.slab 缓存分配器通过对类似大小的对象进行缓存而提 ...
- AspNetCore-MVC实战系列(三)之个人中心
AspNetCore - MVC实战系列目录 . 爱留图网站诞生 . git源码:https://github.com/shenniubuxing3/LovePicture.Web . AspNetC ...
- python中的一些小知识
在最近学习python中遇到的一些小问题汇总一下: 1.在windows7下安装python3.5版本时提示安装不了,缺少ServicePack1. 解决办法是,打开控制面板\系统和安全\Windo ...
- Java学习笔记——浅谈数据结构与Java集合框架(第三篇、Map)
桃李春风一杯酒,江湖夜雨十年灯 --寄黄几复 之前图上写错了,是Hashtable类.t是小写的,它是个很古老的类,以至于命名都没有那么规范.. HashMap HashMap就是存储key-valu ...
- OGNL表达式与EL表达式
一.OGNL表达式 a)什么是OGNL? OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言, 通过它简单一致的表达式语法.主要功能: ...