posts - 15,  comments - 34,  trackbacks - 27

许多应用, 特别是企业应用, 都需要日志记录程序。应用日志有助于服务工程师解决这个领域的难题, 并且能为安全分析提供审计跟踪。

最初, Java 平台包含了很少可用于应用日志记录的资源。被迫面对日志文件中的println语句的开发人员和系统管理员,有的设法发明自家的解决方案,有的转而采用由商业开发商或者开放源码开发者生产的众多优秀(但互不兼容)的日志记录产品中的一种。Java 2版本1.4 改变了这种局面,因为它引入了java.util.logging包。

本期技巧简要地解释了Java日志记录的基本知识,并提供了示例代码,演示如何通过Java消息服务 (JMS)发送应用日志消息到某个独立客户端端。如果您不熟悉JMS, 参看2003年4月15 日那一期的“Publish/Subscribe Messaging With JMS Topics”以及 2003年3月11 日那一期的“使用JMS Queues(Using JMS Queues)”。

java.util.logging

Java logging包最初是作为Java Specification Request (JSR-047)创建的,现在是Java 2, Standard Edition (J2SE)的一部份。它的需求包括以下特性:

  • 最小的运行时性能影响。
  • 运行时启用/禁用日志记录。
  • 细粒度控制。
  • 运行时日志记录服务注册。
  • 与现有日志记录服务的互操作性, 比如,系统日志和遗留日志记录方案。
  • 在合适的时候向用户显示高优先级消息。
  • 能够处理国际化的日志记录消息。
  • 能够记录对象, 而不只是记录字符串 。

由于logging包是J2SE 的一部分, 它在其他Java 平台也是可用的, 包括J2EE。具体地,Java logging可以用于应用客户端、servlets 、JSP 页面、企业bean 和连接器。

Logging类和接口

日志记录程序的主要类是 Logger。 Logger表示一种通道,记录(logging)消息可以通过它进行发送。通常,每个类有它自己的Logger。

Logger 用Level来配置,这是一个指明问题严重性的类,用于指明所报告的问题的严重性和/或该类需要的详情级别。每一条发送到Logger的消息都有一个关联 Level。 Logger 只报告那些Level比该Logger高或者与之相同的错误。

最高的日志记录 Level 是 SEVERE, 表明碰到了一个严重问题—— 经常指的是一个致命错误。其他 Level 值(以递减顺序) 是 WARNING 和 INFO, 分别为可恢复的错误和信息类消息。 CONFIG 级别表明, 配置事件(比如正在读一个属性文件) 发生过。编程人员可以使用 的Level 值有: FINE、FINER 和 FINEST ,以连续报告更加细粒度的登录消息。服务工程师可以使用这些 Level值来隐藏外部细节, 或在类到类(class-by-class)的基础上增加日志记录细节的级别。Logger的缺省 Level 是 INFO。

 LogRecord 是一个表示应该写入日志的一条消息的对象。它包含各种各样的信息, 包括被打印的消息, 最初发送给Logger的名字, Level 和所发送消息的创建时间与日期, 以及调用者的线程id。

一个叫做 Handler的抽象类表示一个知道如何以一种有用方式表示 LogRecord的类。logging包包含一些 Handler类 (比如 ConsoleHandler、FileHandler、StreamHandler 和 SocketHandler) ,它们报告 LogRecords 各种类型的目标。每一 Logger都可以有多 个Handler。 每个 Handler 还可以有一个 Level, 摒除任何 LogRecord ,其Level 在它自己之下。因此, 例如, 单个 Logger 可能有二个Handler: 一个用于在磁盘上写入日记文件,而另一个用于将日志消息发送到系统管理员的寻呼机。磁盘日志 Handler 可以用Level FINEST来配置,因此它将所有日志消息写入磁盘。相反, 寻呼机日志 Handler可能只报告 SEVERE 日志消息。

 Formatter类(及其所定义的任何子类)将LogRecord转换为String以便打印。例如, Formatter 的XMLFormatter 子类将LogRecord 写为格式良好的XML。开发人员可以编写定制的 Formatter 类。

最后, Filter 接口允许编程人员编写方法(isLoggable),该方法允许进行规划性的控制,在这种控制下丢弃或者打印LogMessages。

示例代码

本技巧的示例代码示范了如何设置 Logger, 并使用它发送XML 格式的日志消息,从Web层,通过JMS,到达一个独立JMS 客户。

