springboot -- integrating logs

Keywords: Java Spring xml log4j

Catalog

 

Summary

1. Market log framework and log abstraction layer classes

2. Spring boot default logging

3, summary

Summary

When we are developing projects, we usually want to know how the program is running. We can use sysout.print(); print some key code or view the running status through debug, but for this kind of sysout.print(); currently, the code is redundant. There are also many frameworks in the market to record the operation status. For example, Log4j, JUL, logback, etc., we can choose one to use in the project, but if a new log framework comes out after a period of time, we can remove the previous framework, use the new framework, and modify the api. Can we adopt the idea of interface oriented development, customize the log interface layer of an abstract layer, repackage the unified api, and use the specified log framework , but the interface of the abstraction layer always uses the log abstraction layer, so when we want to change the log framework, we can directly import new dependencies without modifying the existing api.

1. Market log framework and log abstraction layer classes

Log abstraction layer framework: JCL, SLF4j, JBoss logging

Log implementation layer framework: log4j, logback, JUL, log4j2

In development, we select one from the log abstraction layer framework as the abstract interface layer, and then select one from the log implementation layer framework as the implementation class to record the logs in our project

2. Spring boot default logging

In spring boot, the default abstract interface layer of boot uses slf4j, and the implementation layer uses logback. When we can view it from the project, it is as follows

I created a demo project. The dependency files introduced in pom are as follows

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
</dependencies>
If logback is used as the log processing framework in the project, logback includes logback core, logback classic and logback access. Logback core is the basic module of the other two modules. If spring boot starter web dependency tree is introduced into the project, you can see the web dependency tree instead of importing logback separately

After the spring boot project introduces the web module, slf4j+logback logging is configured by default in the bottom layer. We only need to select different levels of log printing output through the logger according to the needs, or we can customize a logging class to record logs using spring's AOP idea at the same time

The recorder mode is as follows, just record where you need

public class TestController{
   //Recorder
   Logger logger = LoggerFactory.getLogger(getClass());
   @Test
   public void contextLoads() {
      //Log level, from low to high, adjust the log level, and only output high-level logs,
      logger.trace("This is trace Tracking information");
      logger.debug("This is debug debug information");
      //springboot outputs the level after info by default, which is root level
      logger.info("This is info Custom information");
      logger.warn("This is warn Warning message");
      logger.error("This is error error message");
   }
}

Log through AOP ideas

@Aspect//section
@Component//assembly
public class LogAspect {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * Here we cut the tangent point into every method under the controller (web) layer
     */
    @Pointcut("execution(* com.javayihao.myweb.controller.*.*(..))")
    public void log() {
    }


    /**
     * Execute this method before executing all methods under com.javayihao.myweb.controller
     *  Obtain the method of url ip request to be recorded and the parameters it takes
     * @param joinPoint
     */
    @Before("log()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String url = request.getRequestURL().toString();
        String ip = request.getRemoteAddr();
        //Class name. Method
        String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        //parameter
        Object[] args = joinPoint.getArgs();
        //Call self encapsulated objects
        RequestLog requestLog = new RequestLog(url, ip, classMethod, args);
        logger.info("Request : {}", requestLog);
    }

    @After("log()")
    public void doAfter() {
//        logger.info("--------doAfter--------");
    }

    //Methods to be executed after all methods under com.javayihao.myweb.controller are executed
    @AfterReturning(returning = "result",pointcut = "log()")
    public void doAfterRuturn(Object result) {
        logger.info("Result : {}", result);
    }

    private class RequestLog {
        private String url;
        private String ip;
        private String classMethod;
        private Object[] args;

        public RequestLog(String url, String ip, String classMethod, Object[] args) {
            this.url = url;
            this.ip = ip;
            this.classMethod = classMethod;
            this.args = args;
        }

        @Override
        public String toString() {
            return "{" +
                    "url='" + url + '\'' +
                    ", ip='" + ip + '\'' +
                    ", classMethod='" + classMethod + '\'' +
                    ", args=" + Arrays.toString(args) +
                    '}';
        }
    }

}

We did not configure any other configuration. We saw that the log was printed on the console. Logback prints the debug level log by default, but we noticed that the debug level log was not recorded. That's because Spring Boot provides the default configuration file, base.xml, for logback. In addition, Spring Boot provides the two output configuration files console-appendix.xml and file-appendix.x Ml, base.xml refers to these two configuration files. So the default log level of Springboot is info. You can see that base.xml references two configurations,

Here is the base.xml for spring boot found on git

<?xml version="1.0" encoding="UTF-8"?>
<!--
Base logback configuration provided for compatibility with Spring Boot 1.1
-->
<included>
	<include resource="org/springframework/boot/logging/logback/defaults.xml" />
	<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
	<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
	<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
	<root level="INFO">
		<appender-ref ref="CONSOLE" />
		<appender-ref ref="FILE" />
	</root>
</included>

Here, you can see that Spring boot has overridden the default logging level of Logback by setting the root logger to INFO, which is why we didn't see the debug message in the above example.

You can simply configure logback in application.properties

#Modify the log output level under the specified package
logging.level.com.javayihao=trace
#Generate the output log of mylog.log under the current project
#logging.file=mylog.log
#Output the log in the specified path
#logging.file=f:/mylog.log
#Create the spring file home and the log folder in the root path of the current disk. Use spring.log as the log file name
logging.path=/spring/log
#Specify the format of the console output log
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS}+++[%thread] %-5level %logger{50} - %msg%n
#Format of output log in execution log file
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS}===[%thread] %-5level %logger{50} - %msg%n

