Due to the impact of Typhoon Lekima, many places have received heavy rainfall, so you can’t go out to play on weekends. Let’s learn together. Let’s start with the basic configuration and then introduce advanced features asynchronous log output. Scroll down a bit if you only want to see how asynchronous logging improves performance.
You will find out by reading this article
- 1. Output logs to files based on
LEVEL
Level Logs are classified and saved to different files - 2. Reduce the number of disks by sending logs asynchronously
IO
To improve performance - 3. Mechanism of asynchronous log output
Configuration file logback-spring.xml
The SpringBoot project comes with logback and SLF4J dependencies, so the focus is on writing configuration files, and what dependencies need to be introduced, and log dependency conflicts are completely irrelevant. The Logback framework loads a configuration file named logback-spring or logback in the classpath by default. Store all logs in one file. The file size grows with the running of the application and it is difficult to troubleshoot problems. The correct method is to separate error logs from other logs and store logs of different levels according to the time period.
<? xml version="1.0" encoding="utf-8"? > <configuration> <property resource="logback.properties"/>
<appender name="CONSOLE-LOG" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n</pattern> </layout> </appender> <! <appender name= -- get logs with levels higher than info (including info) but not error"INFO-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<encoder>
<pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n</pattern> </encoder> <! --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <! -- Path --> <fileNamePattern>${LOG_INFO_HOME}//%d.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<appender name="ERROR-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<encoder>
<pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.sss}] [%C] [%t] [%L] [%-5p] %m%n</pattern> </encoder> <! --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <! -- Path --> <fileNamePattern>${LOG_ERROR_HOME}//%d.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<root level="info">
<appender-ref ref="CONSOLE-LOG" />
<appender-ref ref="INFO-LOG" />
<appender-ref ref="ERROR-LOG" />
</root>
</configuration>
Copy the code
Partial Label Description
<root>
Tag, a mandatory tag that specifies the most basic log output level<appender-ref>
Tag, addappend
<append>
Tag that specifies the collection policy for logsname
Attribute specifiesappender
namedclass
Property specifies the output strategy. There are usually two types, console output and file output, which is to persist the log.ConsoleAppender
Output logs to the console
<filter>
Tag that you can use to specify a filtering policy<level>
The tag specifies the type of filtering
<encoder>
Tag, using the tag under<pattern>
The tag specifies the log output format<rollingPolicy>
The tag specifies a collection policy, such as time-based collection<fileNamePattern>
This configuration has achieved the goal of dividing mobile phone logs by day
Logback Advanced features Asynchronously output logs
The previous log configuration is based on synchronization. Disk I/O is performed every time logs are output to a file. Asynchronous log writing prevents disk I/OS that block threads and cause unnecessary performance loss. Writing logs asynchronously is as simple as adding an appender based on writing logs asynchronously and pointing to the configured appender
<! -- asynchronous output --> <appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender"> <! -- Do not lose logs. The system discards cards with 80% of the queue being full. For example, TRACT, DEBUG, and INFO logs are discarded. <discardingThreshold>0</discardingThreshold> Change the default queue depth, which affects performance. The default value is 256 --> <queueSize>256</queueSize> <! Appender-ref = appender-ref = appender-ref = appender-ref = appender-ref = appender-ref ="INFO-LOG"/>
</appender>
<appender name="ASYNC-ERROR" class="ch.qos.logback.classic.AsyncAppender"> <! -- Do not lose logs. The system discards cards with 80% of the queue being full. For example, TRACT, DEBUG, and INFO logs are discarded. <discardingThreshold>0</discardingThreshold> Change the default queue depth, which affects performance. The default value is 256 --> <queueSize>256</queueSize> <! Appender-ref = appender-ref = appender-ref = appender-ref = appender-ref = appender-ref ="ERROR-LOG"/>
</appender>
Copy the code
Asynchronous output log performance test
If you can improve performance, you must do a test comparison. How many times can synchronous and asynchronous log output improve performance?
Server hardware
CPU
Six nuclear- 8 g memory
Testing tools
Apache Jmeter
Synchronizing Output Logs
- Number of threads: 100
Ramp-Up Loop
0 can be interpreted as 100 threads enabled at the same time- The test results
Focus on indicators
Throughput (TPS)
Throughput: The number of requests processed per unit of time by the system, in synchronous output logsTPS
for44.2 / SEC
Asynchronously Outputting Logs
- The number of threads, 100
Ramp-Up Loop
: 0- The test results
TPS
for497.5 / SEC.Performance increased by more than 10 times!!
Mechanism of asynchronous log output
Start tracing from the logger. info method in the Logback framework. The method call path is shown below:
ch.qos.logback.classic
AsyncAppenderBase
append
protected void append(E eventObject) {
if(! this.isQueueBelowDiscardingThreshold() || ! this.isDiscardable(eventObject)) { this.preprocess(eventObject); this.put(eventObject); }}Copy the code
If not, put it on a blocking queue. By looking at the code, this blocking queue is ArrayBlockingQueueu, with a default size of 256, which can be modified through the configuration file. Logger.info(…) To append (…). It’s done, just stuff the log into the blocking queue, and continue logger.info (…) The following statement. The AsyncAppenderBase class defines a Worker thread. The key parts of the run method are as follows:
E e = parent.blockingQueue.take();
aai.appendLoopOnAppenders(e);
Copy the code
Pull a log from the blocking queue and maintain a list of Appends by calling the appendLoopOnAppenders method of the AppenderAttachableImpl class. The process of calling methods in Worker thread is mainly shown as follows:
encode
write
encode
Complete project code
= = = = = = = = = = = = = = = = = = = = = = Update On 2019/09/02 = = = = = = = = = = = = = = = = = = = = test results in fewer pollution, repetition, less sample size problem, After the retest, the TPS difference between synchronous and asynchronous logback logs was not significant. Attached is the performance test report. But there is still a reduction in time