A full explanation of Java logs (with usage examples)

We cannot judge the value of a moment until it is a memory.

Classification of logs 

First of all, you need to know that the logs used in the project are divided into two categories.

One is the facade of the log, which is equivalent to the interface API in Java, and the underlying specific log implementation is called through this facade API. The other type is the implementation of the log, that is, the specific implementation of the log called by the facade. We generally use the log facade + log implementation in the project .

1. Log facade

- JCL

- slf4j

2. Log implementation

- JUL

- log4j

- logback

- log4j2

log usage

JUL(Java util logging)

The native log framework of jdk does not need to introduce a third-party class library when using it. It is easy to use and is generally used to print test logs when writing demos by yourself.

Example usage:

import org.junit.jupiter.api.Test;

import java.util.logging.Level;
import java.util.logging.Logger;

public class AppTest 
{
    @Test
    public void testJUL() {
        // 1. 创建日志记录器对象
        Logger logger = Logger.getLogger("com.example.AppTest");
        // 2. 日志输出
        logger.info("test JUL");
        logger.log(Level.INFO, "选择日志的输出级别:test JUL");
        // 在日志输出中使用占位符
        String name = "li";
        Integer age = 18;
        logger.log(Level.INFO, "用户姓名:{0}, 用户年龄:{1}", new Object[]{name, age});
    }
}

output:

三月 28, 2023 9:41:12 下午 com.example.AppTest testJUL
信息: test JUL
三月 28, 2023 9:41:12 下午 com.example.AppTest testJUL
信息: 选择日志的输出级别:test JUL
三月 28, 2023 9:41:12 下午 com.example.AppTest testJUL
信息: 用户姓名:li, 用户年龄:18

Use with configuration files:

# Set root logger level to INFO and its only appender to ConsoleAppender.
log4j.rootLogger=INFO, ConsoleAppender

# Configure the console appender
log4j.appender.ConsoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.ConsoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.ConsoleAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %-5p %c %x - %m%n\
  
# Configure the file appender
log4j.appender.FileAppender=org.apache.log4j.RollingFileAppender
log4j.appender.FileAppender.File=mylog.log
log4j.appender.FileAppender.append=true
log4j.appender.FileAppender.MaxFileSize=10MB
log4j.appender.FileAppender.MaxBackupIndex=5
log4j.appender.FileAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.FileAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] %-5p %c %x - %m%n

Explanation:
- This configuration file defines two loggers: ConsoleAppender and FileAppender. ConsoleAppender outputs logs to the console, and FileAppender outputs logs to files.
- log4j.rootLogger defines the root level of the logger as INFO, which means that only log information of INFO, WARN, ERROR and FATAL levels will be recorded.
- og4j.appender.ConsoleAppender defines the layout of the ConsoleAppender, which uses a PatternLayout that outputs the time, thread, log level, logger name, and log message of the log.
- log4j.appender.FileAppender defines the layout and file name of FileAppender, it uses RollingFileAppender, when the log file size exceeds 10MB, it will automatically roll the file. It also sets the maximum number of backups to 5, which means there are at most five backup log files.
- Finally, log4j.appender.FileAppender.layout.ConversionPattern defines the format of the log records.

log4j

Apache's next open source logging framework.

Example of use

Import pom dependencies:

<dependencies>
   <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
   </dependency>

   <!-- log4j -->
   <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
   </dependency>
</dependencies>

Write a test class:

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.junit.Test;

public class AppTest
{
    @Test
    public void testLog4j() {
        // 1. 初始化配置信息
        BasicConfigurator.configure();
        // 2. 获取日志记录器对象
        Logger logger = Logger.getLogger(AppTest.class);
        // 3. 日志输出
        logger.info("hello log4j");
    }
}

Use with configuration file log4j.properties:

Configuration file example 1:

#设置日志级别
log4j.rootLogger=INFO, Console, File

#输出到控制台
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

#输出到文件
log4j.appender.File=org.apache.log4j.RollingFileAppender
log4j.appender.File.File=/var/log/myapp.log
log4j.appender.File.MaxFileSize=10MB
log4j.appender.File.MaxBackupIndex=10
log4j.appender.File.layout=org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

#设置包级别
log4j.logger.org.springframework=INFO
log4j.logger.com.example=DEBUG

Configuration file example 2:

#设置日志级别
log4j.rootLogger = debug,Console,D,E
 
#输出信息到控制台
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

#输出DEBUG 级别以上的日志到=E://logs/error.log
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
 
#输出ERROR 级别以上的日志到=E://logs/error.log
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

JCL + LOG4J

The full name is Jakarta Commons Logging, which is a common logging API provided by Apache.

