Wechat official account: an excellent invalid. If you have any questions, please leave a message in the background. I’m not listening anyway.

preface

Idle idle idle days to see the logging implementation in SpringBoot, to tell you my understanding.

Facade pattern

When it comes to logging frameworks, we have to say facade patterns. The facade pattern, at its core, is that external communication with a subsystem must be done through a unified facade object, making the subsystem easier to use. A graph is used to represent the structure of the facade mode:

Simply put, this mode is to encapsulate some complex processes into an interface for external users to use more easily. In this mode, three characters are designed.

1). Facade characters: the core of the facade pattern. It is invoked by the customer role, which is familiar with the subsystem’s functionality. Several combinations of functions (modules) are predetermined internally according to the requirements of the customer role.

2). Subsystem (module) role: Realizing the functions of subsystems. It is unknown to the customer role and Facade. It can have internal interaction within the system, but also can be called by the external interface.

3). Customer role: Call Facede to accomplish the function to be implemented.

A logging framework on the market

Logging facade The logging implementation
JCL (Jakarta Commons Logging), SLF4j (Simple Logging Facade for Java), jboss-Logging Log4j 、JUL(java.util.logging) 、Log4j2 、 Logback

In short, the logging facade in the table above corresponds to the Facede object in the facade schema. They are only an interface layer and do not provide logging implementation. The logging implementation corresponds to each subsystem or module, and the logics of logging are written in these frameworks on the right; So our application is like a client.

Why use facade mode?

Imagine a scenario where we develop a system that uses many packages with their own logging framework. We use Logback in our system, Hibernate in our system, jboss-Logging in Hibernate, and Spring in our system. The logging system used in Spring is commons-logging.

As a result, our system has to support and maintain Logback, Jboss-Logging, and Commons-logging at the same time, which is very inconvenient. The solution to this problem is to introduce an interface layer, which decides which logging system to use, and all the caller needs to do is print logs without worrying about how to print logs, which is the logging facade in the table above.

For this reason, when we choose logging, we must choose a framework from the logging facade on the left and the logging implementation on the right, and the default choice for SpringBoot is SLF4j and Logback.

Use SLF4j

The official document gives this example:

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

public class HelloWorld {
  public static void main(String[] args) {
    // Helloworld.class is the log of the specified class that you want to print,
    // If you want to print in another class, replace helloWorld.class with the target class name. Class.
    Logger logger = LoggerFactory.getLogger(HelloWorld.class); 
    logger.info("Hello World"); }}Copy the code

To understand how SLF4J works, I took a look at its official documentation and saw this diagram:

Slf4j has six uses and five roles. Application is, of course, our system. The SLF4J API is the logging interface layer (facade); The concrete logging implementation (subsystem) is shown in blue and gray at the bottom; And Adaptation is the Adaptation layer.

Explain the second and third uses of the diagram. The second is the default use of SpringBoot; And why the third? Because Log4J came early, it had no idea that SLF4J was coming. Log4J cannot be implemented directly as logging for SLF4J, so an adaptation layer comes in between. Same with the fourth.

Note that each logging implementation framework has its own configuration file. With SLF4J, the ** configuration file remains the logging implementation framework’s own configuration file. For example, Logback uses logback.xml and Log4j uses the log4j.xml file.

How do I unify all the logs on my system to SLF4J?

I continued to browse the official website and saw this picture:

Slf4j: SlF4J: slF4J: slF4J: SLF4J: SLF4J: SLF4J

1. Exclude other logging frameworks from the system

2. Replace the logging framework with a tundish

3. We import the other implementations of SLF4J

Log relationship in SpringBoot

SpringBoot implements logging using the following dependencies:

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-logging</artifactId>
      <version>2.1.3. RELEASE</version>
      <scope>compile</scope>
</dependency>
Copy the code

Spring-boot-starter-logging has the following diagram:

SpringBoot2.x also uses slf4J +logback or log4j to log. 2. SpringBoot introduces an intermediate replacement package to replace all other logs with SLf4J; If we want to introduce another framework, we can remove the default logging dependency of this framework.

For example, Spring uses the Commons-logging framework, which can be removed like this.

<dependency>
	<groupId>org.springframework</groupId>
	    <artifactId>spring-core</artifactId>
		    <exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
						<artifactId>commons-logging</artifactId>
		        </exclusion>
	        </exclusions>
</dependency>
Copy the code

SpringBoot automatically ADAPTS all logging, and slF4J + Logback is used to record logging. When introducing other frameworks, you only need to exclude the logging framework that this framework depends on.

Log to use

The default configuration (using the Log4j framework as an example), SpringBoot has configured logging for us by default:

    / / recorder
    Logger logger = LoggerFactory.getLogger(getClass());
    @Test
    public void contextLoads(a) {
        // Log level;
        // Trace 
        // Can adjust the output log level; Logs will only take effect at this level at a later high level
        logger.trace("This is the trace log...");
        logger.debug("This is the debug log...");
        // SpringBoot uses the info level by default. If no level is specified, SpringBoot uses the default level. The root level
        logger.info("This is info log...");
        logger.warn("This is a WARN log...");
        logger.error("This is error log...");
    }
Copy the code

2. Log4j. properties Modify the default log configuration

Logging.level.com.nasus=debug #logging.path= # springboot.log is generated in the current project. File =Z:/springboot.log # Create the spring folder and log folder in the root path of the current disk. Path =/spring/log # Format of the log output at the console logging.pattern.console=%d{YYYY-MM-DD} [%thread] %-5level MSG % logger {50} - % % n # specified file format of the log output logging. The pattern. The file = % d - the dd} {yyyy - MM = = = [% thread] - 5 level = = = = = = % % logger {50} = = = = %msg%nCopy the code

3. Specify the configuration

