1.10 Dynamic Configuration Updates
1.18 Remote Access and Serialization
2.2 Changing the Configuration
2.3 Simple Use, Ignoring Global Configuration
3.0 Appendix A: DTD for XMLFormatter Output
1.0 JavaTM Logging Overview
Logging APIS在J2SE API Specification.已经被详细描述。这个文档的目标是提供关键元素的概要。
1.1 Overview of Control Flow 控制流概要
应用程序调用Logger对象来记录日志。(例1.1) Loggers被以一种层次命名形式来组织起来,并且子Logger可能自它们的父Logger中继承一些属性。(例1.2)
应用程序调用Logger对象来记录日志。这些Logger对象定位LogRecord对象,这是一些被传送到Handler对象发布的对象(例1.3)。Loggers和Handlers都使用日志级,和(可选)过滤器来决定是否它们对某个特定记录感兴趣(例1.4)。当需要发布一个记录,一个Handler可以使用一个Formatter来局部化和格式化这条信息,对发布到I/O流之前(例1.5)。
每个Logger保持跟踪一些输出Handlers。默认情况下所有Loggers也发送它们的输出到它们的父Logger(例1.5)。但Logger也可能被配置成忽略上层的Handlers.(例1.6)
一些Handlers可能直接输出到其它Handlers. 例如,MemoryHandler维护一个LogRecord的内部环缓冲,并在触发事件它发布它的LogRecords通过一个目标Handler.在这种情况,任何信息都被链的最后Handler处理。
这些APIS都是有结构的,所以即使logging被禁用Logger APIS也是轻量级的。如果Logging在给出的日志级别被禁用,Logger会执行一个轻量的比较测试和返回。如果logging在指定的级别被启用,Logger仍然小心地把化费尽可能减少,在传LogRecord进入Handlers的时候。 特别地,本地化和格式化是延时的,当Handler请求它们的时候。例如,一个MemoryHandler可以维护一个LogRecords的通知缓冲,在没有化费格式化的时间。
1. 2Log Levels
每个日志信息都有一个相关的日志级。 这个级别粗糙指导日志信息的重要性和紧急性。Log Level 对象封装成一个整数,较高的数值代表较高的优先级。
Level类定义了七个标准日志级。范围从FINEST(最低优先级,最小数值)到SERVER(最高优先组,最大数值)
1. 3Loggers
正如前面规定的,客户代码发送一个日志请求到Logger对象。每个Logger保持跟踪它感兴趣的日志级,并丢弃小于这个级别的日志。
Loggers通常以实体命名,使用点分隔符命名,例如”java.awt”.这个命名空间是层次的,并于LogManager管理. 这个命名空间通常应该由JAVA包名字空间组织. 但不一定要跟随..例如,一个Logger名叫”java.awt”有可能处理一个java.awt包的日志请求,但也可能处理一个在sun.awt中的一个类的日志请求.
别外,也可以创建一个匿名Logger, 一个不出现在共享命名空间的Logger. 具体看1.14.
Logger跟踪它们的父Logger在日志命名空间. 一个Logger的父是它最近的祖先,在日志命名空间. 根Logger(名叫 ””)没有父. Anonymous logger are all given the root logger as their parent. Logger可能继承多个属性从它们的父(在Logger命名空间). 特别的,一个logger可能继承:
*日志级别. 如果一个Logger的级别是设置为null,那么这个日志会从父日志中继承第一个非null级别.
*Handlers.默认一个Logger会记录任何输出信息到它的父Handlers.,并在树中递归.
*资源包名. 如果一个日志有一个null资源包名,那么它会继承任何定义给它的父日志的资源包,并在树中递归.
1.4 Logging Methods
Logger类提供大量方便的方法来产生日志信息. 为了方便,有针对每个级别的方法,以日志级别命名. 例如叫”loger.log(Constants.WARING,…” 开发者可以调用方便的方法”:logger.warning(…”
有两种日志风格,适应不同风格的用户.
第一,有直接取得源类和源方法名的方法.这些方法是用来给开发者用的, 一些想快速定位日志信息的源的人. 这个风格的例子是:
void warning(String source Class, String Source Method, String msg);
第二, 有许多方法不直接取得源类和源方法名. 这些方法是用来给开发者用的, 一些想容易使用logging和不需要详细源信息的开发者.
第二种法方,Logging框架会尽力检测那个类和方法调用logging,并会添加这些信息到LogRecord.. 然而,很重要的是自动检测可能只是大约.
1.5 Handlers
StreamHandler
ConsoleHandler
FileHandler
SocketHandler
MemoryHandler
1.6 Formatters
SimpleFormatter
XMLFormatter
1. 7 logManager
有一个全局LogManager对象跟踪全局日志信息.这包含:
Logger的层次命名空间.
用配置文件读取的Logging控制属性
有一个并只有一个LogManager对像可以通过使用静态LogManager.getLogManager方法取得..
1.8 Configuration File
Logging配置可以使用一个logging配置文件(会在启动是被读取)来初始化.这个配置文件是以java.util.Properties的标准格式实现的.
该默认配置文件的位置和使用方法如下:
c:\program files\java\jdk1.5.0\jre\lib\logging.properties
D:\java>java -Djava.util.logging.config.file=d:\java\logging.properties testLogg
er
另一种选择,logging配置可以通过一个类(可以用来读取初始化信息的类)来初始化.这个机制充许配置数据从多种源读取,例如LDAP,JDBC等等.具体看LogManager API Specification.
有一些全局配置信息.,这些信息在LogManager描述中已详细说明,并包含一系列在启动是安装的root-level Handlers
初始化配置可以指定级别针对特定的loggers. 这些级别衩应用来已命令的logger 和任何在它的命令层次以下的logger. 各种级别以它们在配置文件中定义的顺序来应用.
初始配置可以包含任意的属性,供Handlers或运行日志子系统的使用. 为了方便,这些属性应该以handler类或主Logger的句子作为开头.
例如,MemoryHandler使用一个属性”java.util.logging.MemoryHandler.size”来决定默认ring缓冲大小.
1.9 default configuration
JRE上的默认配置只是一个默认,它可以被ISVs, 系统管理员, 和最终用户改变.
默认配置只限制磁盘空间. 这不提供给用户洪水般的信息,但保证捕获关键错误信息.
默认配置封装一个单独handler在root logger, 用来发送信息到控制台.
1.10 dynamic configuration updates
程序可以更新logging配置在运行时刻,使用以下的任意一种方法:
FileHandlers, MemoryHandlers and PrintHandlers 都可以以多种属性创建.
新Handlers可以添加,并旧的可以删除.
新Logger可以被创建并被特定Handlers支持.
级别可以在Handlers上设置.
1. 11私有方法
logging没有私有方法
1.12XML DTD
XML DTD是被XMLFormatter使用的.
DTD是设计来以”<log>”元素作为顶层文档,单独log记录被以”<record>”元素记录.
注意, 在JVM崩溃的事件中,它有可能没有被以</log>属性清楚终止一个XMLFormatter流.. 因此分析log记录的工具应该要准备没有终结的流.
1.13 Unique Message IDS
JAVA API不提供该功能,因此程序必需自己实现,并在信息字串中包含.
1. 14Security
主要的安装需求是不信任的代码不能改变日志配置,. 特别地,如果日志配置已经被设置为记录一系统日志信息到一个Handler.,这些的话,不信息代码不可能阻止或中断日志.
一个新的安装权限LoggingPermission被定义来控制更来到日志配置.
信任的程序可以调用任何日志配置API.不信任的applets则是另一回事. 不信任applets可以正常创建和使用已命名的Loggers.,但它们不允许改变日志控制设置.例如添加和删除Handlers.或改变日志级别.然而,不信任applets可以创建它们自己的”匿名”日志.并使用它. 匿名日志不注册在全局命名空间,并它们没有访问检查,允许即使不信任的代码改变它们的日志控制设置.
日志框架不尝试防止洪水攻击. 日志产生源的可靠性不能被检测.,因为当一个来自特定源类和源方法的日志记录被要求发布,它可能是伪造的! 同样,如果XMLFormatter之类的formatter,不尝试防止嵌套日志信息在信息字串. 这样, 一个欺骗日志记录可能包含欺骗XML记录在里面, 它字串使它看两来像另一个XML记录.
另外,日志框架不尝试保护自己来防止洪口攻击.任何客户都可以对日志框架以无义意信息隐藏重要信息的方法, 实施洪攻击..
1. 15 Configuration Management
API是结构化的,所以初始化信息作为属性从一个配置文件读取.. 配置信息可能通过调用多种日志类和对像改变.
另外, 在LogManager中有方法允许配置文件重新读取. 当这发生, 配置文件值会覆盖任何被程序改变的值.
1. 16Packaging
所有日志类是在java.*命名空间, 在java.util.loging包.
1.17 Localization 本地化
日信息可能需要被本地化.
每个Logger可能有一个跟它名字相关的资源包. 相应的资源包可以被用来影射未加工的字串和本地字串.
通常本地化会被Formatters执行. 为了方便,formatter类提供一个formaMessage方法来提供一些基本的本地化和格式化支持..
1. 18远程方法和串行化
正如多数JAVA平台APIS. 日志APIS设置来使用内部单独地止空间. 所有调用都有意本地化. 然而, 有时一些handlers可能希望转发它们的输出到它们其它系统. 有几种方法做这些事.
一些Handlers(例如SocketHandler)可能写数据到另外的系统使用XMLFormatter. 这提供一个简单, 标准,的格式可以解析和执行在多种系统.
一些Handlers可能希望传送LogRecord对像通过RMI. LogRecord类因此是可串行化的. 然而有一个问题是怎么样处理LogRecord参数. 一些Parameters可能没有串行化,并其它系统可能没有设计来串行化如此多的状态. 为解决这问题, LogRecord类有一个自定义writeObject方法转换参数为字串(使用Object.toString())在写出它们之前. 具体看LogRecord API Specification.
多类Logging类不尝试串行化. Loggers和handlers都是状态丰富的类,被绑在指定虚拟机. 在这种关系,它们类似java.io类, 也不串行化.
*******************************************************************************
例1. 1
import java.util.logging.Logger;
import java.util.logging.Level;
public class SimpleLogger{
public static void main(String[] args){
Logger s = Logger.getLogger("s");
//因为使用了Logger类,所以需要导入java.util.logging.Logger
s.log(Level.INFO, "this is a info");
////因为使用了Level类,所以需要导入java.util.logging.Level
}
}
//:~
D:\java\logging>java SimpleLogger
2005-3-13 11:09:10 SimpleLogger main
信息: this is a info
*******************************************************************************
例1. 2
import java.util.logging.Logger;
import java.util.logging.Level;
public class SimpleLogger{
public static void main(String[] args){
Logger s = Logger.getLogger("s");
//因为使用了Logger类,所以需要导入java.util.logging.Logger
s.log(Level.INFO, "this is a info");
//因为使用了Level类,所以需要导入java.util.logging.Level
s.setLevel(Level.WARNING);
Logger sb = Logger.getLogger("s.b");
sb.log(Level.INFO, "this is a sb.info");
//因为s设置了Level为WARNING,所以sb从它的父Logger s继承了该属性
//所以sb的Level为WARNING,所以INFO记录不会被发布
sb.log(Level.WARNING, "this is a sb.warning");
}
}
//:~
D:\java\logging>java SimpleLogger
2005-3-13 11:16:00 SimpleLogger main
信息: this is a info
2005-3-13 11:16:00 SimpleLogger main
警告: this is a sb.warning
D:\java\logging>
*******************************************************************************
例:1.3
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.logging.FileHandler;
import java.io.IOException;
public class SimpleLogger{
public static void main(String[] args){
Logger s = Logger.getLogger("s");
//因为使用了Logger类,所以需要导入java.util.logging.Logger
s.log(Level.INFO, "this is a info");
//因为使用了Level类,所以需要导入java.util.logging.Level
s.setLevel(Level.WARNING);
try{
FileHandler myFileHandler = new FileHandler("SimpleLogger.log");
//因为使用了FileHandler类,所以需要导入java.util.logging.FileHandler
//也因为上句产生了IOException,所以了导入该EXCEPTION,并处理它
s.addHandler(myFileHandler);
/*
因为在c:\program files\java\jdk1.5.0\jre\lib\logging.properties
默认设置了ConsoleHandler,所以不添加Handler都会在控制台看到日志
现在添加了myFileHandler,就会在文件中看到日志(默认为XML格式)
*/
}catch(IOException e){};
Logger sb = Logger.getLogger("s.b");
sb.log(Level.INFO, "this is a sb.info");
//因为s设置了Level为WARNING,所以sb从它的父Logger s继承了该属性
//所以sb的Level为WARNING,所以INFO记录不会被发布
sb.log(Level.WARNING, "this is a sb.warning");
}
}
//:~
D:\java\logging>java SimpleLogger
2005-3-13 11:31:20 SimpleLogger main
信息: this is a info
2005-3-13 11:31:20 SimpleLogger main
警告: this is a sb.warning
D:\java\logging>
<?xml version="1.0" encoding="GBK" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
<date>2005-03-13T11:50:41</date>
<millis>1110743441640</millis>
<sequence>2</sequence>
<logger>s.b</logger>
<level>WARNING</level>
<class>SimpleLogger</class>
<method>main</method>
<thread>10</thread>
<message>this is a sb.warning</message>
</record>
</log>
*******************************************************************************
例:1.4
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.logging.Filter;
import java.util.logging.LogRecord;
import java.util.logging.FileHandler;
import java.io.IOException;
public class SimpleLogger{
public static void main(String[] args){
Logger s = Logger.getLogger("s");
//因为使用了Logger类,所以需要导入java.util.logging.Logger
s.log(Level.INFO, "this is a info");
//因为使用了Level类,所以需要导入java.util.logging.Level
s.setLevel(Level.WARNING);
s.setFilter(new MyFilter());
try{
FileHandler myFileHandler = new FileHandler("SimpleLogger.log");
//因为使用了FileHandler类,所以需要导入java.util.logging.FileHandler
//也因为上句产生了IOException,所以了导入该EXCEPTION,并处理它
s.addHandler(myFileHandler);
/*
因为在c:\program files\java\jdk1.5.0\jre\lib\logging.properties
默认设置了ConsoleHandler,所以不添加Handler都会在控制台看到日志
现在添加了myFileHandler,就会在文件中看到日志(默认为XML格式)
*/
}catch(IOException e){};
s.log(Level.WARNING, "this is a s.warning");
//因为myFilter会过滤掉上面这条日志,所以它不会被记录(也就是不显示出来)
Logger sb = Logger.getLogger("s.b");
sb.log(Level.INFO, "this is a sb.info");
//因为s设置了Level为WARNING,所以sb从它的父Logger s继承了该属性
//所以sb的Level为WARNING,所以INFO记录不会被发布
sb.log(Level.WARNING, "this is a sb.warning");
}
}
class MyFilter implements Filter{
//因为使用Filter,所以需要导入java.util.logging.Filter;
public boolean isLoggable(LogRecord record){
//因为使用LogRecord,所以需要导入java.util.logging.LogRecord
if(record.getLevel().intValue() > java.util.logging.Level.WARNING.intValue()){
return true;
}
else
return false;
}
}
//:~
D:\java\logging>java SimpleLogger
2005-3-13 11:50:41 SimpleLogger main
信息: this is a info
2005-3-13 11:50:41 SimpleLogger main
警告: this is a sb.warning
D:\java\logging>
<?xml version="1.0" encoding="GBK" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
<date>2005-03-13T11:50:41</date>
<millis>1110743441640</millis>
<sequence>2</sequence>
<logger>s.b</logger>
<level>WARNING</level>
<class>SimpleLogger</class>
<method>main</method>
<thread>10</thread>
<message>this is a sb.warning</message>
</record>
</log>
***********************************************************************
例1. 5
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.logging.Filter;
import java.util.logging.LogRecord;
import java.util.logging.FileHandler;
import java.util.logging.SimpleFormatter;
import java.io.IOException;
public class SimpleLogger{
public static void main(String[] args){
Logger s = Logger.getLogger("s");
//因为使用了Logger类,所以需要导入java.util.logging.Logger
s.log(Level.INFO, "this is a info");
//因为使用了Level类,所以需要导入java.util.logging.Level
s.setLevel(Level.WARNING);
s.setFilter(new MyFilter());
try{
FileHandler myFileHandler = new FileHandler("SimpleLogger.log");
//因为使用了FileHandler类,所以需要导入java.util.logging.FileHandler
//也因为上句产生了IOException,所以了导入该EXCEPTION,并处理它
myFileHandler.setFormatter(new SimpleFormatter());
//因为使用了SimpleFormatter,所以要导入java.util.logging.SimpleFormatter
//因为设置了Formatter为SimpleFormatter,所以文件的内容会变成简单格式而不是XML格式
s.addHandler(myFileHandler);
/*
因为在c:\program files\java\jdk1.5.0\jre\lib\logging.properties
默认设置了ConsoleHandler,所以不添加Handler都会在控制台看到日志
现在添加了myFileHandler,就会在文件中看到日志(默认为XML格式)
*/
}catch(IOException e){};
s.log(Level.WARNING, "this is a s.warning");
//因为myFilter会过滤掉上面这条日志,所以它不会被记录(也就是不显示出来)
Logger sb = Logger.getLogger("s.b");
sb.log(Level.INFO, "this is a sb.info");
//因为s设置了Level为WARNING,所以sb从它的父Logger s继承了该属性
//所以sb的Level为WARNING,所以INFO记录不会被发布
sb.log(Level.WARNING, "this is a sb.warning");
}
}
class MyFilter implements Filter{
//因为使用Filter,所以需要导入java.util.logging.Filter;
public boolean isLoggable(LogRecord record){
//因为使用LogRecord,所以需要导入java.util.logging.LogRecord
if(record.getLevel().intValue() > java.util.logging.Level.WARNING.intValue()){
return true;
}
else
return false;
}
}
//:~
D:\java\logging>java SimpleLogger
2005-3-13 12:11:48 SimpleLogger main
信息: this is a info
2005-3-13 12:11:49 SimpleLogger main
警告: this is a sb.warning
D:\java\logging>
2005-3-13 12:11:49 SimpleLogger main
警告: this is a sb.warning
例1. 6
使用如下方法即可
java.util.logging.Logger
void
setUseParentHandlers(boolean useParentHandlers)
Specify whether or not this logger should send its output to it's parent Logger.