Revisit the log framework and global log management of SpringBoot series

Revisit the log framework and global log management of SpringBoot series

Architecture of log framework

Various log kits

Log frame

  • JDK java.util.logging package: java.util.logging is a Java logging package released by jdk1.4. It can be said that it is a logging toolkit that has been used for a long time
  • log4j: an open source project of apache, which provides strong java logging support. Even it provides other languages, including C. C + +,. Net and PL/SQL interfaces, so as to realize distributed environment log printing with multi language coexistence. The update has been stopped, so it is not recommended.
  • Logback: another open source logging component designed by the founder of log4j. As the default logging framework of Spring Boot, it is widely used.
  • Log4j2: Apache Log4j2 is an upgrade of log4j. It provides significant improvements over its predecessor Log4j1.x, provides many improvements available in Logback, and fixes some problems in Logback architecture. Based on the Disruptor (an open source lock free concurrency framework) developed by LMAX company, it improves the defects of log4j and Logback in architecture design, has ultra-high throughput and low latency, and has better performance than Log4j1.x and Logback.

Log facade

  • Commons logging: a member of Apache commons class library. As a logging facade, it can automatically choose whether to use log4j or JDK logging, but it does not rely on the API of log4j and JDK logging. If the classpath of the project contains the class library of log4j, log4j will be used, otherwise JDK logging will be used.
  • SLF4J: it can be said to be the most widely used log facade at present. It provides a log abstraction layer that allows you to use any log class library in the background. For example: log4j, log4j2, logback

Significance of log facade

Why not use the log framework directly, but create a log facade?

The log facade (SLF4J) is mainly used to provide a set of standard and standardized API frameworks for Java log access. Its main significance is to provide interfaces. The specific implementation can be implemented by other log frameworks, such as log4j and logback. For general Java projects, the log framework will choose SLF4J API as the facade, coupled with specific implementation frameworks (log4j, log4j2, logback, etc.), and use a bridge to complete the bridging.

Each of the log frameworks described above has its own API. If you want to use the corresponding framework, you need to use its corresponding API, which greatly increases the coupling requirements of the application code for the log framework. With the appearance of SLF4J, programmers are always programming for SLF4J, which can simply and quickly replace the underlying log framework without causing corresponding modifications to the business code

When logging with SLF4J, you usually need to define the Logger variable in each class that needs to log, as shown below:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RestController
public class LogTestController {
    private static final Logger logger = LoggerFactory.getLogger(LogTestController.class);

    @GetMapping("/test")
    public void test(){
        logger.trace("Trace journal...");
        logger.debug("Debug journal...");
        logger.info("Info journal...");
        logger.warn("Warn journal...");
        logger.error("Error journal...");
    }
}

This obviously belongs to repetitive work and reduces the development efficiency. If you introduce Lombok into the project, you can use the @ Slf4j annotation provided by it to automatically generate the above variable. The default variable name is log. If you want to use the customary LOGGER variable name, you can add lombok.config file in the main/java directory of the project, And add the configuration item lombok.log.fieldName=LOGGER in the file

Log frame selection

  • The default logging framework of Spring Boot uses Logback
  • Log4j can be regarded as an outdated function library, which has stopped updating and is not recommended. In contrast, its performance and function are also the worst.
  • Although logback is the default of Spring Boot, its performance is still inferior to Log4j2. Therefore, Log4j2 is preferred for logging at this stage.

SLF4J + Log4j2 is our recommended logging model.

Performance test results

Log4j2 official website

log level

Before going into details on the integration and configuration of various log frameworks, let's have a general understanding of the most common log levels: ERROR, WARN, INFO, DEBUG and TRACE. Other development processes such as ALL, OFF and FATAL should not be involved. Therefore, the following describes the common log levels from low to high.

  • TRACE: TRACE. Generally, it is useful for performance debugging or problem tracking of the core system. This level is very low. Generally, it is not enabled. After it is enabled, the log will soon fill the disk.
  • DEBUG: DEBUG. This should be familiar to everyone. During the development process, it is mainly to print and record some operation information.
  • INFO: information. This is the most common, and most of them are logs of this level by default. Generally, some interaction information, some request parameters and so on are recorded. It is convenient to locate problems or restore the on-site environment. This log is relatively important.
  • WARN: warning. This is generally to record potential information that may cause errors. For example, when starting, a certain configuration file does not exist or a parameter is not set.
  • ERROR: ERROR. This is also common. Generally, it is output when an exception is caught. Although an ERROR occurs, it does not affect the normal operation of the system. However, it may cause system errors or downtime.

