WebSphere Application Server Community Edition 中的应用程序日志记录

使用 java.util.logging、Log4j 和 SLF4j

WebSphere Application Server Community Edition 提供了多种使用 java.util.logging、Log4j 和 SLF4j API 配置应用程序日志记录的方法。尽管配置这些日志记录服务的功能很大程度上独立于任何应用服务器,但 WebSphere Application Server 需要一些调整才能获得您所需的日志记录行为。本教程将通过示例应用程序介绍这些调整的详细步骤。WebSphere® Application Server Community Edition 可供免费下载,因此,您数分钟内就可以着手开始工作了。

Phani Madgula, 软件开发人员, IBM

Phani Madgula 在 India Software Labs (ISL) 从事 WebSphere Process Server 支持工作。他在 IBM 工作了 6 年,曾经在多个产品团队工作过,包括 WebSphere Application Server Community Edition、WebSphere Business Integration Adapters 和 DB2。他有开发 JEE 应用程序、产品支持和数据库管理方面的工作经历。他是经过认证的 Oracle9i 专业人员。



2009 年 7 月 02 日

引言

应用程序日志记录提供了捕获在应用程序执行期间发生的各种事件的方法。它将收集关于应用程序在执行各种任务时在做什么的详细信息。此信息在调试、故障排除甚至审核方面很有用。WebSphere® Application Server Community Edition(以下称为 Community Edition)提供了各种库,可帮助应用程序开发人员配置日志记录服务。这些库是:

  • Log4j
  • SLF4j
  • java.util.logging

java.util.logging 包是可用于所有标准 Java 开发工具包的日志记录 Java API。本教程通过示例介绍如何在 Community Edition 中部署的应用程序中使用这些 API。

您将按 JVM 实例配置 java.util.logging。配置之后,可以将其用于该服务器上运行的所有应用程序。本教程介绍如何在 Community Edition 上运行的应用程序中使用 java.util.logging。

最常用的日志记录 API 是 Apache Software Foundation 中的 Log4j。Community Edition 提供的 Log4j 库可供服务器模块在运行时使用。应用程序也可以使用这些库;它们可以在运行时将消息记录到与服务器日志相同的服务器,也可以根据需要配置自己日志记录目的地和格式。本教程将演示在 Community Edition 中使用 Log4j 配置日志记录的不同方法。

Simple Logging Facade for Java(或 SLF4j)是可供应用程序作为日志记录服务使用的另一个日志记录 API。SLF4j 并没有创建另一个日志记录框架,但允许应用程序使用标准 API,并在部署时插入实际的日志记录实现,如 NOPSimplelog4j V1.2、JDK 1.4 日志记录、JCLlogback。Community Edition 还提供了 SLF4j 库。本教程将演示如何在运行于 Community Edition 的应用程序中在 log4j 上使用 SLF4j。

Community Edition v2.1 是基于 Apache Geronimo v2.1 的轻量级应用服务器。Community Edition 还包含很多其他缺陷修复,并拥有 IBM 提供的世界级支持。您可以免费下载服务器的二进制映像。它是 Java EE 5 的完全认证服务器。

本教程

本教程将介绍如何在旨在 Community Edition 上运行的应用程序中使用 java.util.logging、Log4j 和 SLF4j API。其中包括以下部分:

在每个部分,我们将简单描述相应的日志记录 API,并介绍配置和使用 API 来获得所需的日志记录行为的各种方法。我们将使用 EMPDemo 示例来演示如何使用这三个日志记录 API。EMPDemo 示例可以从 developerWorks 网站下载。

先决条件

您应该拥有相当娴熟的 Java 编程技巧。了解 Java EE 5 概念和数据库概念将会帮助您明确本教程的上下文。如果您有在 Community Edition 上运行 HelloWorld 示例的经验,而且编写过 Community Edition 部署计划,对于充分利用本教程将再好不过。

系统要求

为了开发、部署和运行此应用程序,需要以下环境:

  • IBM Java SDK v1.5.0 SR8 或更高版本
  • Community Edition v2.1.0.1 或更高版本


