當前位置:才華齋>IT認證>SUN認證>

Java日誌系統框架的設計與實現

SUN認證 閱讀(2.86W)

在Java 領域,存在大量的日誌元件,open-open收錄了21個日誌元件。日誌系統作為一種應用程式服務,對於跟蹤除錯、程式狀態記錄、崩潰資料恢復都有著重要的作用,我們可以把Java日誌系統看作是必不可少的跟蹤除錯工具。

Java日誌系統框架的設計與實現

  1.簡介

日誌系統是一種不可或缺的跟蹤除錯工具,特別是在任何無人職守的後臺程式以及那些沒有跟蹤除錯環境的系統中有著廣泛的應用。長期以來,日誌系統作為一種應用程式服務,對於跟蹤除錯、程式狀態記錄、崩潰資料恢復都有非常現實的意義。這種服務通常以兩種方式存在:

1.日誌系統作為服務程序存在。Windows中的的事件日誌服務就屬於這種型別,該型別的日誌系統通常通過訊息佇列機制將所需要記錄的日誌由日誌傳送端傳送給日誌服務。日誌傳送端和日誌儲存端通常不在同一程序當中,日誌的傳送是非同步過程。這種日誌服務通常用於管理員監控各種系統服務的狀態。

2.日誌系統作為系統呼叫存在。Java世界中的日誌系統和Unix環境下諸多守護程序所使用的日誌系統都屬於這種型別。日誌系統的程式碼作為系統呼叫被編譯進日誌傳送端,日誌系統的執行和業務程式碼的執行在同一程序空間。日誌的傳送多數屬於同步過程。這種日誌服務由於能夠同步反映處系統執行狀態,通常用於除錯跟蹤和崩潰恢復。

本文建立的日誌系統基本屬於第二種型別,但又有所不同。該日誌系統將利用Java執行緒技術實現一個既能夠反映統一執行緒空間中程式執行狀態的同步日誌傳送過程,又能夠提供快速的日誌記錄服務,還能夠提供靈活的日誌格式配置和過濾機制。

1.1系統除錯的誤區

在控制檯環境上除錯Java程式時,此時往控制檯或者文字檔案輸出一段文字是檢視程式執行狀態最簡單的做法,但這種方式並不能解決全部的問題。有時候,對於一個我們無法實時檢視系統輸出的系統或者一個確實需要保留我們輸出資訊的系統,良好的日誌系統顯得相當必要。因此,不能隨意的輸出各種不規範的除錯資訊,這些隨意輸出的資訊是不可控的,難以清除,可能為後臺監控、錯誤排除和錯誤恢復帶來相當大的阻力。

1.2日誌系統框架的基本功能

一個完備的日誌系統框架通常應當包括如下基本特性:

所輸出的日誌擁有自己的分類:這樣在除錯時便於針對不同系統的不同模組進行查詢,從而快速定位到發生日誌事件的程式碼。

日誌按照某種標準分成不同級別:分級以後的日誌,可以用於同一分類下的日誌篩選。

支援多執行緒:日誌系統通常會在多執行緒環境中使用,特別是在Java系統當中,因此作為一種系統資源,日誌系統應當保證是執行緒安全的。

支援不同的記錄媒介:不同的工程專案往往對日誌系統的記錄媒介要求不同,因此日誌系統必須提供必要的開發介面,以保證能夠比較容易的更換記錄介質。

高效能:日誌系統通常要提供高速的日誌記錄功能以應對大系統下大請求流量下系統的正常運轉。

穩定性:日誌系統必須是保持高度的穩定性,不能因為日誌系統內部錯誤導致主要業務程式碼的崩潰。

1.3常用日誌系統簡介

在Java世界中,以下三種日誌框架比較優秀:

1)Log4J

最早的Java日誌框架之一,由Apache基金會發起,提供靈活而強大的日誌記錄機制。但是其複雜的配置過程和內部概念往往令使用者望而卻步。

2)JDK1.4LoggingFramework

繼Log4J之後,JDK標準委員會將Log4J的基本思想吸收到JDK當中,在JDK1.4中釋出了第一個日誌框架介面,並提供了一個簡單實現。

3)CommonsLoggingFramwork

