LogBack入数据库重写
项目需要:将info以及error的日志信息写入到数据库中;同时所有的日志都要写入到日志文件中。
可以封装一下,在基类的logError/logInfo中调用了log.error()以及log.info之后在调用一次LoggerDBService进行写入;但是这样就意味着"不美",日志还需要调用两次;而且因为早期设计问题,并不是所有的日志都采用基类的logError/logInfo。
看了一下logback源码,分析了一下其机制,于是决定采用重写DBAppender并结合AsyncAppender进行异步调用的方式进行实现。对于日志类操作,如果写入数据库这种比较消耗资源和时间的事情进行同步,很不值,于是才决定通过异步方式进行处理。
AsyncAppender(AA)是一个独立的Appender,放置到它下面的appender(通过appender-ref属性进行设定)也就不需要在放置到root节点下面,因为AsyncAppender设计的逻辑就是:在root下面引用该Appender,然后通过AA进行调度此appender进行日志输出。
<appender
name="asyncLog"
class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>10000</queueSize>
<appender-ref
ref="dbLog"/>
</appender>
<root
level="debug">
<appender-ref
ref="stdout"
/>
<appender-ref
ref="txtLog"
/>
<appender-ref
ref="asyncLog"/>
</root>
至于调度的逻辑,首先要明白一个概念: LoggingEvent(日志事件),任何一次logback的输出动作,都是一个LogEvent,logEvent里面包括了很多信息,包括要写入的内容,级别等等一系列信息。AA的调度逻辑就是将每次的输出动作放到内置的BlockingQueue中;然后再从BlockingQueue中取出来交给关联的Appender进行处理。LogEvent和Appender是无关的,前者是内容;后者是处理内容。
ILoggingEvent是每次传入append方法的入参。
重写的DB继承自UnsynchronizedAppenderBase<ILoggingEvent>,重写了append方法,里面使用自己的DBManager来进行数据库处理;我没有继承DBAppenderBase,是因为里面固化了一些内容,很多都是不需要的;而且采用它,就必须要指定数据库的连接字符串,用户名密码,这意味着同样的数据库要在两个地方进行配置:应用级别的配置文件以及logback的配置文件。于是我索性就直接继承了UnsynchronizedAppenderBase<ILoggingEvent>,没有重用DBAppender相关内容。
public
class TransportDBLoggerAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
@Override
public
void append(ILoggingEvent eventObject) {
try {
String content = eventObject.getFormattedMessage();
System.out.println("content内容是: " + content);
Map<String, String> map = new HashMap<String, String>();
map.put("LOG_LEVEL", eventObject.getLevel().levelStr);
map.put("CONTENT", content.replace("'", "''"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
map.put("CREATE_DATE", sdf.format(new Date()));
// 拼接SQL语句,然后执行
… …
} catch (Throwable sqle) {
String errorMsg = CommonUtil.getTrace(sqle);
System.out.println(errorMsg);
}
}
}
在配置文件中,还需要指定过滤级别,因为只需要info和error需要写入到数据库中;在过来级别logback提供了两种方式来进行处理,分别是LevelFilter以及ThresholderFilter,前者只能指定过来特定的级别的操作(ACCEPT,NEUTRAL,DENY),后者则是过滤指定级别,之下的将会被拒绝(DENY)。
<appender
name="dbLog"
class="test.MyDBLoggerAppender">
<filter
class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>
调用测试代码,发现并没有走入库逻辑,后来才发现原来是因为测试代码走完后,整个应用退出,于是logback也退出了;换言之,放置到Queue里面的内容根本就没有被处理,logback的线程也就消亡了。于是尝试让测试线程阻塞10秒钟,至此,才看到入库的动作以及数据。
Logger logger = LoggerFactory.getLogger(this.getClass());
logger.info("test transDbLogger INFO");
logger.error("test transDbLogger ERROR");
logger.debug("test transDbLogger DEBUG");
System.out.println("OK, complete!");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
LogBack入数据库重写的更多相关文章
- php批量上传图片并把图片名放入数据库
前几天工作中要做这样一个功能,有八百多个系统 生成的会员:给这八百多个系统会员上传图片:然后把图片名放入数据库. 第一步: 第一步肯定是首先把图片上传到对应的图片目录下,直接用框架中已经有的上传类: ...
- java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】
java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...
- php从数据库中取二进制流文件转换为图片,图片以二进制流存入数据库实现
php从数据库中取二进制流文件转换为图片,图片以二进制流存入数据库实现 function data_uri($contents, $mime) { $base64 = base64_encode($c ...
- 数据处理 数据入数据库 与 Excel
Python 数据处理 中间数据 Excel 团队交流分工 低的沟通成本 数据入数据库 如postgresql
- .NET采集数据,放入数据库总结
第一次做采集Json的还简单一些但是XML的简直了......... JSON //采集数据 public string GetBetRecordToRepository()//随便你返回什么 { t ...
- 关于jsp页面将表单填入数据库出现中文乱码绝对解决方案
在所有jsp页面中添加两句话1.<%@ page language="java" contentType="text/html; charset=utf-8&quo ...
- 导入.sql文件入数据库
1.创建数据库,例如abc create database abc; 2.进入数据库 use abc 3.导入e盘下的ssh.sql文件即可 source e:\ssh.sql; 截图如下:
- 【SQLServer2008】之改变主键当为null时也不会报错,可以入数据库。
在SqlServer红框中设置主键,右键会有添加主键选项,并且设置不能为null. 当我们插入主键数据如果为null时,会插不进去,这时候我们需要修改一下,如下图: “标识规范”中选择“是”,就可以了 ...
- Logback相关知识汇总
例如:%-4relative 表示,将输出从程序启动到创建日志记录的时间 进行左对齐 且最小宽度为4格式修饰符,与转换符共同使用:可选的格式修饰符位于“%”和转换符之间.第一个可选修饰符是左对齐 标志 ...
随机推荐
- PHP读书笔记(2)-变量与数据结构
php中的数据类型: 一.8种主要数据类型 标量类型 1.整型(int|integer):八进制.十进制.十六进制.超过整型存储范围,会产生溢出. 整型数的字长和平台有关,尽管通常最大值是大约二十亿( ...
- Android开发的初学者快速创建一个项目
因为gwf的原因,大陆连不上google所以AndroidSDK是无法更新的 而且设置代理也不一定能解决问题 如果是初学者想快速的了解安卓开发,可以在国内的内网下载整合包 下载地址:http://rj ...
- Swift基础语法-内存管理, 自动引用计数
1. 工作机制 Swift和OC一样,采用自动引用计数来管理内存 当有一个强引用指向某一个对象时,该对象的引用计数会自动+1 当该强引用消失时,引用计数会自动-1 当引用计数为0时,该对象会被销毁 2 ...
- 阅读《RobHess的SIFT源码分析:综述》笔记
今天总算是机缘巧合的找到了照样一篇纲要性质的文章. 如是能早一些找到就好了.不过“在你认为为时已晚的时候,其实还为时未晚”倒是也能聊以自慰,不过不能经常这样迷惑自己,毕竟我需要开始跑了! 就照着这个大 ...
- Linux shell之数组
引言 在Linux平台上工作,我们经常需要使用shell来编写一些有用.有意义的脚本程序.有时,会经常使用shell数组.那么,shell中的数组是怎么表现的呢,又是怎么定义的呢?接下来逐一的进行讲解 ...
- javascript深度克隆与javascript的继承实现
1.javascript深度克隆: //注意这里的对象包括object和array function cloneObject(obj){ var o = obj.constructor === Arr ...
- [转]SQL Server 和Oracle 数据类型对应
本文转自:http://blog.sina.com.cn/s/blog_681cd80d0100q84t.html SqlServer 2k转换为Oracle 10g 列名 SqlServer数据类型 ...
- android 按两次返回键退出应用
private long mExitTime; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCod ...
- 深入理解java的抽象类和接口(转载)
原文链接:http://www.cnblogs.com/dolphin0520/p/3811437.html 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的 ...
- 2013年全国各大著名的IT公司薪资待遇大揭密
以下为转载,特此说明!--西电好网 ============================================ 1: 本人西电通院2013届毕业硕士,根据今年找工作的情况以及身边同学的汇 ...