log4j2的基础使用方式
log4j2是apache的一个使用非常广泛的日志框架,用于记录应用程序的日志信息。
需要的依赖
要想使用该日志框架,需要引入如下依赖。
1 | <!-- <log4j2.version>2.17.2<log4j2.version> --> |
需要的配置
同时在resources目录下,创建日志配置文件,指定将日志输出到控制台。
1 | # log4j2.properties |
就上面的日志配置,解释如下。
log4j2自身内部日志级别
log4j2作为一个日志框架,其在启动,初始化配置,或者其他事件的时候,也会产生一些日志,这些日志被称之为log4j2自身内部的日志。
我们通过status = INFO
,实际上是定义了这些日志的级别。
日志记录器和日志输出器
在log4j2中,有两个核心概念。
- 日志记录器(
rootLogger/logger
):用于在代码中输出日志信息。rootLogger
是全局的根记录器,负责管理所有日志的默认行为。 - 日志输出器(
appender
):负责将日志输出到指定的位置,比如控制台或文件。如上所示,我们定义了一个appender
,该appender
的功能就是可以将日志输出到控制台。
appender配置的逐行解释
appender.console.type = Console
:定义了一个名为console
的日志输出器,其类型为Console
,表示将日志输出到控制台。appender.console.name = STDOUT
:定义了一个名字叫STDOUT
的输出器,这个是该appender的唯一标识符,logger可以通过该name引用这个appender。appender.console.layout.type = PatternLayout
:定义了appender的布局类型为PatternLayout
,表示日志内容的格式化方式,PatternLayout
允许你通过一个模式字符串来完全自定义日志消息的输出格式。其他布局类型还包括JSONLayout
、XMLLayout
等。appender.console.layout.pattern = %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
:定义了日志输出的格式模式。
其中appender.console.layout.pattern
的格式说明如下:
%d{HH:mm:ss.SSS}
:表示日志事件的时间戳,格式为小时:分钟:秒.毫秒。[%t]
:表示当前线程的名称。%-5level
:表示日志级别,左对齐,占5个字符宽度。%logger{36}
:表示日志记录器的名称,最多显示36个字符。-
:表示日志消息前的分隔符,只是为了格式美观%msg
:表示日志消息内容%n
:表示换行符, 确保每条日志消息后都有一个换行。
logger配置的逐行解释
rootLogger.level = debug
:定义了根记录器的日志级别为debug
。rootLogger.appenderRefs = stdout
:指定rootLogger
将引用哪些Appender来输出日志,appenderRefs是一个列表,可以包含多个appender, 表示logger可以将这个日志时间发送给多个appender进行输出。这里仅只定了一个,表示rootLogger
将会把日志时间发送给名为stdout
的appender。rootLogger.appenderRef.stdout.ref = STDOUT
:这里首先定义一个名字叫stdout
的appender引用,该引用实际指向的appender指向上面定义的STDOUT
,表示将日志输出到控制台。
代码示例
在Java代码中,使用该日志框架。
1 | import org.apache.logging.log4j.LogManager; |
运行,在控制台输出如下内容。
1 | 17:18:59.080 [main] INFO com.guluo.App - hello world |
log4j2的实际应用方式
在实际开发中,我们通常不会直接在 Java 代码中使用 log4j2 的 API,因为这样会导致业务代码与具体日志框架强耦合,不利于后续日志框架的替换和维护。
为了实现业务代码与实际的日志框架解耦,常用的办法就是引入slf4j。
slf4j 主要为 Java 日志访问提供了一个标准化的 API 框架,其核心作用是作为日志门面,定义统一的接口,具体的日志实现则由其他框架(如 log4j、logback 等)完成。虽然 slf4j 自身也提供了简单的实现,但实际项目中很少直接使用。通常,Java 项目会选择 slf4j-api 作为日志门面,结合具体实现框架(如 log4j2、logback),并通过桥接器进行集成。
例如,项目中以 slf4j 作为统一日志入口,实际日志实现采用 log4j2 时,可以使用 log4j-slf4j-impl
或 slf4j-log4j12
进行绑定。两者区别在于:
slf4j-log4j12
主要用于对接 log4j 1.x 版本(虽然也可用于 log4j2,但不推荐);log4j-slf4j-impl
专为 log4j2 设计,推荐用于 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 | <dependency> |
然后,日志仍然是log4j2.properties
,我们额外添加了一个普通logger
。
1 | status = INFO |
Java代码如下所示。
1 | import org.slf4j.Logger; |
输出如下所示。
1 | 11:34:03.573 [main] INFO com.guluo.SlfLogTest - hello world..... |
由于test-name
配置的是,仅输出info
级别及以上的日志,因此test_log.debug()
日志不会输出,结果也与预期一致。
快速切换日志实现
如果此时因为业务需要,我们需要将程序中的日志实现,从log4j2切换到logback,只需要做如下修改。
更新日志实现的依赖
删除上述依赖,并添加如下依赖。
1 | <dependency> |
更新日志配置文件
删除log4j2.properties
,并添加logback.xml
,内容如下。
1 |
|
完成上述步骤,即可实现日志框架的快速切换。可以发现,我们仅仅是修改了依赖和配置文件,而业务代码完全不需要修改。
这就是使用日志门面(如 slf4j)和具体日志实现(如 log4j2、logback)的好处。通过这种方式,我们可以轻松地在不同的日志框架之间切换,而不需要修改业务代码,从而实现了日志框架的解耦和灵活性。