0%

使用Log4j记录日志

对于开发者来说,日志的重要性不必多说。Log4j 是用 Java 语言编写的标准日志记录框架,以速度和灵活性为中心概念,使用配置文件便可以细致地控制日志的生成过程。


概述

Log4j 有三个重要的组件:

  • Loggers(记录器):日志级别;
  • Appenders(输出源):日志要输出的地方;
  • Layouts(布局):日志的输出格式。

记录器按照布局中指定的格式把日志信息写入一个或多个输出源。通常使用配置文件来部署这些组件,Log4j 支持 .xml.properties 两种配置文件格式。Log4j2 则使用 log4j2.xml 来进行配置,这里不做介绍。

Loggers

Log4j 允许定义多个记录器,而且记录器之间可以有层次关系。记录器之间通过名字来表明隶属或家族关系,子记录器可以继承父记录器的配置,它们有一个共同的、位于最上层的根记录器 rootLogger,它永远存在且不能通过名字检索或引用。

定义根记录器

在配置文件中定义根记录器:

log4j.properties
1
2
3
4
5
# 根记录器定义格式
log4j.rootLogger=[level], appenderName, appenderName, ...

# 定义根记录器
log4j.rootLogger=INFO, stdout

level 是记录器的级别,分为 OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL 以及自定义的级别,Log4j 建议使用其中的四个级别:FATAL、ERROR、WARN、INFO、DEBUG。级别之间的关系为 DEBUG < INFO < WARN < ERROR < FATAL,Log4j 只输出级别不低于设定级别的日志信息

appenderName 是输出源的名字,应与后面定义的输出源名字一致,可以同时指定多个输出源,用逗号隔开。

定义记录器

在配置文件中定义记录器:

log4j.properties
1
2
3
4
5
6
# 记录器定义格式
log4j.logger.<loggerName>=[level], appenderName, appenderName, …

# 定义记录器 moe.sannaha.testLogger 和 moe.sannaha.testLogger.subLogger
log4j.logger.moe.sannaha.testLogger=
log4j.logger.moe.sannaha.testLogger.subLogger=WARN

其中 loggerName 是自定义记录器的名字,需要与程序中定义的 Logger 名字一致:

1
2
private static Logger testLogger = Logger.getLogger("moe.sannaha.testLogger");
private static Logger subLogger = Logger.getLogger("moe.sannaha.testLogger.subLogger");

子记录器可以从父记录器中继承配置。moe.sannaha.testLoggerrootLogger 中继承记录器级别 INFO 以及输出源 stdoutmoe.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
2
3
4
5
6
7
8
9
10
11
# 输出源定义格式
log4j.appender.<appenderName>=className
# 输出源选项设置格式
log4j.appender.<appenderName>.<option1>=value1
...
log4j.appender.<appenderName>.<optionN>=valueN

# 定义输出源 stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# 设置输出源
log4j.appender.stdout.Threshold=WARN

ConsoleAppender选项

  • Threshold=INFO:指定日志信息的最低输出级别,默认为 DEBUG;
  • ImmediateFlush=true:所有消息都会被立即输出,设为 false 则不输出,默认值是 true
  • Target=System.err:默认值是 System.out

示例:

1
2
3
4
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Threshold=INFO
log4j.appender.stdout.ImmediateFlush=true
log4j.appender.stdout.Target=System.err

FileAppender选项

  • Threshold=INFO:指定日志信息的最低输出级别,默认为 DEBUG;
  • ImmediateFlush=true:所有消息都会被立即输出,设为 false 则不输出,默认值是 true
  • Append=true:表示消息增加到指定文件中,false 则将消息覆盖指定的文件内容,默认值是 true
  • File=D:/file.log:指定消息输出到哪个文件。

示例:

1
2
3
4
5
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.Threshold=INFO
log4j.appender.file.ImmediateFlush=true
log4j.appender.file.Append=true
log4j.appender.file.File=D:/file.log

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
2
3
4
5
6
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.Threshold=INFO
log4j.appender.file.ImmediateFlush=true
log4j.appender.file.Append=true
log4j.appender.file.File=D:/file.log
log4j.appender.file.DatePattern=.yyyy-MM-dd

如果在 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.1file.log.2 两个滚动文件,同时还有一个用于保存最新日志的 file.log 文件。

示例:

1
2
3
4
5
6
7
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.Threshold=INFO
log4j.appender.file.ImmediateFlush=true
log4j.appender.file.Append=true
log4j.appender.file.File=D:/file.log
log4j.appender.file.MaxFileSize=100KB
log4j.appender.file.MaxBackupIndex=2

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
2
3
4
5
6
7
8
9
10
11
# 布局定义格式
log4j.appender.<appenderName>.layout=className
# 布局选项设置格式
log4j.appender.<appenderName>.layout.<Option1>=value1
...
log4j.appender.<appenderName>.layout.<OptionN>=valueN

# 定义输出源 stdout 的布局
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 设置布局
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

示例

引入 log4j 依赖:

pom.xml
1
2
3
4
5
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

配置 log4j.properties

log4j.properties
1
2
3
4
5
6
log4j.rootLogger=INFO, stdout
log4j.logger.moe.sannaha.testLogger=
log4j.logger.moe.sannaha.testLogger.subLogger111=WARN, stdout, file
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %5p [%t] - %m%n

编写 Java 代码:

TestLog
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package moe.sannaha.testlog;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class TestLog {
private static Logger testLogger = Logger.getLogger("moe.sannaha.testLogger");
private static Logger subLogger = Logger.getLogger("moe.sannaha.testLogger.subLogger");

public static void main(String[] args) {
PropertyConfigurator.configure("log4j.properties");
testLogger.info("[INFO] testLogger");
testLogger.warn("[WARN] testLogger");
testLogger.error("[ERROR] testLogger");
subLogger.info("[INFO] subLogger");
subLogger.warn("[WARN] subLogger");
subLogger.error("[ERROR] subLogger");
}
}

运行结果:

1
2
3
4
5
6
7
2021-09-25 17:27:44,334  INFO [main] - [INFO] testLogger
2021-09-25 17:27:44,336 WARN [main] - [WARN] testLogger
2021-09-25 17:27:44,336 ERROR [main] - [ERROR] testLogger
2021-09-25 17:27:44,336 WARN [main] - [WARN] subLogger
2021-09-25 17:27:44,336 WARN [main] - [WARN] subLogger
2021-09-25 17:27:44,336 ERROR [main] - [ERROR] subLogger
2021-09-25 17:27:44,336 ERROR [main] - [ERROR] subLogger

参考资料

PatternLayout
Log4j.properties配置详解
log4j目的,作用和基本配置
浅谈Log4j和Log4j2的区别

  • 本文作者: SANNAHA
  • 本文链接: https://sannaha.moe/Log4j/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!