This is the 13th day of my participation in the August More text Challenge. For details, see: August More Text Challenge

Logback is the default logging configuration for SpringBoot. Logback is a Java domain logging framework. It is considered the successor to Log4J. Logback consists of three modules:

  • Logback-core is the infrastructure on which other modules are built, and obviously logback-core provides some key common mechanisms
  • Logback-classic has the same status and role as Log4J, it is also considered an improved version of Log4J, and it implements the simple logging facade SLF4J
  • Logback-access is primarily a module that interacts with a Servlet container, such as Tomcat or Jetty, and provides some functionality related to HTTP access

1. The LogBack key classes

In Logback, the three most important classes are

  • The Logger class is in the Logback-Classic module
  • Appenders are located in the Logback-core module
  • Layout is located in the Logback-core module

The appenders and Layout do not care about the Logger and do not depend on it. It is also clear that the Logger depends on the appenders and Layout to print logs.

2. Hierarchical naming rules for Logger

In order to control what information needs to be output and what information does not need to be output, Logback introduces a hierarchical concept. Each Logger has a name in the same format as package names in the Java language. You can simply pass a class object into the loggerFactory.getLogger () method as an argument.

The name format of a Logger determines that multiple Loggers form a tree structure. To maintain this hierarchical tree structure, each Logger is bound to a Logger context, which is responsible for the relationship between the loggers.

For example, the logger named com.hanpang is the father of the Logger named com.hanpang.logback and the ancestor of the Logger named com.hanpang.logback.demo.

In the logger context, there is a root Logger, the ancestor of all Loggers, which is maintained internally by LogBack and is not a developer custom logger. This Logger can be obtained in the following ways:

Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
Copy the code

Similarly, using the name of a Logger, you can obtain the corresponding logger instance:

package org.slf4j; 
public interface Logger {
  // Printing methods: 
  public void trace(String message);
  public void debug(String message);
  public void info(String message); 
  public void warn(String message); 
  public void error(String message); 
}
Copy the code

3. Log print level

It feels like there’s nothing to say about this place that everyone should know about.

Loggers have a log print level. You can specify a logger’s log print level. If you do not specify a print level for a Logger, it inherits the print level from the nearest ancestor that has the specified print level. The confusing part is that if a Logger looks for its father first, and the father does not specify a print level, it will immediately ignore its father and continue looking for its grandfather until it finds the root Logger. Therefore, you can also see that to use logBack, you must specify the log print level for the Root Logger.

Logs are printed in the following order from low to advanced: TRACE < DEBUG < INFO < WARN < ERROR

If a Logger is allowed to print a message at a certain log level, it must also be allowed to print messages at higher levels than that and not at lower levels than that.

package com.hanpang.logback.demo.universal;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
/ * * *@author pangsir
 */
public class LogLevelDemo {
 