The log level from small to large is trace < debug < INFO < warn < error < fatal. Since the default log level of the log framework is usually set to INFO, the above sample trace and debug level logs cannot be seen.

2020-08-17 13:59:16.566  INFO c.z.b.l.controller.LogTestController     : Info journal...
2020-08-17 13:59:16.566  WARN  c.z.b.l.controller.LogTestController     : Warn journal...
2020-08-17 13:59:16.566 ERROR  c.z.b.l.controller.LogTestController     : Error journal...

Analysis of common terms and concepts

  • appender: mainly controls where logs are output, such as file, database, console printing, etc
  • logger: used to set the log printing level of a package or a specific class and specify the appender
  • Root: it is also a logger and a special parent logger. All child loggers will eventually give the output stream to root unless additivity = "false" is configured in the child logger.
  • Rolling policy: it is not good to put all logs in one file, so you can specify a rolling policy to cut and store log files according to a certain period or file size.
  • Rollover strategy: log cleanup strategy. It usually refers to the retention time of the log.
  • Asynchronous log: a separate thread is opened for log writing, so as not to block the main thread.
  • When synchronizing logs, the main thread cannot continue to execute downward until the log is written to the disk
  • Asynchronous logging: when the main thread writes logs, it just puts the log messages into a queue and then continues to execute downward. This process is completed at the memory level. Then, a special thread obtains log data from the queue and writes it to disk, so the main thread is not blocked. The execution efficiency of the main thread (core business code) is very high.

logback log framework configuration

Logback can configure logs through both application configuration file and logback-spring.xml. Generally, it is sufficient to use the global configuration file application.yml or properties for configuration. If your log output requirements are particularly complex and personalized, you can consider using the configuration method of logback-spring.xml.

The application configuration file implements log configuration

We can configure logs in the application. Properties (YML) file

logging:
  level:
    root: info
    com.dhy.boot.launch.controller: debug
  file:
    path: D:\logs
    name: D:\logs\boot-launch.log
    max-size: 10MB
    max-history: 10
  pattern:
    console: '%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{10}) - %cyan(%msg%n)'
    file: '%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger : %msg%n'
  • logging.level.root=info specifies that the default log level of the whole system is info, and the log level is unified
  • logging.level.com.dhy.boot.launch.controller=debug. Specify that the log level of a specific package is debug and the log level is personalized. From the perspective of priority, personalized configuration is greater than unified configuration.
  • Logging.file.path outputs the log to the specified directory. If logging.file.name is not specified, the default name of the log file is spring.log. After logging.file.name is configured, the logging.file.path configuration is invalid.
  • No matter what setting, Spring Boot will automatically split the log file by day, that is, a new log file will be automatically generated every day, and the previous log file will be automatically packed into GZ compressed package# Log file size
  • You can set the maximum file size of each log divided by logging. File. Max size = 10MB. After exceeding this size, the logs continue to be separated.
  • You can set the retention log time logging. File. Max history = 10, in days
  • logging.pattern.file the format of the log output to the file
  • logging.pattern.console the format of the console output log. In order to make the display effect clearer during console debugging, color is added to the log. red, green, etc

Here, the log file will be created automatically without manual specification

Placeholder for log format

With this figure, take a look at the relationship between placeholders and the format configuration of logging.pattern.console

  • %d{HH:mm:ss.SSS}: log output time (red)
  • %thread: the name of the process that outputs the log, which is very useful in Web applications and asynchronous task processing (green)
  • %-5level: log level, with 5 characters aligned to the left (highlight blue)
  • %logger: name of the log output class (boldMagenta bold magenta)
  • %msg: log message (cyan)
  • %n: Newline for platform

