简介
任何的软件系统,日志都是非常重要的一部分。良好统一的日志规范会大大提高应用程序的可维护性、可靠性,并进而提高开发效率,指导业务。在早期,Java工程师往往都是利用 System.err.println
或 System.out.println
将 Java 应用内部的状态信息或错误消息打印到系统的控制台中,这种简易的保存方式显然无法满足保存日志信息所需的持久性和便利性等要求。所以,SUN 公司在发布 JDK 1.4 时,在 java.util.logging
包提供了一个日志框架。通常,直接使用 JUL
表示该框架。利用 JUL
的 API,Java 工程师可以输出不同重要级别(比如 error、info 和 debug)的日志信息到一个集中的位置(比如 rotating file)。同时,Java 工程师可以完全控制输出日志信息的重要级别和输出格式。
框架概述
笔者认为,学习任何一门新技术或新概念的最佳方式都是 先整体后细节。所以,笔者先抛出 JUL
的框架概述图:
- Application 将多种级别(level)的日志信息传递给 Logger 对象;
- Logger 对象使用 Level 和 Filter 对接受到的日志信息进行过滤;将日志信息转换成 LogRecord 对象后传递给 Handler 对象;
- Handler 对象使用 Level 和 Filter 对接受到的 LogRecord 对象进行过滤;并使用 Formatter 格式化 LogRecord 对象并输出到外部的文件或者数据库中。
- Logger 对象之间存在着父子层级关系,这种层级关系是通过 Logger 对象的名称来决定。
LogManager(日志管理器)
在 JUL
被 JVM 加载时,会有一个 LogManager 对象被创建出来作为全局组件而存在。这个全局组件主要负责创建和管理 Logger 对象,同时生成和维护全局的日志配置信息,这个全局配置信息可能是从配置文件中读取而来,也可能是从配置类读取而来。在默认配置的情况下,LogManager 只创建一个Level 为 Level.INFO 的 ConsoleHandler,该 ConsoleHandler 的日志信息输出目的地是 System.err
。同时,这个 ConsoleHandle 属于 LogManager 中的 root logger(根记录器)。
在 Java 应用所使用的某个 JVM 中,有且仅有一个 LogManager 对象存在。通常,Java 工程师可以使用如下的代码获取该 LogManager 实例对象:
LogManager manager = LogManager.getLogManager();
通常情况下,Java 工程师都不要与该 LogManager 对象直接交互,除非某些特殊情形。比如重新加载配置类或配置文件,这种情况可以使用如下所示的实例代码:
// 重读配置类或配置文件
manager.readConfiguration();
// 重读特定位置的配置类与配置文件
manager.readConfiguration(inputStream);
通过使用 LogManager 的 getLoggingMXBen() 方法,可以获取一个 MXBen(Java Management Extensions)。简单地实例代码如下:
LoggingMXBean mxBean = manager.getLoggingMXBen();
当然,LogManager 还有很多其他的方法与特性,有兴趣的同学可以进一步查看 JavaDoc 或者源码。
Logger(日志记录器)
JUL
的主要入口类是 java.util.Logger
。进行日志记录的第一步就是创建一个 Logger 对象:
Logger logger = Logger.getLogger("www.tiantianbianma.com");
传递给 Logger 类中 getLogger 工厂方法的字符串 “www.tiantianbianma.com” 就是所创建的 Logger 对象的名称。
在实际的项目开发中,一般的做法是使用当前 Java 类的名称或所在包的名称作为 Logger 对象的名称。一个常见的示例代码如下:
public class Application {
Logger logger = Logger.getLogger(this.getClass().getName());
}
如果需要一个静态的 Logger 对象,示例代码如下:
public class Application {
static Logger logger = Logger.getLogger(Application.class.getName());
}
如果需要查询 Logger 对象的名称,可以使用 getName() 方法。
String loggerName = logger.getName();
使用 Logger 对象进行日志记录的方式很多,部分方式的示例代码如下:
log (Level level, String message);
log (Level level, String message, Object param);
logp (Level level, String sourceClass, String sourceMethod, String msg);
logrb (Level level, String sourceClass, String sourceMethod, String bundle, String msg);
entering (String sourceClass, String sourceMethod);
...