本技巧的示例代码包含一个servlet 和一个独立客户端端。servlet 称作 LogDemoServlet。独立客户端端称作LoggingReceiver。独立客户端端监听正发布给JMS主题的消息, 并打印接收到任何TextMessages。示例应用包含一个用户向LogDemoServlet张贴数据的HTML表单。

Òª¾÷1

注意, 表单提示用户下载一个JAR文件,然后运行该文件作为一个独立客户端。在通过表单张贴数据之前,用户需要完成这些步骤。

servlet 通过向Topic发布一条XML 格式的消息来作出响应。如果 LoggingReceiver正在运行, 用户会看到在屏幕上打印出一条XML 格式的消息。

例如:

   <?xml version="1.0" encoding="MacRoman" standalone="no"?>
  <!DOCTYPE log SYSTEM "logger.dtd">
  <log>
  <record>
     <date>2003-05-05T23:51:20</date>
     <millis>1052200280257</millis>
     <sequence>0</sequence>
     <logger>com.elucify.tips.may2003.LogDemoServlet</logger>
     <level>INFO</level>
     <class>com.elucify.tips.may2003.LogDemoServlet</class>
     <method>doPost</method>
     <thread>10</thread>
     <message>quest= { 'Johnny' }
      FavoriteColor= { 'Violet' }
      name= { 'Johnny' }
  </message>
  </record>

示例代码中的关键部分是servlet LogDemoServlet。这个servlet 简单地将它的POST参数格式化为一个字符串, 并在servlet每次被调用时将该字符记录到Logger 中。方法doPost的开始处设置了 Logger:

    // Handle post request
   public void doPost(HttpServletRequest req,
       HttpServletResponse res)
       throws IOException, ServletException {
       res.setContentType("text/html");
       PrintWriter pw = res.getWriter();
       // Get POST parameters and write them as
       // "variable=value" to a ByteArrayOutputStream
       String postParams = getPostParams(req);
       ByteArrayOutputStream bos =
           new ByteArrayOutputStream();
       Logger logger = Logger.getLogger(
           this.getClass().getName());

servlet 设置内容类型、获得一个Writer, 并格式化POST参量。然后它通过调用静态方法 Logger.getLogger(this.getClass().getName())来创建了一个Logger。这个方法返回该名称现有的Logger, 或者如果不存在的话,就创建一个。代码使用了servlet 类的完全限定名。这是一个公共约定,以确保系统中各种Logger的名称不会发生冲突。

缺省情况下,Logger将它所创建的任何消息写入到标准输出,而不管运行什么代码。例如,Web层消息通常写入Web服务器日志文件。

doPost方法的第二部分向Logger添加一个新的 Handler 。每次消息记录到Logger时, Logger发送消息到两个 Handlers (假设消息的日志级别足够高) 。下面是的doPost方法的第二部分 :

      // Format logging messages as XML,
       // store in byte array
       StreamHandler sh = new StreamHandler(
           bos, new XMLFormatter());
       logger.addHandler(sh);
       logger.log(Level.INFO, postParams);
       sh.flush();


       // Send contents of buffer as JMS message
       // to listeners
       publish(bos.toString());
       pw.println(
           "Logging messages sent to subscribers");
   }

StreamHandler 是一个使用Formatter 来将LogRecord 格式化为字符串,并将它写入OutputStream的处理程序。在本例中, OutputStream 是 ByteArrayOutputStream, 因此日志记录结果被写入内存。这个方法还使用一个 XMLFormatter,以便 LogRecords 被写作XML文件 。对addHandler的调用将新的StreamHandler添加到Logger,然后将包含格式化POST参数的日志消息发送到 Logger。Logger 发送消息到它的所有Handlers,包括新的StreamHandler。对flush()的调用确保了所有已写入字节被刷新到ByteArrayOutputStream。最后, ByteArrayOutputStream 被转换成XML字符串。再通过发布方法将字符串发布给一个JMS Topic。关于如何将消息发送到JMS Topic的详细描述(使用同样的发布方法) ,请参看2003年4月15 日那一期的技巧“Publish/Subscribe Messaging With JMS Topics”。

posted on 2005-02-04 11:25 jacky 阅读(343) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航:
 
<2024年5月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

常用链接

留言簿(10)

随笔档案

文章分类

文章档案

相册

收藏夹

java

搜索

  •  

最新评论