我们使用随 Community Edition 提供的 Apache Derby 数据库部署和运行 EMPDemo 应用程序。EMPDemo 应用程序连接到嵌入式 Derby 数据库中的 EMPLOYEE_DB,并从 EMPLOYEE 表检索信息。我们然后将在浏览器上向用户显示所检索的信息。我们将演示如何在应用程序执行各种数据库操作时使用日志记录 API 记录消息。

持续时间

2 小时


设置环境

在此部分,您将执行以下任务:

  • 安装 Community Edition v2.1.0.1
  • 在嵌入式 Derby 数据库中创建 EMPLOYEE_DB 数据库。
  • 在 EMPLOYEE_DB 数据库上部署 EMPLOYEE_DS 数据源。

安装 Community Edition v2.1.0.1

可以从 developerWorks 下载 Community Edition 安装程序。将服务器程序下载到您的计算机上,并按照 Community Edition v2.1 文档中的说明进行操作。在本教程中,我们使用 <wasce_home> 指代 Community Edition 安装目录。Community Edition 安装程序提供 IBM Java SDK1.5.0。此 JDK 将供安装程序和服务器运行时使用。有关建议平台和兼容平台的更多信息,请参见支持站点

在嵌入式 Derby 数据库中创建 EMPLOYEE_DB 数据库

  1. 启动 Community Edition 服务器,将浏览器窗口指向 http://localhost:8080/console,以启动 Web 管理控制台。
  2. 提供 system 作为用户名,使用 manager 作为密码,以登录到管理控制台。
  3. 在管理控制台左侧的 Console Navigation Portlet 中,单击 DB Manager 链接,以在右侧打开 DB ViewerRun SQL Portlet,如图 1 中所示:
    图 1. DB Viewer 和 Run SQL Portlet 通信
    DB Viewer 和 Run SQL Portlet 的屏幕截图
  4. Run SQL Portlet 上,在 Create DB 文本框中输入 EMPLOYEE_DB,并单击 Create 按钮,这将在嵌入式 Derby 数据库中创建一个 EMPLOYEE_DB 数据库。创建之后,Database List Portlet 将列出 EMPLOYEE_DB 数据库,如图 2 中所示。
    图 2. DB Viewer Portlet 中的 EMPLOYEE_DB
    DB Viewer Portlet 中的 EMPLOYEE_DB 的屏幕截图
  5. 单击 Application 链接,以使 EMPLOYEE_DB 数据库显示在数据库中创建的应用程序表的列表。数据库中当前没有应用程序表。在 SQL Command/s 文本框中,输入清单 1 中的 SQL 语句,以在数据库中创建 EMPLOYEE 表:
    清单 1. 用于创建表的 SQL 语句
    create table EMPLOYEE (EMPNO int, ENAME varchar(50), JOB varchar(10), 
    MGR varchar(10), SAL decimal(15,2), COMM decimal(15,2), DEPTNO int);
  6. 类似地,使用以下 SQL 语句在数据库中插入一些示例行。
    清单 2. 用于插入行的 SQL 语句
    insert into EMPLOYEE values (1, 'PHANI', 'SSE', 'NIKHIL', 10000, 15, 100);
    insert into EMPLOYEE values (2, 'JOE', 'SSE', 'NIKHIL', 12000, 15, 100);
    insert into EMPLOYEE values (3, 'JOHN', 'SSE', 'BOB', 13000, 15, 200);
  7. 最终的表应该与图 3 中所示类似:
    图 3. 最终的 EMPLOYEE_DB 表
    最终的 EMPLOYEE_DB 表的屏幕截图

在 EMPLOYEE_DB 数据库上部署 EMPLOYEE_DS 数据源

  1. 在管理控制台的 Console Navigation Portlet 中单击 Database Pools。此步骤将打开 Database Pools Portlet,其中将列出当前在服务器上部署的数据库池。
  2. 单击 Using the Geronimo database pool wizard 以创建新数据库池。在 Name of the Database Pool 字段输入 EMPLOYEE_DS,并在 Database Type 组合框中选择 Derby embedded,如图 4 中所示。单击 Next
    图 4. 创建数据库池
    创建数据库池的屏幕截图
  3. 在下一屏幕上,在 Database Name 字段中输入 EMPLOYEE_DB(图 5)。在 the Driver JAR 框中选择单个条目,并单击页面底部的 Deploy。此步骤将部署 EMPLOYEE_DS 数据库池。Database pools Portlet 现在将显示新创建的数据库池。
    图 5. 配置数据库池
    配置数据库池的屏幕截图

