Slf4j logging framework

1.1 Slf4j log usage

  1. After the SpringBoot environment is set up, the SLF4J logging framework is integrated by default
    • Reference manual: logback. Qos. Ch/manual/appe…
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RestController
public class LogInfoController {
    private static final Logger LOGGER = LoggerFactory.getLogger(LogInfoController.class);
}
Copy the code
  1. There are five levels of logging in descending order of priority
    • Logger. Trace (” trace “);
    • Logger. The debug (” debug messages “);
    • Logger. The info (” info “);
    • Logger. Warn (” warn “);
    • Logger. The error (” error “);
  2. The Framework has been implemented at the bottom of SpringBoot and can be used directly
  3. By default, SpringBoot outputs messages of the info level or higher. In main, logs of the debug level or higher are displayed
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogUserCore {
    private static final Logger LOGGER = LoggerFactory.getLogger(LogUserCore.class);

    public static void main(String[] args) {
        LOGGER.trace("The trace log");
        LOGGER.debug("The debug log");
        LOGGER.info("Info log, can use parentheses as placeholders, contents [{}]"."The info log");
        LOGGER.warn("Warn log");
        try {
            Integer.parseInt("a");
        } catch (NumberFormatException e) {
            /// logger.error (" {} ", equetmessage (), e);
            LOGGER.error("Error log, error message [{}], can directly put the exception at the end", e.getMessage()); }}}Copy the code
  1. The overall logback class diagram is shown below

1.2 Logback Configuration description

1.2.1 the configuration

  • Configuration is the parent of logback and has only three properties
    • Scan: Automatic load judgment. When the configuration file changes, it will be reloaded. The default value is true
    • ScanPeriod: indicates the interval for checking whether the configuration file is modified. If the unit of time is not specified, the value is millisecond by default. When scan=true, the value takes effect
    • Debug: When this parameter is set to true, internal logback logs are displayed and the logback running information is displayed in real time. The default value is false

1.2.2 logger

  1. Logger is used to set the log printing level and mode for a specific package or class
  2. There can be zero or more appender-refs in a Logger, and the corresponding appenders will be added to the logger
  3. Its properties are as follows
    • Name: specifies the corresponding package path or classpath
    • Level: sets the log printing level. The five common log printing levels are TRACE, DEBUG, INFO, WARN, and ERROR from lowest to highest. If this level is not set, the current Logger inherits the higher level
    • Additivity: indicates whether to pass print information to the upper log. The default value is true

1.2.3 root

  • Root is also a Logger element, but it is the root Logger, the highest level of all Loggers, and has a single level attribute whose name is fixed to root

1. Appender

  • An appender is a child of a Configuration node that defines the log output mode and has two necessary properties
    • Name: Specifies the name of the current appender module
    • Class: Specifies the class of an appender to control log output

1.2.5 encoder

  1. The encoder is responsible for converting log information into byte arrays and writing byte arrays to the output stream
  2. Encoder common converters are as follows

%logger {length}

  • Logger name that outputs logs. It can have an integer parameter to shorten the logger name. If it is set to 0, only the string after the dot on the right of Logger is entered
Conversion Pattern Logger name Result
%logger mainPackage.sub.sample.Bar mainPackage.sub.sample.Bar
%logger{0} mainPackage.sub.sample.Bar Bar
%logger{5} mainPackage.sub.sample.Bar m.s.s.Bar
%logger{10} mainPackage.sub.sample.Bar m.s.s.Bar
%logger{15} mainPackage.sub.sample.Bar m.s.sample.Bar
%logger{16} mainPackage.sub.sample.Bar m.sub.sample.Bar
%logger{26} mainPackage.sub.sample.Bar mainPackage.sub.sample.Bar

%d{pattern}

  • Print log output logs, pattern syntax and Java. Text. SimpleDateFormat compatible
Conversion Pattern Result
%d The 14:06:49 2021-06-20, 812
%date The 14:06:49 2021-06-20, 812
%date{ISO8601} 14:06:49, 2021-0620, 812
%date{HH:mm:ss.SSS} 15:06:49. 812
%date{dd MMM yyyy ; HH:mm:ss.SSS} 20 oct. 2006; 14:06:49.

