log4j有3个主要组成部分:loggers(记录器)、appenders(挂载点)和layouts(布局)。这三种组件一起工作,使开发人员能够按照信息类型和级别记录日志,并且在运行时控制信息的格式和记录位置。
日志的层次结构
相对于平台的System.out.println,所有Logger API的首要优势是能够禁止某些特定的日志信息的输出,而让其它日志信息打印无阻。这样的能力要求对日志信息按照开发人员指定的标准进行分类。正是基于此,之前版本的log4j以category作为其中心概念。从1.2版本开始,Logger类取代了Category类。对于那些熟悉log4j的早期版本, Logger类可以被视为仅仅是Category类的别名。
Logger是命名实体,其名字是大小写敏感的,遵守以下分层的命名规则:
- 如果Logger A的名称后面加一个点,是Logger B名称的前缀,则A是B的祖先。
- 如果Logger A与其后代Logger B之前没有其它祖先,则A是B的父亲。
例如:名为“com.foo”的Logger是“com.foo.Bar”的父亲。同样,“java”是“java.util”的父亲,是“java.util.Vector”的祖先。此命名方案应该是大多数开发人员所熟悉的。
根记录器(root logger)在记录器(logger)的层次结构的顶部。它有两个特点:
- 总是存在的。
- 不能通过名称获取。
调用类静态方法Logger.getRootLogger获取根记录器。所有其他记录器通过类的静态方法Logger.getLogger进行实例化和检索。这个方法需要记录器的名称作为一个参数。使用相同的名称调用getLogger
方法将总是返回同一个Logger对象。因此,不需要将记录器对象的引用传递过来,就可以在代码的任意位置获取已经设定的记录器对象。与生物学上的父子关系矛盾的一点是,可以按任意顺序创建或配置记录器对象,即祖先记录器对象可以晚于子孙记录器对象而实例化。
下面列出了Logger类的一些基本方法。
package org.apache.log4j; public class Logger { // Creation & retrieval methods: public static Logger getRootLogger(); public static Logger getLogger(String name); // printing methods: 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); // generic printing method: public void log(Level l, Object message); }
记录器可能被分配级别。级别定义在org.apache.log4j.Level 类中。包括:TRACE,DEBUG,INFO,WARN,ERROR和FATAL。你可以通过继承Level类的子类来自定义级别,不过不鼓励这么做。更好的方法将在后面解释。
如果一个记录器没有被分配一个级别,那么它的级别继承自与其最接近且已分配级别的祖先。
为了确保所有的记录器最终可以继承一个级别,根记录器总是被分配一个级别。
通过调用logger实例的打印方法记录日志。这些打印方法包括debug、info、warn、error、fatal、log。
打印方法决定了一个日志请求的级别。例如,如果c是一个Logger实例,c.info("..")是INFO级别的日志请求。
当日志请求的级别高于或等于记录器的级别,日志记录请求才是有效的。否则,该请求被禁止。没有指定级别的logger将从记录器的层次结构中继承。这个规则总结如下。写道
日志请求的级别是p,日志记录器的级别为q,仅当p>=q时,该日志请求有效。
这个规则是log4j的核心。标准的等级高低是:DEBUG < INFO < WARN < ERROR < FATAL。
Log4j的环境通常是在程序初始化时进行配置,推荐的方式是读取配置文件。稍后将讨论这种方法。
Log4j可以很容易地为记录器命名。在每一个类中以类的完整限定名初始化一个记录器对象。这是非常有用、直观的一种定义记录器的方法,可以很直观地识别出日志信息的来源。当然,这只是可能的方法中的一种,开发人员可以根据自己的期望来定义记录器。