Configuring logback through the application.properties file is enough for most Spring Boot applications, but for some large enterprise applications, it seems that there are some relatively complex log requirements. In Spring Boot, you can configure logback in logback.xml or logback-spring.xml. Logback-spring.xml is more preferred than logback.xml. If it's a different name, just use the application.properties

Configure logging.config=classpath:logback-boot.xml to use its own log configuration file

Here I post my own commonly used logback-spring.xml

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<configuration>
    <!-- %m Output information,%p log level,%t Thread name,%d date,%c Full name of class,%i Index [increment from number 0],,, -->
    <!-- appender yes configuration Is the component responsible for writing logs. -->
    <!-- ConsoleAppender: Output log to console -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d %p (%file:%line\)- %m%n</pattern>
            <!-- The console is also used UTF-8,Do not use GBK,Otherwise, the Chinese code will be garbled -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!--RollingFileAppender Write log to file-->
    <!-- RollingFileAppender: Scroll to record the file, first record the log to the specified file, and when a certain condition is met, record the log to other files -->
    <!-- The following general meaning is: 1.First, save the log by date. If the date changes, rename the log file name of the previous day to XXX%date%Index, new log is still sys.log -->
    <!--             2.If the date does not change, but the file size of the current log exceeds 1 KB Split and rename the current log-->
    <appender name="syslog"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--Build under current project sys.log Logging output logs-->
        <File>log/sys.log</File>
        <!-- rollingPolicy:When scrolling occurs, decide RollingFileAppender , involving file movement and renaming. -->
        <!-- TimeBasedRollingPolicy:  The most commonly used rolling strategy, which makes rolling strategy according to time, is responsible for rolling as well as starting rolling -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- The name of the activity file will be based on fileNamePattern Value of, changing every other time -->
            <!-- Filename: log/sys.2017-12-05.0.log -->
            <fileNamePattern>log/sys.%d.%i.log</fileNamePattern>
            <!-- Every time a log file is generated, the retention period of the log file is 30 days -->
            <maxHistory>30</maxHistory>
            <timeBasedFileNamingAndTriggeringPolicy  class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- maxFileSize:This is the size of the active file. The default value is 10 MB,Can be set to 1 KB,View demonstration -->
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <!-- pattern Node, used to set the input format of the log -->
            <pattern>
                %d %p (%file:%line\)- %m%n
            </pattern>
            <!-- Code of record log -->
            <charset>UTF-8</charset> <!-- Set character set here -->
        </encoder>
    </appender>
    <!-- Console output log level -->
    <root level="info">
        <appender-ref ref="STDOUT" />
    </root>
    <!-- Specifies the logging level of a package in the project when there is a logging action -->
    <!-- com.javayihao For the root package, that is to say, the permissions for all log operations that occur under the root package are DEBUG -->
    <!-- The level is [from high to low]: FATAL > ERROR > WARN > INFO > DEBUG > TRACE  -->
    <logger name="com.javayihao" level="DEBUG">
        <appender-ref ref="syslog" />
    </logger>
</configuration>

Of course, we can also configure the log level according to the deployment environment, as follows: the production environment and the test environment use different ways

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml" />
 
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
 
    <!-- testing environment+development environment. Multiple separated by commas. -->
    <springProfile name="test,dev">
        <logger name="org.springframework.web" level="INFO">
            <appender-ref ref="FILE"/>
        </logger>
        <logger name="com.example" level="INFO" />
    </springProfile>
 
    <!-- production environment. -->
    <springProfile name="prod">
        <logger name="org.springframework.web" level="ERROR">
            <appender-ref ref="FILE"/>
        </logger>
        <logger name="com.example" level="ERROR" />
    </springProfile>
</configuration>

3. summary

From the above, we know that if we want to log in future projects, we should not directly use one log to implement class records, but we can implement classes through a log abstraction layer + a log abstraction, then call the interface record interface in the abstraction layer, and use the abstract class SLF4j as follows.

This is what boot does. Here we mainly summarize the use of SLF4j and other log implementation classes

Official website: https://www.slf4j.org/

How to use it? A picture on the official website is very clear

Problem: x system is implemented by using Spring (commons logging), Hibernate (JBoss logging), MyBatis, xxxx frameworks. Each framework has a different logging framework. How to use slf4j in a unified way

Solution

1. Exclude other log frames from the system;
2. Use the tundish to replace the original log framework;
3. We import other implementations of slf4j

For example, we need to use slf4j+log4j to record logs, depending on the following

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
<exclusions>
<exclusion>
<artifactId>logback‐classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
<exclusion>
<artifactId>log4j‐over‐slf4j</artifactId>

<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j‐log4j12</artifactId>
</dependency>

As another example, we need to use slf4j+log4j2 to record logs, depending on the following

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

However, slf4j+log4j2 or slf4j+log4j combinations are not recommended for logging in boot projects. Spring boot officially recommends slf4+logback

The public number java number one is more java actual combat project data and technical work. What's more, ape is willing to be a friend on your way to programming!

First address: www.javayihao.top

First public address: java No. 1

Posted by hermzz on Wed, 06 Nov 2019 04:41:48 -0800