%msg

  • Output the information provided by the application

%level

  • Output Log Level

%thread

  • Output the name of the thread that generated the log

%n

  • Output platform related line “\n” or “\r\n”

%ex

  • Output abnormal information

1.2.6 filter

  1. Is a child node of an appender, indicating the configuration mode for filtering the current given log level
<! -- Print only error logs -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>ERROR</level>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
</filter>
Copy the code

1.3 Configuring the Logback Framework

  1. Create a logback configuration file and add the following configuration
  2. You can also specify log levels for packages in a configuration file, but the configuration file is usually used
logging:
  level:
    com.codecoord.springboot.practice.log.info: error
Copy the code
  1. You can specify the location of the log configuration file in the configuration file, and then configure policies such as logs in the log configuration file

      
<! -- Enable debug and scan cycle -->
<configuration debug="true" scan="true" scanPeriod="1 seconds">
    <contextName>logback</contextName>
    <! ${name} -->
    <property name="log_pattern" value="%d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n%ex"/>
    <! -- define log path -->
    <property name="log_path" value="log"/>
    <! -- The maximum number of historical days is 10 -->
    <property name="log_file_max_history" value="10"/>
    <! -- Maximum size of a single log -->
    <property name="log_file_max_size" value="1KB"/>
    <! -- maximum log file size -->
    <property name="log_file_max_total_size" value="1MB"/>

    <! -- ConsoleAppender Used to output logs on screen -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <! -- defines a filter so that log output at a specified LEVEL is not printed -->
        <! The console will not output logs with a level smaller than ERROR -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <! -- define console output format -->
        <encoder>
            <pattern>${log_pattern}</pattern>
        </encoder>
    </appender>

    <! -- File appender-based, no scroll record support -->
    <appender name="FILE_APPENDER" class="ch.qos.logback.core.FileAppender">
        <file>${log_path}/fileAppender.log</file>
        <append>true</append>
        <! -- Set immediateFlush to false for higher log throughput -->
        <immediateFlush>true</immediateFlush>
        <encoder>
            <pattern>${log_pattern}</pattern>
        </encoder>
    </appender>

    <! -- Time based scroll, notice the time (day) based scroll -->
    <appender name="ROLLING_FILE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log_path}/timeBasedRollingPolicy.log</file>
        <! -- true: Events are appended to the end of an existing file. False: Any existing file will be truncated. Default set to true -->
        <append>true</append>
        <! -- Define a log rolling policy, TimeBasedRollingPolicy: % I auto-scroll is not supported -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <! -- define file name format for file scrolling -->
            <fileNamePattern>${log_path}/timeBasedRollingPolicy.%d{yyyy-MM-dd}.log</fileNamePattern>
            <! -- Maximum calendar record -->
            <maxHistory>60</maxHistory>s
            <! -- This property is not supported until version 1.1.6, the total file size, you need to set the maxHistory property -->
            <totalSizeCap>10GB</totalSizeCap>
            <! -- Whether to clear historical data at startup -->
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <encoder>
            <pattern>${log_pattern}</pattern>
        </encoder>
    </appender>

    <! -- Time based scroll, scroll according to file size, suitable for multiple log generation in a day, recommended -->
    <appender name="ROLLING_FILE_TIME_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log_path}/system/sizeAndTime.log</file>
        <append>true</append>
        <! - define log rolling strategy, SizeAndTimeBasedRollingPolicy: support automatic scrolling increase % I serial number -- -- >
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <! -- define file name format for file scrolling -->
            <fileNamePattern>${log_path}/system/sizeAndTime.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <! -- Maximum size of a single file, over automatic rotation, 60 days but not more than 10G -->
            <maxFileSize>1KB</maxFileSize>
            <! -- Maximum calendar, usually used with totalSizeCap -->
            <maxHistory>60</maxHistory>
            <! -- Total file size, maxHistory property set -->
            <totalSizeCap>10GB</totalSizeCap>
            <! -- Whether to clear historical data at startup -->
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <encoder>
            <pattern>${log_pattern}</pattern>
        </encoder>
    </appender>

    <! -- Root is the default Logger, if no appender is configured for logger, use the output configured here -->
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>

    <! - for the classpath to com. Codecoord. Springboot. Practice. The info at the beginning of the Logger, output level is set to info - >
    <! This logger does not specify an appender, it inherits the appender defined in root, because root's appender is configured with debug level, there is no output here -->
    <! --<logger name="com.codecoord.springboot.practice.log.info" level="info"/>-->

    <! -- apptivity = false = do not output the appender configured with rootLogger -->
    <! RootLogger appender will not be used in output because additivity="false" is set -->
    <! If you do not set additivity="false", you may cause a log to output twice on the console -->
    <! --<logger name="com.codecoord.springboot.practice.log.info" level="INFO" additivity="false"> <appender-ref ref="FILE_APPENDER"/> </logger>-->

    <! -- Time based scrolling logging -->
    <logger name="com.codecoord.springboot.practice.log.info" level="INFO" additivity="false">
        <appender-ref ref="ROLLING_FILE_TIME_APPENDER"/>
    </logger>

    <! Additivity ="false", so the logger output will not be output anywhere -->
    <! --<logger name="com.codecoord.springboot.practice.log.error" level="error" additivity="false"/>-->
