日志记录器

每个Java程序员都熟悉System.out.println插入有问题的代码中,用以观察程序行为。

如何采用日志记录器

Java设计了日志API,日志管理系统管理一个通过调用Logger.getGlobal()获得的默认日志记录器(Logger)。使用info方法记录一条信息消息:

Logger.getGlobal().info("Opening file" + filename);

记录打印出来的格式:

Aug 02,2019 22:25:34 PM com.mycompany.MyClass read INFO:Opening file data.txt

系统会自动添加时间、调用类的类名和方法。

但是,如果你调用Logger.getGlobal().setLevel(Level.OFF),则info方法将不会记录日志。

在应用程序中,不会将所有的记录写入一个单独的全局日志记录器。相反,我们可以自行定义日志记录器。

当首次根据给定的名字请求一个日志记录器时,它会被创建出来。

Logger logger = Logger.getLogger("com.mycompany.myapp");

后面调用相同的名称时,会返回同一个日志记录器对象。

日志级别

日志有7种级别:SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST。

默认情况下,前3个级别的日志会被记录下来。可以设置不同的阈值,例如:

Logger.setLevel(Level.FINE);

每一个级别都有相应的记录日志的方法,例如:

Logger.warning(message);
Logger.fine(message);
...

另外一种方式,如果日志级别是一个变量,则可以使用Log方法并提供日志级别:

Level level = ...;
logger.log(level,message);

日志记录的普遍用途是记录意外的异常。有两个便利的方法可以在记录中包含异常的描述信息。

void log(Level l,String message,Throwable t)
void throwing(String className,String methodName,Throwable t)
典型的用法: 
try {
	...
}
catch (IoException ex){
	logger.log(Level.SEVERE,"Cannot read configuration" , ex);
}
和
if(...){
	IOException ex = new IOException("Cannot read configuration");
	logger.throwing("com.mycompany.mylib.Reader","read" , ex);
	thow ex;
}

注意:如果想以多种语言记录日志,以便用户理解日志信息,则需要调用方法将日志本地化。

void logrb(Level level, ResourceBundle bundle , String msg, Object ... params)
void logrb(Level level, ResourceBundle bundle , String msg, Throwable thrown)

日志记录的配置项

通过编辑配置文件,可以改变日志配置系统的不同属性。默认的配置文件位于jre/lib/logging.properties。如果要使用其他的配置文件,则需要在启动应用时设置java.util.logging.config.file属性为你指定的配置文件位置。

java Djava.util.logging.config.file = configFile MainClass

为了改变默认的日志记录级别,编辑配置文件,并且修改下面一行:

.level = INFO

通过添加新行,例如:com.mycompany.myapp.level = FINE,也可以自行指定日志记录级别,也就是,在日志记录器名称后面加上.level后缀。

日志处理器

默认情况下,日志记录器将记录发送给ConsoleHandler, ConsoleHandler通过System.err流打印出日志。具体来说,就是日志记录器将记录发送给父处理器,而他们的终极祖先有一个ConsoleHandler。 类似于日志记录器,处理器也有一个日志级别。一条日志想要被记录下来,则它的日志级别必须高于记录器和处理器的阈值。日志管理器配置文件将默认的控制太管理器的日志级别设为:

java.util.logging.ConsoleHandler.level = INFO;

为了记录INFO级别的记录,必须在配置文件中设置默认日志记录器的级别和处理器的级别。

默认情况下,一个日志记录器将记录发送给自己的处理器和父处理器。后者会将INFO及以上级别的日志发送给控制台。如果不想这些记录被记录两次,则可以将useParentHandlers属性改为false即可。

过滤器和格式化过滤器

除了通过级别过滤日志,每一个日志记录器和处理器也实现了Filter接口的额外过滤器,Filter接口是一个带有如下方法的函数式接口:

boolean isLoggable(LogRecord record)

要给日志记录器或者处理器安装一个过滤器,需要调用setFilter方法(一次最多只能有一个过滤器)。 ConsoleHandler和FileHandler类似于文本和XML格式发送日志。但是也可以自定义格式。继承Formatter类并覆盖如下的方法:

String format(LogRecord record)

格式化数据并且返回结果字符串。

String formatMessage(LogRecord record)

FormatMessage方法格式化记录的消息部分,替代参数以及应用本地化。 许多文本格式(例如XML)需要获取包围着格式记录的头部和尾部。需要覆盖方法:

String getHead(Handler h)
String getTail(Handler h)

最后,调用setFormatter方法将格式化器安装到处理器中。