在 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 对象关系图

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

点击查看代码清单

清单 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 应用程序:

  1. 下载 EMPDemo 应用程序。WAR 文件是 EMPdemo-UtilLogging.war
  2. 使用以下部署命令部署 war 文件:
    <wasce_home>/bin>deploy --user system --password manager deploy EMPdemo-UtilLogging.war
  3. 使用此 URL 在浏览器中访问 EMPDemo Servlet: http://localhost:8080/EMPdemo-UtilLogging/EMPDemo .

您可以在服务器控制台中看到应用程序所记录的所有 INFOWARNINGSEVERE 消息。即使日志级别在 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 上的 FileInputStreamutilPropFile 作为属性在 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, 作为字符串注入到 UtilLogPropGBeanutilPropFile 属性。

在此部分,我们将在 Community Edition 中部署 gbean。部署此 gbean 后,所有使用 java.util.logging API 的应用程序都将使用此配置。请遵循以下步骤部署 gbean:

  1. 下载 zip 文件,并解压缩 gbean (UtilLogPropGBean.jar)、部署计划 (UtilLogPropGBean.xml) 和示例 java.util.logging 配置属性文件 (UtilLogging.properties
  2. 此 jar 文件包含 UtilLogPropGBean.javaUtilLogging.properties 文件定义 ConsoleHandler 和 FileHandler。FileHandler 将消息记录到 C:/temp/applevellogging/UtilLogging/java.log 文件。FileHandler 和 ConsoleHandler 的日志级别分别为 FINERCONFIG。在文件底部,com.ibm.sample.EMPDemo 的日志级别设置为 SEVERE。当然,此值在 EMPDemo Servlet 中被覆盖。您可以修改这些值,以根据您的需要包括日志文件的位置。
  3. 使用 moduleid 配置 GBeans/UtilLoggingCustom/1.0/jarUtilLogPropGBean.jar 上载到 Community Edition 服务器存储库。此链接说明了如何将 Java 库上载到存储库中。
  4. 打开命令提示符,并转到 <wasce_home>/bin 目录。使用 deploy 命令部署 GBean。
    <wasce_home>/bin>deploy –user system –password manager deploy UtilLogPropGBean.xml
  5. 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 或更高日志级别(CONFIGINFOWARNINGSEVERE)记录的消息。

除了清单 5 中的输出(日志文件)外,Community Edition 还会创建 C:/temp/applevellogging/UtilLogging/java.log。因为我们已经为 FileHandler 配置了 XMLFormatter,因此这个文件以 XML 格式记录消息。另外,FileHandler 的日志级别已经设置为 FINER。因此,在此文件中,我们将看到除 FINEST 外在 FINER 或更高级别记录的所有消息。


Community Edition 独特性及充分利用 Log4j

Log4j 是来自 Apache Software Foundation 的日志记录服务开源库。Log4j 在开源社区中广泛使用,包括一些重要的项目,如 Apache Geronimo、JBoss 等。Log4j 的体系结构围绕三个主要概念发展:Logger、AppenderLayout

应用程序首先调用 Logger 对象发起消息的日志记录。记录给定消息时,Logger 将生成 LogEvent 对象来包装给定消息。Logger 然后将 LogEvent 对象传递到关联的 Appender。Appender 将 LogEvent 包含的信息发送到指定的输出目的地。例如,ConsoleAppender 将信息写入 System.out,FileApppender 将其写入日志文件。将信息发送到目的地之前,Appender 可以使用 Layout 创建信息所需格式的表示形式。例如,Appender 可以将设置日志消息的格式的 XMLLayout 作为 XML 字符串使用。

将向 LoggingEvent 分配指示其优先级的级别。缺省级别为(从最高到最低):

  • OFF
  • FATAL
  • ERROR
  • WARN
  • INFO
  • DEBUG
  • ALL

Logger 和 Appender 会被分配一个级别。如果 LogEvent 的日志级别为 WARN,而 Appender 的日志级别是 ERROR,Appender 将不会写入 LogEvent。通过这样,您可以控制日志输出的量。

Log4j 中的所有 Logger 都有一个名称。Log4j 根据名称将 Logger 实例组织为分层的树形结构,就像 Java 语言中的打包命名空间。Log4j 文档中的说明如下

“如果一个 Logger 的名称中点号后面是另一个 Logger 的名称,则称这个 Logger 是后代 Logger 的祖先。如果一个 Logger 与其后代 Logger 之间没有其他祖先,则称第一个 Logger 为第二个 Logger 的父项,第二个 Logger 为第一个 Logger 的子项。”

例如,名为 com.ibm 的 Logger 为 com Logger 的子项。com.ibm.wasce Logger 是 com.ibm Logger 的子项,同时是 com Logger 的二级子项。如果未给 Logger 显式分配级别,则使用其分配了级别的最近祖先的级别。Logger 从其祖先继承 Appender,不过也可以配置为仅使用直接向其分配的 Appender。

您可以在 log4j.propertieslog4j.xml 文件中配置所有 Logger、Appender 和 Layout。配置日志记录服务时,Log4j 库将首先在类路径中查找 log4j.xml 文件,然后查找 log4j.properties

通过上面的讨论,您一定认为 Log4j 与 java.util.logging 类似。当然,它们在概念上是相同的,但 Log4j 比 java.util 更强大。java.util.logging 中的 Handler 执行与 Log4j 中的 Appender 相同的任务。java.util.logging 中的 Formatter 执行与 Log4j 中的 Layout 相同的任务。不过,java.util.logging 只有四个 Handler,而 Log4j 有十多个 Appender。此外,Log4j 提供了很多 Layout,而 java.util.logging 仅仅提供 SimpleFormatter 和 XMLFormatter。Log4j 提供的 Appender 包括:

  • FileAppender:将日志事件追加到文件。
  • RollingFileAppender:扩展 FileAppender,从而在日志文件达到特定大小时进行备份。
  • ConsoleAppender:使用用户指定的布局将日志事件追加到 System.out 或 System.err。缺省的目标是 System.out
  • SocketAppender:将 LoggingEvent 对象发送到远程日志服务器上(通常是一个 SocketNode)。
  • JMSAppender:将事件发布到 JMS 主题的简单 Appender。事件序列化为 JMS 消息类型 ObjectMessage 并使用此格式传输。
  • NTEventLogAppender:追加到 NT 事件日志系统。

Log4j 包括 XMLLayout、SimpleLayout、TTCCLayout、HTMLLayout。有关各个 Appender 和 Layout 的介绍,请参见 Log4j 文档。

在此部分,我们将说明如何在部署 Community Edition 上的应用程序中使用 Log4j。Community Edition 在缺省情况下使用以下 log4j 配置文件:

  • <wasce_home>/var/log/server-log4j.properties:此文件配置服务器组件和在服务器上部署的应用程序的 Appender 和 Layout。此文件配置 ConsoleAppender 和 RollingFileAppender。ConsoleAppender 记录到 System.out,RollingFileAppender 记录到 <wasce_home>/var/log/server.log 文件。缺省日志记录级别为 WARN。它同时会覆盖属性文件中的各个 Logger 的日志级别。
  • <wasce_home>/var/log/deployer-log4j.properties:此文件配置部署器的日志记录服务。部署器组件在使用命令行部署器部署任何应用程序时使用。
  • <wasce_home>/var/log/client-log4.properties:此文件配置 Java EE 应用程序客户端的日志记录服务。

在此部分,我们将按以下方式配置 Log4j

  1. 使用缺省服务器 Log4j 配置
  2. 在应用程序级别设置 Log4j

使用缺省服务器 Log4j 配置

正如前面所述,服务器组件以及在 Community Edition 部署的应用程序都使用 <wasce_home>/var/log/server-log4j.properties 中的配置。我们将使用经过修改、采用 Log4j 进行日志记录的 EMPDemo 示例。另外,它还使用 Community Edition 提供的缺省配置。示例包含相同的 EMPDemo Servlet,不过已修改为使用 Log4j API 进行日志记录。清单 9 显示了修改后的 EMPDemo,其中的日志记录语句使用粗体进行标记。Servlet 获取 Logger 并将日志级别设置为 ALL

清单 9. 修改后使用 Log4j API 的 EMPDemo

点击查看代码清单

清单 9. 修改后使用 Log4j API 的 EMPDemo

Logger logger = Logger.getLogger(EMPDemo.class.getName());logger.setLevel(Level.ALL);
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 environment 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("Created the statement: " +stmt);
    ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEE");
    logger.info("Gto the result set: " +rs);
    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.debug("Debug");logger.info("Info");logger.warn("Warn");logger.error("Error");logger.fatal("Fatal");

}
catch(java.lang.Exception e) {
			
    e.printStackTrace();
    logger.fatal(e.getClass().getName());logger.fatal(e.getMessage());

}

请遵循以下步骤操作,以部署和运行应用程序:

  1. 下载的示例中,将 EMPDemo 解压缩到目录中。war 文件名为 EMPdemo-Log4jLogging1.war
  2. 部署应用程序。
    <wasce_home>/bin>deploy --user system --password manager deploy Log4jLogging1.war.
  3. 将浏览器指向 http://localhost:8080/EMPdemo-log4j1/EMPDemo,以访问 EMPDemo Servlet。Servlet 将在浏览器窗口中显示来自 employee 表的行。

查看控制台窗口,可以看到仅仅记录了清单 10 中所示的日志消息。这是因为 ConsoleAppender 的日志级别缺省为 WARN(在 server-log4j.properties 中)。因此,日志级别为 WARN 或更高的消息记录在控制台中。

清单 10 控制台中的日志消息
14:13:31,687 WARN  [EMPDemo] Warn
14:13:31,687 ERROR [EMPDemo] Error
14:13:31,687 FATAL [EMPDemo] Fatal

打开 <wasce_home>/var/log/server.log 文件,以查看已经记录的所有日志消息。这是因为 FileAppender 的日志级别缺省为 TRACE。因此记录了所有的消息。清单 11 显示了所记录的消息:

清单 11. server.log 文件
14:13:31,687 INFO  [EMPDemo] 
 Created the PrintWriter on the Response object