</configuration>
Copy the code
  1. Create several scheduled tasks to periodically output logs. One of the classes outputs the following

import java.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@EnableScheduling
@Component
public class LogDebugSchedule {
    private static final Logger LOGGER = LoggerFactory.getLogger(LogDebugSchedule.class);

    @Scheduled(cron = "0/1 * * * * ?" )
    public void logDebug(a) {
        LOGGER.debug("LogDebug task executed, current time [{}]", LocalDateTime.now()); }}Copy the code

      
<configuration debug="true" scan="true" scanPeriod="1 seconds">

    <contextName>logback</contextName>
    <! ${name} -->
    <property name="log_pattern" value="%d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n%ex"/>
    <! -- define log path -->
    <property name="log_path" value="log"/>
    <! -- Maximum number of historical days -->
    <property name="log_file_max_history" value="1"/>
    <! -- Maximum size of a single log -->
    <property name="log_file_max_size" value="10MB"/>
    <! -- maximum log file size -->
    <property name="log_file_max_total_size" value="1MB"/>

    <! -- Console output -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <pattern>${log_pattern}</pattern>
        </encoder>
    </appender>

    <! -- Time-based scrolling, scrolling according to file size, suitable for cases where multiple logs are generated in a day -->
    <appender name="ROLLING_FILE_TIME_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log_path}/sizeAndTime.log</file>
        <! -- Append records -->
        <append>true</append>
        <! - define log rolling strategy, SizeAndTimeBasedRollingPolicy: support automatic scrolling increase % I serial number -- -- >
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <! -- define file name format for file scrolling -->
            <fileNamePattern>${log_path}/system/sizeAndTime.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <! -- Maximum size of a single file, over automatic rotation, 60 days but not more than 10G -->
            <maxFileSize>$log_file_max_size}</maxFileSize>
            <! -- Maximum calendar, usually used with totalSizeCap -->
            <maxHistory>${log_file_max_history}</maxHistory>
            <! -- Total file size, maxHistory property set -->
            <totalSizeCap>${log_file_max_total_size}</totalSizeCap>
            <! -- Whether to clear historical data at startup -->
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <encoder>
            <pattern>${log_pattern}</pattern>
        </encoder>
    </appender>

    <! -- Log collection -->
    <logger name="com.codecoord.springboot.elasticsearch.logstash" level="INFO" additivity="false">
        <appender-ref ref="ROLLING_FILE_TIME_APPENDER"/>
    </logger>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>
Copy the code

1.4 Advanced Logback configuration

  1. In addition to using core internal variables, logback can implement custom parameters through MDC
    • Reference: logback. Qos. Ch/manual/MDC….
  2. MDC is a static class, and Logback implements MDC using ThreadLocal, so you need to clear MDC data when you run out
package org.slf4j;

