1. 使用 Log4J 进行日志操作
1.2 Log4J 简介
Log4J主要由三大组件构成:
- Logger:负责生成日志,并能够对日志信息分类筛选。
- Appender:定义了日志信息输出的目的地,这些地方可以是控制台、文件和网络设备等。
- Layout:指定日志信息的输出格式。
一个Logger可以有多个Appender,这意味着日志信息可以同时输出到多个设备,每个Appender都对应一种Layout,Layout决定了输出日志信息的格式。
1.2.1 Logger 组件
Logger是Log4J的核心组件,他代表了Log4J的日志记录器,他能够对日志信息进行分类筛选,决定什么日志信息应该被输出,什么日志信息应该被忽略。
//打印各种级别的日志的方法
public void trace(Object message);
public void debug(Object message);
public void info(Object message);
public void warn(Object message);
public void error(Object message);
public void fatal(Object message);
//打印日志的通用方法
public void log(Level level, Object message);
org.apache.logging.log4j.LogManager 类提供了获得 Logger 实例的静态方法:
//返回根 Logger 对象
public static Logger getRootLogger();
//根据参数指定的名字返回特定的 Logger 对象
public static Logger getLogger(String name);
可以在 Log4J 的 XML 格式的配置文件中配置自己的Logger 组件,例如以下代码配置了一个Logger组件,名为helloappLogger:
<Logger name="helloappLogger" level="warn" additivity="false">
<AppenderRef ref="console"/>
</Logger>
以上代码定义了一个Logger组件。名为helloappLogger,并为它分配了一个日志级别(LEVEL),取值为“WARN”。一共有六种日志级别:FATAL、ERROR、WARN、INFO、DEBUG、TRACE,其中 FATAL 的日志级别最高。
只有当打印日志的级别大于或等于Logger组件配置的日志级别时,日志打印方法才会被执行。
例如对于以上配置的helloappLogger,它的日志级别为 WARN,那么在程序中,他的 fatal()、error() 和 warn() 方法会被执行,而 info()、debug() 和 trace() 方法不会被执行,对于 log() 方法,只有当他的 Level类型的参数level指定的日志级别大于或等于 WARN,这个方法才会被执行。
helloapplogger.log(Level.WARN, "This is a warn message!");
例如以上 log() 方法的 level 参数为Level.WARN,因此该方法会被执行。
假如不需要输出级别为WARN的日志信息,可以在配置文件中把helloappLogger 组件的级别调高。比如调到ERROR或FATAL级别,这样WARN级别以及以下级别的日志就不会输出了。
1.2.2 Appender 组件
目前,Log4J 的 Appender 支持将日志信息输出到以下目的地:
- 控制台(Console)
- 文件(File)
- 远程套接字服务器(Remote socket server)
- NT 的事件记录器
- 远程 UNIX Syslog 守护进程(Remote UNIX Syslog daemon)
一个 Logger可以同时对应多个Appender 。例如要为 helloappLogger 配置两个Appender 。一个是file,一个是console,则可以采用如下配置代码:
<Logger name="helloappLogger" level="warn" additivity="false">
<AppenderRef ref="file"/>
<AppenderRef ref="console"/>
</Logger>
1.2.3 Layout 组件
Layout组件用来决定日志的输出格式,他有以下几种类型:
- org.apache.log4j.PatternLayout(可以灵活的指定布局模式)
- org.apache.log4j.HTMLLayout(以HTML形式布局)
- org.apache.log4j.XMLLayout(以XML形式布局)
- org.apache.log4j.SerializedLayout(产生可以序列化的信息)
PatternLayout 可以让开发者依照 Conversion Pattern(转换模式)去定义输出格式。Conversion Pattern 有点像C语言的print打印函数,开发者可以通过一些预定的符号来指定日志的内容和和格式,这些符号的说明参见表1-1
表1-1 PatternLayout的格式
符号 | 描述 |
%r | 自程序开始运行到输出当前日志信息所消耗的毫秒数 |
%t | 输出产生该日志的线程全名 |
%level | 输出当前日志的级别 |
%d | 输出当前日志的日期和时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日 HH:mm:ss} |
%logger | 输出当前日志的 Logger 的名称 |
%msg%n | 输出日志信息的内容 |
例如,要为名为 “file” 的 Appender 配置的 PatternLayout 布局,可以采用如下配置代码:
<File name="file" fileName="app.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
采用以上PatternLayout 布局,从日志文件中看到的输出日志的形式如下:
11:10:06.758 [main] WARN helloappLogger -
This is a log message from the helloappLogger
以上日志内容中,PatternLayout 的预定符号与具体内容的对应关系如下:
- “d” 对应 “11:10:06.758”
- “%t”对应 “main”
- “%-5level” 中的“-5”设定日志级别在显示时占用五个空格位。
- “%logger{36}” 对应 “helloapplogger”
- “%msg%n” 对应具体的日志信息
1.2.4 Logger 组件的继承性
Log4J 提供了一个root Logger,它是所有Logger组件的“祖先”,以下是配置root Logger的代码:
<Root level="info">
<AppenderRef ref="console"/>
</Root>
用户可以在配置文件中方便的配置存在继承关系的Logger组件,凡是在符号“.” 后面的Logger组件都会成为在符号“.” 前面的Logger组件的子类。例如:
<Logger name="helloappLogger。childLogger" level="INFO" additivity="false">
<AppenderRef ref="console"/>
</Logger>
对于以上配置,childLogger就是helloappLogger的子类Logger组件。
Logger组件的继承关系有以下特点:
- 如果子类Logger组件没有配置日志级别,则将继承父类的日志级别。
- 如果子类Logger组件配置了日志级别,就不会继承父类的日志级别。
- 默认情况下,子类Logger组件会继承父类所有的所有的Appender ,把它们加入到自己的Appender 清单中。
- 如果在配置文件中把子类Logger组件的additivity属性设为false,那么他就不会继承父类的Appender 。additivity标志的默认值为true。
建议在配置文件中把子类的additivity属性设为false。否则,会导致子类Logger组件在输出日志信息时,除了会通过自身的Appender 输出日志,还会用父类的Appender 输出日志,这可能会导致重复输出日志的现象。
1.3 Log4J 的基本使用方法
首先需要在一个配置文件中配置Log4J 的各个组件,然后就可以在程序中通过lLog4J API来操作日志。
1.3.1 创建 Log4J 的配置文件
Log4J 支持 XML 格式的配置文件,这个配置文件的默认名为:log4j2.xml。这个配置文件的默认存放路径是 classpath 的根路径。如下例程1-1的log4j2.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<File name="file" fileName="app.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="console" />
</Root>
<Logger name="helloappLogger" level="warn" additivity="false">
<AppenderRef ref="file" />
<AppenderRef ref="console" />
</Logger>
<Logger name="helloappLogger.childLogger" level="debug" additivity="false">
<AppenderRef ref="console" />
</Logger>
</Loggers>
</Configuration>
比如Web应用的classpath 的根路径为 /WEB-INF/classes 目录。如果要存放到其他目录下,那么还需要在 web.xml文件中通过<context-param>元素进行配置:
<context-param>
<param-name>log4jConfiguration</param-name>
<param-value>/WEB-INF/conf/log4j2.xml</param-value>
</context-param>
以上配置代码表明Log4J的配置文件 log4j2.xml 存放在 WEB-INF/conf 目录下。
1.3.2 在程序中使用 Log4J
需要用到Log4J 的JAR文件。Log4J的下载地址为https://logging.apache.org/log4j。下载了Log4J 的压缩文件 apache-log4j-X-bin.zip后,解压后的目录中包含了Log4J的所有JAR文件。
程序中使用Log4J包含以下步骤:
(1)获得日志记录器
(2)输出日志信息
- 获得日志记录器
//获得 root Logger
Logger rootLogger = LogManager.getRootLogger();
//获得用户自定义的 Logger
Logger helloappLogger = Logger.getLogger("helloappLogger");
Logger childLogger = LogManager.getLogger("helloappLogger.childLogger");
以上的getRootLogger() 和getLogger() 方法会根据 Log4J 的配置文件中的信息来创建并返回相应的Logger对象。
如果不存在配置文件那么rootLogger以及子类 Logger会采用以下默认的配置。他的日志级别为error:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="console" />
</Root>
</Loggers>
</Configuration>
- 输出日志信息
获得了日志记录器Logger对象以后,就可以在程序代码中需要生成日志的地方。调用Logger的各种输出日志方法来输出不同级别的日志,例如:
helloapplogger.warn("This is a log message from the " + helloapplogger.getName());