logback怎么异步日志到oracle数据库中

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了logback怎么异步日志到oracle数据库中相关的知识,希望对你有一定的参考价值。

  logback是log4j作者推出的新日志系统,原生支持slf4j通用日志api,允许平滑切换日志系统,并且对简化应用部署中日志处理的工作做了有益的封装。
  官方地址为:http//logback.qos.ch/
  Logback日志需要依赖一下jar包:
  slf4j-api-1.6.0.jar
  logback-core-0.9.21.jar
  logback-classic-0.9.21.jar
  logback-access-0.9.21.jar
  主配置文件为logback.xml,放在src目录下或是WEB-INF/classes下,logback会自动加载
  logback.xml的基本结构如下:
  <?xml version="1.0" encoding="UTF-8"?>
  <configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
  <pattern>%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger36 - %msg%n</pattern>
  </encoder>
  </appender>
  <root level="DEBUG"><appender-ref ref="STDOUT" /></root>
  </configuration>
  logback.xml的基本配置信息都包含在configuration标签中,需要含有至少一个appender标签用于指定日志输出方式和输出格式,root标签为系统默认日志进程,通过level指定日志级别,通过appender-ref关联前面指定顶的日志输出方式。
  例子中的appender使用的是ch.qos.logback.core.ConsoleAppender类,用于对控制台进行日志输出
  其中encoder标签指定日志输出格式为“时间 线程 级别 类路径 信息”
  logback的文件日志输出方式还提供多种日志分包策略
  1.文件日志
  <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>E:/logs/mylog.txt</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  <!-- rollover daily -->
  <fileNamePattern>E:/logs/mylog-%dyyyy-MM-dd_HH-mm.%i.log</fileNamePattern>
  <maxHistory>5</maxHistory>
  <timeBasedFileNamingAndTriggeringPolicy
  class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  <!-- or whenever the file size reaches 100MB -->
  <maxFileSize>100MB</maxFileSize>
  </timeBasedFileNamingAndTriggeringPolicy>
  </rollingPolicy>
  <encoder>
  <pattern>%date %level [%thread] %logger36 [%file : %line] %msg%n</pattern>
  </encoder>
  </appender
  文件日志输出采用的ch.qos.logback.core.rolling.RollingFileAppender类,它的基本属性包括<file>指定输入文件路径,encoder指定日志格式。其中,rollingPolicy标签指定的是日志分包策略,ch.qos.logback.core.rolling.TimeBasedRollingPolicy类实现的是基于时间的分包策略,分包间隔是根据fileNamePattern中指定的事件最小单位,比如例子中的%dyyyy-MM-dd_HH-mm的最小事件单位为分,它的触发方式就是1分钟,策略在每次想日志中添加新内容时触发,如果满足条件,就将mylog.txt复制到E:/logs/目录并更名为mylog-2010-06-22_13-13.1.log,并删除原mylog.txt。maxHistory的值为指定E:/logs目录下存在的类似mylog-2010-06-22_13-13.1.log文件的最大个数,当超过时会删除最早的文件。此外,策略还可以互相嵌套,比如本例中在时间策略中又嵌套了文件大小策略,ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP实现对单文件大小的判断,当超过maxFileSize中指定大大小时,文件名中的变量%i会加一,即在不满足时间触发且满足大小触发时,会生成mylog-2010-06-22_13-13.1.log和mylog-2010-06-22_13-13.2.log两个文件。
  2.数据库日志
  <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
  <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
  <dataSource
  class="com.mchange.v2.c3p0.ComboPooledDataSource">
  <driverClass>com.mysql.jdbc.Driver</driverClass>
  <url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
  <user>root</user>
  <password>root</password>
  </dataSource>
  </connectionSource>
  </appender>
  数据库输出使用ch.qos.logback.classic.db.DBAppender类,数据源支持c3p0数据连接池,例子中使用的MySql,其他配置方式请参考官方文档。
  使用数据库输出需要在数据库中建立3个表,建表脚本如下
  # Logback: the reliable, generic, fast and flexible logging framework.
  # Copyright (C) 1999-2010, QOS.ch. All rights reserved.
  #
  # See http://logback.qos.ch/license.html for the applicable licensing
  # conditions.
  # This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender.
  #
  # It is intended for MySQL databases. It has been tested on MySQL 5.1.37
  # on Linux
  BEGIN;
  DROP TABLE IF EXISTS logging_event_property;
  DROP TABLE IF EXISTS logging_event_exception;
  DROP TABLE IF EXISTS logging_event;
  COMMIT;
  BEGIN;
  CREATE TABLE logging_event
  (
  timestmp BIGINT NOT NULL,
  formatted_message TEXT NOT NULL,
  logger_name VARCHAR(254) NOT NULL,
  level_string VARCHAR(254) NOT NULL,
  thread_name VARCHAR(254),
  reference_flag SMALLINT,
  arg0 VARCHAR(254),
  arg1 VARCHAR(254),
  arg2 VARCHAR(254),
  arg3 VARCHAR(254),
  caller_filename VARCHAR(254) NOT NULL,
  caller_class VARCHAR(254) NOT NULL,
  caller_method VARCHAR(254) NOT NULL,
  caller_line CHAR(4) NOT NULL,
  event_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
  );
  COMMIT;
  BEGIN;
  CREATE TABLE logging_event_property
  (
  event_id BIGINT NOT NULL,
  mapped_key VARCHAR(254) NOT NULL,
  mapped_value TEXT,
  PRIMARY KEY(event_id, mapped_key),
  FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
  );
  COMMIT;
  BEGIN;
  CREATE TABLE logging_event_exception
  (
  event_id BIGINT NOT NULL,
  i SMALLINT NOT NULL,
  trace_line VARCHAR(254) NOT NULL,
  PRIMARY KEY(event_id, i),
  FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
  );
  COMMIT;
  3.其他
  此外logback还提供基于mail,基于jmx等多种日志输出方式,你也可以通过继承ch.qos.logback.core.AppenderBase 自己写appender实现
  除了使用默认的日志主线程<root>外,还可以通过<logger>标签定制其他日志线程如:
  <logger name="com.test" level="DEBUG">
  <appender-ref ref="STDOUT" />
  </logger>
  其中name指定线程针对的包路径,level是日志级别,<appender-ref>定义使用那种appender。
  例如要实现打印jdbc提交的sql,可以加入如下logger:
  <logger name="java.sql.Connection" level="DEBUG"><appender-ref ref="STDOUT" /></logger>
  贴出我完整的logback.xml
  <?xml version="1.0" encoding="UTF-8"?>
  <configuration>
  <!-- log output to file -->
  <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <file>E:/logs/mylog.txt</file>
  <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  <!-- rollover daily -->
  <fileNamePattern>E:/logs/mylog-%dyyyy-MM-dd_HH-mm.%i.log</fileNamePattern>
  <maxHistory>5</maxHistory>
  <timeBasedFileNamingAndTriggeringPolicy
  class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  <!-- or whenever the file size reaches 100MB -->
  <maxFileSize>100MB</maxFileSize>
  </timeBasedFileNamingAndTriggeringPolicy>
  </rollingPolicy>
  <encoder>
  <pattern>%date %level [%thread] %logger36 [%file : %line] %msg%n</pattern>
  </encoder>
  </appender>
  <!-- log output to console -->
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
  <pattern>%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger36 - %msg%n</pattern>
  </encoder>
  </appender>
  <!-- log output to db-->
  <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
  <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
  <dataSource
  class="com.mchange.v2.c3p0.ComboPooledDataSource">
  <driverClass>com.mysql.jdbc.Driver</driverClass>
  <url>jdbc:mysql://127.0.0.1:3306/tunneldb</url>
  <user>root</user>
  <password>123123</password>
  </dataSource>
  </connectionSource>
  </appender>
  <logger name="com.ttt.ttt" level="DEBUG">
  <appender-ref ref="STDOUT" />
  </logger>
  <logger name="java.sql.Connection" level="DEBUG"><appender-ref ref="STDOUT" /></logger>
  <!-- 打印sql
  <logger name="java.sql.Statement" level="DEBUG"><appender-ref ref="STDOUT" /></logger>
  <logger name="java.sql.PreparedStatement" level="DEBUG"><appender-ref ref="STDOUT" /></logger>
  <logger name="java.sql.ResultSet" level="DEBUG"><appender-ref ref="STDOUT" /></logger>
  -->
  <root level="DEBUG"><appender-ref ref="ROLLING" /></root>
  </configuration>
  总结:logback提供了丰富而高效的日志输出方式,并通过滚动策略,将实施时复杂的备份策略整合,极大的简化的部署成本。
