项目需要:将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入数据库重写的更多相关文章

  1. php批量上传图片并把图片名放入数据库

    前几天工作中要做这样一个功能,有八百多个系统 生成的会员:给这八百多个系统会员上传图片:然后把图片名放入数据库. 第一步: 第一步肯定是首先把图片上传到对应的图片目录下,直接用框架中已经有的上传类: ...

  2. java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】

    java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...

  3. php从数据库中取二进制流文件转换为图片,图片以二进制流存入数据库实现

    php从数据库中取二进制流文件转换为图片,图片以二进制流存入数据库实现 function data_uri($contents, $mime) { $base64 = base64_encode($c ...

  4. 数据处理 数据入数据库 与 Excel

    Python  数据处理   中间数据 Excel   团队交流分工   低的沟通成本    数据入数据库 如postgresql

  5. .NET采集数据,放入数据库总结

    第一次做采集Json的还简单一些但是XML的简直了......... JSON //采集数据 public string GetBetRecordToRepository()//随便你返回什么 { t ...

  6. 关于jsp页面将表单填入数据库出现中文乱码绝对解决方案

    在所有jsp页面中添加两句话1.<%@ page language="java" contentType="text/html; charset=utf-8&quo ...

  7. 导入.sql文件入数据库

    1.创建数据库,例如abc create database abc; 2.进入数据库 use abc 3.导入e盘下的ssh.sql文件即可 source e:\ssh.sql; 截图如下:

  8. 【SQLServer2008】之改变主键当为null时也不会报错,可以入数据库。

    在SqlServer红框中设置主键,右键会有添加主键选项,并且设置不能为null. 当我们插入主键数据如果为null时,会插不进去,这时候我们需要修改一下,如下图: “标识规范”中选择“是”,就可以了 ...

  9. Logback相关知识汇总

    例如:%-4relative 表示,将输出从程序启动到创建日志记录的时间 进行左对齐 且最小宽度为4格式修饰符,与转换符共同使用:可选的格式修饰符位于“%”和转换符之间.第一个可选修饰符是左对齐 标志 ...

随机推荐

  1. iOS开发之静态库.a的制作教程

    第一种方法:直接新建一个工程. 1.新建项目-> 选择 “Cocoa Touch Static Library” 2.添加库需要包含的源代码,将你工程里的代码添加到打静态库工程里: 3.配置一下 ...

  2. Time complexity analysis of algorithms

    时间复杂性的计算一般而言,较小的问题所需要的运行时间通常要比较大的问题所需要的时间少.设一个程序P所占用的时间为T,则 T(P)=编译时间+运行时间. 编译时间与实例特征是无关的,且可假设一个编译过的 ...

  3. Centos 6.5 安装 chrome , mplayer , alarm , clock

    http://my.oschina.net/jianweizhang/blog/306946 Chrome wget http://chrome.richardlloyd.org.uk/install ...

  4. 比较ASP生成静态HTML文件的几种方法

    将动态页面转换生成静态Html文件有许多好处,比如生成html网页有利于被搜索引擎收录(特别是对接受动态参数的页面).前台访问时,脱离了数据访问,减轻对数据库访问的压力,加快网页打开速度. 当然,凡事 ...

  5. 陷阱~SQL全表扫描与聚集索引扫描

    SqlServer中在查询时,我们为了优化性能,通常会为where条件的字段建立索引,如果条件比较固定还会建立组合索引,接下来,我们来看一下索引与查询的相关知识及相关陷阱. SQL表自动为主键加聚集索 ...

  6. 命令行创建Android应用,生成签名,对APK包签名并编译运行

    一.命令行创建Android应用 android create project -n HelloWorld -t android-22 -p HelloWorld1 -k org.crazyit.he ...

  7. oracle数据同步方案

    数据同步方案:--用DBLINK 创建与所需同步表的链接------------------------------------------------------------------------ ...

  8. WCF编程系列(二)了解WCF

    WCF编程系列(二)了解WCF   面向服务     服务是复用进化的结果,起初的复用是函数,面向对象编程的出现使复用从函数上升到对象,随后面向组件编程又将复用从对象上升到组件,现在面向服务编程将复用 ...

  9. 注意事项: Oracle Not Exists 及 Not In 使用

    select value from temp_a awhere a.id between 1 and 100and not exists(select * from temp_b b where a. ...

  10. iOS UIView 快速修改 frame,

    在iOS开发布局修改 frame 时需要繁琐的代码实现,今天偶尔看到一播客说到快速修改的 frame 的方法,自己动手写了一遍实现代码. 快速实现主要通过 添加类目的方式,对UIView 控件添加了一 ...