Log4j2使用

log4j2的基础使用方式

log4j2是apache的一个使用非常广泛的日志框架,用于记录应用程序的日志信息。

需要的依赖

要想使用该日志框架,需要引入如下依赖。

1
2
3
4
5
6
7
8
9
10
<dependency>  
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>

需要的配置

同时在resources目录下,创建日志配置文件,指定将日志输出到控制台。

1
2
3
4
5
6
7
8
9
10
11
12
13
# log4j2.properties
status = INFO

# 定义控制台输出
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n

# 根记录器配置
rootLogger.level = debug
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = STDOUT

代码示例

在Java代码中,使用该日志框架。

1
2
3
4
5
6
7
8
9
10
11
import org.apache.logging.log4j.LogManager;  
import org.apache.logging.log4j.Logger;

public class App {
private static final Logger log = LogManager.getLogger(App.class);
public static void main(String[] args) {
log.info("hello world");
log.debug("--------------");
System.out.println("aaaa");
}
}

运行,在控制台输出如下内容。

1
2
3
17:18:59.080 [main] INFO  com.guluo.App - hello world
17:18:59.087 [main] DEBUG com.guluo.App - --------------
aaaa

log4j2的通常使用方式

在实际中,我们并不会在Java代码中,直接通过这种方式来使用log4j2,原因是这样我们业务代码就与该日志框架强绑定了,不利于后面可能出现的日志框架切换问题。

为了实现业务代码与实际的日志框架解耦,常用的办法就是引入slf4j。

slf4j简单介绍

slf4j主要是为了给Java日志访问提供一个标准、规范的API框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架,例如log4j和logback等。
当然slf4j自己也提供了功能较为简单的实现,但是一般很少用到。
对于一般的Java项目而言,日志框架会选择slf4j-api作为门面,配上具体的实现框架(log4j、logback等),中间使用桥接器完成桥接。

比如在项目中,使用slf4j作为日志统一入口,具体的日志实现使用log4j2。
那么我们可以使用,log4j-slf4j-impl或者slf4j-log4j12,实现slf4j与具体的日志实现框架log4j2的绑定。两者的区别在于

  • slf4j-log4j12主要是为了对接log4j 1.x版本的日志框架 【虽然基于该依赖,也可以对接log4j2日志框架】
  • log4j-slf4j-impl 主要是为了对接log4j2日志框架

log4j2与log4j的简单对比

可以简单认为log4j2是log4j的进阶版本,弥补了log4j日志框架的一些不足。下面是两者的比较。

  • 安全性:最显著的区别是安全性。log4j存在一些安全漏洞,其中最为严重的是远程代码执行漏洞,可能导致系统被攻击。log4j2在安全性方面做了改进,修复了这些漏洞,提高了系统的安全性。
    详情参考: Log4j 严重漏洞修复方案参考 CVE-2021-44228 – KINGX
  • 性能:log4j2在设计上进行了优化,采用异步日志记录机制,因此在性能方面通常比log4j更高效。log4j2能够更好地处理大量日志记录并提供更好的性能表现。
  • 配置灵活性:log4j2提供了更灵活的配置选项和功能,使得开发人员可以更好地控制日志记录的行为。相对而言,log4j2在配置方面更加灵活和强大。

总的来说,log4j2相对于log4j在安全性、性能和配置灵活性方面都有所改进和优势,因此在选择日志框架时,更推荐使用log4j2以获得更好的体验和保障。

集成方式

由于目前log4j2使用更为普遍,因此在采用log4j-slf4j-impl作为桥接器实现log4j2和slf4j的集成。

在基础使用方式的基础上,再添加依赖,如下所示。

1
2
3
4
5
<dependency>  
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.2</version>
</dependency>

然后,进行如下配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
status = INFO  

# 定义控制台输出
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n

# 根记录器配置
rootLogger.level = debug
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = STDOUT


logger.http.name = test-name
logger.http = info,Console

需要注意的是,logger.http = debug,Console这个简写形式的配置,是自2.17.2版本才开始支持的,如果是之前的版本,并不支持简写,需要写成如下方式。

1
2
logger.http.level = info
logger.http.appender = Console

详情见:LOG4J2-3341 Support passing something like ‘-Dlog4j.rootLogger=INFO,Console’ from command line to set level and appenders at once - ASF JIRA (apache.org)

上述配置的意思是。

  • 名字为test-name的日志,按照logger.http* 方式控制
  • 其余日志按照rootLogger方式控制

Java代码如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;

public class SlfLogTest {
private static final Logger LOG = LoggerFactory.getLogger(SlfLogTest.class);
private static final Logger test_log = LoggerFactory.getLogger("test-name");

public static void main(String[] args) {
LOG.info("hello world.....");
LOG.debug("sssssssssssssssssssssss");

test_log.info("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
test_log.debug("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
}

输出如下所示。

1
2
3
11:34:03.573 [main] INFO  com.guluo.SlfLogTest - hello world.....
11:34:03.582 [main] DEBUG com.guluo.SlfLogTest - sssssssssssssssssssssss
11:34:03.583 [main] INFO test-name - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

由于test-name配置的是,仅输出info级别及以上的日志,因此test_log.debug()日志不会输出,结果也与预期一致。