14:13:31,687 INFO  [EMPDemo] 
 Got environment context: 
 org.apache.xbean.naming.context.ImmutableContext$NestedImmutableContext@5b9e5b9e
14:13:31,687 INFO  [EMPDemo] 
 Got DataSource: org.tranql.connector.jdbc.DataSource@8660866
14:13:31,687 INFO  [EMPDemo] 
 Got Connection: org.tranql.connector.jdbc.ConnectionHandle@a1e0a1e
14:13:31,687 INFO  [EMPDemo] 
 Created the statement: org.tranql.connector.jdbc.StatementHandle@c980c98
14:13:31,687 INFO  [EMPDemo] 
 Got the result set: org.tranql.connector.jdbc.ResultSetHandle@11221122

14:13:31,687 INFO  [EMPDemo] Table EMP after SELECT:
14:13:31,687 INFO  [EMPDemo] 1   PHANI   SSE
14:13:31,687 INFO  [EMPDemo]    NIKHIL   100
14:13:31,687 INFO  [EMPDemo] 2   JOE   SSE
14:13:31,687 INFO  [EMPDemo]    NIKHIL   100
14:13:31,687 INFO  [EMPDemo] 3   JOHN   SSE
14:13:31,687 INFO  [EMPDemo]    BOB   200
14:13:31,687 DEBUG [EMPDemo] Debug
14:13:31,687 INFO  [EMPDemo] Info
14:13:31,687 WARN  [EMPDemo] Warn
14:13:31,687 ERROR [EMPDemo] Error
14:13:31,687 FATAL [EMPDemo] Fatal

在应用程序级别设置 Log4j

有时候,您可能希望在应用程序级别配置 Log4j,而忽略服务器级别的配置。您可以将 Log4j 库和 log4j.properties 配置与应用程序本身打包在一起,然后部署应用程序,从而实现此目标。不过,这里有点小问题——Community Edition 使用“父项优先”类加载器策略。这意味着,如果类在父类加载器中可用,则将会从父类加载器进行加载。由于 Log4j 由服务器组件使用,并由类加载器加载(位于类加载器层次结构中较高的位置),因此将始终使用服务器级别配置的 Log4j,即使 Log4j 库和 log4.properties 文件与应用程序打包在一起也是如此。

