程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> WebSphere >> WebSphere Application Server Community Edition中的應用程序日志記錄

WebSphere Application Server Community Edition中的應用程序日志記錄

編輯:WebSphere

引言

應用程序日志記錄提供了捕獲在應用程序執行期間發生的各種事件的方法。它將收集關於應用程序在執行各種任務時在做什麼的詳細信息。此信息在調試、故障排除甚至審核方面很有用。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,並在部署時插入實際的日志記錄實現,如 NOP、Simple、log4j V1.2、JDK 1.4 日志記錄、JCL 和 logback。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。其中包括以下部分:

設置環境

在 Community Edition 中配置 java.util.logging

Community Edition 獨特性及充分利用 Log4j

在 Community Edition 中使用 SLF4j

在每個部分,我們將簡單描述相應的日志記錄 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 數據庫

啟動 Community Edition 服務器,將浏覽器窗口指向 http://localhost:8080/console,以啟動 Web 管理控制台。

提供 system 作為用戶名,使用 manager 作為密碼,以登錄到管理控制台。

在管理控制台左側的 Console Navigation Portlet 中,單擊 DB Manager 鏈接,以在右側打開 DB Viewer 和 Run SQL Portlet,如圖 1 中所示:

圖 1. DB Viewer 和 Run SQL Portlet 通信

在 Run SQL Portlet 上,在 Create DB 文本框中輸入 EMPLOYEE_DB,並單擊 Create 按鈕,這將在嵌入式 Derby 數據庫中創建一個 EMPLOYEE_DB 數據庫。創建之後,Database List Portlet 將列出 EMPLOYEE_DB 數據庫,如圖 2 中所示。

圖 2. DB Viewer Portlet 中的 EMPLOYEE_DB

單擊 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);

類似地,使用以下 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);

最終的表應該與圖 3 中所示類似:

圖 3. 最終的 EMPLOYEE_DB 表

在 EMPLOYEE_DB 數據庫上部署 EMPLOYEE_DS 數據源

在管理控制台的 Console Navigation Portlet 中單擊 Database Pools。此步驟將打開 Database Pools Portlet,其中將列出當前在服務器上部署的數據庫池。

單擊 Using the Geronimo database pool wizard 以創建新數據庫池。在 Name of the Database Pool 字段輸入 EMPLOYEE_DS ,並在 Database Type 組合框中選擇 Derby embedded,如圖 4 中所示。單擊 Next。

圖 4. 創建數據庫池

在下一屏幕上,在 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 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 服務器存儲庫。

打開命令提示符,並轉到 <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 或更高級別記錄的所有消息。

Community Edition 獨特性及充分利用 Log4j

Log4j 是來自 Apache Software Foundation 的日志記錄服務開源庫。Log4j 在開源社區中廣泛使用,包括一些重要的項目,如 Apache Geronimo、JBoss 等。Log4j 的體系結構圍繞三個主要概念發展:Logger、Appender 和 Layout。

應用程序首先調用 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.properties 或 log4j.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

使用缺省服務器 Log4j 配置

在應用程序級別設置 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

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());

}

請遵循以下步驟操作,以部署和運行應用程序:

在下載的示例中,將 EMPDemo 解壓縮到目錄中。war 文件名為 EMPdemo-Log4jLogging1.war。

部署應用程序。
<wasce_home >/bin>deploy --user system --password manager deploy Log4jLogging1.war.

將浏覽器指向 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>。

此部分將說明如何在應用程序級別配置 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 布局。請遵循以下步驟來部署此應用程序。

在下載的示例中,解壓縮經過修改的 Web 應用程序。WAR 文件名為 EMPdemo-Log4jLogging2.war。

部署應用程序。
<wasce_home>/bin>deploy --user system --password manager deploy EMPdemo-Log4jLogging2.war

將浏覽器指向 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。

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

配置 SLF4j 以在應用程序級別使用 Log4j

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

在此部分,我們將在 EMPDemo Servlet 中使用 SLF4j API 替代 Log4j API。不過,它在服務器級別使用 Log4j 實現作為具體實現。清單 15 顯示了這個 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>

請遵循以下步驟操作,以部署和運行應用程序:

在下載的示例中,解壓縮應用程序文件。war 文件為 Log4j-SLF4j-WEB.war。

部署應用程序。
<wasce_home>/bin>deploy --user system –-password manager deploy Log4j-SLF4j-WEB.war

通過 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 包從父類加載器隱藏。請遵循以下步驟來部署此應用程序。

下載應用程序,將其保存到目錄中。WAR 文件名為 Log4j-SLF4j-AppLevel-WEB.war。

部署應用程序。
<wasce_home>/bin>deploy –user system –password manager deploy Log4j-SLF4j-AppLevel-WEB.war.

通過 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 獲益,您能夠在部署時插入所需的日志記錄實現。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved