项目需要:将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. 将指定SQL的执行计划从共享池删除的方法

    如果Oracle的优化器产生了某种错误的执行计划,或者我们希望Oracle对于某个SQL重新进行分析,那么就需要这个SQL的执行计划在共享池中过期,而简单的方法在10.2.0.4以后才出现.   对于 ...

  2. nmblookup

    域网内可以通过下述命令来根据ip地址查询其他主机名(Linux) 使用nmblookup -A ip命令查询 [admin@v015213 ~/lpmall]$ nmblookup -A 10.19. ...

  3. mapping 详解5(dynamic mapping)

    概述 在使用 ES 的时,我们不需要事先定义好映射设置就可以直接向索引中导入文档.ES 可以自动实现每个字段的类型检测,并进行 mapping 设置,这个过程就叫动态映射(dynamic mappin ...

  4. override和new的区别【摘】

    override 1. override是派生类用来重写基类中方法的: 2. override不能重写非虚方法和静态方法: 3. override只能重写用virtual.abstract.overr ...

  5. WindowManage与Window的在Activity的一点小应用

    super.onCreate(savedInstanceState); getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN ...

  6. NetMQ(ZeroMQ)Client => Server => Client 模式的实现

    ØMQ (也拼写作ZeroMQ,0MQ或ZMQ)是一个为可伸缩的分布式或并发应用程序设计的高性能异步消息库.它提供一个消息队列, 但是与面向消息的中间件不同,ZeroMQ的运行不需要专门的消息代理(m ...

  7. ArcEngine 直连连接SDE

    关键代码IPropertySet pPropertySet = new PropertySetClass();             pPropertySet.SetProperty("S ...

  8. ###《Video Event Detection by Inferring Temporal Instance Lables》

    论文作者:Kuan-Ting Lai, Felix X. Yu, Ming-Syan Chen and Shih-Fu Chang. #@author: gr #@date: 2014-01-25 # ...

  9. iOS开发,多个button数组,每个数组只能选中5项,多个数组只能选择3个。

    由于常用xib,所以不想用代码写那么多个button.而且也懒的算位置 直接xib拉线成四个数组.水果,零食,饮料,甜点. 入题实现的功能就是,在这四个数组之中只能在3个数组只选中5项.有点绕(就比如 ...

  10. props验证

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...