为了解决这个问题,我们需要将 Log4j 从父类加载器中隐藏,使其始终从应用程序类加载器进行加载。要隐藏 Log4j,请在 Community Edition 应用程序部署计划中为 Log4j 类指定 <hidden-classes>。有关 Community Edition 提供的其他各种类加载器策略,请参见此技术说明
此部分将说明如何在应用程序级别配置 Log4j。我们使用与之前部分相同的示例。不过,我们将对 Community Edition 应用程序部署计划 (geronimo-web.xml) 进行修改,以隐藏 Log4j 类。清单 12 显示了经过修改的 Geronimo 部署计划,计划中的相关部分以粗体显示。

清单 12. 修改后的 geronimo-web.xml 部署计划
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<web:web-app xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2" 
    xmlns:conn="http://geronimo.apache.org/xml/ns/j2ee/connector-1.2" 
    xmlns:name="http://geronimo.apache.org/xml/ns/naming-1.2" 
    xmlns:ejb="http://openejb.apache.org/xml/ns/openejb-jar-2.2" 
    xmlns:pkgen="http://openejb.apache.org/xml/ns/pkgen-2.1" 
    xmlns:app="http://geronimo.apache.org/xml/ns/j2ee/application-2.0" 
    xmlns:sec="http://geronimo.apache.org/xml/ns/security-2.0" 
    xmlns:web="http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1"
    xmlns:pers="http://java.sun.com/xml/ns/persistence" 
    xmlns:client="http://geronimo.apache.org/xml/ns/j2ee/application-client-2.0">
    <dep:environment>
        <dep:moduleId>
            <dep:groupId>com.ibm.wasce.samples</dep:groupId>
            <dep:artifactId>EMPdemo-log4j-2</dep:artifactId>
            <dep:version>2.1.0.0</dep:version>
            <dep:type>war</dep:type>
        </dep:moduleId>
        <dependencies>
            <dependency>
                <groupId>console.dbpool</groupId>
                <artifactId>EMPLOYEE_DS</artifactId>
            </dependency>
        </dependencies>
        <hidden-classes>
  	<filter>org.apache.log4j</filter>
       </hidden-classes>
    </dep:environment>
    <web:context-root>/EMPdemo-log4j2</web:context-root>
    <name:resource-ref>
        <name:ref-name>jdbc/DataSource</name:ref-name>
        <name:resource-link>EMPLOYEE_DS</name:resource-link>
    </name:resource-ref>
</web:web-app>

另外,我们将 log4j.properties 文件复制到 EMPDemo 应用程序的 WEB-INF/classes 目录,并将 log4j-1.2.14.jar 复制到 WEB-INF/lib 目录。清单 13 显示了 log4j.properties 文件:

清单 13. log4j.properties 文件
log4j.logger.com.ibm.sample=debug,applog

log4j.appender.applog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.applog.File=C:/temp/applevellogging/Log4J/applog1.log
log4j.appender.applog.layout=org.apache.log4j.PatternLayout

log4j.appender.applog.layout.ConversionPattern=%d{ABSOLUTE} %-5p [%c{1}] %m%n

此属性文件定义 Servlet 的 Logger,并将日志级别设置为 DEBUG。但是 Servlet 将此值覆盖,更改为 ALL。另外,还定义了一个 DailyRollingFileAppender,将消息记录到 C:/temp/applevellogging/Log4J/applog1.log 文件。此 Appender 所使用的 Layout 是 the server-log4j.properties 文件中使用的标准 Community Edition 布局。请遵循以下步骤来部署此应用程序。

  1. 下载的示例中,解压缩经过修改的 Web 应用程序。WAR 文件名为 EMPdemo-Log4jLogging2.war
  2. 部署应用程序。
    <wasce_home>/bin>deploy --user system --password manager deploy EMPdemo-Log4jLogging2.war
  3. 将浏览器指向 http://localhost:8080/EMPdemo-log4j2/EMPDemo,以访问 EMPDemo Servlet。Servlet 将在浏览器中显示来自 employee 表的行。

请注意,服务器控制台或 server.log 文件中并不会记录任何消息,因为我们覆盖了服务器级别的 Log4j 配置,而在应用程序级别进行配置。另外,应用程序会创建 C:/temp/applevellogging/Log4J/applog1.log 文件,并在此文件中记录消息。清单 14 显示了文件中记录的消息:

清单 14. applog1.log 文件中的消息
15:18:36,078 INFO  [EMPDemo] 
 Created the PrintWriter on the Response object
15:18:36,093 INFO  [EMPDemo] 
 Got environment context: 
 org.apache.xbean.naming.context.ImmutableContext$NestedImmutableContext@d760d76
15:18:36,093 INFO  [EMPDemo]
 Got DataSource: org.tranql.connector.jdbc.DataSource@32a232a2
15:18:36,109 INFO  [EMPDemo]
 Got Connection: org.tranql.connector.jdbc.ConnectionHandle@61e461e4
15:18:36,109 INFO  [EMPDemo]
 Created the statement: org.tranql.connector.jdbc.StatementHandle@67206720
15:18:36,109 INFO  [EMPDemo]
 Got the result set: org.tranql.connector.jdbc.ResultSetHandle@6f9a6f9a

15:18:36,109 INFO  [EMPDemo] Table EMP after SELECT:
15:18:36,109 INFO  [EMPDemo] 1   PHANI   SSE
15:18:36,109 INFO  [EMPDemo]    NIKHIL   100
15:18:36,109 INFO  [EMPDemo] 2   JOE   SSE
15:18:36,109 INFO  [EMPDemo]    NIKHIL   100
15:18:36,109 INFO  [EMPDemo] 3   JOHN   SSE
15:18:36,109 INFO  [EMPDemo]    BOB   200
15:18:36,109 DEBUG [EMPDemo] Debug
15:18:36,109 INFO  [EMPDemo] Info
15:18:36,109 WARN  [EMPDemo] Warn
15:18:36,109 ERROR [EMPDemo] Error
15:18:36,109 FATAL [EMPDemo] Fatal

在 Community Edition 中使用 SLF4J

Simple Logging Facade for Java (SLF4J) 作为各种日志记录 API 的简单 Facade 使用,可用于在部署时插入所需的实现。SLF4j 并没有创建另一个日志记录框架,而是让应用程序使用标准 API,在部署时插入实际的日志记录实现。

SLF4j 支持多个日志记录系统,如 NOP、Simple、Log4j V1.2、java.util.logging、JCL 和 logback。SLF4j 分发通过多个 JAR 文件提供:

  • slf4j-nop.jar
  • slf4j-simple.jar
  • slf4j-log4j12.jar
  • slf4j-log4j13.jar
  • slf4j-jdk14.jar
  • slf4j-jcl.jar.

其中的每个 jar 文件都在编译时硬连接,只使用一个实现。所有 SLF4j 的绑定都依赖于 slf4j-api.jar,此文件必须在类路径中,绑定才能正常工作。另外,还提供了迁移路径,以便应用程序通过桥接模块使用具体的日志记录实现。Community Edition 提供了可在应用程序中使用的以下库:

  • slf4j-api-1.4.3.jar
  • slf4j-log4j12-1.4.3.jar
  • jcl104-over-slf4j-1.4.3.jar

在此部分,我们将说明如何采用以下方式使用 SLF4j。

  1. 配置 SLF4j 以使用服务器 Log4j 配置
  2. 配置 SLF4j 以在应用程序级别使用 Log4j

配置 SLF4j 以使用服务器 Log4j 配置

在此部分,我们将在 EMPDemo Servlet 中使用 SLF4j API 替代 Log4j API。不过,它在服务器级别使用 Log4j 实现作为具体实现。清单 15 显示了这个 Servlet 的代码:

清单 15. 使用 SLF4j API 的 EMPDemo Servlet

点击查看代码清单

清单 15. 使用 SLF4j API 的 EMPDemo Servlet

Logger logger =  LoggerFactory.getLogger(EMPDemo.class.getName());
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 environment 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("Created the statement: " +stmt);
    ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEE");
    logger.info("Gto the result set: " +rs);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.trace("Trace");logger.debug("Debug");logger.info("Info");logger.warn("Warn");logger.error("Error");

}
catch(java.lang.Exception e) {
			
        e.printStackTrace();
        logger.error(e.getClass().getName());logger.error(e.getMessage());

}

清单 16 显示了 Community Edition 应用程序部署计划 (geronimo-web.xml) 中为 SLF4j 声明的依赖关系。