該框架同樣是Apache基金會專案,其出現主要是為了使得Java專案能夠在Log4J和JDK1.4lLoggingFramework的使用上隨意進行切換,因此該框架提供了統一的呼叫介面和配置方法。

  2.系統設計

由於Log4J得到廣泛應用,從使用者的角度考慮,本文所設計的框架,採用了部分Log4J的介面和概念,但內部實現則完全不同。使用Java實現日誌框架,關鍵的.技術在於前面提及的日誌框架特性的內部實現,特別是:日誌的分類和級別、日誌分發框架的設計、日誌記錄器的設計以及在設計中的高效能和高穩定性的考慮。

2.1系統架構

日誌系統框架可以分為日誌記錄模組和日誌輸出模組兩大部分。日誌記錄模組負責建立和管理日誌記錄器(Logger),每一個Logger物件負責按照不同的級別(LoggerLevel)接收各種記錄了日誌資訊的日誌物件(LogItem),Logger物件首先獲取所有需要記錄的日誌,並且同步地將日誌分派給日誌輸出模組。日誌輸出模組則負責日誌輸出器(Appender)的建立和管理,以及日誌的輸出。系統中允許有多個不同的日誌輸出器,日誌輸出器負責將日誌記錄到儲存介質當中。

日誌記錄器Logger是整個日誌系統框架的使用者使用介面,程式設計師可以通過該介面記錄日誌,為了實現對日誌進行分類,系統設計允許存在多個Logger物件,每一個Logger負責一類日誌的記錄,Logger類同時實現了對其物件本身的管理。LoggerLevel類定義了整個日誌系統的級別,在客戶端建立和傳送日誌時,這些級別會被使用到。Logger物件在接收到客戶端建立和傳送的日誌訊息時,同時將該日誌訊息包裝成日誌系統內部所使用的日誌物件LogItem,日誌物件除了傳送端所傳送的訊息以外,還會包裝諸如傳送端類名、傳送事件、傳送方法名、傳送行號等等。這些額外的訊息對於系統的跟蹤和除錯都非常有價值。包裝好的LogItem最終被髮送給輸出器,由這些輸出器負責將日誌資訊寫入最終媒介,輸出器的型別和個數均不固定,所有的輸出器通過AppenderManager進行管理,通常通過配置檔案即可方便擴展出多個輸出器。

2.2日誌記錄部分的設計

如前文所述,日誌記錄部分負責接收日誌系統客戶端傳送來的日誌訊息、日誌物件的管理等工作。下面詳細描述了日誌記錄部分的設計要點:

1.日誌記錄器的管理

系統通過保持多個Logger物件的方式來進行日誌記錄的分類。每一個Logger物件代表一類日誌分類。因此,Logger物件的名稱屬性是其唯一標識,通過名稱屬性獲取一個Logger物件:

erLoggerlogger=ogger(“LoggerName”);

一般的,使用類名來作為日誌記錄器的名稱,這樣做的好處在於能夠儘量減少日誌記錄器命名之間的衝突(因為Java類使用包名),同時能夠將日誌記錄分類得儘可能的精細。因此,假定有一UserManager類需要使用日誌服務,則更一般的使用方式為:

erLoggerlogger=ogger(s);

2.日誌分級的實現

按照日誌目的不同,將日誌的級別由低到高分成五個級別:

◆DEBUG-表示輸出的日誌為一個除錯資訊;

◆INFO-表示輸出的日誌是一個系統提示;

◆WARN-表示輸出的日誌是一個警告資訊;

◆ERROR-表示輸出的日誌是一個系統錯誤;

◆FATAL-表示輸出的日誌是一個導致系統崩潰嚴重錯誤。

這些日誌級別定義在LoggerLevel介面中,被日誌記錄器Logger在內部使用。而對於日誌系統客戶端則可使用Logger類介面對直接呼叫並輸出這些級別的日誌,Logger的這些介面描述如下:

icvoiddebug(Stringmsg);//輸出除錯資訊

icvoidinfo(Stringmsg);//輸出系統提示

icvoidwarn(Stringmsg);//輸出警告資訊

icvoidfatal(Stringmsg);//輸出系統錯誤