Log configuration using logback-spring.xml

demand

Generally, it is sufficient to use the global configuration file application.yml or properties for configuration. If your log output requirements are particularly complex, you can consider using the configuration method of logback-spring.xml.

spring boot uses its own logback to print logs, which can be printed in multiple environments:

  • Output the production environment to the console and files, one file a day for 30 days
  • The development environment outputs to the console and prints sql(mybatis) output. The production environment does not print this information
  • The test environment is only output to the console. Do not export to file

To print Mybatis SQL, you only need to adjust the log level of the package used in Mybatis to DEBUG to print the SQL.

Premise: the project already supports the profile multi environment configuration of application.yml

Requirement realization

Because logback is the default logging framework of spring boot, there is no need to introduce maven dependency. Directly put logback-spring.xml under resources

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--Introduce some default settings-->
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <!--web information-->
    <logger name="org.springframework.web" level="info"/>

    <!--Write log to console appender,Use default,But get rid of it charset,otherwise windows lower tomcat Lower garbled code-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!--Define the storage address of the log file LogBack Relative paths are used in the configuration of-->
    <property name="LOG_PATH" value="D:/logs/boot-launch"/>
    <!--Write log to file appender-->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--The file name of the log file output,One file per day-->
            <FileNamePattern>${LOG_PATH}.%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--Log file retention days-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <!--Maximum size of log file-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!--Write log to file asynchronously-->
    <appender name="asyncFileAppender" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <queueSize>500</queueSize>
        <appender-ref ref="FILE"/>
    </appender>

    <!--production environment :Print console and output to file-->
    <springProfile name="prod">
        <root level="info">
            <appender-ref ref="CONSOLE"/>
            <appender-ref ref="asyncFileAppender"/>
        </root>
    </springProfile>

    <!--development environment :Print Console -->
    <springProfile name="dev">
        <!-- Print sql -->
        <logger name="com.dhy.boot.launch" level="DEBUG"/>
        <root level="DEBUG">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>

    <!--testing environment:Print Console -->
    <springProfile name="test">
        <root level="info">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>
</configuration>

Asynchronous log configuration:

  • The default value of asynchronous log queueSize is 256, which is the capacity of asynchronous log queue.
  • Discardthreshold: when the remaining capacity of the asynchronous log queue is less than this threshold, TRACE, DEBUG or INFO level logs will be discarded. If you do not want to discard the log (i.e. save in full), you can set it to 0. However, when the queue is full, the non blocking asynchronous log will become a blocked synchronous log. Therefore, in the system with high concurrency and low latency requirements, the discarding threshold discarding policy can be set for unimportant logs, and the value is greater than 0.

Test it

After the above configuration is completed, you can use the following code to test whether it meets the requirements

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RestController
public class LogTestController {
    private static final Logger logger = LoggerFactory.getLogger(LogTestController.class);

    @GetMapping("/testlog")
    public void test(){
        logger.trace("Trace journal...");
        logger.debug("Debug journal...");
        logger.info("Info journal...");
        logger.warn("Warn journal...");
        logger.error("Error journal...");
    }
}

Integration and use of log4j2 logging framework

Introducing maven dependency

Spring Boot uses LogBack by default, but we don't see the dependent jar package. In fact, the jar package Spring Boot starter logging is a part of Spring Boot starter web or Spring Boot starter dependency.

If you want to use Log4j2 here, you need to remove the spring boot starter logging dependency from the spring boot starter web, and display the dependent jar package that declares to use Log4j2, as follows:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

In addition, log4j is a widely used software before, which is easy to conflict with log4j2. If there is a conflict, log4j will be excluded from the corresponding software, such as dozer

<dependency>
    <groupId>net.sf.dozer</groupId>
    <artifactId>dozer</artifactId>
    <version>5.4.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Add the configuration file log4j2-spring.xml