Example usage:

import dependencies

 <dependencies>
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.11</version>
         <scope>test</scope>
     </dependency>

     <!-- jcl日志门面 -->
     <dependency>
         <groupId>commons-logging</groupId>
         <artifactId>commons-logging</artifactId>
         <version>1.2</version>
     </dependency>

     <!-- log4j -->
     <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
         <version>1.2.17</version>
     </dependency>
 </dependencies>

write test code

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;

public class AppTest
{
    @Test
    public void testJCL() {
        Log log = LogFactory.getLog(AppTest.class);

        log.info("hello jcl");
    }
}

output

22:28:25.433 [main] INFO com.example.AppTest - hello jcl

slf4j + logback

The logging framework used by default at the bottom of springboot.

- Simple Logging Facade For Java The simple log facade is mainly to provide a standard and standardized API framework for java log access. Its main significance is to provide interfaces, and the specific implementation can be handed over to other log frameworks.

- is another open source log component designed by the founder of log4j, with better performance than log4j.

Example usage:

import dependencies

<dependencies>
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.11</version>
         <scope>test</scope>
     </dependency>

     <!-- slf4j -->
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.7.30</version>
     </dependency>

     <!-- logback -->
     <dependency>
         <groupId>ch.qos.logback</groupId>
         <artifactId>logback-classic</artifactId>
         <version>1.2.3</version>
     </dependency>
 </dependencies>

write test class

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

    @Test
    public void testLogback() {
        LOGGER.info("hello logback");
    }
}

output

22:19:12.237 [main] INFO com.example.AppTest - hello logback

Use with logback.xml configuration file

<configuration>

  <!-- 定义日志输出格式 -->
  <property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>

  <!-- 控制台输出 -->
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>${PATTERN}</pattern>
    </encoder>
  </appender>

  <!-- 文件输出 -->
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logs/app.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>logs/app-%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>
    <encoder>
      <pattern>${PATTERN}</pattern>
    </encoder>
  </appender>

  <!-- 日志级别 -->
  <root level="INFO">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE"/>
  </root>

</configuration>

- The above configuration file defines two output sources, console and file. ConsoleAppender is used for console output, RollingFileAppender is used for file output, and TimeBasedRollingPolicy is used to rotate log files by time.
- The <root> element defines the log level as INFO, and outputs the log to the console and to the file. The verbosity of the log output can be controlled by specifying different levels in the <root> element. For example, setting the level attribute to DEBUG can include more detailed information in the log.

log4j2

Log4j2 is an upgraded version of Log4j. It refers to some excellent designs of logback and fixes some problems, so it brings some major improvements, mainly including: - Exception handling.
In logback, exceptions in Appender will not be processed Application aware, but in log4j2, some exception handling mechanisms are provided.
- Performance improvement, log4j has obvious performance improvement compared to logback.
- The automatic reload mechanism refers to the design of logback. Of course, it will provide automatic refresh parameter configuration. The most practical thing is that we can dynamically modify the log level in production without restarting the application.
- No garbage mechanism. In most cases, log4j can use its designed garbage-free mechanism to avoid jvm gc caused by frequent log collection.

Example usage:

import dependencies

<dependencies>
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>3.8.1</version>
         <scope>test</scope>
     </dependency>

     <!-- 使用slf4j作为日志门面 -->
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.7.30</version>
     </dependency>

     <!-- 使用log4j2作为日志实现 -->
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-log4j12</artifactId>
         <version>2.0.7</version>
     </dependency>
     <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-api</artifactId>
         <version>2.13.3</version>
     </dependency>
     <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-core</artifactId>
         <version>2.20.0</version>
     </dependency>
 </dependencies>

write test class

import junit.framework.TestCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AppTest
    extends TestCase
{
    private static final Logger logger = LoggerFactory.getLogger(AppTest.class);

    public void testLog4j2() {
        logger.info("This is an info message.");
        logger.error("This is an error message.");
    }
}

output result

20:30:16.428 [main] INFO com.example.AppTest - This is an info message.
20:30:16.431 [main] ERROR com.example.AppTest - This is an error message.

Use with configuration files

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
    </Console>
    <RollingFile name="RollingFile" fileName="logs/app.log"
                 filePattern="logs/app-%d{yyyy-MM-dd}.log.gz">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
      <Policies>
        <TimeBasedTriggeringPolicy interval="1" modulate="true" />
        <SizeBasedTriggeringPolicy size="10MB" />
      </Policies>
      <DefaultRolloverStrategy max="10" />
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="INFO">
      <AppenderRef ref="Console" />
      <AppenderRef ref="RollingFile" />
    </Root>
  </Loggers>