icvoiderror(Stringmsg);//輸出嚴重錯誤

通過對Logger物件上這些介面的呼叫,直接為日誌資訊賦予了級別屬性,這樣為後繼的按照不同級別進行輸出的工作奠定了基礎。

  3.日誌物件資訊的獲取

日誌物件上包含了一條日誌所具備的所有資訊。通常這些資訊包括:輸出日誌的時間、Java類、類成員方法、所在行號、日誌體、日誌級別等等。在JDK1.4中可以通過在方法中丟擲並且捕獲住一個異常,則在捕捉到的異常物件中已經由JVM自動填充好了系統呼叫的堆疊,在JDK1.4中則可以使用kTraceElement獲取到每一個堆疊項的基本資訊,通過對日誌客戶端輸出日誌方法呼叫層數的推算,則可以比較容易的獲取到StackTraceElement物件,從而獲取到輸出日誌時的Java類、類成員方法、所在行號等資訊。在JDK1.3或者更早的版本中,相應的工作則必須通過將異常的堆疊資訊輸出到字串中,並分析該字串格式得到。

2.3日誌輸出部分的設計

日誌輸出部分的設計具有一定的難度,在本文設計的日誌系統中,日誌的輸出、多執行緒的支援、日誌系統的擴充套件性、日誌系統的效率等問題都交由日誌輸出部分進行管理。

1.日誌輸出器的繼承結構

在日誌的輸出部分採用了二層結構,即定義了一個抽象的日誌輸出器(AbstractLoggerAppender),然後從該抽象類繼承出實際的日誌輸出器。AbstractLoggerAppender定義了一系列的對日誌進行過濾的方法,而具體輸出到儲存媒介的方法則是一個抽象方法,由子類實現。在系統中預設實現了控制檯輸出器和檔案輸出器兩種,其中控制檯輸出器的實現頗為簡單。

2.檔案輸出器的內部實現

在日誌記錄部分的實現中,並沒有考慮多執行緒、高效率等問題,因此檔案輸出器必須考慮這些問題的處理。在檔案輸出器內部使用or定義了一個執行緒安全的高速緩衝,所有通過日誌記錄部分分派到檔案輸出器的日誌被直接放置到該高速緩衝當中。同時在檔案輸出器內部定義一個工作執行緒,負責定期將高速緩衝中的內容儲存到檔案,在儲存的過程中同時可以進行日誌檔案的備份等工作。由於採用了高速緩衝的結構,很顯然日誌客戶端的呼叫已經不再是一個同步呼叫,從而不再會需要等到檔案操作後才返回,提高的系統呼叫的速度。該原理如圖3所示:

2.4設計難點

通過上述設計,一個具有良好擴充套件能力的高效能日誌系統框架就已經具有了一定的雛形。在設計過程中幾個難點問題需要進一步反思。

一、是否整個系統應當採用完全非同步的結構,通過類似於訊息機制的方式來進行由日誌客戶端傳送日誌給日誌系統。這種方式可以作為日誌系統框架另一種執行方式,在後繼設計中加以考慮。

二、在檔案輸出器中可以看到,目前雖然可以擴充套件多個日誌輸出器,但是目前提供的抽象類中僅僅提供了對日誌的過濾機制,而沒有提供的快取機制,目前的快取機制被放在檔案輸出器中實現,因此在未來的進一步設計中,可以將檔案輸出器中的快取機制上移到抽象類當中。

2.5設計模式

在設計過程中我們特別注意使用了數個經典的設計模式。如:Logger物件的建立使用了工廠方法模式(FactoryMethod)、由AbstractLoggerAppender和ConsoleAppender以及FileAppender構成了策略模式(Strategy),除此以外,還大量使用了單例模式(Singleton)。在設計中適當運用設計模式能夠加快設計進度、提高設計質量。

3.總結

本文探討了日誌系統的基本特性、實現日誌系統的意義、方法和內部結構,並且給出了一種基於Java平臺的日誌系統的詳細設計。同時也指出日誌系統會向服務化、非同步化的方向發展。作為一種方便的跟蹤除錯、資料恢復工具,應當提倡在適當的環境下對日誌系統的使用。