public class MDC {
  //Put a context value as identified by key
  //into the current thread's context map.
  public static void put(String key, String val);

  //Get the context identified by the key parameter.
  public static String get(String key);

  //Remove the context identified by the key parameter.
  public static void remove(String key);

  //Clear all entries in the MDC.
  public static void clear(a);
}
Copy the code
  1. Put (“key”, “value”) in the code and use it in the configuration file with %X{key}**
  2. Code sample
import java.time.LocalDateTime;
import java.util.Random;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@EnableScheduling
@Component
public class LogstashLogbackAggregation {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogstashLogbackAggregation.class);
    private static final Random RANDOM = new Random();

    @Scheduled(cron = "0/3 * * * * ?" )
    public void logbackMdc(a) {
        MDC.put("code", UUID.randomUUID().toString());
        MDC.put("createTime", LocalDateTime.now().toString());
        MDC.put("content"."Logstash log collection error" + LocalDateTime.now());
        LOGGER.info("Logstash Log collection, current time [{}]", LocalDateTime.now());
        MDC.clear();
        System.out.println(String.format("Logstash Log collection, current time [%s]", LocalDateTime.now())); }}Copy the code
  1. Logback configuration

      
<configuration debug="false" scan="true" scanPeriod="1 seconds">

    <contextName>logback</contextName>
    <! ${name} -->
    <property name="log_pattern" value="%d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n%ex"/>
    <! -- define log path -->
    <property name="log_path" value="log"/>
    <! -- Maximum number of historical days -->
    <property name="log_file_max_history" value="1"/>
    <! -- Maximum size of a single log -->
    <property name="log_file_max_size" value="10MB"/>
    <! -- maximum log file size -->
    <property name="log_file_max_total_size" value="1GB"/>

    <! -- Console output -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <pattern>${log_pattern}</pattern>
        </encoder>
    </appender>

    <! -- Time-based scrolling, scrolling according to file size, suitable for cases where multiple logs are generated in a day -->
    <appender name="ROLLING_FILE_TIME_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log_path}/sizeAndTime.log</file>
        <! -- Append records -->
        <append>true</append>
        <! - define log rolling strategy, SizeAndTimeBasedRollingPolicy: support automatic scrolling increase % I serial number -- -- >
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <! -- define file name format for file scrolling -->
            <fileNamePattern>${log_path}/system/sizeAndTime.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <! -- Maximum size of a single file, beyond automatic rotation -->
            <maxFileSize>${log_file_max_size}</maxFileSize>
            <! -- Maximum calendar, usually used with totalSizeCap -->
            <maxHistory>${log_file_max_history}</maxHistory>
            <! -- Total file size, maxHistory property set -->
            <totalSizeCap>${log_file_max_total_size}</totalSizeCap>
            <! -- Whether to clear historical data at startup -->
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <encoder>
            <pattern>${log_pattern}</pattern>
        </encoder>
    </appender>

    <! -- MDC -->
    <appender name="ROLLING_FILE_TIME_APPENDER_MDC" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log_path}/mdc.log</file>
        <append>true</append>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log_path}/system/mdc.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>${log_file_max_size}</maxFileSize>
            <maxHistory>${log_file_max_history}</maxHistory>
            <totalSizeCap>${log_file_max_total_size}</totalSizeCap>
            <cleanHistoryOnStart>true</cleanHistoryOnStart>
        </rollingPolicy>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %X{code} %X{createTime} %X{content} % MSG %n</pattern>
        </encoder>
    </appender>

    <! -- Logger -->
    <logger name="com.codecoord.springboot.elasticsearch.logstash" level="INFO" additivity="false">
        <appender-ref ref="ROLLING_FILE_TIME_APPENDER_MDC"/>
    </logger>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>
Copy the code

1.5 Log Error Handling

Empty watch file list. Disabling

  • The scan is enabled in the configuration, but the jar package cannot be scanned. Therefore, save the scan and remove the debug of the configuration
    • Configuration problem
<configuration debug="true" scan="true" scanPeriod="1 seconds">
Copy the code
  • Adjust the configuration
<configuration scan="true" scanPeriod="30 seconds">
Copy the code