Log4j 2、Logpack、SLF4j日志框架介绍

  • Log4j 2、Logpack、SLF4j日志框架,及其区别
  • 1.1 Log4j 2
  • 1.1.1 日志级别
  • 1.1.2 日志输出目标位置
  • 1.1.3 日志刷新机制
  • 1.1.4 结构化打印日志
  • 1.1.5 异步打印日志
  • 1.1.6 在Cloud云环境汇集日志信息
  • 1.2 LogPack
  • 1.3 SLF4j
  • 1.4 区别


Log4j 2、Logpack、SLF4j日志框架,及其区别

1.1 Log4j 2

注意二者在包名上的区别,考虑到目前使用的大多是Log4j 2,Log4j的使用就不单开一节做介绍了。
Log4j : org.apache.log4j.xxx
Log4j 2 : org.apache.logging.log4j.xxx

<dependencies>
        
        <!--log4j 2日志框架-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.20.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.20.0</version>
        </dependency>
        
     </dependencies>
1.1.1 日志级别

你可能还会见到Log4j 2的说法,Log4j 2是Log4j的更新一代版本。总共有六个日志级别,数值越小越严重。

(1)TRACE (600) : 最不严重的日志级别,通常用来打印细粒度信息,如进入与退出一个函数的过程信息、变量值信息以及其它可以帮助你理解代码之间内部工作关系的细节信息。
(2)DEBUG (500) : 可以用来追踪一个函数是否有正确执行。
(3)INFO (400) : it is used for informational messages that record events that occur during the normal operation of your application,such as user authentication, API calls, or database access. These messages help you understand what’s happening within your application.
(4)WARN (300) : events logged at this level indicate potential issues that might require your attention before they become significant problems.
(5)ERROR (200) : it is used to record unexpected errors that occur during the course of program execution.
(6)FATAL (100) : this is the most severe log level, and it indicates an urgent situation affecting your application’s core component that should be addressed immediately.

java 中info级别日志会打印 报错的 java打印log日志_log4j


打印日志有个规律,配置文件如果要打印TRACE级别,那么比TRACE级别高的DEBUG级别一定不可避免会被打印出来,其它的以此类推。

除了这六个级别以外,你也可以自定义级别,定义方法如下

package com.example;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Level;

public class App {
    protected static final Logger logger = LogManager.getLogger();

    public static void main(String[] args) {
        logger.log(Level.getLevel("VERBOSE"), "a verbose message");
    }
}
1.1.2 日志输出目标位置

还有就是log4j可以定义你的日志输出目标位置,是console控制台、还是files文件、亦或是database数据库或者云环境等。假设下面这段内容是/src/resources/log4j2.xml配置文件的内容,最终的日志会输出到当前项目根目录下的./logs/app.log文件中。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <File name="file" fileName="./logs/app.log">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </File>
    </Appenders>

    <Loggers>
        <Root level="info">
            <AppenderRef ref="file" />
        </Root>
    </Loggers>
</Configuration>
1.1.3 日志刷新机制

同时,为了防止文件无限度的增长,需要让log4j开辟一个新文件去存储,这可以用RollingFile来实现,即文件滚动。还是在上一段xml的基础上,修改了一点内容。那么可以看到,日志会输出至.gz后缀的压缩文件,一旦文件到了1KB,就会新建另一个.gz后缀的压缩文件,这里选1KB是为了方便运行观察效果,实际中肯定是选百MB或GB级别的。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">

    <Appenders>
        <RollingFile name="rolling" fileName="logs/app.log"
            filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
            <Policies>
                <TimeBasedTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="250 MB" />
            </Policies>
        </RollingFile>
    </Appenders>

    <Loggers>
        <Root level="info">
            <AppenderRef ref="rolling" />
        </Root>
    </Loggers>

</Configuration>

除了根据大小刷新日志,还有定时刷新日志的功能,更多功能具体请看参考文章[1],不过这篇文章在cron表达式与OnStartupTriggeringPolicy处有错误,不能全部都信。

1.1.4 结构化打印日志

除了PatternLayout规定的格式,我们还可以用JSONXML格式来打印日志,可以用JsonLayout来打印JSON格式的日志,首先要添加jar包依赖

<!--pom.xml-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.15.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.15.0</version>
    </dependency>
<!--log4j2.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">

    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <JsonLayout />
        </Console>
    </Appenders>

    <Loggers>
        <Root level="trace">
            <AppenderRef ref="console" />
        </Root>
    </Loggers>

</Configuration>

运行

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

public class Log4j_JSON {
    protected static final Logger logger = LogManager.getLogger();
    public static void main(String[] args) {
        ThreadContext.put("orderNumber", "1234567890");
        ThreadContext.put("buyerName", "jack");
        ThreadContext.put("destination", "xxxxxxxxxx");

        logger.info("Order shipped successfully."+ThreadContext.getContext());

        ThreadContext.clearAll();
    }
}

这是打印效果

{
  "instant" : {
    "epochSecond" : 1702643420,
    "nanoOfSecond" : 977000000
  },
  "thread" : "main",
  "level" : "INFO",
  "loggerName" : "lyp.basic.logFrame.Log4j_JSON",
  "message" : "Order shipped successfully.{buyerName=jack, destination=xxxxxxxxxx, orderNumber=1234567890}",
  "endOfBatch" : false,
  "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
  "threadId" : 1,
  "threadPriority" : 5
}

你也可以配置自己的json模版,具体看文章里的教程。

1.1.5 异步打印日志

什么是同步(Synchronism)?一件一件事情来,等结果执行完成再开始下一件。
什么是异步(ASynchronism,前面就多了个A)?事情一起开始,有结果再汇报,然后再处理。我们的日常生活就是异步的,所以不要觉得异步反人性,它可能反编程直觉,但绝对是符合事物本质逻辑的。 所以打日志这种事情,交给手下的日志框架去完成,打印完了汇报下就可以,这就是异步打印日志。但异步打印日志也有缺点,比如

(1) 内存占比增加
(2) 系统崩溃时,可能丢失数据
(3) 日志信息顺序混乱,这可能给debug带来困难
(4)
这里文章[1]没讲明白,另找文章。

1.1.6 在Cloud云环境汇集日志信息

Logtail: Cloud-based log management platforms.

1.2 LogPack

略,有兴趣请看文章。

1.3 SLF4j

SLF4j = Simple Logging Facade for Java (abbreviated SLF4J)Facade意思为房屋外观,还有一种设计模式叫外观模式(也叫门面模式),名字正好就是Facade Pattern,故SLF4j的全部意思是 “Java的简单日志外观”SLF4j支持不同的日志框架(e.g., java.util.logging, logback, Log4j)。

It offers a generic API, making the logging independent of the actual implementation.This allows for different logging frameworks to coexist.它提供了一个通用的API接口,使得logging本身是独立于具体实现的。这使得SLF4J可以运行各种不同的日志框架共存

SLF4J如何引用Log4j 2?

<dependencies>
    <!--slf4j框架-->
        <!--slf4j 接口-->    
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
            <version>2.22.0</version>
        </dependency>
        <dependency> <!--使用slf4j框架,进行AsyncLogging异步日志打印时,若出现java.lang.NoClassDefFoundError: com/lmax/disruptor/EventHandler时需要引入-->
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.4.4</version>
        </dependency>
    </dependencies>


1.4 区别

首先,Log4j 2SLF4j并非同一事物,虽然在搜索Log4j 2时,时常会搜索出混杂了SLF4jLog4j 2的内容。