Spring Boot支持Java Util Logging、Log4J、Log4J2和LockBack作为日志框架,无论使用哪种日志框架,Spring Boot都为当前使用的日志框架的控制台及文件输出做好了配置。
默认使用LockBack日志框架。
在application.properties文件中配置日志级别:
logging.file=E:\logs\spring-boot-student
logging.level.org.springframework.web=debug
日志 默认的格式
%d{yyyy-MM-dd HH:mm:ss.SSS} -%5p ${PID:-} [%15.15t] %-40.40logger{39} : %m%n
输出的节点( items) 如下:
配置项:
myapp.log
:默认的日志文件路径和名称配置通过application.properties文件配置Logback,对于大多数Spring Boot应用来说已经足够了,但是对于一些大型的企业应用来说似乎有一些相对复杂的日志需求。在Spring Boot中你可以在logback.xml或者在logback-spring.xml中对Logback进行配置,相对于logback.xml,logback-spring.xml更加被偏爱。下面我们以logback-spring.xml为例。
在src/main/resources目录下新建logback.xml
"1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="com.xiaolyuh" level="debug" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
logger>
configuration>
工作原理:
当Logging Event进入AsyncAppender后,AsyncAppender会调用appender方法,append方法中在将event填入Buffer(这里选用的数据结构为BlockingQueue)中前,会先判断当前buffer的容量以及丢弃日志特性是否开启,当消费能力不如生产能力时,AsyncAppender会超出Buffer容量的Logging Event的级别,进行丢弃,作为消费速度一旦跟不上生产速度,中转buffer的溢出处理的一种方案。AsyncAppender有个线程类Worker,它是一个简单的线程类,是AsyncAppender的后台线程,所要做的工作是:从buffer中取出event交给对应的appender进行后面的日志推送。
从上面的描述中可以看出,AsyncAppender并不处理日志,只是将日志缓冲到一个BlockingQueue里面去,并在内部创建一个工作线程从队列头部获取日志,之后将获取的日志循环记录到附加的其他appender上去,从而达到不阻塞主线程的效果。因此AsynAppender仅仅充当事件转发器,必须引用另一个appender来做事。
在使用AsyncAppender的时候,有些选项还是要注意的。由于使用了BlockingQueue来缓存日志,因此就会出现队列满的情况。正如上面原理中所说的,在这种情况下,AsyncAppender会做出一些处理:默认情况下,如果队列80%已满,AsyncAppender将丢弃TRACE、DEBUG和INFO级别的event,从这点就可以看出,该策略有一个惊人的对event丢失的代价性能的影响。
另外其他的一些选项信息,也会对性能产生影响,下面列出常用的几个属性配置信息:
属性名 | 类型 | 描述 |
---|---|---|
queueSize | int | BlockingQueue的最大容量,默认情况下,大小为256。 |
discardingThreshold | int | 默认情况下,当BlockingQueue还有20%容量,他将丢弃TRACE、DEBUG和INFO级别的event,只保留WARN和ERROR级别的event。为了保持所有的events,设置该值为0。 |
includeCallerData | boolean | 提取调用者数据的代价是相当昂贵的。为了提升性能,默认情况下,当event被加入到queue时,event关联的调用者数据不会被提取。默认情况下,只有"cheap"的数据,如线程名。 |
默认情况下,event queue配置最大容量为256个events。如果队列被填满,应用程序线程被阻止记录新的events,直到工作线程有机会来转发一个或多个events。因此队列深度需要根据业务场景进行相应的测试,做出相应的更改,以达到较好的性能。
下面给出一个使用的配置示例:
"1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0discardingThreshold>
<queueSize>2048queueSize>
<includeCallerData>trueincludeCallerData>
<appender-ref ref="FILE" />
appender>
<logger name="com.xiaolyuh" level="debug" additivity="true">
<appender-ref ref="CONSOLE" />
<appender-ref ref="ASYNC_FILE" />
logger>
configuration>
目前研究logBack提供AsynAppender,发现此AsynAppender用了个BlockingQueue,但是不知道为什么用ArrayBlockingQueue,不用LinkedBlockingQueue,在大并发的时候,此queue有明显的优势。
因为AsynAppender不能单独使用,需要另挂一个Appender,比如RollingFileAppender。这个Appender继承了OutputStreamFileAppender,OutputStreamFileAppender只是把BufferedOutPutStream包装一下,加入一些layout以及一些格式方面的东西。但是OutputStreamFileAppender在同步方面使用大量synchronized,由于AsynAppender已经做了,同步了,再次同步已经没必要了,而且synchronized的性能又不那么好,看来有优化的余地。
另外LayoutWrappingEncoder是配合OutputStreamFileAppender一起使用的,里面有个ImmediateFlush的开关,可以延迟写io,但是什么写io呢,取决于bufferedOutputStream的时机。
所以这里可以通过一个后台线程在不忙的时候flush积极一些
注意: 在Spring Boot的main方法里的日志不会记录到日志文件。