深探java.util.logging包

80酷酷网    80kuku.com

1.0 Java Logging Overview    1.1 Overview of Control Flow      1.2 Log Levels     1.3 Loggers     1.4 Logging Methods     1.5 Handlers     1.6 Formatters     1.7 The LogManager     1.8 Configuration File     1.9 Default Configuration     1.10 Dynamic Configuration Updates     1.11 Native Methods     1.12 XML DTD     1.13 Unique Message IDs     1.14 Security     1.15 Configuration Management     1.16 Packaging     1.17 Localization     1.18 Remote Access and Serialization2.0 Examples     2.1 Simple Use     2.2 Changing the Configuration     2.3 Simple Use, Ignoring Global Configuration     2.4 Sample XML Output3.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.



 




分享到
  • 微信分享
  • 新浪微博
  • QQ好友
  • QQ空间
点击: