 |
在 Community Edition 中配置 java.util.logging
在此部分,我们将简单地介绍 java.util.logging API,并说明它如何在 Community Edition 中工作。我们并不会详细介绍此 API 的各种功能。不过,我们将列出涉及的对象,并说明在应用程序中使用此日志记录服务的不同方法。
应用程序对 Logger 对象 进行日志记录调用。Logger 对象按层次结构命名空间方式组织,子 Logger 可以从层次结构中的父项继承一些日志记录属性。Logger 对象在进行日志记录调用时分配 LogRecord 对象。它们将 LogRecord 对象传递到 Handler 对象,以便发布到目的地。Logger 和 Handler 可能会使用日志记录级别和可选的筛选器来评估是否对 LogRecord 感兴趣。如果 LogRecord 必须发布,则 Handler 可以选择使用 Formatter 进行本地化,设置消息的格式,然后再发送到目的地。图 6 说明了所有这些对象如何相关:
图 6. java.util.logging 对象关系
java.util.logging API 提供了以下处理程序:
-
StreamHandler:将格式化记录写入 OutputStream 的简单处理程序。
-
ConsoleHandler:将格式化记录写入 System.err 的简单处理程序。
-
FileHandler:将格式化日志记录写入单个文件或日志文件循环集的处理程序。
-
SocketHandler:将格式化日志记录写入远程 TCP 端口的处理程序。
-
MemoryHandler:将日志记录缓存在内存中的处理程序。
除了上面的处理程序外,API 还提供了以下格式化工具:
-
SimpleFormatter:写入日志记录简短的可读摘要。
-
XMLFormatter:写入采用 XML 结构的详细信息
java.util.logging 定义以下日志级别:
-
SEVERE(最高)
-
WARNING
-
INFO
-
CONFIG
-
FINE
-
FINER
-
FINEST(最低)
在此部分,我们将使用 EMPDemo 应用程序演示 java.util.logging 如何工作,从而介绍 java.util.logging 的以下方面:
-
使用缺省 java.util.logging 配置
-
使用 gbean 自定义 java.util.logging
使用缺省 java.util.logging 配置
缺省情况下,java.util.logging 使用 <
JAVA_HOME
>/jre/lib/logging.properties 文件来配置 Logger、Handler 和 Formatter。不过,您可以在运行时以编程方式添加新 Handler 和 Formatter。所提供的缺省配置非常简单,仅仅配置具有 SimpleFormatter 的 ConsoleHandler。为 ConsoleHandler 设置的日志级别为 INFO;即缺省情况下,ConsoleHandler 将记录日志级别为 INFO 或更高的消息。
我们可以修改 logging.properties 文件,以添加新 Handler 或 Formatter。EMPDemo 包含连接到 EMPLOYEE_DB 数据库的 com.ibm.sample.EMPDemo Servlet,将从 EMPLOYEE 表检索行。另外,还会在执行各种数据库操作时记录消息。清单 3 显示了对应的代码,其中的日志记录语句使用粗体进行标记:
清单 3. 缺省 java.util.logging
Logger logger = Logger.getLogger(EMPDemo.class.getName());
logger.setLevel(Level.FINEST);
Connection con = null;
Statement stmt = null;
PrintWriter out = response.getWriter();
logger.info("Created the PrintWriter on the Response object");
try {
Context initContext = new InitialContext();
Context envContext = Context)initContext.lookup("java:comp/env");
logger.info("Got Initial context: " +envContext);
DataSource ds = (DataSource)envContext.lookup("jdbc/DataSource");
logger.info("Got DataSource: " +ds.toString());
con = ds.getConnection();
logger.info("Got Connection: " +con.toString() +"\n");
stmt = con.createStatement();
logger.info("Got Statement : " +stmt);
ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEE");
logger.info("Table EMP after SELECT:");
out.println("Your EMP table contains the following entries:<BR>");
out.println("<table>");
out.println("<tr>");
out.println("<th>Empno</th>");
out.println("<th>Name</th>");
out.println("<th>Job</th>");
out.println("<th>Manager</th>");
out.println("<th>Salary</th>");
out.println("<th>Commission</th>");
out.println("<th>Deptno</th>");
out.println("</tr>");
while (rs.next()) {
String emp = rs.getString("EMPNO");
String name = rs.getString("ENAME");
String job = rs.getString("JOB");
String mgr = rs.getString("MGR");
String sal = rs.getString("SAL");
String comm = rs.getString("COMM");
String dept = rs.getString("DEPTNO");
out.println("<tr>");
out.println("<td>"+emp+"</td>");
out.println("<td>"+name+"</td>");
out.println("<td>"+job+"</td>");
out.println("<td>"+mgr+"</td>");
out.println("<td>"+sal+"</td>");
out.println("<td>"+comm+"</td>");
out.println("<td>"+dept+"</td>");
out.println("</tr>");
logger.info(emp + " " + name + " " + job);
logger.info(" " + mgr + " " + dept);
}
out.println("</table>");
rs.close();
stmt.close();
con.close();
logger.severe("my severe message");
logger.warning("my warning message");
logger.info("my info message");
logger.config("my config message");
logger.fine("my fine message");
logger.finer("my finer message");
logger.finest("my finest message");
}
catch(java.lang.Exception e) {
e.printStackTrace();
logger.severe(e.getClass().getName());
logger.severe(e.getMessage());
}
}
|
Servlet 获取 Logger ,并将缺省日志记录覆盖(在 <
JAVA_HOME
>/jre/lib/logging.properties 文件中为 INFO),更改为 FINEST。它将在执行期间在多个地方使用 logger.info() 方法在 INFO 级别开始对消息进行记录。为了演示不同级别的日志记录,还会在显示 EMPLOYEE 表的行之后在所有级别对示例消息进行记录。最后,在 catch 块中,将记录 SEVERE 级别的异常。请遵循以下步骤操作,以部署和运行 EMPDemo 应用程序:
-
下载 EMPDemo 应用程序。WAR 文件是
EMPdemo-UtilLogging.war。
-
使用以下部署命令部署 war 文件:
<wasce_home>/bin>deploy --user system --password manager deploy EMPdemo-UtilLogging.war
-
使用此 URL 在浏览器中访问 EMPDemo Servlet:
http://localhost:8080/EMPdemo-UtilLogging/EMPDemo
.
您可以在服务器控制台中看到应用程序所记录的所有 INFO、WARNING 和 SEVERE 消息。即使日志级别在 Servlet 中覆盖为 FINEST,控制台也不显示使用其他日志级别记录的消息。这是因为,在缺省情况下,ConsoleHandler 将仅按照 <JAVA_HOME>/jre/lib/logging.properties 文件中的配置记录 INFO 或更高日志级别的消息。清单 4 显示了相应的输出:
清单 4 控制台中记录的消息
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO:
Created the PrintWriter on the Response object
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO:
Got Initial context:
org.apache.xbean.naming.context.ImmutableContext$NestedImmutableContext@16801680
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO:
Got DataSource: org.tranql.connector.jdbc.DataSource@55425542
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO:
Got Connection: org.tranql.connector.jdbc.ConnectionHandle@30363036
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO:
Got Statement : org.tranql.connector.jdbc.StatementHandle@43aa43aa
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: Table EMP after SELECT:
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: 1 PHANI SSE
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: NIKHIL 100
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: 2 JOE SSE
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: NIKHIL 100
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: 3 JOHN SSE
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: BOB 200
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost SEVERE: my severe message
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost WARNING: my warning message
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: my info message
|
您可以修改 logging.properties 文件,以添加 FileHandler 来将消息记录到文件中。您还可以使用 XMLFormatter 替代 SimpleFormatter。例如,将 ConsoleHandler 的日志记录设置为 FINEST,可以看到 Servlet 中在所有级别记录的所有日志消息都记录到控制台中。要修改的代码行如下所示。
java.util.logging.ConsoleHandler.level = FINEST.
如果您采用了缺省 <
JAVA_HOME
>/jre/lib/logging.properties 文件之外的配置,则可以在服务器启动期间将文件作为 JVM 参数提供,如清单 5 中所示(针对 Windows)。
清单 5. 使用属性文件参数启动 Windows 服务器
C:\>set -Djava.util.logging.config.file=<new_configuration.properties>
C:\>startup.bat
|
使用 gbean 自定义 java.util.logging
有时候您可能会希望使用 java.util.logging API 以编程方式调整日志记录配置。即,动态添加新处理程序,并调整日志记录级别等。由于 java.util.logging 按 JVM 实例配置,因此最好在独立模块(而非任何应用程序)中进行编程配置。通过这样,您可以方便地在这个独立的模块中对日志记录配置进行所需的任何更改。Community Edition 提供了用于开发和部署自定义服务的 gbean 机制。此部分将介绍 gbean 服务。
清单 6 显示了 UtilLogPropGBean.java,其中实现了一个 gbean 服务,相关部分以粗体显示:
清单 6. UtilLogPropGBean.java
package com.ibm.sample;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.LogManager;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.geronimo.gbean.GBeanLifecycle;
public class UtilLogPropGBean implements GBeanLifecycle{
private static final GBeanInfo GBEAN_INFO;
private final String objectName;
private String utilPropFile;
static {
GBeanInfoBuilder infoFactory =
new GBeanInfoBuilder(UtilLogPropGBean.class.getName(),
UtilLogPropGBean.class);
infoFactory.addAttribute("objectName", String.class, false);
infoFactory.addAttribute("utilPropFile", String.class, true);
infoFactory.setConstructor(
new String[]{"objectName","utilPropFile"});
GBEAN_INFO = infoFactory.getBeanInfo();
}
public UtilLogPropGBean(String objectName, String utilPropFile) {
this.objectName = objectName;
this.utilPropFile = utilPropFile;
}
public UtilLogPropGBean() {
objectName = null;
utilPropFile = null;
}
public void doFail() {
System.out.println("UtilLogPropGBean has failed");
}
public void doStart(){
LogManager logManager;
try{
System.out.println("[UtilLogPropGBean] GBean " + objectName + " Started");
InputStream in = new FileInputStream(utilPropFile);
logManager = LogManager.getLogManager();
logManager.reset();
logManager.readConfiguration(in);
System.out.println("Properties file successfully read!!");
}catch(IOException exp){
exp.printStackTrace();
logManager = LogManager.getLogManager();
}catch(Exception exp){
exp.printStackTrace();
}
}
public void doStop(){
System.out.println("GBean " + objectName + " Stoped");
}
public static GBeanInfo getGBeanInfo() {
return GBEAN_INFO;
}
}
|
部署此 gbean 时,Community Edition 中的 GBean 内核将对 gbean 调用 doStart() 方法。此方法将打开 utilPropFile 上的 FileInputStream;utilPropFile 作为属性在 gbean 部署计划中指定并注入 gbean。然后,LogManager 将从输入流读取配置,并配置 java.util.logging。
清单 7 显示了 gbean 的部署计划
清单 7. gbean 部署计划
<module xmlns="http://geronimo.apache.org/xml/ns/deployment-1.2">
<environment>
<moduleId>
<groupId>UtilLogPropGBean</groupId>
<artifactId>UtilLogPropGBean-app</artifactId>
<version>1.0</version>
<type>car</type>
</moduleId>
<dependencies>
<dependency>
<groupId>GBeans</groupId>
<artifactId>UtilLoggingCustom</artifactId>
<version>1.0</version>
<type>jar</type>
</dependency>
</dependencies>
</environment>
<gbean name="UtilLogPropGBean"
class="com.ibm.sample.UtilLogPropGBean" xsi:type="dep:gbeanType"
xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<attribute name="utilPropFile">
C:/temp/applevellogging/UtilLogging/UtilLogging.properties
</attribute>
</gbean>
</module>
|
在清单 6 中,java.util.logging 配置属性文件 C:/temp/applevellogging/UtilLogging/UtilLogging.properties, 作为字符串注入到 UtilLogPropGBean 的 utilPropFile 属性。
在此部分,我们将在 Community Edition 中部署 gbean。部署此 gbean 后,所有使用 java.util.logging API 的应用程序都将使用此配置。请遵循以下步骤部署 gbean:
-
下载 zip 文件,并解压缩 gbean (
UtilLogPropGBean.jar)、部署计划 (UtilLogPropGBean.xml) 和示例 java.util.logging 配置属性文件 (UtilLogging.properties。
-
此 jar 文件包含
UtilLogPropGBean.java。UtilLogging.properties 文件定义 ConsoleHandler 和 FileHandler。FileHandler 将消息记录到 C:/temp/applevellogging/UtilLogging/java.log 文件。FileHandler 和 ConsoleHandler 的日志级别分别为 FINER 和 CONFIG。在文件底部,com.ibm.sample.EMPDemo 的日志级别设置为 SEVERE。当然,此值在 EMPDemo Servlet 中被覆盖。您可以修改这些值,以根据您的需要包括日志文件的位置。
-
使用
moduleid 配置 GBeans/UtilLoggingCustom/1.0/jar将 UtilLogPropGBean.jar 上载到 Community Edition 服务器存储库。此链接说明了如何将 Java 库上载到存储库中。
-
打开命令提示符,并转到
<
wasce_home
>/bin 目录。使用 deploy 命令部署 GBean。
<
wasce_home
>/bin>deploy –user system –password manager deploy UtilLogPropGBean.xml
-
gbean 读取
UtilLogging.properties 文件并配置 java.util.logging 系统。将浏览器指向此 URL http://localhost:8080/EMPdemo-UtilLogging/EMPDemo
(在前一部分部署),以访问 EMPDemo Servlet。
清单 8 显示了服务器控制台中的消息:
清单 8. 服务器控制台消息
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO:
Created the PrintWriter on the Response object
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO:
Got Initial context:
org.apache.xbean.naming.context.ImmutableContext$NestedImmutableContext@16801680
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO:
Got DataSource: org.tranql.connector.jdbc.DataSource@a000a00
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO:
Got Connection: org.tranql.connector.jdbc.ConnectionHandle@1b3a1b3a
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO:
Got Statement : org.tranql.connector.jdbc.StatementHandle@3b6e3b6e
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: Table EMP after SELECT:
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: 1 PHANI SSE
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: NIKHIL 100
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: 2 JOE SSE
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: NIKHIL 100
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: 3 JOHN SSE
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: BOB 200
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost SEVERE: my severe message
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost WARNING: my warning message
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: my info message
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost CONFIG: my config message
|
ConsoleHandler 的日志级别已经在 UtilLogging.properties 文件中设置为 CONFIG。因此,我们将看到在 CONFIG 或更高日志级别(CONFIG、INFO、WARNING 和 SEVERE)记录的消息。
除了清单 5 中的输出(日志文件)外,Community Edition 还会创建 C:/temp/applevellogging/UtilLogging/java.log。因为我们已经为 FileHandler 配置了 XMLFormatter,因此这个文件以 XML 格式记录消息。另外,FileHandler 的日志级别已经设置为 FINER。因此,在此文件中,我们将看到除 FINEST 外在 FINER 或更高级别记录的所有消息。
|  |