【转】Java Util Logging技术介绍

来源:互联网 发布:男士钱包 知乎 编辑:程序博客网 时间:2024/05/16 15:07

1.1 Overview of Control Flow控制流概要

 

应用程序调用Logger对象来记录日志。(1.1) Loggers被以一种层次命名形式来组织起来,并且子Logger可能自它们的父Logger中继承一些属性。(1.2)

 

应用程序调用Logger对象来记录日志。这些Logger对象定位LogRecord对象,这是一些被传送到Handler对象发布的对象(1.3)LoggersHandlers都使用日志级,和(可选)过滤器来决定是否它们对某个特定记录感兴趣(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.2 Log Levels

每个日志信息都有一个相关的日志级。这个级别粗糙指导日志信息的重要性和紧急性。Log Level对象封装成一个整数,较高的数值代表较高的优先级。

 

Level类定义了七个标准日志级。范围从FINEST(最低优先级,最小数值)到SERVER(最高优先组,最大数值)

 

1.3 Loggers

正如前面规定的,客户代码发送一个日志请求到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 testLogger

 

另一种选择,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,系统管理员, 和最终用户改变.

默认配置只限制磁盘空间.这不提供给用户洪水般的信息,但保证捕获关键错误信息.

默认配置封装一个单独handlerroot logger,用来发送信息到控制台.

 

1.10 dynamic configuration updates

程序可以更新logging配置在运行时刻,使用以下的任意一种方法:

FileHandlers, MemoryHandlers and PrintHandlers都可以以多种属性创建.

Handlers可以添加,并旧的可以删除.

Logger可以被创建并被特定Handlers支持.

级别可以在Handlers上设置.

 

1. 11私有方法

logging没有私有方法

 

1.12 XML DTD

XML DTD是被XMLFormatter使用的.

DTD是设计来以”<log>”元素作为顶层文档,单独log记录被以”<record>”元素记录.

 

注意,JVM崩溃的事件中,它有可能没有被以</log>属性清楚终止一个XMLFormatter..因此分析log记录的工具应该要准备没有终结的流.

 

1.13 Unique Message IDS

JAVA API不提供该功能,因此程序必需自己实现,并在信息字串中包含.

 

1. 14 Security

主要的安装需求是不信任的代码不能改变日志配置,.特别地,如果日志配置已经被设置为记录一系统日志信息到一个Handler.,这些的话,不信息代码不可能阻止或中断日志.

一个新的安装权限LoggingPermission被定义来控制更来到日志配置.

 

信任的程序可以调用任何日志配置API.不信任的applets则是另一回事.不信任applets可以正常创建和使用已命名的Loggers.,但它们不允许改变日志控制设置.例如添加和删除Handlers.或改变日志级别.然而,不信任applets可以创建它们自己的”匿名”日志.并使用它.匿名日志不注册在全局命名空间,并它们没有访问检查,允许即使不信任的代码改变它们的日志控制设置.

 

日志框架不尝试防止洪水攻击.日志产生源的可靠性不能被检测.,因为当一个来自特定源类和源方法的日志记录被要求发布,它可能是伪造的!同样,如果XMLFormatter之类的formatter,不尝试防止嵌套日志信息在信息字串.这样, 一个欺骗日志记录可能包含欺骗XML记录在里面,它字串使它看两来像另一个XML记录.

 

另外,日志框架不尝试保护自己来防止洪口攻击.任何客户都可以对日志框架以无义意信息隐藏重要信息的方法,实施洪攻击..

 

1.15 Configuration Management

API是结构化的,所以初始化信息作为属性从一个配置文件读取..配置信息可能通过调用多种日志类和对像改变.

 

另外,LogManager中有方法允许配置文件重新读取.当这发生, 配置文件值会覆盖任何被程序改变的值.

 

1. 16 Packaging

所有日志类是在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类不尝试串行化. Loggershandlers都是状态丰富的类,被绑在指定虚拟机.在这种关系,它们类似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设置了LevelWARNING,所以sb从它的父Logger s继承了该属性

             //所以sbLevelWARNING,所以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设置了LevelWARNING,所以sb从它的父Logger s继承了该属性

             //所以sbLevelWARNING,所以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设置了LevelWARNING,所以sb从它的父Logger s继承了该属性

             //所以sbLevelWARNING,所以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

                    //因为设置了FormatterSimpleFormatter,所以文件的内容会变成简单格式而//不是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设置了LevelWARNING,所以sb从它的父Logger s继承了该属性

             //所以sbLevelWARNING,所以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

 

原创粉丝点击