﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-hiker-随笔分类-Tabloid</title><link>http://www.blogjava.net/hiker/category/21208.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 18 Sep 2007 08:01:24 GMT</lastBuildDate><pubDate>Tue, 18 Sep 2007 08:01:24 GMT</pubDate><ttl>60</ttl><item><title>关于struts2启动tomcat的错误</title><link>http://www.blogjava.net/hiker/archive/2007/09/18/146158.html</link><dc:creator>hiker</dc:creator><author>hiker</author><pubDate>Tue, 18 Sep 2007 06:43:00 GMT</pubDate><guid>http://www.blogjava.net/hiker/archive/2007/09/18/146158.html</guid><wfw:comment>http://www.blogjava.net/hiker/comments/146158.html</wfw:comment><comments>http://www.blogjava.net/hiker/archive/2007/09/18/146158.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hiker/comments/commentRss/146158.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hiker/services/trackbacks/146158.html</trackback:ping><description><![CDATA[创建struts.properties<br />
struts.locale=en_utf-8<br />
（注：如不创建此文件也可以，但在启动tomcat时候会有个警告：警告: <font color="#c00000"><strong>Settings: Could not parse struts.locale setting, substituting default VM locale</strong></font>） 
<img src ="http://www.blogjava.net/hiker/aggbug/146158.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hiker/" target="_blank">hiker</a> 2007-09-18 14:43 <a href="http://www.blogjava.net/hiker/archive/2007/09/18/146158.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Commons-logging + Log4j 入门指南(转摘)</title><link>http://www.blogjava.net/hiker/archive/2007/09/13/144766.html</link><dc:creator>hiker</dc:creator><author>hiker</author><pubDate>Thu, 13 Sep 2007 03:03:00 GMT</pubDate><guid>http://www.blogjava.net/hiker/archive/2007/09/13/144766.html</guid><wfw:comment>http://www.blogjava.net/hiker/comments/144766.html</wfw:comment><comments>http://www.blogjava.net/hiker/archive/2007/09/13/144766.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hiker/comments/commentRss/144766.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hiker/services/trackbacks/144766.html</trackback:ping><description><![CDATA[http://touch.javaeye.com/blog/31632<br />
<img src ="http://www.blogjava.net/hiker/aggbug/144766.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hiker/" target="_blank">hiker</a> 2007-09-13 11:03 <a href="http://www.blogjava.net/hiker/archive/2007/09/13/144766.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>几篇关于线程的文章</title><link>http://www.blogjava.net/hiker/archive/2007/09/07/143342.html</link><dc:creator>hiker</dc:creator><author>hiker</author><pubDate>Fri, 07 Sep 2007 03:02:00 GMT</pubDate><guid>http://www.blogjava.net/hiker/archive/2007/09/07/143342.html</guid><wfw:comment>http://www.blogjava.net/hiker/comments/143342.html</wfw:comment><comments>http://www.blogjava.net/hiker/archive/2007/09/07/143342.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hiker/comments/commentRss/143342.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hiker/services/trackbacks/143342.html</trackback:ping><description><![CDATA[http://blog.csdn.net/buaawhl/archive/2005/01/18/257653.aspx<br />
<br />
http://blog.csdn.net/buaawhl/archive/2003/03/21/19839.aspx<br />
<br />
http://blog.csdn.net/buaawhl/archive/2003/03/18/19837.aspx<br />
<br />
http://blog.csdn.net/buaawhl/archive/2003/03/11/19833.aspx
<img src ="http://www.blogjava.net/hiker/aggbug/143342.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hiker/" target="_blank">hiker</a> 2007-09-07 11:02 <a href="http://www.blogjava.net/hiker/archive/2007/09/07/143342.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts2学习，http://www.blogjava.net/max/</title><link>http://www.blogjava.net/hiker/archive/2007/04/16/110908.html</link><dc:creator>hiker</dc:creator><author>hiker</author><pubDate>Mon, 16 Apr 2007 03:06:00 GMT</pubDate><guid>http://www.blogjava.net/hiker/archive/2007/04/16/110908.html</guid><wfw:comment>http://www.blogjava.net/hiker/comments/110908.html</wfw:comment><comments>http://www.blogjava.net/hiker/archive/2007/04/16/110908.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hiker/comments/commentRss/110908.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hiker/services/trackbacks/110908.html</trackback:ping><description><![CDATA[<a href="http://lavasoft.blog.51cto.com/blog/62575/dir/1"><br />
http://www.blogjava.net/max/<br />
<br />
<br />
一个优秀的bolg，学习之<br />
http://lavasoft.blog.51cto.com/blog/62575/dir/1</a> 
<img src ="http://www.blogjava.net/hiker/aggbug/110908.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hiker/" target="_blank">hiker</a> 2007-04-16 11:06 <a href="http://www.blogjava.net/hiker/archive/2007/04/16/110908.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java调试的变迁：从System.out.println到log4j【zz】 </title><link>http://www.blogjava.net/hiker/archive/2007/04/03/108198.html</link><dc:creator>hiker</dc:creator><author>hiker</author><pubDate>Tue, 03 Apr 2007 06:17:00 GMT</pubDate><guid>http://www.blogjava.net/hiker/archive/2007/04/03/108198.html</guid><wfw:comment>http://www.blogjava.net/hiker/comments/108198.html</wfw:comment><comments>http://www.blogjava.net/hiker/archive/2007/04/03/108198.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hiker/comments/commentRss/108198.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hiker/services/trackbacks/108198.html</trackback:ping><description><![CDATA[<div class=postText align=left><font face=Verdana size=2><strong><u><font color=#cc0000><font size=3>jungleford如是说 <img title=log4j的logo height=55 alt=o_log4j.jpg src="http://www.blogjava.net/images/blogjava_net/jungleford/924/o_log4j.jpg" width=82 border=0></font><br><br></font></u></strong>&nbsp;&nbsp;&nbsp;&nbsp;用惯了<a href="http://msdn.microsoft.com/visualc/" target=_blank><font color=#618b2c><u>VC</u></font></a>的人刚接触<a href="http://java.sun.com/" target=_blank><font color=#618b2c><u>Java</u></font></a>大概很不习惯代码的调试，的确，在<a href="http://www.microsoft.com/" target=_blank><font color=#618b2c><u>M$</u></font></a>的大部分IDE都做得相当出色，包括像VJ++这样一直被Java程序员称为是&#8220;垃圾&#8221;的类库（记得以前在<a href="http://bbs.ustc.edu.cn/" target=_blank><font color=#618b2c><u>瀚海星云</u></font></a>的<a href="http://bbs.ustc.edu.cn/cgi-bin/bbsdoc?board=Java" target=_blank><font color=#618b2c><u>Java版</u></font></a>提有关VJ问题的人是有可能被封的，^_^），它的开发工具在调试上都相当容易。Java也有命令行方式的调试和IDE的调试，但现在的像<a href="http://www.borland.com/jbuilder/" target=_blank><font color=#618b2c><u>JB</u></font></a>这样的玩意又是个庞然大物，低配置的机器可能就是个奢望，不像VC那样。怎么办呢，高手们说，&#8220;我的jdb用得贼熟练&#8221;，那我会报以景仰的目光，像我这样的菜鸟基本上就没使过jdb，还是老老实实在代码里面System.out.println(...)。直到1996年一个叫做&#8220;欧洲安全电子市场&#8221;（E.U. <a href="http://www.semper.org/" target=_blank><font color=#618b2c><u>SEMPER</u></font></a>）的项目启动，&#8220;调试&#8221;不再是一件&#8220;体力活&#8221;，而是一种软件设计的艺术，这个项目组开发的日志管理接口后来成为<a href="http://www.apache.org/" target=_blank><font color=#618b2c><u>Apache</u></font></a> <a href="http://jakarta.apache.org/" target=_blank><font color=#618b2c><u>Jakarta</u></font></a>项目中的一员，它就是现在我们所熟悉的<a href="http://logging.apache.org/" target=_blank><font color=#618b2c><u>log4j</u></font></a>。下面的文字将概要介绍与Java日志记录相关的一些技术，目的不是让您放弃老土的System.out.println(...)，而是说，在Java的世界里可以有许多种选择，你今天觉得掌握了一件高级武器，明天可能就是&#8220;过时&#8221;的了，呵呵。
<p class=postText align=left><strong><u><font color=#cc0000><font size=3>始祖：System.out.println(...)</font><br><br></font></u></strong>&nbsp;&nbsp;&nbsp;&nbsp;为什么还是要一再提到它？毕竟我们的习惯不是那么容易改变的，而且<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html" target=_blank><font color=#618b2c><u>System</u></font></a>.<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#out" target=_blank><font color=#618b2c><u>out</u></font></a>（别忘了还有System.<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#err" target=_blank><font color=#618b2c><u>err</u></font></a>）是一个直接和控制台打交道的<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/PrintStream.html" target=_blank><font color=#618b2c><u>PrintStream</u></font></a>对象，是终端显示的基础，高级的Logger要在终端显示日志内容，就必然会用到这个。一个小规模的程序调试，恰当地使用System.out.<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/PrintStream.html#println(java.lang.Object)" target=_blank><font color=#618b2c><u>println</u></font></a>(...)我认为仍然是一种最方便最有效的方法，所以我们仍把它放在最开始，以示不能&#8220;数典忘祖&#8221; :)</p>
<p class=postText align=left><strong><u><font color=#cc0000><font size=3>不常用的关键字：assert</font><br><br></font></u></strong>&nbsp;&nbsp;&nbsp;&nbsp;assert对多数人来讲可能还比较陌生，它也是一个调试工具，好像是<a href="http://java.sun.com/j2se/1.4.2/" target=_blank><font color=#618b2c><u>J2SE 1.4</u></font></a>才加进来的东东，一种常见的用法是：</p>
<p class=postText align=left>&nbsp;<font size=-1><strong><font color=#ff0000>assert</font></strong> (布尔表达式);</font></p>
<p class=postText align=left><font size=-1><br>&nbsp;&nbsp;&nbsp;&nbsp;当表达式为true时没有任何反映，如果为false系统将会抛出一个<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/AssertionError.html" target=_blank><font color=#618b2c><u>AssertionError</u></font></a>。如果你要使用assert，在编译时必须加上&#8220;<strong>-source 1.4</strong>&#8221;的选项，在运行时则要加上&#8220;<strong>-ea</strong>&#8221;选项。<br></font></p>
<p class=postText align=left><strong><u><font color=#cc0000><font size=3>后生可畏：Java Logging API一瞥</font><br><br></font></u></strong>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(...)对于较高要求的用户是远远不够的，它还不是一个日志系统，一个比较完善的日志系统应当有输出媒介、优先级、格式化、日志过滤、日志管理、参数配置等功能。伴随J2SE 1.4一起发布的Java日志包<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/package-summary.html" target=_blank><font color=#618b2c><u>java.util.logging</u></font></a>适时地满足了我们的初步需求，在程序中按一定格式显示和记录丰富的调试信息已经是一件相当easy的事情。</p>
<p class=postText align=left><strong>1. 日志记录器：Logger</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html" target=_blank><font color=#618b2c><u>Logger</u></font></a>是一个直接面向用户的日志功能调用接口，从用户的角度上看，它完成大部分日志记录工作，通常你得到一个Logger对象，只需要使用一些简单方法，譬如info，warning，log，logp，logrb等就能完成任务，简单到和System.out.println(...)一样只用一条语句，但后台可能在向控制台，向文件，向数据库，甚至向网络同时输出该信息，而这个过程对用户是完全透明的。<br>&nbsp;&nbsp;&nbsp;&nbsp;在使用Logger之前，首先需要通过<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#getLogger(java.lang.String)" target=_blank><font color=#618b2c><u>getLogger</u></font></a>()或<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#getAnonymousLogger()" target=_blank><font color=#618b2c><u>getAnonymousLogger</u></font></a>()静态方法得到一个Logger对象（想想看，这里是不是设计模式当中的&#8220;工厂方法&#8221;的一个实实在在的应用？可以参考一下Logger的源代码，你就明白<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/LogManager.html" target=_blank><font color=#618b2c><u>LogManager</u></font></a>是&#8220;工厂类&#8221;而Logger是&#8220;产品类&#8221;，凡事都要学以致用嘛，呵呵）。这里我们需要了解的是Logger的&#8220;名字空间&#8221;（<strong>namespace</strong>）的概念：通常我们调试时需要清楚地知道某个变量是出现在什么位置，精确到哪个类的哪个方法，namespace就是这么个用处。我们用getLogger()得到Logger时需要指定这个Logger的名字空间，通常是一个包名，譬如&#8220;com.jungleford.test&#8221;等，如果是指定了namespace，那么将在一个全局对象LogManager中注册这个namespace，Logger会基于namespace形成层次关系，譬如namespace为&#8220;com.jungleford&#8221;的Logger就是namespace为&#8220;com.jungleford.test&#8221;的Logger的父，后者调用<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#getParent()" target=_blank><font color=#618b2c><u>getParent</u></font></a>()方法将返回前者，如果当前没有namespace为&#8220;com.jungleford&#8221;的Logger，则查找namespace为&#8220;com&#8221;的Logger，要是按照这个链找不到就返回根Logger，其namespace为""，根Logger的父是null。从理论上说，这个namespace可以是任意的，通常我们是按所调试的对象来定，但如果你是使用getAnonymousLogger()方法产生的Logger，那它就没有namespace，这个&#8220;匿名Logger&#8221;的父是根Logger。<br>&nbsp;&nbsp;&nbsp;&nbsp;得到一个Logger对象后就可以记录日志了，下面是一些常用的方法： </p>
<p class=postText align=left><br><font size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#finest(java.lang.String)" target=_blank><font color=#618b2c><u>finest</u></font></a>、<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#finer(java.lang.String)" target=_blank><font color=#618b2c><u>finer</u></font></a>、<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#fine(java.lang.String)" target=_blank><font color=#618b2c><u>fine</u></font></a>、<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#info(java.lang.String)" target=_blank><font color=#618b2c><u>info</u></font></a>、<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#config(java.lang.String)" target=_blank><font color=#618b2c><u>config</u></font></a>、<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#warning(java.lang.String)" target=_blank><font color=#618b2c><u>warning</u></font></a>、<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#severe(java.lang.String)" target=_blank><font color=#618b2c><u>severe</u></font></a>：简洁的方法，输出的日志为指定的级别。关于日志级别我们在后面将会详细谈到。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#log(java.util.logging.Level, java.lang.String)" target=_blank><font color=#618b2c><u>log</u></font></a>：不仅可以指定消息和级别，还可以带一些参数，甚至可以直接是一个LogRecord对象（这些参数是LogRecord对象的重要组成部分）。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String)" target=_blank><font color=#618b2c><u>logp</u></font></a>：更加精细了，不但具有log方法的功能，还可以不使用当前的namespace，定义新的类名和方法名。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#entering(java.lang.String, java.lang.String)" target=_blank><font color=#618b2c><u>entering</u></font></a>、<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#exiting(java.lang.String, java.lang.String)" target=_blank><font color=#618b2c><u>exiting</u></font></a>：这两个方法在调试的时候特别管用，用来观察一个变量变化的情况，就如同我们在VC的调试状态下watch一个变量，然后按F10，呵呵。</font><br></p>
<p class=postText align=left><strong>2. 输出媒介控制：Handler</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;日志的意义在于它可以以多种形式输出，尤其是像文件这样可以长久保存的媒介，这是System.out.println(...)所无法办到的。Logging API的<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Handler.html" target=_blank><font color=#618b2c><u>Handler</u></font></a>类提供了一个处理日志记录（<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/LogRecord.html" target=_blank><font color=#618b2c><u>LogRecord</u></font></a>，它是对一条日志消息的封装对象）的接口，包括几个已实现的API：</p>
<p class=postText align=left><br><font size=-1></font><font size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/ConsoleHandler.html" target=_blank><font color=#618b2c><u>ConsoleHandler</u></font></a>：向控制台输出。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/FileHandler.html" target=_blank><font color=#618b2c><u>FileHandler</u></font></a>：向文件输出。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/SocketHandler.html" target=_blank><font color=#618b2c><u>SocketHandler</u></font></a>：向网络输出。</font></p>
<font size=-1>
<p class=postText align=left><br>&nbsp;&nbsp;&nbsp;&nbsp;这三个输出控制器都是<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/StreamHandler.html" target=_blank><font color=#618b2c><u>StreamHandler</u></font></a>的子类，另外Handler还有一个MemoryHandler的子类，它有特殊的用处，我们在后面将会看到。在程序启动时默认的Handler是ConsoleHandler，不过这个是可以配置的，下面会谈到logging配置文件的问题。<br>&nbsp;&nbsp;&nbsp;&nbsp;此外用户还可以定制自己输出控制器，继承Handler即可，通常只需要实现Handler中三个未定义的抽象方法： </p>
<p class=postText align=left><font size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Handler.html#publish(java.util.logging.LogRecord)" target=_blank><font color=#618b2c><u>publish</u></font></a>：主要方法，把日志记录写入你需要的媒介。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Handler.html#flush()" target=_blank><font color=#618b2c><u>flush</u></font></a>：清除缓冲区并保存数据。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Handler.html#close()" target=_blank><font color=#618b2c><u>close</u></font></a>：关闭控制器。</font></p>
</font><font size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Handler.html#publish(java.util.logging.LogRecord)" target=_blank><font color=#618b2c><u>publish</u></font></a>：主要方法，把日志记录写入你需要的媒介。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Handler.html#flush()" target=_blank><font color=#618b2c><u>flush</u></font></a>：清除缓冲区并保存数据。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Handler.html#close()" target=_blank><font color=#618b2c><u>close</u></font></a>：关闭控制器。</font>
<p class=postText align=left><font size=-1><br>&nbsp;&nbsp;&nbsp;&nbsp;通过重写以上三个方法我们可以很容易就实现一个把日志写入数据库的控制器。<br></font></p>
<p class=postText align=left><strong>3. 自定义输出格式：Formatter</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;除了可以指定输出媒介之外，我们可能还希望有多种输出格式，譬如可以是普通文本、HTML表格、XML等等，以满足不同的查看需求。Logging API中的<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Formatter.html" target=_blank><font color=#618b2c><u>Formatter</u></font></a>就是这样一个提供日志记录格式化方法接口的类。默认提供了两种Formatter：<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/SimpleFormatter.html" target=_blank><font color=#618b2c><u>SimpleFormatter</u></font></a>：标准日志格式，就是我们通常在启动一些诸如<a href="http://jakarta.apache.org/tomcat/" target=_blank><font color=#618b2c><u>Tomcat</u></font></a>、<a href="http://www.jboss.org/" target=_blank><font color=#618b2c><u>JBoss</u></font></a>之类的服务器的时候经常能在控制台下看到的那种形式，就像这样： </p>
<p class=postText align=left><br><font size=-1>2004-12-20 23:08:52 org.apache.coyote.http11.Http11Protocol init<br>信息: Initializing Coyote HTTP/1.1 on http-8080<br><br>2004-12-20 23:08:56 org.apache.coyote.http11.Http11Protocol init<br>信息: Initializing Coyote HTTP/1.1 on http-8443 </font></p>
<font size=-1>
<p class=postText align=left><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/XMLFormatter.html" target=_blank><font color=#618b2c><u>XMLFormatter</u></font></a>：XML形式的日志格式，你的Logger如果add了一个new XMLFormatter()，那么在控制台下就会看到下面这样的形式，不过更常用的是使用上面介绍的FileHandler输出到XML文件中： </p>
<p class=postText align=left><font size=-1>&lt;?xml version="1.0" encoding="GBK" standalone="no"?&gt;<br>&lt;!DOCTYPE log SYSTEM "logger.dtd"&gt;<br>&lt;log&gt;<br>&lt;record&gt;<br>&nbsp;&nbsp;&lt;date&gt;2004-12-20T23:47:56&lt;/date&gt;<br>&nbsp;&nbsp;&lt;millis&gt;1103557676224&lt;/millis&gt;<br>&nbsp;&nbsp;&lt;sequence&gt;0&lt;/sequence&gt;<br>&nbsp;&nbsp;&lt;logger&gt;Test&lt;/logger&gt;<br>&nbsp;&nbsp;&lt;level&gt;WARNING&lt;/level&gt;<br>&nbsp;&nbsp;&lt;class&gt;Test&lt;/class&gt;<br>&nbsp;&nbsp;&lt;method&gt;main&lt;/method&gt;<br>&nbsp;&nbsp;&lt;thread&gt;10&lt;/thread&gt;<br>&nbsp;&nbsp;&lt;message&gt;warning message&lt;/message&gt;<br>&lt;/record&gt;</font></p>
</font><font size=-1>&lt;?xml version="1.0" encoding="GBK" standalone="no"?&gt;<br>&lt;!DOCTYPE log SYSTEM "logger.dtd"&gt;<br>&lt;log&gt;<br>&lt;record&gt;<br>&nbsp;&nbsp;&lt;date&gt;2004-12-20T23:47:56&lt;/date&gt;<br>&nbsp;&nbsp;&lt;millis&gt;1103557676224&lt;/millis&gt;<br>&nbsp;&nbsp;&lt;sequence&gt;0&lt;/sequence&gt;<br>&nbsp;&nbsp;&lt;logger&gt;Test&lt;/logger&gt;<br>&nbsp;&nbsp;&lt;level&gt;WARNING&lt;/level&gt;<br>&nbsp;&nbsp;&lt;class&gt;Test&lt;/class&gt;<br>&nbsp;&nbsp;&lt;method&gt;main&lt;/method&gt;<br>&nbsp;&nbsp;&lt;thread&gt;10&lt;/thread&gt;<br>&nbsp;&nbsp;&lt;message&gt;warning message&lt;/message&gt;<br>&lt;/record&gt;</font><font size=-1>
<p class=postText align=left><br>&nbsp;&nbsp;&nbsp;&nbsp;与Handler类似，我们也可以编写自己的格式化处理器，譬如API里没有将日志输出为我们可通过浏览器查看的HTML表格形式的Formatter，我们只需要重写3个方法： </p>
<p class=postText align=left><font size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Formatter.html#format(java.util.logging.LogRecord)" target=_blank><font color=#618b2c><u>format</u></font></a>：格式化LogRecord中包含的信息。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Formatter.html#getHead(java.util.logging.Handler)" target=_blank><font color=#618b2c><u>getHead</u></font></a>：输出信息的头部。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Formatter.html#getTail(java.util.logging.Handler)" target=_blank><font color=#618b2c><u>getTail</u></font></a>：输出信息的尾部。</font><font size=-1></font><br></p>
</font><font size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Formatter.html#format(java.util.logging.LogRecord)" target=_blank><font color=#618b2c><u>format</u></font></a>：格式化LogRecord中包含的信息。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Formatter.html#getHead(java.util.logging.Handler)" target=_blank><font color=#618b2c><u>getHead</u></font></a>：输出信息的头部。<br><br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Formatter.html#getTail(java.util.logging.Handler)" target=_blank><font color=#618b2c><u>getTail</u></font></a>：输出信息的尾部。</font><font size=-1></font><br>
<p class=postText align=left><font size=-1><strong>4. 定义日志级别：Level</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;大家可能都知道Windows的&#8220;事件查看器&#8221;，里面有三种事件类型：&#8220;信息&#8221;、&#8220;警告&#8221;、&#8220;错误&#8221;。这其实就是日志级别的一种描述。Java日志级别用<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html" target=_blank><font color=#618b2c><u>Level</u></font></a>类表示，一个日志级别对应的是一个整数值，范围和整型值的范围是一致的，该整数值愈大，说明警戒级别愈高。Level有9个内置的级别，分别是： </font></p>
<p class=postText align=left><font size=-1><strong>类型</strong>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font>&nbsp;<font size=-1><strong>对应的整数</strong><br></font><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html#OFF" target=_blank><u>OFF</u></a></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <font size=-1>最大整数（<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Integer.html" target=_blank><font color=#618b2c><u>Integer</u></font></a>.<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Integer.html#MAX_VALUE" target=_blank><font color=#618b2c><u>MAX_VALUE</u></font></a>）<br></font><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html#SEVERE" target=_blank><u>SEVERE</u></a></font>&nbsp;&nbsp;&nbsp; &nbsp;<font size=-1>1000<br></font><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html#WARNING" target=_blank><u>WARNING</u></a></font>&nbsp;&nbsp; <font size=-1>900<br></font><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html#INFO" target=_blank><u>INFO</u></a></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font size=-1>800<br></font><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html#CONFIG" target=_blank><u>CONFIG</u></a></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font size=-1>700<br></font><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html#FINE" target=_blank><u>FINE</u></a></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<font size=-1>500<br></font><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html#FINER" target=_blank><u>FINER</u></a></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font size=-1>400<br></font><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html#FINEST" target=_blank><u>FINEST</u></a></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font size=-1>300<br></font><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html#ALL" target=_blank><u>ALL</u></a></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<font size=-1>最小整数（Integer.<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Integer.html#MIN_VALUE" target=_blank><font color=#618b2c><u>MIN_VALUE</u></font></a>）</font></p>
<font size=-1>
<p class=postText align=left><br>&nbsp;&nbsp;&nbsp;&nbsp;你也可以定义自己的日志级别，但要注意的是，不是直接创建Level的对象（因为它的构造函数是protected的），而是通过继承Level的方式，譬如： </p>
<p class=postText align=left><font color=#ff0000 size=-1><strong>class</strong></font><font size=-1> AlertLevel <strong><font color=#ff0000>extends</font></strong> java.util.logging.Level<br>{<br>&nbsp;&nbsp;<strong><font color=#ff0000>public</font></strong> AlertLevel()<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;super(<font color=#ff00ff>"ALERT"</font>, <font color=#0000ff>950</font>);<br>&nbsp;&nbsp;}<br>}<br>...<br><strong><font color=#990000>Logger</font></strong> logger = <strong><font color=#990000>Logger</font></strong>.getAnonymousLogger();<br>logger.log(<strong><font color=#ff0000>new</font></strong> AlertLevel(), <font color=#ff00ff>"A dangerous action!"</font>);</font></p>
</font><font color=#ff0000 size=-1><strong>class</strong></font><font size=-1> AlertLevel <strong><font color=#ff0000>extends</font></strong> java.util.logging.Level<br>{<br>&nbsp;&nbsp;<strong><font color=#ff0000>public</font></strong> AlertLevel()<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;super(<font color=#ff00ff>"ALERT"</font>, <font color=#0000ff>950</font>);<br>&nbsp;&nbsp;}<br>}<br>...<br><strong><font color=#990000>Logger</font></strong> logger = <strong><font color=#990000>Logger</font></strong>.getAnonymousLogger();<br>logger.log(<strong><font color=#ff0000>new</font></strong> AlertLevel(), <font color=#ff00ff>"A dangerous action!"</font>);</font><font size=-1>
<p class=postText align=left><br>&nbsp;&nbsp;&nbsp;&nbsp;上面定义了一个高于WARNING但低于SEVERE的日志级别。<br>&nbsp;&nbsp;&nbsp;&nbsp;于是可能有朋友会兴冲冲地用以下的语句来记录一个事件： </p>
<p class=postText align=left><font color=#990000 size=-1><strong>Logger</strong></font><font size=-1> logger = <strong><font color=#990000>Logger</font></strong>.getAnonymousLogger();<br>logger.fine(<font color=#ff00ff>"Everything seems ok."</font>);<br><font color=#006600>//或者是<br>//logger.log(Level.FINE, "Everything seems ok.");</font></font></p>
</font><font color=#990000 size=-1><strong>Logger</strong></font><font size=-1> logger = <strong><font color=#990000>Logger</font></strong>.getAnonymousLogger();<br>logger.fine(<font color=#ff00ff>"Everything seems ok."</font>);<br><font color=#006600>//或者是<br>//logger.log(Level.FINE, "Everything seems ok.");</font></font>
<p class=postText align=left><font color=#006600></font><font size=-1><br>&nbsp;&nbsp;&nbsp;&nbsp;但是一程序运行，奇怪了，怎么没有打印出任何消息呢？下一小节我们就来谈这个问题。</font></p>
<p class=postText align=left><font size=-1><strong>5. 日志过滤器：Filter</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;所谓过滤器是控制哪些日志该输出哪些不该输出的一种组件。上面你写的那条日志没有能在控制台显示出来，是因为logging API预先设定的缺省级别是INFO，也就是说只有级别不低于INFO（即其整数值不小于800）的日志才会被输出，这个就是Filter的功能。所以我们可以看到SEVERE、WARNING、INFO以及上面我们定义的ALERT消息，但看不到FINE、FINER和FINEST消息。当然，你尽可以用Logger的<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#setLevel(java.util.logging.Level)" target=_blank><font color=#618b2c><u>setLevel</u></font></a>方法或者修改配置文件的方法（什么是配置文件，我们后面将会看到）来重新定义Logger输出的最低级别。<br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Filter.html" target=_blank><font color=#618b2c><u>Filter</u></font></a>不仅仅可以按日志级别过滤，你也可以定义自己的Filter，实现其中的<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Filter.html#isLoggable(java.util.logging.LogRecord)" target=_blank><font color=#618b2c><u>isLoggable</u></font></a>方法，随便按照LogRecord携带的任何信息进行过滤，譬如（顺便复习一下匿名类，呵呵）： </font></p>
<p class=postText align=left><font color=#990000 size=-1><strong>Logger</strong></font><font size=-1> logger = <strong><font color=#990000>Logger</font></strong>.getAnonymousLogger();<br>logger.setFilter(<strong><font color=#ff0000>new</font></strong> <strong><font color=#990000>Filter</font></strong>()<br>{<br>&nbsp;&nbsp;<strong><font color=#ff0000>public</font></strong> <strong><font color=#ff0000>boolean</font></strong> isLoggable(<strong><font color=#990000>LogRecord</font></strong> rec)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<font color=#006600>//从LogRecord里得到过滤信息<br></font>&nbsp;&nbsp;}<br>});</font></p>
<p class=postText align=left><strong><br>6. 预定义参数<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;LogManager是一个实现了Singleton模式的全局对象（由于是一个唯一的对象，LogManager需要是线程安全的），它管理着程序启动以后所有已注册（包层次）或匿名的Logger，以及相关配置信息。这里的配置信息通常是从<strong>&lt;JAVA_HOME&gt;\jre\lib\logging.properties</strong>文件得到的。logging.properties对于logging API来说是一个很重要的文件，它的内容一般是：<br></p>
<font size=-1></font><font size=-1>
<p class=postText align=left>############################################################<br># Default Logging Configuration File<br>#<br># You can use a different file by specifying a filename<br># with the java.util.logging.config.file system property. <br># For example java -Djava.util.logging.config.file=myfile<br>############################################################</p>
<p class=postText align=left>############################################################<br># Global properties<br>############################################################</p>
<p class=postText align=left># "handlers" specifies a comma separated list of log Handler <br># classes. These handlers will be installed during VM startup.<br># Note that these classes must be on the system classpath.<br># By default we only configure a ConsoleHandler, which will only<br># show messages at the INFO and above levels.<br>handlers= java.util.logging.ConsoleHandler</p>
<p class=postText align=left># To also add the FileHandler, use the following line instead.<br>#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler</p>
<p class=postText align=left># Default global logging level.<br># This specifies which kinds of events are logged across<br># all loggers. For any given facility this global level<br># can be overriden by a facility specific level<br># Note that the ConsoleHandler also has a separate level<br># setting to limit messages printed to the console.<br>.level= INFO</p>
<p class=postText align=left>############################################################<br># Handler specific properties.<br># Describes specific configuration info for Handlers.<br>############################################################</p>
<p class=postText align=left># default file output is in user's home directory.<br>java.util.logging.FileHandler.pattern = %h/java%u.log<br>java.util.logging.FileHandler.limit = 50000<br>java.util.logging.FileHandler.count = 1<br>java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter</p>
<p class=postText align=left># Limit the message that are printed on the console to INFO and above.<br>java.util.logging.ConsoleHandler.level = INFO<br>java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter<br></p>
<p class=postText align=left>############################################################<br># Facility specific properties.<br># Provides extra control for each logger.<br>############################################################</p>
<p class=postText align=left># For example, set the com.xyz.foo logger to only log SEVERE<br># messages:<br>com.xyz.foo.level = SEVERE</p>
</font><font size=-1>
<div class=postText align=left><br>&nbsp;&nbsp;&nbsp;&nbsp;你可以通过修改这个配置文件来改变运行时Logger的行为，譬如：.level定义的是上面所说的默认输出的最低日志级别；XXXHandler相关属性定义了各种输出媒介等等。<br>&nbsp;&nbsp;&nbsp;&nbsp;这里比较有意思的是关于日志文件，也就是FileHandler，当然，你可以在程序中创建一个FileHandler，然后添加到logger中： </div>
<div class=postText align=left>&nbsp;</div>
<div class=postText align=left><font color=#990000 size=-1><strong>FileHandler</strong></font><font size=-1> fhd = <strong><font color=#ff0000>new</font></strong> <strong><font color=#990000>FileHandler</font></strong>(<font color=#ff00ff>"%h/java%u.log"</font>, <font color=#0000ff>5000</font>, <font color=#0000ff>1</font>, <strong><font color=#ff0000>true</font></strong>);<br>fhd.setLevel(<strong><font color=#990000>Level</font></strong>.ALL);<br>fhd.setFormatter(<strong><font color=#ff0000>new</font></strong> <strong><font color=#990000>XMLFormatter</font></strong>());<br>logger.addHandler(fhd);</font></div>
</font><font color=#990000 size=-1><strong>FileHandler</strong></font><font size=-1> fhd = <strong><font color=#ff0000>new</font></strong> <strong><font color=#990000>FileHandler</font></strong>(<font color=#ff00ff>"%h/java%u.log"</font>, <font color=#0000ff>5000</font>, <font color=#0000ff>1</font>, <strong><font color=#ff0000>true</font></strong>);<br>fhd.setLevel(<strong><font color=#990000>Level</font></strong>.ALL);<br>fhd.setFormatter(<strong><font color=#ff0000>new</font></strong> <strong><font color=#990000>XMLFormatter</font></strong>());<br>logger.addHandler(fhd);</font><font size=-1>
<div class=postText align=left><br>&nbsp;&nbsp;&nbsp;&nbsp;这段代码等价于上面logging.properties中的文字段： </div>
<div class=postText align=left>&nbsp;</div>
<div class=postText align=left><font size=-1>java.util.logging.FileHandler.pattern = %h/java%u.log<br>java.util.logging.FileHandler.limit = 50000<br>java.util.logging.FileHandler.count = 1<br>java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter</font></div>
</font><font size=-1>java.util.logging.FileHandler.pattern = %h/java%u.log<br>java.util.logging.FileHandler.limit = 50000<br>java.util.logging.FileHandler.count = 1<br>java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter</font><font size=-1>
<div class=postText align=left><br>&nbsp;&nbsp;&nbsp;&nbsp;这里的pattern代表用转义字符定义的一个日志文件名： <font size=-1>转义字符串</font> <font size=-1>含义</font> <font size=-1>%t</font> <font size=-1>临时目录</font> <font size=-1>%h</font> <font size=-1>用户目录，即系统属性&#8220;user.home&#8221;对应的值</font> <font size=-1>%g</font> <font size=-1>一个随机生成的数字，可以重复</font> <font size=-1>%u</font> <font size=-1>一个随机生成的非重复数字</font><font size=-1><br>&nbsp;&nbsp;&nbsp;&nbsp;以上面的&#8220;%h/java%u.log&#8221;为例，在Windows 2000下代表日志文件可能就是：C:\Documents and Settings\Administrator\java<strong>x</strong>.log。这里x代表一个不重复的数字，如果是第一次，那么就是java0.log；如果在该目录下已经存在了一个java0.log的文件，那么logger就产生一个java1.log的新的日志文件。<br>&nbsp;&nbsp;&nbsp;&nbsp;当然，你可以在别的地方使用自己写的配置文件，不过在启动程序时候需要指定<strong>java.logging.config.file</strong>属性： </font></div>
</font><font size=-1>转义字符串</font> <font size=-1>含义</font> <font size=-1>%t</font> <font size=-1>临时目录</font> <font size=-1>%h</font> <font size=-1>用户目录，即系统属性&#8220;user.home&#8221;对应的值</font> <font size=-1>%g</font> <font size=-1>一个随机生成的数字，可以重复</font> <font size=-1>%u</font> <font size=-1>一个随机生成的非重复数字</font><font size=-1><br>&nbsp;&nbsp;&nbsp;&nbsp;以上面的&#8220;%h/java%u.log&#8221;为例，在Windows 2000下代表日志文件可能就是：C:\Documents and Settings\Administrator\java<strong>x</strong>.log。这里x代表一个不重复的数字，如果是第一次，那么就是java0.log；如果在该目录下已经存在了一个java0.log的文件，那么logger就产生一个java1.log的新的日志文件。<br>&nbsp;&nbsp;&nbsp;&nbsp;当然，你可以在别的地方使用自己写的配置文件，不过在启动程序时候需要指定<strong>java.logging.config.file</strong>属性： </font>
<div class=postText align=left>&nbsp;</div>
<div class=postText align=left><font size=-1>java -Djava.logging.config.file=...</font></div>
<div class=postText align=left><br><strong>7. 资源与本地化</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;Logger里还有个方法叫<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html#logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String)" target=_blank><font color=#618b2c><u>logrb</u></font></a>，可能初学者不太会用到。如果你安装的JDK是国际版的，那么你将会看到在中文Windows平台下日志输出的INFO、WARNING显示的是&#8220;信息&#8221;、&#8220;警告&#8221;等中文字样。因为logrb是一个和Java i18n/l10n相关的方法，你可以定义自己的&#8220;资源包&#8221;（Resource Bundle），然后在logrb方法中指定相应的资源名称，那么在输出日志中你就能看到用自己定义的本地语言、时间等显示的信息。如果你对i18n/l10n感兴趣，可以参考<a href="http://java.sun.com/j2se/1.4.2/docs/guide/intl/index.html" target=_blank><font color=#618b2c><u>Java Localization文档</u></font></a>。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;了解以上组件后，我们回顾一个完整的日志处理的工作过程：<br>&nbsp;&nbsp;&nbsp;&nbsp;程序启动日志服务，创建Logger对象，LogManager按照namespace的层次结构组织Logger，在同一个namespace里子Logger将继承父Logger的属性；同时，LogManager从logging.properties中读取相应的属性对Logger进行初始化，如果在程序中设置了属性则使用新的配置。当应用程序产生一条日志，Logger将创建一个LogRecord对象，该对象封装了一条日志的全部信息。Logger需要根据当前设置的Filter来判断这条日志是否需要输出，并将有用的日志传给相应的Handler处理，而Handler根据当前设置的Formatter和Resource Bundle将日志消息转换成一定的显示格式，然后输出到预定的媒介（控制台、文件等）中去。整个过程大致如图1所示： <br></div>
<p class=postText align=center></p>
<p class=postText align=center><img title=日志处理流程 height=151 alt=o_logging1.gif src="http://www.blogjava.net/images/blogjava_net/jungleford/924/o_logging1.gif" width=632 border=0></p>
<p class=postText align=left>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图1<br><br>&nbsp;&nbsp;&nbsp;&nbsp;前面我们在介绍Handler的时候提到过一个特殊的类叫<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/MemoryHandler.html" target=_blank><font color=#618b2c><u>MemoryHandler</u></font></a>，这里我们要了解一下&#8220;Handler链&#8221;的概念，日志在输出之前可能经过多个Handler的处理，MemoryHandler在这种情况下就是一个中间角色，它维持一个内存中的日志缓冲区，当日志没有填满缓冲区时就将全部日志送到下一个Handler，否则新进来的日志将会覆盖最老的那些日志，因此，使用MemoryHandler可以维护一定容量的日志，另外，MemoryHandler也可以不需要使用Formatter来进行格式化，从而具有较高的效率。一个使用Handler链的例子如图2所示： </p>
<p class=postText align=left></p>
<div class=postText align=center><img title="一个 Handler 链" height=149 alt=o_logging2.gif src="http://www.blogjava.net/images/blogjava_net/jungleford/924/o_logging2.gif" width=700 border=0><br>图2 </div>
<p class=postText align=center></p>
<p class=postText align=left><strong><u><font color=#cc0000><font size=3>青出于蓝：Apache Jakarta log4j日志工具包</font><br><br></font></u></strong>&nbsp;&nbsp;&nbsp;&nbsp;应付日常的日志需求，J2SE的Logging API可以说已经做得相当出色了，但追求完美的开发人员可能需要可扩展性更好的专业日志处理工具，log4j正是当前比较流行的一个工具包，它提供更多的输出媒介、输出格式和配置选择，你会发现原来在J2SE里一些仍需要自己手工构建的功能在log4j当中都已经为你实现了。关于log4j我可能谈得不会太多，可以看看文后所附的&#8220;<a href="http:///#ref"><font color=#618b2c><u>参考资料</u></font></a>&#8221;，网上也有很详细的介绍，我在这里做的是一个对比，因为log4j和J2SE 1.4 Logging API的用法是很相似的，一些名称不同的组件你会发现他们所处的地位其实是一样的： <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<font size=-1><strong>J2SE 1.4中的类</strong></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font size=-1><strong>log4j中的类</strong><br></font><strong><font size=-1>日志记录器</font></strong>&nbsp;&nbsp; &nbsp;<font size=-1>Logger&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font size=-1><a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/Logger.html" target=_blank><font color=#618b2c><u>Logger</u></font></a><br></font><font size=-1><strong>日志管理器</strong>&nbsp;&nbsp; &nbsp;</font><font size=-1>LogManager&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff size=-1><a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/LogManager.html" target=_blank><u>LogManager</u></a></font><br><strong></strong><font size=-1><strong>日志对象</strong>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</font>&nbsp;<font size=-1>LogRecord&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff size=-1><a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/spi/LoggingEvent.html" target=_blank><u>LoggingEvent</u></a></font><br><font size=-1><strong>输出媒介控制</strong></font> <font size=-1>Handler&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>&nbsp;<font size=-1><a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/Appender.html" target=_blank><font color=#618b2c><u>Appender</u></font></a><br></font><font size=-1><strong>格式化</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font>&nbsp; <font size=-1>Formatter&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>&nbsp;<font size=-1><a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/Layout.html" target=_blank><font color=#618b2c><u>Layout</u></font></a><br></font><font size=-1><strong>级别</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font>&nbsp; <font size=-1>Level&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>&nbsp;<font color=#0000ff size=-1><a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/Layout.html" target=_blank><u>Level</u></a></font><br><font size=-1><strong>过滤器</strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font size=-1>Filter&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font>&nbsp;<font size=-1><a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/spi/Filter.html" target=_blank><font color=#618b2c><u>Filter</u></font></a><br></font><font size=-1><br>&nbsp;&nbsp;&nbsp;&nbsp;log4j可以做到更精细更完善的控制，譬如J2SE里没有现成向数据库里写日志的方法，但log4j却有<a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/jdbc/JDBCAppender.html" target=_blank><font color=#618b2c><u>JDBCAppender</u></font></a>，它甚至还能向GUI图形界面（<a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/lf5/LF5Appender.html" target=_blank><font color=#618b2c><u>LF5Appender</u></font></a>，一种以JTree方式显示的层次结构）、Windows NT事件查看器（<a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/nt/NTEventLogAppender.html" target=_blank><font color=#618b2c><u>NTEventLogAppender</u></font></a>）、UNIX的syslogd服务（<a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/net/SyslogAppender.html" target=_blank><font color=#618b2c><u>SyslogAppender</u></font></a>）、电子邮箱（<a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/net/SMTPAppender.html" target=_blank><font color=#618b2c><u>SMTPAppender</u></font></a>）、Telnet终端（<a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/net/TelnetAppender.html" target=_blank><font color=#618b2c><u>TelnetAppender</u></font></a>）、JMS消息（<a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/net/JMSAppender.html" target=_blank><font color=#618b2c><u>JMSAppender</u></font></a>）输出日志，牛吧；J2SE里默认只能用%JAVA_HOME%\jre\lib\logging.properties做配置文件，但log4j却可以在代码中设置其它路径下的properties文件或XML格式的配置文件。log4j的其它方面同样很丰富，总之，log4j的最大的特点就是&#8220;灵活&#8221;，无论是Appender、Layout还是Configurator，你可以把日志轻松地弄成几乎任何你想要的形式。</font></p>
<p class=postText align=left><strong><u><font color=#cc0000><font size=3>框架与标准：JSR议案</font><br><br></font></u></strong>&nbsp;&nbsp;&nbsp;&nbsp;从时间顺序上讲，log4j要比J2SE Logging API来得早，很多概念都是log4j先有的，但成为一个标准，则是在<a href="http://www.jcp.org/en/jsr/detail?id=47" target=_blank><font color=#618b2c><u>JSR 47</u></font></a>的形成。可能有人还不太了解<a href="http://www.jcp.org/en/jsr/overview" target=_blank><font color=#618b2c><u>JSR</u></font></a>，这还要谈到<a href="http://www.jcp.org/en/home/index" target=_blank><font color=#618b2c><u>JCP</u></font></a>，即&#8220;Java Community Process&#8221;，它是一个于1998年成立的旨在为Java技术制定民间标准的开放组织，你可以通过<a href="http://www.jcp.org/en/participation/membership" target=_blank><font color=#618b2c><u>http://www.jcp.org/en/participation/membership</u></font></a>申请成为它的付费或免费会员，JCP的主要工作就是制定和发布JSR（Java Specification Requests），JSR对于Java的意义就相当于RFC对于网络技术的意义，由于JCP会员们的集思广益，使得JSR成为Java界的一个重要标准。JSR 47即&#8220;Logging API Specification&#8221;，制定了调试和日志框架，J2SE Logging API正是该框架的一个实现。由于种种原因，在JSR 47出来以前，log4j就已经成为一项成熟的技术，使得log4j在选择上占据了一定的优势，但不能因此就说JSR 47是过时的规范，标准总是在发展的嘛！</p>
<p class=postText align=left><strong><u><font color=#cc0000><font size=3>并不是全部：其它日志处理工具</font><br><br></font></u></strong>&nbsp;&nbsp;&nbsp;&nbsp;除了J2SE Logging API和log4j，日志处理方面还有别的技术：Jakarta的<a href="http://jakarta.apache.org/commons/" target=_blank><font color=#618b2c><u>commons</u></font></a>组件项目中的<a href="http://jakarta.apache.org/commons/logging/" target=_blank><font color=#618b2c><u>JCL</u></font></a>（Jakarta Commons Logging）是一个不错的选择，它有点类似于GSS-API（通用安全服务接口）中的思想，其日志服务机制是可以替换的，也就是说既可以用J2SE Logging API也可以用log4j，但JCL对开发人员提供一致的接口，这一点相当重要，组件可重用正是Jakarta Commons项目追求的一个目标；<a href="http://www.ibm.com/" target=_blank><font color=#618b2c><u>IBM</u></font></a>的<a href="http://www.alphaworks.ibm.com/tech/loggingtoolkit4j" target=_blank><font color=#618b2c><u>JLog</u></font></a>也是在J2SE Logging API之前推出的一个工具包，但JLog是一个商业产品。<br>&nbsp;&nbsp;&nbsp;&nbsp;至于日志API的应用那可就多了，现在哪个大一点的工具或平台不用到日志模块呢？Tomcat、JBoss&#8230;&#8230;<br></p>
<p class=postText align=left>&nbsp;&nbsp;&nbsp;&nbsp;说了这么多，我们无非需要知道的一件事就是，&#8220;调试&#8221;也是一门学问。在我们一个劲地用System.out.println(...)而且用得很爽的时候，也应该想想看，如何让这样一条菜鸟语句也能变得人性化和丰富多彩。</p>
<p class=postText align=left><a name=ref></a><strong><u><font color=#cc0000 size=3>参考资料</font></u></strong> </p>
<div class=postText align=left>
<ul>
    <li><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/guide/util/logging/index.html" target=_blank><u>Java Logging Documentation</u></a></font>
    <li><font color=#0000ff size=-1><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/package-summary.html" target=_blank><u>Java Logging APIs</u></a></font>
    <li><font size=-1>J2SE进阶, by <a href="http://www.javaresearch.org/" target=_blank><em><font color=#618b2c><u>www.javaresearch.org</u></font></em></a></font>
    <li><font size=-1><a href="http://logging.apache.org/log4j/docs/manual.html" target=_blank><font color=#618b2c><u>Short introduction to log4j</u></font></a>, by <em>Ceki G&#252;lc&#252;</em></font>
    <li><font color=#0000ff size=-1><a href="http://logging.apache.org/log4j/docs/api/index.html" target=_blank><u>log4j APIs</u></a></font>
    <li><font color=#0000ff size=-1><a href="http://logging.apache.org/log4j/docs/faq.html" target=_blank><u>FAQ about log4j</u></a></font></li>
</ul>
</div>
</font></div>
<img src ="http://www.blogjava.net/hiker/aggbug/108198.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hiker/" target="_blank">hiker</a> 2007-04-03 14:17 <a href="http://www.blogjava.net/hiker/archive/2007/04/03/108198.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>