Create a new log4j2-spring.xml file in the resources directory and put it in the src/main/resources directory to be recognized by the Spring Boot application.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <properties>
        <!--Log output location-->
        <property name="LOG_HOME">D:/logs</property>
    </properties>

    <Appenders>
        <!-- Output log to console-->
        <Console name="CONSOLE" target="SYSTEM_OUT">
            <!--Set log format and color-->
            <PatternLayout
                    pattern="[%style{%d}{bright,green}][%highlight{%p}][%style{%t}{bright,blue}][%style{%C}{bright,yellow}]: %msg%n%style{%throwable}{red}"
                    disableAnsi="false" noConsoleNoAnsi="false"/>
        </Console>

        <!-- Output log to file-->
        <RollingFile name="FILE-APPENDER"
                     fileName="${LOG_HOME}/log4j2-demo.log"
                     filePattern="${LOG_HOME}/log4j2-demo-%d{yyyy-MM-dd}-%i.log">
            <!--Format log-->
            <PatternLayout>
                <pattern>[%d][%p][%t][%C] %m%n</pattern>
            </PatternLayout>
            <Policies>
                <!-- Set log file segmentation parameters -->
                <SizeBasedTriggeringPolicy size="100 MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--Set maximum number of Archives-->
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>
    </Appenders>

    <Loggers>
        <!-- Root log settings -->
        <Root level="debug">
            <AppenderRef ref="CONSOLE" level="debug"/>
            <AppenderRef ref="FILE-APPENDER" level="info"/>
        </Root>

        <!--spring journal-->
        <Logger name="org.springframework" level="info"/>
        <!-- mybatis journal -->
        <Logger name="com.mybatis" level="warn"/>
    </Loggers>
</configuration>
  • The above two Appenders, one called CONSOLE, are used to output logs to the CONSOLE, and the other called file Appender is used to output logs to files
  • PatternLayout is used to specify the format of the output log, [% D] [% P] [% t] [% C]% m% n these placeholders will be introduced in combination with the test results below
  • Policies is used to specify file segmentation parameters

The default size of timebasedtriggingpolicy is 1. Combined with the filePattern definition%d{yyyy MM DD}, a file is generated every day (the minimum time segmentation granularity is hours) < sizebasedtriggingpolicy size = "100 MB" / > when the file size reaches 100MB, cut a new log file

  • < defaultrolloverstrategy max = "20" / > indicates the maximum number of archived files, and the redundant files will be deleted
  • The log format placeholders mentioned above will be introduced to you at the end of the test.

Custom profile

However, we usually have a requirement that different environments use different configurations. For example, we need three log4j2 xml files:

  • log4j2-dev.xml development environment log configuration
  • log4j2-prod.xml production environment log configuration
  • log4j2-test.xml test environment log configuration

However, Spring Boot does not know what log4j2 - < profile >. XML configuration files do, so it needs to display the declaration in the application.yml file.

Example: use the log4j2-dev.xml configuration file in application-dev.yml

logging:
    config: classpath:log4j2-dev.xml

By analogy, use the log4j2-prod.xml configuration file in application-prod.yml and the log4j2-test.xml configuration file in application-test.yml.

Test it

Let's talk about placeholders in combination with the following code

<PatternLayout pattern="[%style{%d}{bright,green}][%highlight{%p}][%style{%t}{bright,blue}][%style{%C}{bright,yellow}]: %msg%n%style{%throwable}{red}"
                    disableAnsi="false" noConsoleNoAnsi="false"/>
  • %d: date time
  • %p: Log level
  • %t: Thread thread name
  • %C: class file name
  • %msg: log information
  • %n line feed
  • %style{%throwable}{red} plus style, and the exception information is displayed in red

log4j2 asynchronous log configuration

Introducing disruptor

Log4j2 is based on the Disruptor (an open source lock free concurrency framework) developed by LMAX company, which improves the defects of log4j and Logback in architecture design, with ultra-high throughput and low latency.

<!-- Needed for Async Logging with Log4j 2 -->
<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.3.6</version>
</dependency>

Therefore, if we want to obtain the performance improvement brought by log4j2 asynchronous logging, we must first introduce disruptor

Global asynchronous mode

The global asynchronous mode greatly improves the log output performance. It is an officially recommended asynchronous log output mode. There are two ways to configure asynchronous logs for Spring Boot applications. The first is to use System.setProperty in the application startup class. The code is as follows:

@SpringBootApplication
public class BootLaunchApplication {

   public static void main(String[] args) {
      //The following statement makes Log4j2 log output use asynchronous processing to reduce the impact of log output on performance
      System.setProperty("Log4jContextSelector",
                  "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector");

      SpringApplication.run(BootLaunchApplication.class, args);
   }
}

The second is to set the global asynchronous log through the startup parameters

java -jar 
-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector 
boot-launch-1.0.jar

After the above configuration is completed, we can set the breakpoint at the location of log printing. When we see the Log4j2-TF-1-AsyncLogger thread in the red border in the figure below, it indicates that our global asynchronous log configuration is successful.

Asynchronous / synchronous hybrid mode

In addition to the global asynchronous mode, slf4j also supports asynchronous / synchronous mixed mode. Although the global asynchronous mode is the best log output mode, it also consumes the most host resources. If your application server performance is average and you want to obtain better log output performance, you can use the following methods.

Adopt asynchronous/The above configuration is not required for synchronous mixed mode Log4jContextSelector

Modify the Loggers configuration in log4j2 xml and add AsyncLogger, that is, asynchronous log. Only the logs generated by the code in com.dhy.boot.launch package (if it is known that this package has high requirements for processing performance) adopt asynchronous mode, and other logs still use synchronous mode.

<Loggers>
        <!-- in the light of com.dhy.boot.launch The logs under the package are asynchronous logs -->
        <AsyncLogger name="com.dhy.boot.launch" level="debug" additivity="false">
            <AppenderRef ref="CONSOLE" level="debug"/>
            <AppenderRef ref="FILE-APPENDER" level="info"/>
        </AsyncLogger>

        <!-- System default log settings -->
        <Root level="debug">
            <AppenderRef ref="CONSOLE" level="debug"/>
            <AppenderRef ref="FILE-APPENDER" level="info"/>
        </Root>
</Loggers>
  • appender: mainly controls where logs are output, such as file, database, console printing, etc
  • logger: used to set the log printing level of a package or a specific class and specify the appender
  • Root: it is also a logger and a special parent logger. All child loggers will eventually give the output stream to root unless additivity = "false" is configured in the child logger.
  • Rolling policy: it is not good to put all logs in one file, so you can specify a rolling policy to cut and store log files according to a certain period or file size.
  • Rollover strategy: log cleanup strategy. It usually refers to the retention time of the log.
  • Asynchronous log: a separate thread is opened for log writing, so as not to block the main thread.

Interceptor implements unified access log

demand

  • For each interface access of the current system, record who accessed it (user name), when it was accessed, how long it took to access it, and what HTTP was used Method method, access result, etc. It can be called audit log.
  • Output the access record audit log to a separate log file access.log

Define access log content record entity class

@Data
public class AccessLog {
    //Visitor user name
    private String username;
    //Request path
    private String url;
    //Request consumption time
    private Integer duration;
    //http methods: GET, POST, etc
    private String httpMethod;
    //http request response status code
    private Integer httpStatus;
    //Visitor ip
    private String ip;
    //Creation time of this record
    private Date createTime;
}

Custom log interceptor

Record the audit log by customizing the interceptor.

  • The preHandle method of the interceptor can be used to intercept the start of request processing. It is used to record the request start time and save it to Http Request, used to calculate the duration of subsequent requests.
  • The postHandle method of the interceptor can be used to intercept the completion of Request processing. You can obtain the start time from the Request object and calculate the total processing time of this Request.
public class AccessLogInterceptor implements HandlerInterceptor {
    //Request start time id
    private static final String LOGGER_SEND_TIME = "SEND_TIME";
    //Request log entity ID
    private static final String LOGGER_ACCESSLOG = "ACCESSLOG_ENTITY";


    private static final Logger logger = LoggerFactory.getLogger("ACCESS-LOG");

    /**
     * Start logging entities before entering the Controller of spring MVC
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {

        //Create log entity
        AccessLog accessLog = new AccessLog();

        // Set IP address
        accessLog.setIp(AdrressIpUtils.getIpAdrress(request));

        //Set request method, GET,POST
        accessLog.setHttpMethod(request.getMethod());

        //Set request path
        accessLog.setUrl(request.getRequestURI());

        //Set request start time
        request.setAttribute(LOGGER_SEND_TIME,System.currentTimeMillis());

        //Set the request entity into the request to facilitate the afterCompletion method call
        request.setAttribute(LOGGER_ACCESSLOG,accessLog);
        return true;
    }


    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) throws Exception {

        //Get the request log entity
        AccessLog accessLog = (AccessLog) request.getAttribute(LOGGER_ACCESSLOG);

        //Obtain the request error code and store it in the database according to the demand. It is not saved here
        int status = response.getStatus();
        accessLog.setHttpStatus(status);

        //Set visitor (temporarily dead here)
        // Because different applications may put visitor information in session s, and some pass it through request s,
        // In short, it can be obtained, but the methods are different
        accessLog.setUsername("admin");

        //current time 
        long currentTime = System.currentTimeMillis();

        //Request start time
        long snedTime = Long.valueOf(request.getAttribute(LOGGER_SEND_TIME).toString());


        //Set request time difference
        accessLog.setDuration(Integer.valueOf((currentTime - snedTime)+""));

        accessLog.setCreateTime(new Date());
        //Persist sysLog objects
        logger.info(accessLog.toString());
    }
}

LoggerFactory.getLogger("ACCESS-LOG") in the above section obtains the name of the Logger in the log configuration, which is used to print log output and persist to the log file. The log Logger definition of "ACCESS-LOG" is described below.

Interceptor registration

@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {

    //Set the exclusion path, spring boot 2. *. Note that the path of static resources is excluded, otherwise the static resources cannot be accessed
    private final String[] excludePath = {"/static"};

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AccessLogInterceptor()).addPathPatterns("/**").excludePathPatterns(excludePath);
    }
}

Tool class for obtaining ip access address

The above code involves a tool class used to obtain the ip of the requesting client. The code is as follows:

public class AdrressIpUtils {
    /**
     * Get Ip address
     * @param request HttpServletRequest
     * @return ip
     */
    public static String getIpAdrress(HttpServletRequest request) {
        String Xip = request.getHeader("X-Real-IP");
        String XFor = request.getHeader("X-Forwarded-For");
        if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
            //After multiple reverse proxies, there will be multiple ip values, and the first ip is the real ip
            int index = XFor.indexOf(",");
            if(index != -1){
                return XFor.substring(0,index);
            }else{
                return XFor;
            }
        }
        XFor = Xip;
        if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
            return XFor;
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getRemoteAddr();
        }
        return XFor;
    }
}

Log Logger definition of "ACCESS-LOG"

The configuration reference below takes Log4J2 configuration as an example

  • LoggerFactory.getLogger("ACCESS-LOG") The code goes to the configuration file to find a Logger configuration whose name is ACCESS-LOG.
  • The Logger is an asyncloger, and the output target pointed to is ACCESS-APPENDER
  • ACCESS-APPENDER is a log file output configuration. The log file is access-log.log
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <properties>
        <!--Log output location-->
        <property name="LOG_HOME">D:/logs</property>
    </properties>
    <Appenders>
        <!-- Output log to file-->
        <RollingFile name="ACCESS-APPENDER"
                     fileName="${LOG_HOME}/access.log"
                     filePattern="${LOG_HOME}/access-%d{yyyy-MM-dd}-%i.log">
            <!--Format log-->
            <PatternLayout>
                <pattern>[%d][%p][%t][%C] %m%n</pattern>
            </PatternLayout>
            <Policies>
                <!-- Set log file segmentation parameters -->
                <SizeBasedTriggeringPolicy size="100MB"/>
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <!--Set maximum number of Archives-->
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>
    </Appenders>

    <Loggers>
        <AsyncLogger name="ACCESS-LOG" level="debug" additivity="false">
            <AppenderRef ref="ACCESS-APPENDER" level="info"/>
        </AsyncLogger>
    </Loggers>
</configuration>

Added by GooberDLX on Tue, 07 Dec 2021 21:57:08 +0200