首先说明在springBoot高版本中(1.5之后)不在使用log4j作为日志输出,而是使用的log4j2,本文章采用logback实现异步日志。
异步日志的好处:在高并发高流量响应延迟要求比较小的系统中同步打日志已经满足不了需求了,同步打日志会阻塞调用打日志的线程,而打日志本身是需要写磁盘的,所以会造成rt增加。异步日志就是为了解决这个问题。下面借用别人的两张图:
如上图,多个业务线程打印日志时候要等把内容写入磁盘后才会返回,所以打日志的rt就是写入磁盘的耗时。
如上图多个业务线程打印日志时候是把打印任务放入内存队列后就直接返回了,而具体打印日志是有日志系统的一个日志线程去队列里面获取然后执行,可见这种打印rt就是写入内存队列的耗时
下面主要看代码,我使用的是xml的格式 logback.xml这样的文件,springBoot中只要你引入相应spring-boot-starter-web的jar包就已经包含logback日志包,把这个文件放在resources下就可以自动扫描到否则的话需要在application.yml文件中配置
下面主要是配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="30 seconds">
<jmxConfigurator/>
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss:SSS}:[%c:%L] [%thread] %-5level %msg%n"/>
<property name="log.home" value="D:\\data\\logs\\db-server"/>
<property name="log.level" value="INFO"/>
<property name="log.max.file.size" value="100MB"/>
<property name="log.max.history" value="72"/>
<!-- 控制台输出日志 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!--文件日志 -->
<appender name="FILE-INFO"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<OnMatch>ACCEPT</OnMatch>
<OnMismatch>DENY</OnMismatch>
</filter>
<File>${log.home}/info.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.home}/%d{yyyy-MM-dd}/info/info-%d{yyyy-MM-dd}-.log</FileNamePattern>
<MaxHistory>${log.max.history}</MaxHistory>
</rollingPolicy>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- WARN文件输出日志 (文件小时大小策略进行文件输出,超过指定大小对文件备份) -->
<appender name="FILE-WARN"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<OnMatch>ACCEPT</OnMatch>
<OnMismatch>DENY</OnMismatch>
</filter>
<File>${log.home}/warn.log</File>
<append>true</append>
<!--日志归档策略 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${log.home}/%d{yyyy-MM-dd}/warn/warn-%d{yyyy-MM-dd}-%i.log
</FileNamePattern>
<MaxFileSize>${log.max.file.size}</MaxFileSize>
<MaxHistory>${log.max.history}</MaxHistory>
</rollingPolicy>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- ERROR文件输出日志 (文件小时大小策略进行文件输出,超过指定大小对文件备份) -->
<appender name="FILE-ERROR"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<OnMatch>ACCEPT</OnMatch>
<OnMismatch>DENY</OnMismatch>
</filter>
<File>${log.home}/error.log</File>
<append>true</append>
<!--日志归档策略 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${log.home}/%d{yyyy-MM-dd}/error/error-%d{yyyy-MM-dd}-%i.log
</FileNamePattern>
<MaxFileSize>${log.max.file.size}</MaxFileSize>
<MaxHistory>${log.max.history}</MaxHistory>
</rollingPolicy>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- 异步输出,异步的log片段必须在同步段后面,否则不起作用 -->
<appender name="FILE-INFO-ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<!--阙值 当队列大小低于这个将丢弃日志 为0的话用不丢弃 -->
<discardingThreshold>0</discardingThreshold>
<!-- 队列的大小-->
<queueSize>1024</queueSize>
<!-- 不设置neverBolck的话调用的是put方法是阻塞的,设置后调用offer方法是不阻塞的-->
<neverBlock>true</neverBlock>
<appender-ref ref="FILE-INFO"/>
</appender>
<appender name="FILE-WARN-ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>512</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="FILE-WARN"/>
</appender>
<appender name="FILE-ERROR-ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>512</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="FILE-ERROR"/>
</appender>
<!--文件日志 -->
<root level="${log.level}">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE-INFO-ASYNC"/>
<appender-ref ref="FILE-WARN-ASYNC"/>
<appender-ref ref="FILE-ERROR-ASYNC"/>
</root>
<!-- 配置UserController日志输出至单独的日志文件中 -->
<appender name="UserController" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志归档策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${log.home}/%d{yyyy-MM-dd}/info/userController-%d{yyyy-MM-dd}-%i.log</FileNamePattern>
<MaxFileSize>${log.max.file.size}</MaxFileSize>
<MaxHistory>${log.max.history}</MaxHistory>
</rollingPolicy>
<encoder
class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<!-- 日志输出编码 -->
<layout class="ch.qos.logback.classic.PatternLayout">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>${FILE_LOG_PATTERN}</pattern>
</layout>
</encoder>
<!--日志文件最大的大小-->
<!--<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>-->
</appender>
<!--需要将日志单独输出的包路径-->
<logger name="com.leaveword.controller.UserController" additivity="false">
<appender-ref ref="UserController"/>
<!--同时控制台打印-->
<appender-ref ref="STDOUT" />
</logger>
</configuration>
yml文件中添加配置
启动项目,日志打印就输出文件和控制台了