参考技术A logback是log4j作者推出的新日志系统,原生支持slf4j通用日志api,允许平滑切换日志系统,并且对简化应用部署中日志处理的工作做了有益的封装。
官方地址为:http://logback.qos.ch/
Logback日志需要依赖一下jar包:
slf4j-api-1.6.0.jar
logback-core-0.9.21.jar
logback-classic-0.9.21.jar
logback-access-0.9.21.jar
主配置文件为logback.xml,放在src目录下或是WEB-INF/classes下,logback会自动加载
logback.xml的基本结构如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger36 - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG"><appender-ref ref="STDOUT" /></root>
</configuration>
logback.xml的基本配置信息都包含在configuration标签中,需要含有至少一个appender标签用于指定日志输出方式和输出格式,root标签为系统默认日志进程,通过level指定日志级别,通过appender-ref关联前面指定顶的日志输出方式。
例子中的appender使用的是ch.qos.logback.core.ConsoleAppender类,用于对控制台进行日志输出
其中encoder标签指定日志输出格式为“时间 线程 级别 类路径 信息”
logback的文件日志输出方式还提供多种日志分包策略
1.文件日志
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>E:/logs/mylog.txt</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>E:/logs/mylog-%dyyyy-MM-dd_HH-mm.%i.log</fileNamePattern>
<maxHistory>5</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger36 [%file : %line] %msg%n</pattern>
</encoder>
</appender
文件日志输出采用的ch.qos.logback.core.rolling.RollingFileAppender类,它的基本属性包括<file>指定输入文件路径,encoder指定日志格式。其中,rollingPolicy标签指定的是日志分包策略,ch.qos.logback.core.rolling.TimeBasedRollingPolicy类实现的是基于时间的分包策略,分包间隔是根据fileNamePattern中指定的事件最小单位,比如例子中的%dyyyy-MM-dd_HH-mm的最小事件单位为分,它的触发方式就是1分钟,策略在每次想日志中添加新内容时触发,如果满足条件,就将mylog.txt复制到E:/logs/目录并更名为mylog-2010-06-22_13-13.1.log,并删除原mylog.txt。maxHistory的值为指定E:/logs目录下存在的类似mylog-2010-06-22_13-13.1.log文件的最大个数,当超过时会删除最早的文件。此外,策略还可以互相嵌套,比如本例中在时间策略中又嵌套了文件大小策略,ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP实现对单文件大小的判断,当超过maxFileSize中指定大大小时,文件名中的变量%i会加一,即在不满足时间触发且满足大小触发时,会生成mylog-2010-06-22_13-13.1.log和mylog-2010-06-22_13-13.2.log两个文件。
2.数据库日志
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<dataSource
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
<user>root</user>
<password>root</password>
</dataSource>
</connectionSource>
</appender>
数据库输出使用ch.qos.logback.classic.db.DBAppender类,数据源支持c3p0数据连接池,例子中使用的MySql,其他配置方式请参考官方文档。
使用数据库输出需要在数据库中建立3个表,建表脚本如下
# Logback: the reliable, generic, fast and flexible logging framework.
# Copyright (C) 1999-2010, QOS.ch. All rights reserved.

