1. 程式人生 > >JDK1.4的java.util.Logging包的使用說明與示例

JDK1.4的java.util.Logging包的使用說明與示例

Sun公司推出的JDK1.4版本在java.util.Logging軟體包中新增加了處理應用程式日誌工作的核心API函式。這個Java日誌軟體包提供了一種為Java應用程式嵌入多級日誌的簡單而又靈活的方法。

簡要介紹

java.util.Logging包括1個介面: Filter;15個類: Logger, LogManager, ErrorManager, Level, LogRecord, LoggingPermission, Handler, MemoryHandler, StreamHandler, ConsoleHandler, FileHandler, SocketHandler, Formatter, SimpleFormatter, XMLFormatter,

下面是這些類的簡單關係是

處理器的繼承關係

Handler

MemoryHandler

ConsoleHandler

StreamHandler

FileHandler

SocketHandler


格式化器的繼承關係

Formatter


SimpleFormatter

XMLFormatter

/介面功能概要

1.Filter(過濾器):控制日誌記錄的輸出粒度, 粒度範圍超過了Level類提供的功能,在每個handlersetFilter方法中設定該型別

2.Logger(日誌記錄器): 為了利用日誌軟體包,Logger物件並呼叫Logger中多個記錄方法中的某一個,例如info(String message)。日誌記錄器Logger建立一個LogRecord(包含應用程式具體的日誌資訊)物件並把它傳遞到一個或者多個HandlerHandler物件再把它輸出到目標,這樣就實現了日誌記錄的輸出。在日誌的輸出過程中,LoggerHandler物件可以根據日誌等級和過濾器(Filter)來判斷那些日誌需要記錄下來。同時,HandlerFormatter協同工作,Formatter對日誌資訊進行格式化,決定日誌記錄如何輸出到日誌

3.LogManager(日誌管理器):管理一個日誌記錄器物件的名稱空間,所有已命名的日誌記錄器都被儲存在這個名稱空間中;管理一套日誌記錄的控制屬性,這些是簡單的值對像,可以被Handlerlogging物件使用來進行自我配置;

4.ErrorManager(錯誤管理器): ErrorManager物件依附在Handler物件上,用來處理在記錄日誌期間發生在Handler物件上的任何錯誤.但在處理輸出日誌時,假如Handler物件遇到問題時, Handler並沒有丟擲異常給日誌記錄的呼叫者,而是用依附在Handler上的ErrorManager來處理。

5.Level(等級): Java 日誌軟體包對每一個日誌訊息都賦以一個等級,以控制日誌記錄的輸出。等級是一個整型資料,記錄的等級越高,那麼這個整型資料也就越大。下面的等級是在Level類中定義的(按照從低到高的順序排列):

級別

重要性

日誌記錄器相應的日誌方法

級別數值

SEVERE

非常重要

severe(String message);

1000

WARNING

針對警告

warning(String message);

900

INFO

資訊化的執行時間訊息

info(String message);

800

CONFIG

靜態設定的訊息

config(String message);

700

FINE

提供追蹤資訊

fine(String message);

500

FINER

顯示詳細的追蹤資訊

finer(String message);

400

FINEST

更詳細的追蹤資訊

finest(String message);

300

ALL

顯示所有應該日誌記錄的資訊

沒有可應用的

Integer.MIN_VALUE

OFF

關閉日誌

沒有可應用的

Integer.MAX_VALUE

6.LogRecord(記錄資訊): LogRecord物件用來在日誌框架和單個日誌記錄Handler之間傳遞日誌記錄請求,當一個LogRecord被傳遞進框架時, 在邏輯上它是屬於框架的,不應該被客戶應用程式使用或更新

注意:假如客戶應用程式沒有指定一個顯式的來源方法名稱和來源類名稱, 當他們(方法或類)第一次被訪問時(由於對getSourceMethodName或者getSourceClassName方法的呼叫),LogRecord類將通過分析呼叫堆疊,自動推斷他們.因此,假如一個日誌處理器想停止傳遞一個LogRecord給另一個執行緒,或者通過RMI傳播,並且假如它後來想得到方法和類名,它應該呼叫getSourceClassNamegetSourceMethodName來確保有值被填入.