清单 16. 包含 SLF4j 的依赖关系的 geronimo-web.xml 文件
<dependencies>
        …………
        …………

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.4.3</version>
    <type>jar</type>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.4.3</version>
    <type>jar</type>
    </dependency>
</dependencies>

请遵循以下步骤操作,以部署和运行应用程序:

  1. 下载的示例中,解压缩应用程序文件。war 文件为 Log4j-SLF4j-WEB.war
  2. 部署应用程序。
    <wasce_home>/bin>deploy --user system –-password manager deploy Log4j-SLF4j-WEB.war
  3. 通过 http://localhost:8080/Log4j-SLF4j-WEB/EMPDemo 访问 EMPDemo Servlet。

清单 17 显示了在服务器控制台上显示的日志消息:

清单 17. 服务器控制台消息
10:25:18,593 WARN  [EMPDemo] Warn
10:25:18,593 ERROR [EMPDemo] Error

之所以显示这些消息,是因为 ConsoleAppender 的日志级别在 server-log4j.properties 文件中设置为 WARN。因此,只有日志级别为 WARN 或更高的消息记录在控制台中。不过,您可以看到,所有日志消息都记录在 server.log 文件中。

配置 SLF4j 以在应用程序级别使用 Log4j

在此部分,我们将配置 SLF4j 在 EMPDemo Servlet 的应用程序级别使用所配置的 Log4j。并未更改清单 13 中的 Servlet 代码。不过,应用程序带一个 log4j.properties 文件,替代了服务器级别的 Log4j 配置。EMPDemo Servlet 使用 SLF4j API 记录消息。清单 18 显示了 log4j.properties 文件:

清单 18. log4j.properties 文件
log4j.logger.com.ibm.sample=debug,applog

log4j.appender.applog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.applog.File=C:/temp/applevellogging/SLF4j/java.log
log4j.appender.applog.layout=org.apache.log4j.PatternLayout

log4j.appender.applog.layout.ConversionPattern=%d{ABSOLUTE} %-5p [%c{1}] %m%n

这个 log4j.properties 文件配置 Log4j 服务使用 DailyRollingFileAppender 将消息记录到 C:/temp/applevellogging/SLF4j/java.log 文件。它使用记录消息的 Community Edition 格式。

清单 19 显示了应用程序的 Community Edition 应用程序部署计划 (geronimo-web.xml) 中的相关部分:

清单 19. Community Edition 应用程序部署计划
<dep:environment>
	…………………
	…………………

        <dependencies>
	…………………
	…………………
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>1.4.3</version>
                <type>jar</type>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.4.3</version>
                <type>jar</type>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.14</version>
                <type>jar</type>
            </dependency>
        </dependencies>   
        <hidden-classes>
  	<filter>org.apache.log4j</filter>
       </hidden-classes>             
    </dep:environment>

部署计划声明对 Log4j 和 SLF4j 库的依赖关系,并将 Log4j 包从父类加载器隐藏。请遵循以下步骤来部署此应用程序。

  1. 下载应用程序,将其保存到目录中。WAR 文件名为 Log4j-SLF4j-AppLevel-WEB.war
  2. 部署应用程序。
    <wasce_home>/bin>deploy –user system –password manager deploy Log4j-SLF4j-AppLevel-WEB.war.
  3. 通过 http://localhost:8080/Log4j-SLF4j-WEB/EMPDemo 访问 EMPDemo Servlet。

您可以发现服务器控制台或 server.log 文件中都没有记录消息。不过,应用程序会创建 C:/temp/applevellogging/SLF4j/java.log 文件并按照所配置的方式记录消息。


结束语

我们介绍了如何使用 Community Edition 以各种方式使用 java.util.logging、Log4j 和 SLF4j。您了解了如何使用 gbean 在服务器范围配置服务。您还了解了在需要为日志记录服务使用特定于应用程序的配置时,日志类加载器问题可能会带来什么麻烦。最后,您的应用程序可以通过使用 SLF4j 作为日志记录标准 API 获益,您能够在部署时插入所需的日志记录实现。


下载

描述名字大小
Sample codewasce_logging.zip358KB

参考资料

学习

获得产品和技术

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere, Open source
ArticleID=399470
ArticleTitle=WebSphere Application Server Community Edition 中的应用程序日志记录
publish-date=07022009