Logback 这样配置,TPS提高10倍

获取学习资料

通过阅读本篇文章将了解到

1、日志输出到文件并根据 LEVEL级别将日志分类保存到不同文件

2、通过异步输出日志减少磁盘 IO提高性能

3、异步输出日志的原理

配置文件logback-spring.xml

SpringBoot工程自带 logbackslf4j的依赖,所以重点放在编写配置文件上,需要引入什么依赖,日志依赖冲突统统都不需要我们管了。logback框架会默认加载 classpath下命名为 logback-springlogback的配置文件。将所有日志都存储在一个文件中文件大小也随着应用的运行越来越大并且不好排查问题,正确的做法应该是将 error日志和其他日志分开,并且不同级别的日志根据时间段进行记录存储。

 
   
   
 
  1. <?xml version="1.0" encoding="utf-8"?>

  2. <configuration>

  3. <property resource="logback.properties"/>

  4. <appender name="CONSOLE-LOG" class="ch.qos.logback.core.ConsoleAppender">

  5. <layout class="ch.qos.logback.classic.PatternLayout">

  6. <pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n</pattern>

  7. </layout>

  8. </appender>

  9. <!--获取比info级别高(包括info级别)但除error级别的日志-->

  10. <appender name="INFO-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">

  11. <filter class="ch.qos.logback.classic.filter.LevelFilter">

  12. <level>ERROR</level>

  13. <onMatch>DENY</onMatch>

  14. <onMismatch>ACCEPT</onMismatch>

  15. </filter>

  16. <encoder>

  17. <pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n</pattern>

  18. </encoder>


  19. <!--滚动策略-->

  20. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

  21. <!--路径-->

  22. <fileNamePattern>${LOG_INFO_HOME}//%d.log</fileNamePattern>

  23. <maxHistory>30</maxHistory>

  24. </rollingPolicy>

  25. </appender>

  26. <appender name="ERROR-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">

  27. <filter class="ch.qos.logback.classic.filter.ThresholdFilter">

  28. <level>ERROR</level>

  29. </filter>

  30. <encoder>

  31. <pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n</pattern>

  32. </encoder>

  33. <!--滚动策略-->

  34. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

  35. <!--路径-->

  36. <fileNamePattern>${LOG_ERROR_HOME}//%d.log</fileNamePattern>

  37. <maxHistory>30</maxHistory>

  38. </rollingPolicy>

  39. </appender>


  40. <root level="info">

  41. <appender-ref ref="CONSOLE-LOG" />

  42. <appender-ref ref="INFO-LOG" />

  43. <appender-ref ref="ERROR-LOG" />

  44. </root>

  45. </configuration>


  46. 复制代码

