- 相關(guān)推薦
Java日志系統(tǒng)框架的設(shè)計(jì)與實(shí)現(xiàn)
在Java 領(lǐng)域,存在大量的日志組件,open-open收錄了21個(gè)日志組件。日志系統(tǒng)作為一種應(yīng)用程序服務(wù),對(duì)于跟蹤調(diào)試、程序狀態(tài)記錄、崩潰數(shù)據(jù)恢復(fù)都有著重要的作用,我們可以把Java日志系統(tǒng)看作是必不可少的跟蹤調(diào)試工具。
1.簡(jiǎn)介
日志系統(tǒng)是一種不可或缺的跟蹤調(diào)試工具,特別是在任何無(wú)人職守的后臺(tái)程序以及那些沒(méi)有跟蹤調(diào)試環(huán)境的系統(tǒng)中有著廣泛的應(yīng)用。長(zhǎng)期以來(lái),日志系統(tǒng)作為一種應(yīng)用程序服務(wù),對(duì)于跟蹤調(diào)試、程序狀態(tài)記錄、崩潰數(shù)據(jù)恢復(fù)都有非常現(xiàn)實(shí)的意義。這種服務(wù)通常以?xún)煞N方式存在:
1.日志系統(tǒng)作為服務(wù)進(jìn)程存在。Windows中的的事件日志服務(wù)就屬于這種類(lèi)型,該類(lèi)型的日志系統(tǒng)通常通過(guò)消息隊(duì)列機(jī)制將所需要記錄的日志由日志發(fā)送端發(fā)送給日志服務(wù)。日志發(fā)送端和日志保存端通常不在同一進(jìn)程當(dāng)中,日志的發(fā)送是異步過(guò)程。這種日志服務(wù)通常用于管理員監(jiān)控各種系統(tǒng)服務(wù)的狀態(tài)。
2.日志系統(tǒng)作為系統(tǒng)調(diào)用存在。Java世界中的日志系統(tǒng)和Unix環(huán)境下諸多守護(hù)進(jìn)程所使用的日志系統(tǒng)都屬于這種類(lèi)型。日志系統(tǒng)的代碼作為系統(tǒng)調(diào)用被編譯進(jìn)日志發(fā)送端,日志系統(tǒng)的運(yùn)行和業(yè)務(wù)代碼的運(yùn)行在同一進(jìn)程空間。日志的發(fā)送多數(shù)屬于同步過(guò)程。這種日志服務(wù)由于能夠同步反映處系統(tǒng)運(yùn)行狀態(tài),通常用于調(diào)試跟蹤和崩潰恢復(fù)。
本文建立的日志系統(tǒng)基本屬于第二種類(lèi)型,但又有所不同。該日志系統(tǒng)將利用Java線(xiàn)程技術(shù)實(shí)現(xiàn)一個(gè)既能夠反映統(tǒng)一線(xiàn)程空間中程序運(yùn)行狀態(tài)的同步日志發(fā)送過(guò)程,又能夠提供快速的日志記錄服務(wù),還能夠提供靈活的日志格式配置和過(guò)濾機(jī)制。
1.1系統(tǒng)調(diào)試的誤區(qū)
在控制臺(tái)環(huán)境上調(diào)試Java程序時(shí),此時(shí)往控制臺(tái)或者文本文件輸出一段文字是查看程序運(yùn)行狀態(tài)最簡(jiǎn)單的做法,但這種方式并不能解決全部的問(wèn)題。有時(shí)候,對(duì)于一個(gè)我們無(wú)法實(shí)時(shí)查看系統(tǒng)輸出的系統(tǒng)或者一個(gè)確實(shí)需要保留我們輸出信息的系統(tǒng),良好的日志系統(tǒng)顯得相當(dāng)必要。因此,不能隨意的輸出各種不規(guī)范的調(diào)試信息,這些隨意輸出的信息是不可控的,難以清除,可能為后臺(tái)監(jiān)控、錯(cuò)誤排除和錯(cuò)誤恢復(fù)帶來(lái)相當(dāng)大的阻力。
1.2日志系統(tǒng)框架的基本功能
一個(gè)完備的日志系統(tǒng)框架通常應(yīng)當(dāng)包括如下基本特性:
所輸出的日志擁有自己的分類(lèi):這樣在調(diào)試時(shí)便于針對(duì)不同系統(tǒng)的不同模塊進(jìn)行查詢(xún),從而快速定位到發(fā)生日志事件的代碼。
日志按照某種標(biāo)準(zhǔn)分成不同級(jí)別:分級(jí)以后的日志,可以用于同一分類(lèi)下的日志篩選。
支持多線(xiàn)程:日志系統(tǒng)通常會(huì)在多線(xiàn)程環(huán)境中使用,特別是在Java系統(tǒng)當(dāng)中,因此作為一種系統(tǒng)資源,日志系統(tǒng)應(yīng)當(dāng)保證是線(xiàn)程安全的。
支持不同的記錄媒介:不同的工程項(xiàng)目往往對(duì)日志系統(tǒng)的記錄媒介要求不同,因此日志系統(tǒng)必須提供必要的開(kāi)發(fā)接口,以保證能夠比較容易的更換記錄介質(zhì)。
高性能:日志系統(tǒng)通常要提供高速的日志記錄功能以應(yīng)對(duì)大系統(tǒng)下大請(qǐng)求流量下系統(tǒng)的正常運(yùn)轉(zhuǎn)。
穩(wěn)定性:日志系統(tǒng)必須是保持高度的穩(wěn)定性,不能因?yàn)槿罩鞠到y(tǒng)內(nèi)部錯(cuò)誤導(dǎo)致主要業(yè)務(wù)代碼的崩潰。
1.3常用日志系統(tǒng)簡(jiǎn)介
在Java世界中,以下三種日志框架比較優(yōu)秀:
1)Log4J
最早的Java日志框架之一,由Apache基金會(huì)發(fā)起,提供靈活而強(qiáng)大的日志記錄機(jī)制。但是其復(fù)雜的配置過(guò)程和內(nèi)部概念往往令使用者望而卻步。
2)JDK1.4LoggingFramework
繼Log4J之后,JDK標(biāo)準(zhǔn)委員會(huì)將Log4J的基本思想吸收到JDK當(dāng)中,在JDK1.4中發(fā)布了第一個(gè)日志框架接口,并提供了一個(gè)簡(jiǎn)單實(shí)現(xiàn)。
3)CommonsLoggingFramwork
該框架同樣是Apache基金會(huì)項(xiàng)目,其出現(xiàn)主要是為了使得Java項(xiàng)目能夠在Log4J和JDK1.4lLoggingFramework的使用上隨意進(jìn)行切換,因此該框架提供了統(tǒng)一的調(diào)用接口和配置方法。
2.系統(tǒng)設(shè)計(jì)
由于Log4J得到廣泛應(yīng)用,從使用者的角度考慮,本文所設(shè)計(jì)的框架,采用了部分Log4J的接口和概念,但內(nèi)部實(shí)現(xiàn)則完全不同。使用Java實(shí)現(xiàn)日志框架,關(guān)鍵的技術(shù)在于前面提及的日志框架特性的內(nèi)部實(shí)現(xiàn),特別是:日志的分類(lèi)和級(jí)別、日志分發(fā)框架的設(shè)計(jì)、日志記錄器的設(shè)計(jì)以及在設(shè)計(jì)中的高性能和高穩(wěn)定性的考慮。
2.1系統(tǒng)架構(gòu)
日志系統(tǒng)框架可以分為日志記錄模塊和日志輸出模塊兩大部分。日志記錄模塊負(fù)責(zé)創(chuàng)建和管理日志記錄器(Logger),每一個(gè)Logger對(duì)象負(fù)責(zé)按照不同的級(jí)別(LoggerLevel)接收各種記錄了日志信息的日志對(duì)象(LogItem),Logger對(duì)象首先獲取所有需要記錄的日志,并且同步地將日志分派給日志輸出模塊。日志輸出模塊則負(fù)責(zé)日志輸出器(Appender)的創(chuàng)建和管理,以及日志的輸出。系統(tǒng)中允許有多個(gè)不同的日志輸出器,日志輸出器負(fù)責(zé)將日志記錄到存儲(chǔ)介質(zhì)當(dāng)中。
日志記錄器Logger是整個(gè)日志系統(tǒng)框架的用戶(hù)使用接口,程序員可以通過(guò)該接口記錄日志,為了實(shí)現(xiàn)對(duì)日志進(jìn)行分類(lèi),系統(tǒng)設(shè)計(jì)允許存在多個(gè)Logger對(duì)象,每一個(gè)Logger負(fù)責(zé)一類(lèi)日志的記錄,Logger類(lèi)同時(shí)實(shí)現(xiàn)了對(duì)其對(duì)象本身的管理。LoggerLevel類(lèi)定義了整個(gè)日志系統(tǒng)的級(jí)別,在客戶(hù)端創(chuàng)建和發(fā)送日志時(shí),這些級(jí)別會(huì)被使用到。Logger對(duì)象在接收到客戶(hù)端創(chuàng)建和發(fā)送的日志消息時(shí),同時(shí)將該日志消息包裝成日志系統(tǒng)內(nèi)部所使用的日志對(duì)象LogItem,日志對(duì)象除了發(fā)送端所發(fā)送的消息以外,還會(huì)包裝諸如發(fā)送端類(lèi)名、發(fā)送事件、發(fā)送方法名、發(fā)送行號(hào)等等。這些額外的消息對(duì)于系統(tǒng)的跟蹤和調(diào)試都非常有價(jià)值。包裝好的LogItem最終被發(fā)送給輸出器,由這些輸出器負(fù)責(zé)將日志信息寫(xiě)入最終媒介,輸出器的類(lèi)型和個(gè)數(shù)均不固定,所有的輸出器通過(guò)AppenderManager進(jìn)行管理,通常通過(guò)配置文件即可方便擴(kuò)展出多個(gè)輸出器。
2.2日志記錄部分的設(shè)計(jì)
如前文所述,日志記錄部分負(fù)責(zé)接收日志系統(tǒng)客戶(hù)端發(fā)送來(lái)的日志消息、日志對(duì)象的管理等工作。下面詳細(xì)描述了日志記錄部分的設(shè)計(jì)要點(diǎn):
1.日志記錄器的管理
系統(tǒng)通過(guò)保持多個(gè)Logger對(duì)象的方式來(lái)進(jìn)行日志記錄的分類(lèi)。每一個(gè)Logger對(duì)象代表一類(lèi)日志分類(lèi)。因此,Logger對(duì)象的名稱(chēng)屬性是其唯一標(biāo)識(shí),通過(guò)名稱(chēng)屬性獲取一個(gè)Logger對(duì)象:
1.LoggerLoggerlogger=Logger.getLogger(“LoggerName”);
一般的,使用類(lèi)名來(lái)作為日志記錄器的名稱(chēng),這樣做的好處在于能夠盡量減少日志記錄器命名之間的沖突(因?yàn)镴ava類(lèi)使用包名),同時(shí)能夠?qū)⑷罩居涗浄诸?lèi)得盡可能的精細(xì)。因此,假定有一UserManager類(lèi)需要使用日志服務(wù),則更一般的使用方式為:
2.LoggerLoggerlogger=Logger.getLogger(UserManager.class);
2.日志分級(jí)的實(shí)現(xiàn)
按照日志目的不同,將日志的級(jí)別由低到高分成五個(gè)級(jí)別:
◆DEBUG-表示輸出的日志為一個(gè)調(diào)試信息;
◆INFO-表示輸出的日志是一個(gè)系統(tǒng)提示;
◆WARN-表示輸出的日志是一個(gè)警告信息;
◆ERROR-表示輸出的日志是一個(gè)系統(tǒng)錯(cuò)誤;
◆FATAL-表示輸出的日志是一個(gè)導(dǎo)致系統(tǒng)崩潰嚴(yán)重錯(cuò)誤。
這些日志級(jí)別定義在LoggerLevel接口中,被日志記錄器Logger在內(nèi)部使用。而對(duì)于日志系統(tǒng)客戶(hù)端則可使用Logger類(lèi)接口對(duì)直接調(diào)用并輸出這些級(jí)別的日志,Logger的這些接口描述如下:
3.publicvoiddebug(Stringmsg);//輸出調(diào)試信息
4.publicvoidinfo(Stringmsg);//輸出系統(tǒng)提示
5.publicvoidwarn(Stringmsg);//輸出警告信息
6.publicvoidfatal(Stringmsg);//輸出系統(tǒng)錯(cuò)誤
7.publicvoiderror(Stringmsg);//輸出嚴(yán)重錯(cuò)誤
通過(guò)對(duì)Logger對(duì)象上這些接口的調(diào)用,直接為日志信息賦予了級(jí)別屬性,這樣為后繼的按照不同級(jí)別進(jìn)行輸出的工作奠定了基礎(chǔ)。
3.日志對(duì)象信息的獲取
日志對(duì)象上包含了一條日志所具備的所有信息。通常這些信息包括:輸出日志的時(shí)間、Java類(lèi)、類(lèi)成員方法、所在行號(hào)、日志體、日志級(jí)別等等。在JDK1.4中可以通過(guò)在方法中拋出并且捕獲住一個(gè)異常,則在捕捉到的異常對(duì)象中已經(jīng)由JVM自動(dòng)填充好了系統(tǒng)調(diào)用的堆棧,在JDK1.4中則可以使用java.lang.StackTraceElement獲取到每一個(gè)堆棧項(xiàng)的基本信息,通過(guò)對(duì)日志客戶(hù)端輸出日志方法調(diào)用層數(shù)的推算,則可以比較容易的獲取到StackTraceElement對(duì)象,從而獲取到輸出日志時(shí)的Java類(lèi)、類(lèi)成員方法、所在行號(hào)等信息。在JDK1.3或者更早的版本中,相應(yīng)的工作則必須通過(guò)將異常的堆棧信息輸出到字符串中,并分析該字符串格式得到。
2.3日志輸出部分的設(shè)計(jì)
日志輸出部分的設(shè)計(jì)具有一定的難度,在本文設(shè)計(jì)的日志系統(tǒng)中,日志的輸出、多線(xiàn)程的支持、日志系統(tǒng)的擴(kuò)展性、日志系統(tǒng)的效率等問(wèn)題都交由日志輸出部分進(jìn)行管理。
1.日志輸出器的繼承結(jié)構(gòu)
在日志的輸出部分采用了二層結(jié)構(gòu),即定義了一個(gè)抽象的日志輸出器(AbstractLoggerAppender),然后從該抽象類(lèi)繼承出實(shí)際的日志輸出器。AbstractLoggerAppender定義了一系列的對(duì)日志進(jìn)行過(guò)濾的方法,而具體輸出到存儲(chǔ)媒介的方法則是一個(gè)抽象方法,由子類(lèi)實(shí)現(xiàn)。在系統(tǒng)中默認(rèn)實(shí)現(xiàn)了控制臺(tái)輸出器和文件輸出器兩種,其中控制臺(tái)輸出器的實(shí)現(xiàn)頗為簡(jiǎn)單。
2.文件輸出器的內(nèi)部實(shí)現(xiàn)
在日志記錄部分的實(shí)現(xiàn)中,并沒(méi)有考慮多線(xiàn)程、高效率等問(wèn)題,因此文件輸出器必須考慮這些問(wèn)題的處理。在文件輸出器內(nèi)部使用java.lang.Vector定義了一個(gè)線(xiàn)程安全的高速緩沖,所有通過(guò)日志記錄部分分派到文件輸出器的日志被直接放置到該高速緩沖當(dāng)中。同時(shí)在文件輸出器內(nèi)部定義一個(gè)工作線(xiàn)程,負(fù)責(zé)定期將高速緩沖中的內(nèi)容保存到文件,在保存的過(guò)程中同時(shí)可以進(jìn)行日志文件的備份等工作。由于采用了高速緩沖的結(jié)構(gòu),很顯然日志客戶(hù)端的調(diào)用已經(jīng)不再是一個(gè)同步調(diào)用,從而不再會(huì)需要等到文件操作后才返回,提高的系統(tǒng)調(diào)用的速度。該原理如圖3所示:
2.4設(shè)計(jì)難點(diǎn)
通過(guò)上述設(shè)計(jì),一個(gè)具有良好擴(kuò)展能力的高性能日志系統(tǒng)框架就已經(jīng)具有了一定的雛形。在設(shè)計(jì)過(guò)程中幾個(gè)難點(diǎn)問(wèn)題需要進(jìn)一步反思。
一、是否整個(gè)系統(tǒng)應(yīng)當(dāng)采用完全異步的結(jié)構(gòu),通過(guò)類(lèi)似于消息機(jī)制的方式來(lái)進(jìn)行由日志客戶(hù)端發(fā)送日志給日志系統(tǒng)。這種方式可以作為日志系統(tǒng)框架另一種運(yùn)行方式,在后繼設(shè)計(jì)中加以考慮。
二、在文件輸出器中可以看到,目前雖然可以擴(kuò)展多個(gè)日志輸出器,但是目前提供的抽象類(lèi)中僅僅提供了對(duì)日志的過(guò)濾機(jī)制,而沒(méi)有提供的緩存機(jī)制,目前的緩存機(jī)制被放在文件輸出器中實(shí)現(xiàn),因此在未來(lái)的進(jìn)一步設(shè)計(jì)中,可以將文件輸出器中的緩存機(jī)制上移到抽象類(lèi)當(dāng)中。
2.5設(shè)計(jì)模式
在設(shè)計(jì)過(guò)程中我們特別注意使用了數(shù)個(gè)經(jīng)典的設(shè)計(jì)模式。如:Logger對(duì)象的創(chuàng)建使用了工廠方法模式(FactoryMethod)、由AbstractLoggerAppender和ConsoleAppender以及FileAppender構(gòu)成了策略模式(Strategy),除此以外,還大量使用了單例模式(Singleton)。在設(shè)計(jì)中適當(dāng)運(yùn)用設(shè)計(jì)模式能夠加快設(shè)計(jì)進(jìn)度、提高設(shè)計(jì)質(zhì)量。
3.總結(jié)
本文探討了日志系統(tǒng)的基本特性、實(shí)現(xiàn)日志系統(tǒng)的意義、方法和內(nèi)部結(jié)構(gòu),并且給出了一種基于Java平臺(tái)的日志系統(tǒng)的詳細(xì)設(shè)計(jì)。同時(shí)也指出日志系統(tǒng)會(huì)向服務(wù)化、異步化的方向發(fā)展。作為一種方便的跟蹤調(diào)試、數(shù)據(jù)恢復(fù)工具,應(yīng)當(dāng)提倡在適當(dāng)?shù)沫h(huán)境下對(duì)日志系統(tǒng)的使用。
【Java日志系統(tǒng)框架的設(shè)計(jì)與實(shí)現(xiàn)】相關(guān)文章:
sun認(rèn)證java程序員須知Java日志框架09-05
OA系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)07-23
企業(yè)OA系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)07-13
航標(biāo)業(yè)務(wù)系統(tǒng)架構(gòu)的設(shè)計(jì)和實(shí)現(xiàn)10-15
OA系統(tǒng)網(wǎng)絡(luò)安全設(shè)計(jì)與實(shí)現(xiàn)07-11
關(guān)于JAVA實(shí)現(xiàn)httpClient的實(shí)例11-05
Java多線(xiàn)程的實(shí)現(xiàn)方式11-03