【从零单排】详解 Log4j + Slf4j 等日志框架(番外)

日志框架的上,下两篇把大部分的内容都涵盖了,有些额外的小知识点(但是同样十分重要),放到这里来说。

知识点1:Log4j Properties File 配置详解

关于Logger

一般来说,一定(最好)要配一个 rootLogger ,告诉 log4j 默认情况下的 logger 的配置情况。

# 第一个参数是日志级别,后面可以跟多个 logger
log4j.rootLogger = INFO, stdout, testlog1, testlog2

另外,还可以在 package / class 级别,设置 logger 。

# 设置一个名为 testlog 的 logger ,只输出 com.my.app 下的内容
log4j.logger.com.my.app = INFO, testlog
# 设置该 logger 不再输出到 root logger 中
log4j.additivity.com.my.app = false

# 设置 rootLogger/logger 的日志级别,且只针对 com.my.app 下的内容
log4j.logger.com.my.app = INFO

这两招配合使用,可以控制日志灵活地输出。

举个例子,我改了某个类,新加了很多 DEBUG log,跑 Integration Test 的时候会输出大量 DEBUG 用于分析。但是我不想污染主 log 文件。咋办?

改动如下:main 是原来的配置,不去动它,新增 temp 部分,这样,所有 com.my.app.Log4jApp 的 DEBUG log 会单独输出到一个文件,不会污染主 log 文件。(测完了把新增部分删除即可)

# main
log = D:/codebase/LogTestSystem/logdir
log4j.rootLogger = INFO, testlog
log4j.appender.testlog=org.apache.log4j.FileAppender
log4j.appender.testlog.File=${log}/log.out
log4j.appender.testlog.layout=org.apache.log4j.PatternLayout
log4j.appender.testlog.layout.conversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] - [%c] %m%n

# temp
log4j.logger.com.my.app.Log4jApp = Debug, testlogNew
log4j.additivity.com.my.app.Log4jApp = false
log4j.appender.testlogNew=org.apache.log4j.FileAppender
log4j.appender.testlogNew.File=${log}/log3.out
log4j.appender.testlogNew.layout=org.apache.log4j.PatternLayout
log4j.appender.testlogNew.layout.conversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] - [%c] %m%n

关于Layout

格式如下:

%c 输出日志信息所属的类的全名
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy-MM-dd HH:mm:ss },输出类似:2002-10-18- 22:10:28
%l 输出日志事件的发生位置,即输出日志信息的语句处于它所在的类的第几行
%m 输出代码中指定的信息,如log(message)中的message
%n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL。如果是调用debug()输出的,则为DEBUG,依此类推
%r 输出自应用启动到输出该日志信息所耗费的毫秒数
%t 输出产生该日志事件的线程名

一个常见的配置如下:

log4j.appender.testlog.layout.conversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] - [%c] %m%n

输出如下:

2021-04-24 15:16:21 [ main:0 ] - [ INFO ] - [Log4jModule2] hello world

(详细见参考1,参考3)

知识点2:对 Log4j Properties File 文件重命名

实际使用中,为了区分不同环境,可能的 log4j.properties 文件集合如下:

log4j_alice_personal.properties
log4j_stg.properties
log4j_uat.properties
log4j_prd.properties

那么怎么使之生效呢?可以在启动参数中做如下配置:

java -Dlog4j.configuration=file:/some_path/log4j_stg.properties MyApp

(详细见参考4)

知识点3:Apache Commons Logging 的兼容性问题

如果项目中或依赖的包中使用了JCL,那么需要注意兼容性。
一般最容易报的错是 JCL 无法正确地根据配置文件创建对应的 Logger 。

99%的情况,这是由于pom.xmlxxx.properties/xxx.xml冲突导致的。

所以,我们需要理解 JCL 是如何创建 Logger 的,我简单总结如下:

  1. 优先选用环境变量 org.apache.commons.logging.Log / org.apache.commons.logging.LogFactory 指定的 Logger
  2. 其次是 Log4j
  3. 然后是 JDK Logging
  4. 最后是 Simple Log

第一步中,这个环境变量,一种方式是通过 commons-logging.properties 配置,如下:

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

另外,也有可能,在某些 jar 包中,会自己设置。比如,log4j-jcl:2.11.1中,显示地设置了

org.apache.common.logging.LogFactory = org.apache.logging.log4j.jcl.LogFactoryImpl

LOG

这就导致了,只要我引用了log4j-jcl:2.11.1这个包,JCL 一定会初始化一个 Log4j2 的 Logger !如果找不到就报错。(如果你问我是咋知道的?踩坑踩出来的呗...)

(详细见参考2)

参考

posted @ 2021-05-10 20:47  MaxStack  阅读(108)  评论(0编辑  收藏  举报