7.LoggingPermission(記錄許可):當代碼和一個呼叫日誌記錄控制方法的安全管理器(SecurityManager)一起執行的時候,安全管理器(SecurityManager)將檢測這個許可.當前僅僅有一個LoggingPermission.這值控制,並且它有控制日誌記錄配置的能力,例如新增或刪除Handler,新增或刪除過濾器,或者改變日誌等級.程式設計師不必直接建立LoggingPermission物件.而是由讀取的安全策略檔案(security policy file)來建立

8.Handler(處理器): Handler物件從Logger那裡獲得日誌資訊並且將它輸出。可能會輸出到控制檯,或者輸出到檔案,或者把這些日誌資訊傳送到網路中的日誌服務,或者把它們轉發給作業系統日誌,或者其他什麼。。JDK1.4日誌API提供了兩大類Handler物件。MemoryHandler簡單的把日誌訊息儲存在迴圈記憶體緩衝(circular memory buffer),當特定的觸發事件發生時,再把它們釋出到目標handler。典型的觸發事件是接收到等級符合釋出等級的日誌訊息。如果需要其它釋出標準,MemoryHandler類可以擴充套件,重寫日誌方法來按照使用者定義的日誌記錄條件來發布記憶體緩衝。StreamHandler向指定的輸出流釋出日誌記錄。Java日誌API指定了三種StreamHandler物件。ConsoleHandler向標準錯誤流釋出日誌記錄。FileHandler向指定的檔案釋出日誌記錄,它也可以配置成向迴圈檔案集寫入日誌記錄。SocketHandler向網路流釋出日誌記錄(與其它應用通訊)。可以通過呼叫setLevel(Level.OFF)使處理器無效,也可以通過呼叫setLevel方法的一個適當的等級使其有效.處理器類用LogManager屬性來設定處理器的過濾器,格式化和等級的預設值.

9.MemoryHandler(儲存處理器):把請求緩衝在記憶體的迴圈緩衝區內,通常這個處理器簡單地把引入的LogRecord存貯在緩衝區,並丟棄以前的記錄.這個緩衝很便宜並且避免了格式化.在某些特殊情況下, MemoryHandler將把當前緩衝區中內容擠出到目標緩衝區. 主要有三種引發擠壓緩衝區的模型:

n引入的LogRecord有一個大於以前定義等級的型別,也就是擠壓等級

n一個外部類顯示地呼叫擠壓方法

n一個子類過載log方法,並且掃描每個引入的LogRecord,假如它匹配需求標準,將呼叫擠壓方法

10.StreamHandler(流處理器):流基於日誌記錄處理器(logging Handler),這主要是作為一個基類或支援類來實現其他日誌記錄處理器. LogRecord被髮送到一個給定的java.io.OutputStream.

11.ConsoleHandler(控制檯處理器):這個處理器向標準錯誤流(System.err)傳送日誌記錄,預設SimpleFormatter被用來產生簡短的概要

12.FileHandler(檔案處理器):簡單檔案日誌處理器.FileHandler可以寫到一個指定的檔案,或者一套迴圈檔案.對一套迴圈檔案,當每個檔案達到一個指定大小的時候,它將被關閉,迴圈出去,一個新的檔案被開啟.老的檔案將按順序加上"0", "1", "2". 預設用XMLFormatter來格式化

13.SocketHandler(網路處理器):釋出LogRecord到一個網路流連線.預設用XMLFormatter來格式化

14.Formatter(格式化器):格式化器提供格式化LogRecord支援.每個日誌處理器器都有一個格式化器格.式化器獲得一個LogRecord,並把它轉化為字串.有一些格式化器(例如XMLFormatter)需要包裝頭和尾字串圍繞一套格式化記錄. GetHeadergetTail方法可以用來獲得這些字串.