    public static void main(String[] args) {
        
        // In this case, the cast is used to set the logger Level
        ch.qos.logback.classic.Logger logger = 
                (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.hanpang");
        logger.setLevel(Level.INFO);
        
        Logger barlogger = LoggerFactory.getLogger("com.hanpang.Bar");
 
        // This statement can be printed because WARN > INFO
        logger.warn("can be printed because WARN > INFO");
 
        // This statement cannot be printed because DEBUG < INFO.
        logger.debug("can not be printed because DEBUG < INFO");
 
        // barlogger 是 logger 的一个子 logger
        // It inherits the INFO level of Logger
        // The following statement can be printed because INFO >= INFO
        barlogger.info("can be printed because INFO >= INFO");
 
        // The following statement cannot be printed because DEBUG < INFO
        barlogger.debug("can not be printed because DEBUG < INFO"); }}// Print the result description
/** 00:27:19.251 [main] WARN com.foo -can be printed because WARN > INFO 00:27:19.255 [main] INFO com.foo.Bar -can be printed because INFO >= INFO */
Copy the code

3. Get the Logger

In logBack, each Logger is a singleton, and when you call loggerFactory. getLogger, if you pass in the same Logger name, you get the same instance of Logger.

When naming loggers, it is the best policy to use the fully qualified class name of the class as the Logger name so that the source of each log message can be traced.

4. The Appender and Layout

In the logback world, logs can be printed not only to the Console, but also to a file, or even to a network stream. The destination of logs is determined by the appenders, and different appenders can print logs to different destinations.

Appenders are bound to Loggers, and a Logger can be bound to multiple appenders, meaning a message can be printed to different destinations at the same time. For example, it is common for log messages to be both output to the console and recorded to a log file, which requires binding two different Loggers to the Logger.

Appenders are bound to Loggers, and Loggers are inherited, so a destination Appender for a Logger to print messages needs to refer to its father and ancestor. In Logback, by default, if a Logger prints a message, the message will be printed first to its own Appender, then to its father’s Appender, and then to any ancestor’s Appender. If its father sets additivity = false, then the logger will only print to its father’s Appender besides its own Appender, because its father’s additivity is set to false. The logger is becoming unattached, so it only recognizes its parent Appender. In addition, for the father of the Logger, if the father’s Logger prints a message, it will only print to its own Appender (if any) because the father has forgotten the grandfather and above.

A printed log contains a destination and a format for displaying the log information. In Logback, Layout is used to represent the log print format. For example, PatternLayout can recognize the following format: %-4relative [%thread] %-5level %logger{32} – % MSG %n 176 [main] DEBUG com.hanpang.HelloWorld2 – Hello world.

This format of the first field representatives from the application, after the number of milliseconds after the start of start, the second field representatives to print out this piece of log thread name, the third field on behalf of the journal of information level of printing, the fourth field represents the logger name, the fifth field is the log information, the sixth field is only represents a newline character.

5. Parameter logs are displayed

You can use the following methods to print logs:

logger.debug("the message is " + msg + " from " + somebody);
Copy the code

One drawback to printing logs this way is that the program always performs the concatenation of the string “the message is “+ MSG +” from “+ somebody first, regardless of the log level. When logger is set to a higher level than DEBUG, DEBUG messages are not printed back. Obviously, concatenation of strings is unnecessary. When concatenation of a large number of strings is unnecessary, it can cause a significant loss of performance.

Thus, an improved way of printing logs was discovered:

if(logger.isDebugEnabled()) { 
  logger.debug("the message is " + msg + " from " + somebody);
}
Copy the code

This approach does avoid unnecessary loss of string concatenation, but it is not the best approach, when the log level is DEBUG, then print this line, need to determine the log level twice. One is logger.isdebugenabled () and the other is a judgment also made inside the logger.debug() method. It also creates a bit of an efficiency problem, and who wants to ignore wasted efficiency if a better way can be found?

Recommended method: Use placeholders to print logs in parameterized mode. For example, the above statement can be written as follows:

logger.debug("the message {} is from {}", msg, somebody);
Copy the code

In this way, string concatenation is avoided, and the log level judgment is also avoided.

6.LogBack internal execution process

When an application makes a logging request, such as info(), logback’s internal flow is shown below

  1. Get filter chain
  2. Check log levels to determine whether to continue printing
  3. To create aLoggingEventobject
  4. Call Appenders
  5. Format log information
  6. sendLoggingEventTo the corresponding destination

7. LogBack configuration

Logback provides the following configuration methods:

  • Programmatic configuration
  • XML format
  • Groovy format

When logback starts, follow these steps to find the configuration file:

  1. Look for the logback-test.xml file in your classpath
  2. If logback-test.xml is not found, look for the logback.groovy file in your classpath
  3. If logback.groovy cannot be found, then look for the logback.xml file in your classpath
  4. If none of the above files can be found, Logback will use the JDK’s SPI mechanism to look for themMETA-INF/services/ch.qos.logback.classic.spi.ConfiguratorThe logback configuration implementation class must be implementedConfigurationInterface, which is configured using its implementation
  5. If all else fails, logback uses its ownBasicConfigurator, and output logs to the console

Logback-test. XML is used to log your test code. For maven projects, you would put logback-test. XML in SRC /test/resources. Maven does not package this file into a JAR. Logback takes about 100 milliseconds to parse configuration files when it starts,

7.1 Default Configuration

The default configuration mentioned above is made up of the BasicConfiguator class. The configuration of this class can be represented by the following configuration files:

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <! -- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>
 
  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
Copy the code

If logback has a warning message or error message when parsing the configuration file at startup, logback will automatically print out its own status information first.

(1) In the configuration file, you can set the debug property of the configuration to true

<configuration debug="true">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <! -- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
            </pattern>
        </encoder>
    </appender>
 
    <root level="debug">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>
Copy the code

(2) Set the execution of a listener for processing

<configuration>
  <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />. the rest of the configuration file</configuration>
Copy the code

7.2 Automatic Hot Loading of Configuration Files

To enable the configuration file to be automatically reloaded, you need to set the Scan property to true. By default, the scan is performed every minute. You can specify the scanning interval:

<configuration scan="true" scanPeriod="30 seconds" >.</configuration> 
Copy the code

Note that the scan interval is in milliseconds, seconds, minutes, and hours. If a number is specified but no unit is specified, this defaults to milliseconds.

Inside the logback, when setting scan attribute to true, a process called ReconfigureOnChangeFilter filters will be involved, it is responsible for judging whether it is time to scan, and whether the reload the configuration. This filter is triggered when any method of Logger that prints logs is called, so the performance of this filter itself becomes important. Logback currently uses a mechanism that allows the filter to do its job only when the number of calls to logger reaches a certain number, which is 16 by default, and logback dynamically adjusts this number at run time based on the frequency of calls.

8. Format description of the configuration file

The root node is the Configuration, which can contain zero or more appenders, zero or more Loggers, and at most one root.

8.1 Configuring logger Nodes

In the configuration file, logger is configured in the

tag. There is only one attribute for the

tag, and that is the name attribute. In addition to the name attribute, there is also the level attribute and the additivity attribute, but they are optional. The value of level can be TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF, INHERITED, NULL. INHERITED is the same as NULL. Instead, it forces the Logger to inherit a logging level from its parent. The value of additivity is a Boolean, true or false.

There is only one element under the

tag,

, and there can be zero or more, meaning that appenders are bound to this logger.

8.2 Configuring the Root Node

The

tag has the same configuration as the

tag, except that the

tag allows only one attribute, the level attribute, and its value range can only be TRACE, DEBUG, INFO, WARN, ERROR, ALL, and OFF. Zero or more

are allowed under the

tag.

8.3 Configuring appender Nodes

The

tag has two mandatory attributes, name and class, which specifies the implementation class. The

tag can contain up to one

, zero or more

, zero or more

. In addition to these tags, the

tag can contain some Javabeans-like configuration tags.

< Layout > contains a mandatory attribute class that specifies the specific implementation class, although it can be left unfilled if the implementation class is of type PatternLayout. < Layout >, like

, can contain Javabean-like configuration tags. The

tag contains a mandatory attribute class that specifies the specific implementation class. If the class is of type PatternLayoutEncoder, the class attribute may be left unfilled. If you want to attach an appender to a Logger, use the following:

<logger name="HELLO" level="debug">
    <appender-ref ref="FILE" />
    <appender-ref ref="STDOUT" />
</logger>
Copy the code

8.4 set ContextName

<configuration>
  <contextName>myAppName</contextName>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d %contextName [%t] %level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>
 
  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
Copy the code

8.5 Substitution of Variables

In Logback, ${varName} is supported to reference variables

You can define variables directly in logback.xml

<configuration>
 
  <property name="USER_HOME" value="/home/sebastien" />
 
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${USER_HOME}/myApp.log</file>
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>
 
  <root level="debug">
    <appender-ref ref="FILE" />
  </root>
</configuration>
Copy the code

Files in the CLASspath are also supported for external files

<configuration>
 
  <property resource="resource1.properties" />
 
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
     <file>${USER_HOME}/myApp.log</file>
     <encoder>
       <pattern>%msg%n</pattern>
     </encoder>
   </appender>
 
   <root level="debug">
     <appender-ref ref="FILE" />
   </root>
</configuration>
Copy the code

Reference: blog.csdn.net/HSH205572/a…