SpringBoot will automatically load the configuration files of the corresponding framework in the classpath, so we just need to put the configuration file of each logging framework on the classpath, and SpringBoot will not use the default configuration.

The framework naming
Logback logback-spring.xml.logback-spring.groovy.logback.xml or logback.groovy
Log4j2 log4j2-spring.xml or log4j2.xml
JDK (Java Util Logging) `logging.properties

Logback.xml: Is recognized directly by the logging framework.

Logback-spring. XML: The log framework does not load the log configuration items directly. SpringBoot parses the log configuration and uses the advanced Profile function of SpringBoot.

<springProfile name="staging">
    <! -- configuration to be enabled when the "staging" profile is active -->You can specify that a certain configuration takes effect only in a certain environment</springProfile>
Copy the code

Examples (using the Logback framework as an example) :

<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <! - Log output format: % D indicates the date and time, %thread indicates the thread name, %-5level: indicates the level. The width is 5 characters from the left. % Logger {50} indicates that the maximum length of the logger name is 50 characters. % MSG: log message, %n: newline -->
        <layout class="ch.qos.logback.classic.PatternLayout">
                 <! -- Specify that the console uses this format to output logs in dev environment -->
                 <springProfile name="dev">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern>
            </springProfile>
            <! -- Specifies that in a non-dev environment, the console uses this format to output logs -->
            <springProfile name=! "" dev">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern>
            </springProfile>
        </layout>
    </appender>
Copy the code

If you use logback. XML as the log configuration file instead of logback-spring. XML and use the profile function, you will get the following error:

no applicable action for [springProfile]
Copy the code

Switching logging Frameworks

Knowing SpringBoot’s underlying logging dependencies, we can follow slF4J’s log adaptation diagram to make the switch.

For example, if you switch to SLf4J +log4j, you can do this

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <exclusions>
    <exclusion>
      <artifactId>logback-classic</artifactId>
      <groupId>ch.qos.logback</groupId>
    </exclusion>
  </exclusions>
</dependency>

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
</dependency>
Copy the code

If I switch to log4j2, I can do that.

<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>
Copy the code

Finally, logback-spring. XML is configured in detail for your own projects.

<?xml version="1.0" encoding="UTF-8"? >
<! -- scan: When this property is set to true, the configuration file will be reloaded if it changes. The default value is true. ScanPeriod: indicates the interval for checking whether the configuration file is modified. If no time unit is given, the default unit is ms. This parameter takes effect when scan is true. The default interval is 1 minute. Debug: When this attribute is set to true, internal logback logs are displayed to view the running status of logback in real time. The default value is false. -->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
    <! Define log root directory -->
    <property name="LOG_HOME" value="/app/log" />
    <! Define log file name -->
    <property name="appName" value="nasus-springboot"></property>
    <! - ch. Qos. Logback. Core. ConsoleAppender said console output -- -- >
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <! - Log output format: % D indicates the date and time, %thread indicates the thread name, %-5level: indicates the level. The width is 5 characters from the left. % Logger {50} indicates that the maximum length of the logger name is 50 characters. % MSG: log message, %n: newline -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <springProfile name="dev">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern>
            </springProfile>
            <springProfile name=! "" dev">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern>
            </springProfile>
        </layout>
    </appender>

    <! -- Scroll to log file, first log to specified file, when a condition is met, log to other files -->  
    <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <! -- Specify log file name -->
        <file>${LOG_HOME}/${appName}.log</file>
        <! TimeBasedRollingPolicy determines the behavior of the RollingFileAppender when scrolling occurs, involving file movement and renaming. TimeBasedRollingPolicy: the most commonly used rollingpolicy. It is responsible for both rolling and starting rolling based on time. -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <! %d{YYYY-MM-DD} : the file is scrolled by day % I: the file is scrolled by I when the file size exceeds maxFileSize -->
            <fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <! -- Optional node that controls the maximum number of archived files that can be retained, and deletes old files if the number exceeds it. If daily scrolling is set and maxHistory is 365, only the files of the last 365 days are saved and the old files before that are deleted. Note that when old files are deleted, directories created for archiving are also deleted. -->
            <MaxHistory>365</MaxHistory>
            <! - when a log file over maxFileSize size is specified, according to the above mentioned to the log file % I roll Pay attention to the configuration SizeBasedTriggeringPolicy rolling according to the file size is not impossible to achieve, You must configure timeBasedFileNamingAndTriggeringPolicy -- -- >
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <! -- Log output format: -->     
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
        </layout>
    </appender>

    <! Logger is mainly used to store log objects. You can also define log types and log levels. Name: indicates the matched logger type prefix, that is, the first half of the package level: The log level to log, including TRACE < DEBUG < INFO < WARN < ERROR additivity: depends on whether the children-Logger outputs using an appender configured for rootLogger. False: True: Indicates that both logger appender-ref and rootLogger appender-ref are valid.
    <! -- hibernate logger -->
    <logger name="com.nasus" level="debug" />
    <! -- Spring framework logger -->
    <logger name="org.springframework" level="debug" additivity="false"></logger>



    <! -- Root is parent to logger, default to root if there is no specific definition. Each class corresponds to only one logger, either the defined logger or root. The key is to find this logger. Then determine the logger's appender and level. -->
    <root level="info">
        <appender-ref ref="stdout" />
        <appender-ref ref="appLogAppender" />
    </root>
</configuration> 
Copy the code

reference

www.importnew.com/28494.html

www.cnblogs.com/lthIU/p/586…

After the language

If this article is of any help to you, please help to read it. Your good looks are my motivation to keep writing.

In addition, after paying attention to send 1024 can receive free learning materials.

For more information, see this article: Python, C++, Java, Linux, Go, front-end, algorithm sharing