部分标签说明

  • <root>标签,必填标签,用来指定最基础的日志输出级别

    • <appender-ref>标签,添加 append

  • <append>标签,通过使用该标签指定日志的收集策略

    • name属性指定 appender命名

    • class属性指定输出策略,通常有两种,控制台输出和文件输出,文件输出就是将日志进行一个持久化。 ConsoleAppender将日志输出到控制台

  • <filter>标签,通过使用该标签指定过滤策略

    • <level>标签指定过滤的类型

  • <encoder>标签,使用该标签下的 <pattern>标签指定日志输出格式

  • <rollingPolicy>标签指定收集策略,比如基于时间进行收集

logback 高级特性异步输出日志

之前的日志配置方式是基于同步的,每次日志输出到文件都会进行一次磁盘IO。采用异步写日志的方式而不让此次写日志发生磁盘IO,阻塞线程从而造成不必要的性能损耗。异步输出日志的方式很简单,添加一个基于异步写日志的 appender,并指向原先配置的 appender即可

 
   
   
 
  1. <!-- 异步输出 -->

  2. <appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender">

  3. <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->

  4. <discardingThreshold>0</discardingThreshold>

  5. <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->

  6. <queueSize>256</queueSize>

  7. <!-- 添加附加的appender,最多只能添加一个 -->

  8. <appender-ref ref="INFO-LOG"/>

  9. </appender>


  10. <appender name="ASYNC-ERROR" class="ch.qos.logback.classic.AsyncAppender">

  11. <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->

  12. <discardingThreshold>0</discardingThreshold>

  13. <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->

  14. <queueSize>256</queueSize>

  15. <!-- 添加附加的appender,最多只能添加一个 -->

  16. <appender-ref ref="ERROR-LOG"/>

  17. </appender>

