Apache Log4j2 详解 (一)
log4j2 是一个优秀的日志框架,和他对应的其他的日志框架例如logback;之前的版本是log4j 1.x 这个是升级版。我们一般都是搭配slf4j使用。
一、什么是log4j2
log4j2 是一个优秀的日志框架,和他对应的其他的日志框架例如logback; 之前的版本是log4j 1.x 这个是升级版。我们一般都是搭配slf4j使用
1.1 日志框架和日志输出接口的关系
日志输出接口,通常我们也叫他日志门面,现在Java中认可度最高的日志门面就是 slf4j (Simple logging facade for Java)
slf4j 和 log4j2 有什么关系呢
slf4j 并不是一个框架,他是一个抽象层,使用适配器模式,它本身不输出日志,还是对接 log4j logback这样的日志输出框架,实现日志输出。
为啥要用 slf4j 这样的门面输出日志啊? log4j logback 不能输出吗?
当然不是,日志框架当然也能输出日志,但是有很多缺陷。
使用 slf4j 的优点
- 他以适配器模式对接 各种各样的日志框架, 这样当你使用不同的日志框架的时候,不用再去维护两套配置和环境
- 他本身 提供类似占位符 “{}” 这样的功能,不用再做日志拼接,占用更多内存
- 注解的引入方式可以更少的节省代码 @slf4j 可以直接通过注解的方式使用, 不用在类之前做繁杂的定义啦
当然 slf4j 的优点还有很多,这里就不一一例举了,感兴趣的可以自己在网上搜一搜。
二、 Log4j2的入门
2.1 最简单的log4j2的使用
接下来我们一点点接触 log4j2, 首先我们不使用 slf4j, 我们直接使用log4j 自己的日志输出
maven 引入依赖
xml复制代码<dependencies>
<!-- log4j 自带的日志输出 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<!-- log4j 的内核 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
</dependencies>
我们来手写第一个demo
arduino复制代码import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2Application {
private static Logger logger = LogManager.getLogger(Log4j2Application.class);
public static void main(String[] args) {
// 当没有任何配置文件的时候, 只会打印error及以上级别,但是至少,他能打印
logger.debug(" debug level ");
logger.info(" info level ");
logger.warn(" warn level ");
logger.error(" error level ");
logger.fatal(" fatal level ");
}
}
输出:
ini复制代码10:09:02.444 [main] ERROR com.chason.Log4j2Application - error level
10:32:04.712 [main] FATAL com.chason.Log4j2Application - fatal level
我们发现,没有任何配置文件的时候 log4j 也是能进行输出的,但是他只是输出了 error 及以上级别的日志。
2.2 配置log4j
Log4j2 可以以多种方式进行配置,我们来看看官方文档咋说的
Configuration of Log4j 2 can be accomplished in 1 of 4 ways:
- Through a configuration file written in XML, JSON, YAML, or properties format.
- Programmatically, by creating a ConfigurationFactory and Configuration implementation.
- Programmatically, by calling the APIs exposed in the Configuration interface to add components to the default configuration.
- Programmatically, by calling methods on the internal Logger class.
翻译一下
- 通过XML、JSON、YAML或者properties格式的配置文件;
- 通过创建一个 ConfigurationFactory 和 Configuration 接口的实现
- 调用 Configuration 接口暴露的方法来在默认配置的基础上添加其他组件
- 通过在内部 Logger 类上调用方法
下面我们一点点的尝试配置的方法
2.2.1 xml文件的方式配置
这种方式是我们生产中最常见的方式了,弄一个log4j2.xml的配置文件,直接把所有的日志输出方式都写在里面,只要开发过的应该都有映象哈
resources 下新建一个log4j2.xml文件,文件内容如下
xml复制代码<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="debug" monitorInterval="30">
<Properties>
<Property name="date_format" value="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Property name="log_path">D:/logs</Property>
</Properties>
<Appenders>
<Console name="ConsoleAppend" target="SYSTEM_OUT">
<PatternLayout pattern="${date_format}"/>
</Console>
<File name="FileAppend" fileName="${log_path}/xml_config.log" bufferedIO="true" immediateFlush="true">
<PatternLayout>
<pattern>${date_format}</pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="ConsoleAppend"/>
<AppenderRef ref="FileAppend"/>
</Root>
</Loggers>
</Configuration>
我们测试代码基本不变:
arduino复制代码import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2Application {
private static Logger logger = LogManager.getLogger(Log4j2Application.class);
public static void main(String[] args) {
// 配置了log4j2.xml文件之后
logger.debug(" debug level ");
logger.info(" info level ");
logger.warn(" warn level ");
logger.error(" error level ");
logger.fatal(" fatal level ");
}
}
执行结果:
ini复制代码10:44:35.713 [main] INFO com.chason.Log4j2Application - info level
10:44:35.715 [main] WARN com.chason.Log4j2Application - warn level
10:44:35.716 [main] ERROR com.chason.Log4j2Application - error level
10:44:35.716 [main] FATAL com.chason.Log4j2Application - fatal level
对应的目录下也出现了日志文件
下面我么简单解释下上面的配置文件:
xml复制代码monitorInterval: Log4j每隔指定的秒数来重新读取配置文件,刷新配置
<Properties> : 里面是一些自定义的参数 上面的例子定义了一个输出格式和日志输出的文件夹
<Appenders> : 使用Appenders元素可以将日志事件数据写到各种目标位置
<Console> : 控制台打印日志的配置
<File> : 普通文件日志的配置
2.2.2 properties 文件配置的方式
我们在resources 创建一个 log4j2.properties文件
文件内容如下
ini复制代码# 类比成 log4j2.xml 中的<property>
property.filename = D:/logs/proFile.log
# 控制台输出的相关配置
# 输出类型 控制台
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} - %m%n
# 文件输出的相关配置
# 输出类型 文件
appender.file.type = File
# 起个名字
appender.file.name = LocalFile
# 输出到哪个文件
appender.file.fileName = ${filename}
# 输出格式
appender.file.layout.type = PatternLayout
appender.file.layout.pattern = %d{HH:mm:ss.SSS} --> [%t] %-5level %logger{36} - %m%n
# root 节点相关配置
# 日志级别: 这个级别 是个兜底级别,真的级别还是根据我们配置的对应的日志级别而定
# 如果我们配置了过滤器的级别 ,那么会生效过滤器级别,否则以这个日志级别为准
rootLogger.level = debug
# 2.17.2 版本以下通过这种方式将 root 和 Appender关联起来
# 2.17.2 版本以上有更简便的写法
rootLogger.appenderRef.stdout.ref = STDOUT
rootLogger.appenderRef.file.ref = LocalFile
运行结果如下:
ini复制代码16:37:17.749 [main] DEBUG com.chason.app.Log4j2Application - debug level
16:37:17.753 [main] INFO com.chason.app.Log4j2Application - info level
16:37:17.753 [main] WARN com.chason.app.Log4j2Application - warn level
16:37:17.753 [main] ERROR com.chason.app.Log4j2Application - error level
16:37:17.757 [main] FATAL com.chason.app.Log4j2Application - fatal level
同时对应的文件夹下也生成了文件
好了,截止到目前为止,我们已经使用了两种配置文件的方法配置log4j2 并实现对应的日志输出,其他配置文件的方法大家参考官方文档自己尝试尝试,如果真的看不懂或者懒得看,留言给我吧,大家都期望的话我把配置文件的方式给补全。
大家发现一个问题没有,当前我的resources下面其实有两个配置文件, 我在演示properties配置的时候没有让大家删除xml文件吧,那么为啥在有了两个配置文件之后,log4j2居然没有迷糊, 而且这次好像xml配置文件没有生效?这是怎么回事呢?
我们来看看log4j的启动加载过程,我们在 idea中加入 启动参数 -Dlog4j.debug
再次运行程序,我们看看控制台, 我们发现控制台中多了好多东西啊, 但是我们先别慌,关注下面一段内容
kotlin复制代码TRACE StatusLogger Trying to find [log4j2-test18b4aac2.properties] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.properties] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.properties] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.properties] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.yml] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.yml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.yml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.yml] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.yaml] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.yaml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.yaml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.yaml] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.json] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.json] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.json] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.json] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.jsn] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.jsn] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.jsn] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.jsn] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.xml] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.xml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.xml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test18b4aac2.xml] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test.properties] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test.properties] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.properties] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.properties] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test.yml] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test.yml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.yml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.yml] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test.yaml] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test.yaml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.yaml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.yaml] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test.json] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test.json] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.json] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.json] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test.jsn] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test.jsn] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.jsn] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.jsn] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2-test.xml] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j2-test.xml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.xml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j2-test.xml] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j218b4aac2.properties] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j218b4aac2.properties] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.properties] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.properties] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j218b4aac2.yml] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j218b4aac2.yml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.yml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.yml] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j218b4aac2.yaml] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j218b4aac2.yaml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.yaml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.yaml] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j218b4aac2.json] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j218b4aac2.json] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.json] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.json] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j218b4aac2.jsn] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j218b4aac2.jsn] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.jsn] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.jsn] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j218b4aac2.xml] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
TRACE StatusLogger Trying to find [log4j218b4aac2.xml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.xml] using sun.misc.Launcher$AppClassLoader@18b4aac2 class loader.
TRACE StatusLogger Trying to find [log4j218b4aac2.xml] using ClassLoader.getSystemResource().
TRACE StatusLogger Trying to find [log4j2.properties] using context class loader sun.misc.Launcher$AppClassLoader@18b4aac2.
发现 log4j 其实在启动过程中找了很多配置文件,从properties 到 yml 再到 yaml 再到 json 再到 jsn 再到 xml, 当找到了一个配置文件之后,他就开始加载配置,后面的配置文件就不再加载了。
这我们就明白了,原来配置文件的加载还有先后顺序。 不仅文件类型有讲究,文件名也有讲究啊。
OK, 这就明白为啥 有 properties 之后 xml 配置文件没有生效了。
官方文档怎么说的呢?
- Log4j will inspect the
"log4j2.configurationFile"
system property and, if set, will attempt to load the configuration using theConfigurationFactory
that matches the file extension. Note that this is not restricted to a location on the local file system and may contain a URL. - If no system property is set the properties ConfigurationFactory will look for
log4j2-test.properties
in the classpath. - If no such file is found the YAML ConfigurationFactory will look for
log4j2-test.yaml
orlog4j2-test.yml
in the classpath. - If no such file is found the JSON ConfigurationFactory will look for
log4j2-test.json
orlog4j2-test.jsn
in the classpath. - If no such file is found the XML ConfigurationFactory will look for
log4j2-test.xml
in the classpath. - If a test file cannot be located the properties ConfigurationFactory will look for
log4j2.properties
on the classpath. - If a properties file cannot be located the YAML ConfigurationFactory will look for
log4j2.yaml
orlog4j2.yml
on the classpath. - If a YAML file cannot be located the JSON ConfigurationFactory will look for
log4j2.json
orlog4j2.jsn
on the classpath. - If a JSON file cannot be located the XML ConfigurationFactory will try to locate
log4j2.xml
on the classpath. - If no configuration file could be located the
DefaultConfiguration
will be used. This will cause logging output to go to the console.
翻译一下:
- log4j 会去检查 log4j2.configurationFile 系统属性 ,若被配置了 ,将尝试使用与文件扩展名匹配的ConfigurationFactory加载配置, 注意,这并不局限于本地文件系统上的某个位置,而且可能包含一个URL。
- 如果没有设置系统属性,则ConfigurationFactory属性将查找 classpath 中的 log4j2-test.perperties
- 若没找到,则YAML ConfigurationFactory就在 classpath 中寻找log4j2-test.yaml 或 log4j2-test.yml配置文件
- 若没找到,则JSON ConfigurationFactory就在 classpath 中寻找 log4j2-test.json 或 log4j2-test.json 配置文件
- 若没找到,则XML ConfigurationFactory 就在 classpath 中寻找log4j2-test.xml配置文件
- 若没找到测试配置文件,则properties ConfigurationFactory就在 classpath 中寻找log4j2.properties配置文件
- 若没找到,则YAML ConfigurationFactory就在 classpath 中寻找 log4j2.yaml 或 log4j2.yml 配置文件
- 若没找到,则JSON ConfigurationFactory就在 classpath 中寻找 log4j2.json 或 log4j2.jsn 配置文件
- 若没找到,则XML ConfigurationFactory 就在 classpath 中寻找 log4j2.xml 配置文件 (生产环境常用)
- 如果找不到配置文件,将使用DefaultConfiguration。这将导致日志输出到控制台
OK , 第一节,我们就简单说说 log4j2 是啥, 和slf4j 的关系, 以及入门级别的用法, 配置文件的加载顺序等等。 后面我们将继续深入,了解怎么通过代码进行 log4j2的配置,以及log4j2的更深原理,他为什么这么快。
下节见
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)