15.SimpleFormatter(簡單格式化器): Print a brief summary of the LogRecord in a human readable format. The summary will typically be 1 or 2 lines用一種可以閱讀的格式來列印LogRecord的簡單概要.典型的概要是1或者2.

16.XMLFormatter(XML格式化器):LogRecord格式化尾標準的XML格式.DTD規範在Java Logging APIs規範的附錄A中提供

示例剖析

1.簡單示例

這個示例說明logging的常用操作

public class JDK14LoggingTest {

/**

日誌記錄器

*/

Logger log = Logger.getLogger(getClass().getName());

/**

* 日誌輸出物件

*/

Handler fileHandler = null;

/**

* 構造方法

*/

public JDK14LoggingTest() {

//設定輸出到檔案

try {

fileHandler = new FileHandler("%h/java%u.log");

//fileHandler = new FileHandler("%h/java%u.log",10,5,true);

//設定記錄級別

fileHandler.setLevel(Level.WARNING);

//設定過濾器,已達到更細粒度的記錄

//fileHandler.setFilter();

//設定輸出格式,有兩種型別:SimpleFormatterXMLFormatter,

//預設是XMLFormatter,當然自己也可以擴張,只要繼承Formatter類就可以了

fileHandler.setFormatter(new SimpleFormatter());

//指定日誌編碼格式

//fileHandler.setEncoding("");

//設定錯誤處理

//fileHandler.setErrorManager(new ErrorManager());

}

catch (Exception ex) {

ex.printStackTrace();

}

log.addHandler(fileHandler);

}

public void testLog(){

log.info(getClass().getName());

log.log(Level.WARNING,getClass().getName(),"testLog");

}

public static void main(String[] args) {

JDK14LoggingTest test = new JDK14LoggingTest();

test.testLog();

}

}

2.資料庫Handler示例

從上面的描述可以看出,jdk1.4logging沒有提供輸出到資料庫的Handler,下面將介紹一個怎樣把日誌輸出到資料庫, 我們知道Handler物件負責從Logger那裡獲取日誌資訊然後把它輸出到目的地。而使用者希望把日誌儲存到資料庫中,其實這只是把日誌資訊的輸出目標替換為資料庫而已。所以編寫擴充套件HandlerJDBCHandler類,由它來實現把日誌資訊寫入到資料庫中。要想擴充套件Handler類,必須實現Handler定義的三個抽象函式(abstract):

public abstract void flush() ;

public abstract void publish(LogRecord record) ;

public abstract void close() throws java.lang.SecurityException;

其中,publish(LogRecord record)方法最為重要,它最終實現把日誌資訊輸出到目標。close()方法負責釋放所有handler所擁有的資源。這次我們只在publish(LogRecord record)方法中實現把日誌資訊(封裝在LogRecord物件中)通過合適的JDBC驅動程式插入到資料庫中就可以了, 下面我就以向MySql資料庫輸出日誌記錄為例,完整原始碼的實現如下:

package com.benqguru.commons.logging.test;

import java.util.logging.*;

import java.sql.*;

class JDBCHandler

extends Handler {

public void flush() {

}

public void publish(LogRecord record) {

Connection conn = null;

PreparedStatement pstmt = null;

try {

Class.forName("org.gjt.mm.mysql.Driver");

conn = DriverManager.getConnection("mysql://10.89.58.228:3306/logtest","root","");

if (conn != null) {

Object[] content = record.getParameters();

String sql = "insert into MyLog(logTime,EventType) values(?,?)";

pstmt = conn.prepareStatement(sql);

pstmt.setLong(1, record.getMillis());

pstmt.setString(2, (String) content[0]);

//save loginfo in databse

pstmt.execute();

}

}

catch (Exception e) {

e.printStackTrace();

}

finally {

if (conn != null) {

try {

conn.close();

}

catch (Exception ex) {