异步输出日志性能测试

既然能提高性能的话,必须进行一次测试比对,同步和异步输出日志性能到底能提升多少倍?

服务器硬件

  • CPU 六核

  • 内存 8G

测试工具

ApacheJmeter

同步输出日志

  • 线程数:100

  • Ramp-Up Loop(可以理解为启动线程所用时间) :0 可以理解为100个线程同时启用

  • 测试结果

Logback 这样配置,TPS提高10倍

重点关注指标 ThroughputTPS吞吐量:系统在单位时间内处理请求的数量,在同步输出日志中 TPS44.2/sec

异步输出日志

  • 线程数 100

  • Ramp-Up Loop:0

  • 测试结果

Logback 这样配置,TPS提高10倍

TPS为497.5/sec,性能提升了10多倍!!!

异步日志输出原理

logback框架下的 Logger.info方法开始追踪。一路的方法调用路径如下图所示:Logback 这样配置,TPS提高10倍

异步输出日志中最关键的就是配置文件中 ch.qos.logback.classic包下 AsyncAppenderBase类中的 append方法,查看该方法的源码:

 
   
   
 
  1. protected void append(E eventObject) {

  2. if(!this.isQueueBelowDiscardingThreshold() || !this.isDiscardable(eventObject)) {

  3. this.preprocess(eventObject);

  4. this.put(eventObject);

  5. }

  6. }

通过队列情况判断是否需要丢弃日志,不丢弃的话将它放到阻塞队列中,通过查看代码,这个阻塞队列为 ArrayBlockingQueueu,默认大小为256,可以通过配置文件进行修改。Logger.info(...)append(...)就结束了,只做了将日志塞入到阻塞队列的事,然后继续执行 Logger.info(...)下面的语句了。在 AsyncAppenderBase类中定义了一个 Worker线程, run方法中的关键部分代码如下:

 
   
   
 
  1. E e = parent.blockingQueue.take();

  2. aai.appendLoopOnAppenders(e);

从阻塞队列中取出一个日志,并调用 AppenderAttachableImpl类中的 appendLoopOnAppenders方法维护一个 Append列表。Worker线程中调用方法过程主要如下图:

最主要的两个方法就是 encodewrite方法,前一个法方会根据配置文件中 encode指定的方式转化为字节码,后一个方法将转化成的字节码写入到文件中去。所以写文件是通过新起一个线程去完成的,主线程将日志扔到阻塞队列中,然后又去做其他事情了。

来源:juejin.im/post/5d4d61326fb9a06aff5e5ff5

整编:搜云库技术团队,欢迎广大技术人员投稿

如果对本文的内容有疑问,请在文章留言区留言,谢谢。

更多技术干货

《2000道 互联网Java工程师面试题 共768页.pdf》
推荐:  
1、  
2、
 
3、
 
4、
 
5、
 
6、
 

以上是关于logback怎么异步日志到oracle数据库中的主要内容,如果未能解决你的问题,请参考以下文章

怎么将logback的日志信息异步到oracle数据库

如何 用slf4j logback 把日志异步记录到数据库中

logback.xml的使用,将日志异步保存到数据库中

logback 异步日志配置

logback高级特性使用-异步记录日志

logback如何设置打印的日志信息的最大字段长度