</Configuration>

- The configuration file defines two Appenders (Console and RollingFile) and a Root Logger.
- The Console Appender outputs logs to the console, and the RollingFile Appender outputs logs to a rolling log file.
- RollingFile Appender uses two trigger strategies of time and size, generates a new log file every day, and keeps up to 10 log files.

Three ways to realize log4j2 asynchronous log

In the case of high concurrency or complex business processing, use asynchronous log implementation.

1. Use AsyncLogger

AsyncLogger is one of the asynchronous log implementations provided in log4j2. To use AsyncLogger, you need to specify the use of AsyncLogger in the log4j2.xml configuration file.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
        <Logger name="async" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
    </Loggers>
    <AsyncLogger name="async" level="info" additivity="false">
        <AppenderRef ref="Console"/>
    </AsyncLogger>
</Configuration>

In the configuration above, we defined a Logger called async and set its level to info. Then, we use AsyncLogger to implement asynchronous logging and output the log to the Console Appender.

2. Use AsyncAppender

AsyncAppender is another asynchronous log implementation provided by log4j2. To use AsyncAppender, you need to specify the use of AsyncAppender in the log4j2.xml configuration file, and at the same time specify the Appender to be used.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <Async name="Async">
            <AppenderRef ref="Console"/>
        </Async>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
        <Logger name="async" level="info" additivity="false">
            <AppenderRef ref="Async"/>
        </Logger>
    </Loggers>
</Configuration>

In the configuration above, we defined an AsyncAppender named Async and set its Appender to Console Appender. Then, we set the Appender of async Logger to Async Appender to realize asynchronous logging.

3. Use Disruptor and other similar frameworks

Disruptor is a high-performance concurrency framework that can be used in log4j2 to implement asynchronous logging.

To use the Disruptor, you need to specify the use of the Disruptor in the log4j2.xml configuration file, and at the same time specify the Appender to be used.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <Disruptor name="Disruptor" bufferSize="1024">
            <AppenderRef ref="Console"/>
        </Disruptor>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
        <Logger name="async" level="info" additivity="false">
            <AppenderRef ref="Disruptor"/>
        </Logger>
    </Loggers>
</Configuration>

In the configuration above, we defined a Disruptor Appender named Disruptor and set its Appender to Console Appender. Then, we set the Appender of the async Logger as the Disruptor Appender to realize asynchronous logging.

Efficiency 3 > 2 > 1

springboot uses slf4j + log4j2 

1. Exclude the default logback dependency inside springboot and import log4j dependency

2. Create a new log4j2.xml file in the src/main/resources directory with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
 
  <Appenders>
    <Console name="console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %highlight{%-5level} %logger{36} - %msg%n"/>
    </Console>
 
    <RollingFile name="file" fileName="logs/myapp.log"
                 filePattern="logs/myapp-%d{yyyy-MM-dd}-%i.log.gz">
      <PatternLayout>
        <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Pattern>
      </PatternLayout>
      <Policies>
        <SizeBasedTriggeringPolicy size="100 MB"/>
      </Policies>
      <DefaultRolloverStrategy max="20"/>
    </RollingFile>
  </Appenders>
 
  <Loggers>
    <Root level="info">
      <AppenderRef ref="console"/>
      <AppenderRef ref="file"/>
    </Root>
  </Loggers>
 
</Configuration>

In the above configuration file, two Appenders are defined, one is Console Appender, which is used to output logs to the console; the other is RollingFile Appender, which is used to output logs to files and supports file rolling. Among them, RollingFile Appender uses SizeBasedTriggeringPolicy to control file size, and DefaultRolloverStrategy to control file rolling. Finally, Root Logger is configured in Loggers to output logs to Console and RollingFile Appender.

3. In the application.properties file of Spring Boot, configure the log level:

logging.level.root=info

The above configuration sets the log level of Root Logger to info, and you can also set the log level of other Loggers as needed.

4. Use Log4j2 to output logs in the code:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class MyApp {
 
    private static final Logger logger = LoggerFactory.getLogger(MyApp.class);
 
    public static void main(String[] args) {
        logger.debug("Debug message");
        logger.info("Info message");
        logger.warn("Warn message");
        logger.error("Error message");
    }
 
}

After using the above configuration, the logs will be output to the console and files according to the configuration. If you need to change the path of the log output, you can modify the fileName attribute in the RollingFile Appender in the log4j2.xml file. If you need to change the format of the log file, you can modify the pattern attribute in PatternLayout. If you need to set other Appenders and Loggers, you can configure them in the log4j2.xml file.

Guess you like

Origin blog.csdn.net/2301_76354366/article/details/129938838