对于开发者来说,日志的重要性不必多说。Log4j 是用 Java 语言编写的标准日志记录框架,以速度和灵活性为中心概念,使用配置文件便可以细致地控制日志的生成过程。
概述
Log4j 有三个重要的组件:
- Loggers(记录器):日志级别;
- Appenders(输出源):日志要输出的地方;
- Layouts(布局):日志的输出格式。
记录器按照布局中指定的格式把日志信息写入一个或多个输出源。通常使用配置文件来部署这些组件,Log4j 支持 .xml
和 .properties
两种配置文件格式。Log4j2 则使用 log4j2.xml
来进行配置,这里不做介绍。
Loggers
Log4j 允许定义多个记录器,而且记录器之间可以有层次关系。记录器之间通过名字来表明隶属或家族关系,子记录器可以继承父记录器的配置,它们有一个共同的、位于最上层的根记录器 rootLogger
,它永远存在且不能通过名字检索或引用。
定义根记录器
在配置文件中定义根记录器:
1 | # 根记录器定义格式 |
level
是记录器的级别,分为 OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL 以及自定义的级别,Log4j 建议使用其中的四个级别:FATAL、ERROR、WARN、INFO、DEBUG。级别之间的关系为 DEBUG < INFO < WARN < ERROR < FATAL,Log4j 只输出级别不低于设定级别的日志信息。
appenderName
是输出源的名字,应与后面定义的输出源名字一致,可以同时指定多个输出源,用逗号隔开。
定义记录器
在配置文件中定义记录器:
1 | # 记录器定义格式 |
其中 loggerName
是自定义记录器的名字,需要与程序中定义的 Logger 名字一致:
1 | private static Logger testLogger = Logger.getLogger("moe.sannaha.testLogger"); |
子记录器可以从父记录器中继承配置。moe.sannaha.testLogger
从 rootLogger
中继承记录器级别 INFO
以及输出源 stdout
;moe.sannaha.testLogger.subLogger
则用 WARN
覆盖了父记录器的记录器级别,并从 moe.sannaha.testLogger
继承输出源 stdout
。
Appenders
Log4j 允许定义多个输出源,可以把日志输出到不同的地方。常用的类如下:
- org.apache.log4j.ConsoleAppender(控制台)
- org.apache.log4j.FileAppender(文件)
- org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
- org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
- org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
- org.apache.log4j.SocketAppender (Socket)
在配置文件中定义输出源,可以通过选项对输出源进行设置:
1 | # 输出源定义格式 |
ConsoleAppender选项
- Threshold=INFO:指定日志信息的最低输出级别,默认为 DEBUG;
- ImmediateFlush=true:所有消息都会被立即输出,设为
false
则不输出,默认值是true
; - Target=System.err:默认值是
System.out
。
示例:
1 | org.apache.log4j.ConsoleAppender = |
FileAppender选项
- Threshold=INFO:指定日志信息的最低输出级别,默认为 DEBUG;
- ImmediateFlush=true:所有消息都会被立即输出,设为
false
则不输出,默认值是true
; - Append=true:表示消息增加到指定文件中,
false
则将消息覆盖指定的文件内容,默认值是true
; - File=D:/file.log:指定消息输出到哪个文件。
示例:
1 | org.apache.log4j.FileAppender = |
DailyRollingFileAppender选项
- Threshold=INFO:指定日志信息的最低输出级别,默认为 DEBUG;
- ImmediateFlush=true:所有消息都会被立即输出,设为
false
则不输出,默认值是true
; - Append=true:表示消息增加到指定文件中,
false
则将消息覆盖指定的文件内容,默认值是true
; - File=D:/file.log:指定消息输出到哪个文件;
- DatePattern=.yyyy-MM-dd:每天滚动一次日志文件,即把昨天的日志文件重名名为
file.log.yyyy-MM-dd
,当天的日志文件仍为file.log
。根据日期字符串的不同,可以按照月、周、天、时、分等尺度来滚动日志文件,对应的格式如下: - .yyyy-MM:每月
- .yyyy-ww:每周
- .yyyy-MM-dd:每天
- .yyyy-MM-dd-a:每天两次
- .yyyy-MM-dd-HH:每小时
- .yyyy-MM-dd-HH-mm:每分钟
示例:
1 | org.apache.log4j.DailyRollingFileAppender = |
如果在 Windows 平台使用 1.2.17
版本的 log4j(比如 spark-core_2.11:2.4.0-cdh6.1.0
中使用的 log4j),使用 DailyRollingFileAppender
时会出现重命名错误,这一 BUG 在 1.3.x
中修复:
1 | log4j:ERROR Failed to rename [D:/file.log] to [D:/file.log.2021-09-24-15:34]. |
RollingFileAppender选项
- Threshold=INFO:指定日志信息的最低输出级别,默认为 DEBUG;
- ImmediateFlush=true:所有消息都会被立即输出,设为
false
则不输出,默认值是true
; - Append=true:表示消息增加到指定文件中,
false
则将消息覆盖指定的文件内容,默认值是true
; - File=D:/file.log:指定消息输出到哪个文件;
- MaxFileSize=100KB:当日志文件达到指定大小时将会自动滚动,将原来的日志内容保存为
file.log.1
,单位可以是 KB、MB 或 GB; - MaxBackupIndex=2:指定最多可以产生几个滚动文件。如果设置为
2
,则可以产生file.log.1
和file.log.2
两个滚动文件,同时还有一个用于保存最新日志的file.log
文件。
示例:
1 | org.apache.log4j.RollingFileAppender = |
Layouts
Log4j 提供了四种日志输出布局,常用的类如下:
- org.apache.log4j.HTMLLayout(以HTML表格形式布局)
- org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
- org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
- org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)
如果使用的是 PatternLayout,Log4j 还提供类似 C 语言中的 printf
函数来格式化日志信息:
%c
:输出记录器的名称;%d
:输出时间,默认格式为yyyy-MM-dd HH:mm:ss,SSS
,也可以指定格式为%d{yyyy/MM/dd HH:mm:ss,SSS}
,输出效果为2021/09/25 17:03:59,351
;%l
:输出日志事件的发生位置,包括全类名、发生的线程、文件以及在代码中的行数。比如:moe.sannaha.testlog.TestLog.main(TestLog.java:14)
;%m
:输出代码中指定的消息;%n
:输出一个换行符,Windows平台为/r/n
,Unix 平台为/n
;%p
:输出优先级,即 DEBUG,INFO,WARN,ERROR,FATAL;%5p
:以 5 个字符的宽度输出优先级,默认为右对齐,对于 INFO、WARN 会在前面补空格,可以在前面添加-
实现左对齐;%r
:输出自应用启动到输出该日志信息耗费的毫秒数;%t
:输出产生该日志事件的线程名。
在配置文件中定义布局,可以通过选项对布局进行设置:
1 | # 布局定义格式 |
示例
引入 log4j 依赖:
1 | <dependency> |
配置 log4j.properties
:
1 | INFO, stdout = |
编写 Java 代码:
1 | package moe.sannaha.testlog; |
运行结果:
1 | 2021-09-25 17:27:44,334 INFO [main] - [INFO] testLogger |
参考资料
PatternLayout
Log4j.properties配置详解
log4j目的,作用和基本配置
浅谈Log4j和Log4j2的区别