欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
如何用自己的 appender 來(lái)擴展 log4j 框架
如何用自己的 appender 來(lái)擴展 log4j 框架

級別:高級

Ruth Zamorano (ruth.zamorano@orange-soft.com),軟件架構師,Orange Soft
Rafael Luque (rafael.luque@orange-soft.com), CTO,Orange Soft

2003年 9 月

日志記錄不僅是開(kāi)發(fā)和測試周期中的一個(gè)重要元素——提供關(guān)鍵調試信息,而且對于系統已部署到生產(chǎn)環(huán)境之后調試錯誤也是很有用的——提供修復錯誤所需的準確上下文信息。在本文中,Orange Soft 公司(這是一家專(zhuān)業(yè)從事面向對象技術(shù)、服務(wù)器端Java 平臺和 Web 可訪(fǎng)問(wèn)性的西班牙公司)的共同創(chuàng )辦人 Ruth Zamorano 和 Rafael Luque 闡述了如何利用 log4j 的擴展能力,使得分布式 Java 應用程序能夠通過(guò)即時(shí)消息傳送(instant messaging,IM)來(lái)監視。

不管您編寫(xiě)多少設計良好的測試用例,即使是最小的應用程序也會(huì )在部署到生產(chǎn)環(huán)境之后隱藏著(zhù)一個(gè)或多個(gè)錯誤。雖然測試驅動(dòng)的開(kāi)發(fā)和 QA 手段可以提高代碼質(zhì)量 并增強對應用程序的信心,但是當某個(gè)系統失敗時(shí),開(kāi)發(fā)人員和系統管理員需要了解系統的相關(guān)執行上下文信息。有了適當的信息,他們就能確定問(wèn)題的本質(zhì)并快速解決問(wèn)題,從而節省時(shí)間和金錢(qián)。

監視分布式應用程序要求能夠對遠程資源進(jìn)行日志記錄——通常是一臺中央日志服務(wù)器或者系統管理員的計算機。log4j 環(huán)境提供一組適用于遠程日志記錄的 appender,比如 SocketAppender、JMSAppenderSMTPAppender。在本文中,我們將向您展示一種新的遠程類(lèi)(remote-class)appender:IMAppender。

讓我們首先簡(jiǎn)要回顧一下 log4j ,然后再深入研究 appender。自然地,理解 appender 的最好方式就是試著(zhù)編寫(xiě)一個(gè) appender,因此我們將在最后一節實(shí)現一個(gè)例子 IM(即時(shí)消息傳送)appender,以說(shuō)明 AppenderSkeleton 類(lèi)的工作原理。

讀者應該熟悉 log4j 框架。關(guān)于 log4j 的更多信息,請參見(jiàn)本文后面的 參考資料 。

log4j 概述
log4j 框架是用 Java 語(yǔ)言編寫(xiě)的事實(shí)上的標準日志記錄框架。作為 Jakarta 項目的一部分,它在 Apache 軟件許可證(Apache Software License)下分發(fā),Apache 軟件許可證是由開(kāi)放源代碼促進(jìn)會(huì )(Open Source Initiative ,OSI)認證的一種流行的開(kāi)放源代碼許可證。log4j 環(huán)境是完全可配置的,或者通過(guò)編程方式完成,或者通過(guò)屬性中的配置文件或者 XML 格式的配置文件完成。此外,它還允許開(kāi)發(fā)人員無(wú)需修改源代碼就可以選擇性地篩選出日志記錄請求。

log4j 環(huán)境包括三個(gè)主要組件:

  • logger(日志記錄器):控制要啟用或禁用哪些日志記錄語(yǔ)句??梢詫θ罩居涗浧髦付ㄈ缦录墑e:ALL、DEBUG、INFO、WARN、ERROR, FATA或OFF。

  • layout(布局):根據用戶(hù)的愿望格式化日志記錄請求。

  • appender:向目的地發(fā)送格式化的輸出。

理解 appender
log4j 框架允許向任何日志記錄器附加多個(gè) appender??梢栽谌魏螘r(shí)候對某個(gè)日子記錄器添加(或刪除)appender。附隨 log4j 分發(fā)的 appender 有多個(gè),包括:

  • ConsoleAppender
  • FileAppender
  • SMTPAppender
  • JDBCAppender
  • JMSAppender
  • NTEventLogAppender
  • SyslogAppender

也可以創(chuàng )建自己的自定義 appender。

log4j 最主要的特性之一就是它的靈活性。遺憾的是,沒(méi)有多少現存文檔說(shuō)明了如何編寫(xiě)自己的 appender。學(xué)習編寫(xiě) appender 的方式之一就是分析可用的源代碼,然后嘗試推斷 appender 是如何工作的——本文將幫助 您完成這個(gè)任務(wù)。

揭開(kāi)面紗
所有的 appender 都必須擴展 org.apache.log4j.AppenderSkeleton 類(lèi),這是一個(gè)抽象類(lèi),它實(shí)現了 org.apache.log4j.Appenderorg.apache.log4j.spi.OptionHandler 接口。AppenderSkeleton 類(lèi)的 UML 類(lèi)圖看起來(lái)如圖1所示:

圖 1. AppenderSkeleton 的 UML 類(lèi)圖

下面讓我們研究一下 AppenderSkeleton 類(lèi)所實(shí)現的 Appender 接口的方法。如清單1所示,Appender 接口中的幾乎所有方法都是 setter 方法和 getter 方法:

清單1. Appender 接口
package org.apache.log4j;public interface Appender {    void addFilter(Filter newFilter);                        void clearFilters() ;                                                   void close();                                                            void doAppend(LoggingEvent event);                ErrorHandler getErrorHandler();         Filter getFilter();             Layout getLayout();              String getName();           boolean requiresLayout();            void setErrorHandler(ErrorHandler errorHandler);            void setLayout(Layout layout);           void setName(String name);         }

這些方法處理 appender 的如下屬性:

  • name: Appender 是命名的實(shí)體,因此有一個(gè)針對其名稱(chēng)的 setter/getter。

  • layout: Appender 可以具有關(guān)聯(lián)的 Layout,因此還有另一個(gè)針對 layout 的setter/getter 方法。注意我們說(shuō)的是“可以”而不是“必須”。這是因為有些 appender 不需要 layout。lauout 管理格式輸出——也就是說(shuō),它返回 LoggingEvent String 表示形式。另一方面,JMSAppender 發(fā)送的事件是 串行化的,因此您不需要對它附加 layout。如果自定義的 appender 不需要 layout,那么 requiresLayout() 方法必須返回 false,以避免 log4j 抱怨說(shuō)丟失了 layout 信息。

  • errorHandler: 另一個(gè) setter/getter 方法是為 ErrorHandler 而存在的。appender 可能把它們的錯誤處理委托給一個(gè) ErrorHandler 對象——即 org.apache.log4j.spi 包中的一個(gè)接口。實(shí)現類(lèi)有兩個(gè):OnlyOnceErrorHandlerFallbackErrorHandler。OnlyOnceErrorHandle 實(shí)現 log4j 的默認錯誤處理策略,它發(fā)送出第一個(gè)錯誤的消息并忽略其余的所有錯誤。錯誤消息將輸出到 System.err。FallbackErrorHandler 實(shí)現 ErrorHandler 接口,以便能夠指定一個(gè)輔助的 appender。如果主 appender 失敗,輔助 appender 將接管工作。錯誤消息將輸出到 System.err,然后登錄到新的輔助 appender。

還有管理過(guò)濾器的其他方法(比如 ddFilter()、clearFilters()getFilter() 方法 )。盡管 log4j 具有過(guò)濾日志請求的多種內置方法(比如知識庫范圍級、日志記錄器級和 appender 閾值級),但它使用自定義過(guò)濾器方法的能力也是非常強大的。

一個(gè) appender 可以包含多個(gè)過(guò)濾器。自定義過(guò)濾器必須擴展 org.apache.log4j.spi.Filter 抽象類(lèi)。這個(gè)抽象類(lèi)要求把過(guò)濾器組織為線(xiàn)性鏈。 對每個(gè)過(guò)濾器的 decide(LoggingEvent) 方法的調用要按照過(guò)濾器被添加到鏈中的順序來(lái)進(jìn)行。自定義過(guò)濾器基于三元邏輯。decide() 方法必須返回 DENY、NEUTRAL 或者 ACCEPT 這三個(gè)整型常量值之一。

除了 setter/getter 方法以及和過(guò)濾器相關(guān)的方法外,還有另外兩個(gè)方法:close()doAppend()。close() 方法釋放 appender 中分配的任何資源,比如文件句柄、網(wǎng)絡(luò )連接,等等。在編寫(xiě)自定義 appender 代碼時(shí),務(wù)必要實(shí)現這個(gè)方法,以便當您的 appender 關(guān)閉時(shí),它的 closed 字段將被設置為 true。

如清單2所示的 doAppend() 方法遵循“四人組模板方法(Gang of Four Template Method )”設計模式(參見(jiàn) 參考資料)。這個(gè)方法提供了一個(gè)算法框架,它把某些步驟推遲到子類(lèi)中來(lái)實(shí)現。

清單2:doAppend() 方法的實(shí)際源代碼
public synchronized void doAppend (LoggingEvent event) {    if (closed) {         // step 1     LogLog.error("Attempted to append to closed appender [" + name + "].");     return;    }    if ( !isAsSevereAsThreshold (event.level) ) {        // step 2        return;    }    Filter f = this.headFilter;        // step 3    FILTER_LOOP:    while ( f != null) {        switch ( f .decide(event) ) {        case Filter.DENY: return;        case Filter.ACCEPT: break FILTER_LOOP;        case Filter.NEUTRAL: f = f.next;        }    }    this.append(event);        // step 4}

如清單2所示,該算法:

  1. 檢查 appender 是否關(guān)閉。附加關(guān)閉的 appender 是一個(gè)編程錯誤。
  2. 檢查正在記錄日志的事件是否處于 appender 的閾值之下。
  3. 檢查是否有過(guò)濾器附加到 appender,如果有,則拒絕請求。
  4. 調用 appender 的 append() 方法。這個(gè)步驟被委托給每個(gè)子類(lèi)。

我們已經(jīng)介紹了 AppenderSkeletonAppender 繼承來(lái)的方法和屬性。下面讓我們看看“為什么”AppenderSkeleton 要實(shí)現 OptionHandler 接口。OptionHandler 僅包含一個(gè)方法:activateOptions()。這個(gè)方法在對屬性調用 setter 方法之后由一個(gè)配置器類(lèi)調用。有些屬性彼此依賴(lài),因此它們在全部加載完成之前是無(wú)法激活的,比如在 activateOptions() 方法中就是這樣。這個(gè)方法是開(kāi)發(fā)人員在 appender 變?yōu)榧せ詈途途w之前用來(lái)執行任何必要任務(wù)的機制。

除了上面提到的所有方法,讓我們再回頭觀(guān)察一下圖1。注意 AppenderSkeleton 提供了一個(gè)新的抽象方法(append() 方法)和一個(gè)新的 JavaBean 屬性(threshold)。threshold 屬性由 appender 用來(lái)過(guò)濾日志記錄請求,只有超過(guò)閾值的請求才會(huì )得到處理。我們在談到 doAppend() 方法之前就提到了 append() 方法。它是自定義 appender 必須實(shí)現的一個(gè)抽象方法,因為框架在 doAppend() 方法內調用 append() 方法。append()方法是框架的鉤子(hook)之一。

現在我們已經(jīng)看到了 AppenderSkeleton 類(lèi)中的所有可用方法,下面讓我們看看幕后發(fā)生的事情。圖2演示了 log4j 中的一個(gè) appender 對象的 生命周期。

圖 2. appender 的生命周期圖

讓我們逐步地研究一下這個(gè)圖表:

  • appender 實(shí)例不存在。 或許框架還沒(méi)有配置好。

  • 框架實(shí)例化了一個(gè)新的 appender。這發(fā)生在配置器類(lèi)分析配置腳本中的一個(gè) appender 聲明的時(shí)候。配置器類(lèi)調用 Class.newInstance(YourCustomAppender.class),這等價(jià)于動(dòng)態(tài)調用 new YourCustomAppender()??蚣苓@樣做是為了避免被硬編碼為任何特定的 appender 名稱(chēng);框架是通用的,適用于任何 appender。

  • 框架判斷 appender 是否需要 layout。如果該 appender 不需要 layout,配置器就不會(huì )嘗試從配置腳本中加載 layout 信息。

  • Log4j 配置器調用 setter 方法。 在所有屬性都已設置好之后,框架就會(huì )調用這個(gè)方法。程序員可以在這里激活必須同時(shí)激活的屬性。

  • 配置器調用 activateOptions() 方法。 在所有屬性都已設置好之后,框架就會(huì )調用這個(gè)方法。程序員可以在這里激活必須同時(shí)激活的屬性。

  • Appender 準備就緒。 此刻,框架可以調用 append() 方法來(lái)處理日志記錄請求。這個(gè)方法由 AppenderSkeleton.doAppend() 方法調用。

  • 最后,關(guān)閉appender。 當框架即將要刪除您的自定義 appender 實(shí)例時(shí),它會(huì )調用您的 appender 的 close() 方法。close() 是一個(gè)清理方法,意味著(zhù) 您需要釋放已分配的所有資源。它是一個(gè)必需的方法,并且不接受任何參數。它必須把 closed 字段設置為 true,并在有人嘗試使用關(guān)閉的 appender 時(shí)向框架發(fā)出警報。

現在我們已經(jīng)回顧了與建立自己的 appender 相關(guān)的概念,下面讓我們考慮一個(gè)包括真實(shí)例子appender 的完整案例研究。

編寫(xiě)自定義 appender 的訣竅

  1. 擴展 AppenderSkeleton 抽象類(lèi)。

  2. 指定您的 appender 是否需要 layout。

  3. 如果某些屬性必須同時(shí)激活,則應該在activateOptions()方法內完成。

  4. 實(shí)現 close() 方法。它必須把 closed 字段的值設置為 true。記 得釋放所有資源。

  5. 可選地指定要使用的默認 ErrorHandler 對象。

  6. 編寫(xiě) append() 方法的代碼。這個(gè)方法負責附加日志記錄事件,并在錯誤發(fā)生時(shí)負責調用錯誤處理程序。

編寫(xiě)基于 IM 的 appender
本文給出的代碼說(shuō)明了如何擴展 log4j 框架以集成 IM 特性。它被設計來(lái)使得 log4j 相容的應用程序能夠把輸出記錄到 IM 網(wǎng)絡(luò )上。IM appender 實(shí)際上充當一個(gè)自定義的 客戶(hù)機。然而,它不是把 System.out、文件或者 TCP 套接字當作底層輸出設備,而是把 IM 網(wǎng)絡(luò )當作底層輸出設備。

為了提供 IM 支持,我們不需要在開(kāi)發(fā)特定解決方案時(shí)完全重新開(kāi)始。相反,我們將利用一個(gè)我們認為是該類(lèi)別中最好的工具:Jabber。Jabber 是一種用于即時(shí)消息傳送和展示的基于 XML 的開(kāi)放協(xié)議,它由 Jabber 社區開(kāi)發(fā),非 營(yíng)利性的 Jabber 軟件基金會(huì )(Jabber Software Foundation)對它提供技術(shù)支持。

我們之所以選擇 Jabber 而沒(méi)有選擇其他 IM 系統,是因為 Jabber 提供了廣泛的好處,包括它的:

  • 開(kāi)放性質(zhì): 不像其他的專(zhuān)有系統,Jabber 的規范和源代碼是可以免費獲得的,從而允許任何人無(wú)成本地創(chuàng )建 Jabber 實(shí)現。

  • 簡(jiǎn)單性: Jabber 使用基于 XML 的簡(jiǎn)單協(xié)議作為它的標準數據格式,并且遵循大多數人都理解的客戶(hù)機/服務(wù)器 架構。

  • 與其他 IM 系統的互操作性:Jabber 傳輸模塊(transport module)使得 Jabber 用戶(hù)訪(fǎng)問(wèn)諸如 AIM、Yahoo!Messager 和 ICQ 等其他即時(shí)消息傳送系統成為可能。

  • 資源敏感:Jabber 對多客戶(hù)機訪(fǎng)問(wèn)提供明確的支持。同一個(gè)用戶(hù)可以通過(guò)不同的客戶(hù)機(或者說(shuō)資源)同時(shí)地連接到Jabber 服務(wù)器,消息將被恰當地路由到可用的最佳資源。

為什么要把日志記錄到 IM 網(wǎng)絡(luò )?
日志記錄是開(kāi)發(fā)人員必須養成的良好編碼習慣,就像編寫(xiě)單元測試、處理異?;蛘呔帉?xiě) Javadoc 注釋一樣。插入到代碼中明確位置的日志記錄語(yǔ)句起著(zhù)審核工具的功能,提供了關(guān)于應用程序內部狀態(tài)的有用信息。與主流意見(jiàn)相反,我們認為在許多情況下,將日志語(yǔ)句保留在生產(chǎn)代碼中是方便的。如果 您擔心計算成本,就必須考慮從應用程序中刪除日志記錄功能所帶來(lái)的少量性能提升是否值得。此外,log4j 的靈活性允許您聲明式地控制日志記錄行為。您可以建立嚴格的日志記錄策略來(lái)降低日志的累贅性并改進(jìn)性能。

圖3顯示了 IMAppender 的一個(gè)使用場(chǎng)景:一個(gè)配置為使用 IMAppender 的 log4j 應用程序記錄 它的被包裝為 IM 消息的調試數據。即時(shí)消息通過(guò) Jabber 公司網(wǎng)絡(luò )被路由到系統管理員的Jabber 地址(注意,公開(kāi)可用的 Jabber 服務(wù)器對生產(chǎn)應用可能不足夠可靠)。因而,無(wú)論何時(shí)系統管理員需要檢查應用程序的狀態(tài),他們只需加載最喜歡的 Jabber 客戶(hù)機,然后連接到Jabber 服務(wù)器。如圖3所示,管理員可以通過(guò)不同的設備來(lái)訪(fǎng)問(wèn)。他可以使用辦公室的 PC 來(lái)登錄服務(wù)器,或者當他離開(kāi)辦公桌時(shí),可以使用運行在手持設備上的 Jabber 客戶(hù)機來(lái)檢查消息。

圖 3. IMAppender 使用場(chǎng)景

但是為什么需要 IM appender 呢?因為向 IM 服務(wù)器發(fā)送消息將允許您通過(guò)自由選擇的工具(比如Jabber客戶(hù)機)來(lái)更容易地監視應用程序行為。

IMAppender提供了多個(gè)優(yōu)點(diǎn):

  • 獲得實(shí)時(shí)通知——我們稱(chēng)之為“即時(shí)日志記錄”。

  • 支持一對一(聊天)和一對多(小組聊天)模式。

  • Jabber 不只是用于臺式計算機。用于諸如 PDA 和移動(dòng)電話(huà)等無(wú)線(xiàn)設備的客戶(hù)機也正在開(kāi)發(fā)之中。

  • 要進(jìn)入或退出應用程序正在向其轉發(fā)日志數據的聊天室很容易。而要訂閱和取銷(xiāo)訂閱由 SMTPAppender 發(fā)送的電子郵件則很困難。

  • 通過(guò)安全套接字層(SSL)上的隧道來(lái)保證安全很容易。當然,您可以加密電子郵件,但是 SSL上 的 Jabber 既方便又快捷。

進(jìn)階
IMAppender 模仿隨 log4j 一起分發(fā)的 SMTPAppender 的日志記錄策略。IMAppender 把日志記錄事件存儲在一個(gè)內部循環(huán)緩沖區(cyclic buffer)中,并且僅當所接收到的日志記錄請求觸發(fā)了某個(gè)用戶(hù)指定的條件時(shí),才把這些事件作為即時(shí)消息來(lái)發(fā)送?;蛘?,用戶(hù)也可以提供一個(gè)觸發(fā)事件鑒別器類(lèi)(triggering event evaluator class)。然而在默認情況下,消息傳送是由指定為 ERROR 或者更高級別的事件所觸發(fā)的。

每個(gè)消息中傳送的日志記錄事件的數量是由緩沖區的大小決定的。循環(huán)緩沖區僅保留最后的 bufferSize 個(gè)日志記錄事件,當它裝滿(mǎn)時(shí)就會(huì )溢出并丟棄較舊的事件。

為了連接到 Jabber 服務(wù)器,IMAppender 需要依賴(lài) Jive Software 公司的 Smack API。Smack 是一個(gè)開(kāi)放源代碼的高級庫,它處理與 Jabber 服務(wù)器通信的協(xié)議細節。這樣, 您無(wú)需任何特別的 Jabber 或者 XML 專(zhuān)業(yè)經(jīng)驗就能理解代碼。

IMAppender 的屬性總結在表 1中:

表 1. IMAppender 屬性

屬性說(shuō)明類(lèi)型是否必需
host服務(wù)器的主機名稱(chēng)String
portJabber服務(wù)器的端口號int否,默認為 5222
username應用程序的Jabber帳戶(hù)用戶(hù)名String
password應用程序的Jabber帳戶(hù)密碼String
recipient

接收方的Jabber地址。Jabber地址也稱(chēng)為Jabber ID,它在一個(gè)@字符后面指定用戶(hù)的Jabber 域,就像電子郵件地址一樣

這個(gè)屬性可以保存任何聊天地址或者聊天室地址。例如,您可以指定這樣的聊天地址:sysadmin@company.com;或者 您可能希望向 sysadmin@company.com 小組聊天服務(wù)器上名為"java-apps"的某個(gè)聊天小組發(fā)送日志記錄消息(例如,java-apps@conference.company.com

String
chatroom接受一個(gè)布爾值。如果為 true,recipient 值將被接受為小組聊天地址。如果要設置這個(gè)選項,還應該設置 nickname 選項。默認情況下,recipient 值被解釋為一個(gè)聊天地址boolean否,默認為 false
nickname僅當設置了chatroom 屬性時(shí)才會(huì )考慮這個(gè)屬性。否則,它將被忽略

用戶(hù)可以選擇 appender 使用的任意小組聊天昵稱(chēng)來(lái)加入小組聊天。昵稱(chēng)不一定要和 Jabber用戶(hù)名有關(guān)
String
SSL用于保護與 Jabber 服務(wù)器的連接boolean否,默認為false
bufferSize可以保留在循環(huán)緩沖區中的日志記錄事件的最大數量int否,默認為16
evaluatorClass

這個(gè)屬性的值被當作一個(gè)類(lèi)的完全限定名稱(chēng)的字符串表示形式,該類(lèi)實(shí)現了 org.apache.log4j.spi. TriggeringEventEvaluator 接口(換句話(huà)說(shuō),也就是一個(gè)包含自定義觸發(fā)邏輯的類(lèi),它覆蓋了默認的觸發(fā)邏輯)。如果沒(méi)有指定這個(gè)選項,IMAppender 將使用 DefaultEvaluator 類(lèi)的一個(gè)實(shí)例,這個(gè)類(lèi)根據被指定為 ERROR 或更高級別的事件觸發(fā)響應

String否,默認為 DefaultEvaluator

現在讓我們進(jìn)一步觀(guān)察代碼。IMAppender 類(lèi)遵循清單3所示的結構:

清單 3. IMAppender 類(lèi)的總體結構
package com.orangesoft.logging;import org.apache.log4j.AppenderSkeleton;import org.apache.log4j.spi.LoggingEvent;import org.apache.log4j.spi.TriggeringEventEvaluator;public class IMAppender extends AppenderSkeleton {    private String host;    private int port = 5222;    private String username;    private String password;    private String recipient;    private boolean chatroom = false;    private String nickname;    private boolean SSL = false;    private int bufferSize = 16;    protected TriggeringEventEvaluator evaluator;        // Set/Get methods for properties        public void setHost(String host) {        this.host = host;     }        public String getHost() {         return this.host;     }        ...other set/get methods...        // AppenderSkeleton callback methods        public boolean requiresLayout() { ... }    public void activateOptions() { ... }    public void append(LoggingEvent event) { ... }    public synchronized void close() { ... }    }

請注意關(guān)于我們的 appender 的如下幾個(gè)方面:

  • IMAppender 類(lèi)擴展 org.apache.log4j.AppenderSkeleton,這是所有自定義 appender 都必須要做的。IMAppenderAppenderSkeleton 繼承諸如 appender 閾值和自定義過(guò)濾之類(lèi)的公共功能。

  • 我們的 appender 的第一部分很簡(jiǎn)單。每個(gè) appender 都有字段和 set/get 方法。屬性和方法簽名遵守 JavaBeans 命名約定。因而,log4j 能夠通過(guò)反射來(lái)分析 appender,透明地處理 appender 配置。為節省篇幅,上述代碼片斷僅顯示了 setHost()getHost() 方法。

  • 為了完成我們的 appender,我們必須實(shí)現 log4j 框架調用來(lái)管理我們的 appender 的回調方法:requiresLayout()、activateOptions()、append()close()。

log4j 框架調用 requiresLayout() 方法來(lái)判斷自定義 appender 是否需要 layout。注意 ,有些appender 使用內置格式或者根本就不格式化事件,因此它們不需要 Layout 對象。IMAppender 需要 layout,因而該方法返回 true,如 清單4所示:

清單 4. requiresLayout() 方法
public boolean requiresLayout() {    return true;}

注意,AppenderSkeleton 實(shí)現了 org.apache.log4j.spi.OptionHandler 接口(參見(jiàn) 圖 1 )。AppenderSkeleton 把這個(gè)接口的單個(gè)方法 activateOptions() 實(shí)現為一個(gè)空方法。我們的 IMAppender 需要這個(gè)方法是由于其屬性之間的相互依賴(lài)性。例如,與 Jabber 服務(wù)器的連接依賴(lài) Host、PortSSL 屬性,因此 IMAppender 在這三個(gè)屬性被初始化之前無(wú)法建立連接。log4j 框架調用 activateOptions() 方法來(lái)通知 appender 所有屬性都已設置就緒。

IMAppender.activateOptions() 方法激活指定的屬性(比如 Jabber 主機、端口、bufferSize,等等),所采取的方式是實(shí)例化依賴(lài)這些屬性值的更高級對象,如清單5所示:

清單 5. 只有在調用 activateOptions() 方法之后,屬性才會(huì )被激活且變得有效
protected org.apache.log4j.helpers.CyclicBuffer cb;protected org.jivesoftware.smack.XMPPConnection con;protected org.jivesoftware.smack.Chat chat;protected org.jivesoftware.smack.GroupChat groupchat;public void activateOptions() {    try {                cb = new CyclicBuffer(bufferSize);            if (SSL) {            con = new SSLXMPPConnection(host, port);        } else {            con = new XMPPConnection(host, port);        }        con.login(username, password);             if (chatroom) {            groupchat = con.createGroupChat(recipient);            groupchat.join(nickname != null ? nickname : username);        } else {            chat = con.createChat(recipient);        }                           } catch (Exception e) {        errorHandler.error("Error while activating options for appender           named [" + name + "]",             e, ErrorCode.GENERIC_FAILURE);    } }

activateOptions() 方法完成以下任務(wù):

  • 建立 bufferSize 個(gè)事件的最大循環(huán)緩沖區。我們使用了 org.apache.log4j.helpers.CyclicBuffer 的一個(gè)實(shí)例,org.apache.log4j.helpers.CyclicBuffer 是 log4j 附帶的一個(gè)輔助類(lèi),它提供了緩沖區的邏輯。

  • Smack 的 XMPPConnection 類(lèi)創(chuàng )建了一個(gè)到 XMPP (Jabber) 服務(wù)器的連接,這個(gè)服務(wù)器是通過(guò) hostport 屬性來(lái)指定的。為了創(chuàng )建一個(gè) SSL 連接,我們要使用 SSLXMPPConnection 子類(lèi)。

  • 大多數服務(wù)器都要求您在執行其他任務(wù)之前首先登錄,因此我們使用由 usernamepassword 屬性所定義的 Jabber 帳戶(hù)來(lái)登錄,同時(shí)調用 XMPPConnection.login() 方法。

  • 在登錄之后,我們創(chuàng )建一個(gè) Chat 或者 GroupChat 對象,具體視 chatroom 值而定。

activateOptions() 方法返回之后,appender 就準備好處理日志記錄請求了。如 清單6所示,由 AppenderSkeleton.doAppend() 調用的 append() 方法將執行大多數實(shí)際的日志附加工作。

清單 6. append() 執行實(shí)際的輸出操作
public void append(LoggingEvent event) {    // check pre-conditions    if (!checkEntryConditions()) {        return;    }    cb.add(event);    if (evaluator.isTriggeringEvent(event)) {        sendBuffer();    }}protected  boolean checkEntryConditions() {    if ((this.chat == null) && (this.groupchat == null)) {        errorHandler.error("Chat object not configured");        return false;    }    if (this.layout == null) {     errorHandler.error("No layout set for appender named [" + name + "]");     return false;    }    return true;}

append() 方法中的第一個(gè)語(yǔ)句判斷進(jìn)行附加嘗試是否有意義。checkEntryConditions() 方法檢查是否有可用于附加到輸出的 Chat 或者 GroupChat 對象,以及是否有用于格式化傳入 event 對象的 Layout 對象。如果這些前提條件得不到滿(mǎn)足,那么 append() 將輸出一條警告消息并返回,從而不會(huì )繼續進(jìn)行輸出操作。下一個(gè)語(yǔ)句把事件添加到循環(huán)緩沖區實(shí)例 cb。然后,if 語(yǔ)句把日志記錄事件提交給 evaluator,這是一個(gè) TriggeringEventEvaluator 實(shí)例。如果 evaluator 返回 true,這意味著(zhù)該事件與觸發(fā)條件匹配,sendBuffer() 就會(huì )被調用。

清單7顯示了 sendBuffer() 方法的代碼

清單 7. sendBuffer()方法
protected void sendBuffer() {    try {        StringBuffer buf = new StringBuffer();                    int len = cb.length();        for (int i = 0; i < len; i++) {            LoggingEvent event = cb.get();            buf.append(layout.format(event));                        // if layout doesn‘t handle exceptions, the appender has             // to do it            if (layout.ignoresThrowable()) {                String[] s = event.getThrowableStrRep();                if (s != null) {                    for (int j = 0; j < s.length; j++) {                        buf.append(LINE_SEP);                        buf.append(s[j]);                    }                }            }        }        if (chatroom) {            groupchat.sendMessage(buf.toString());        } else {            chat.sendMessage(buf.toString());        }    } catch(Exception e) {        errorHandler.error("Could not send message           in IMAppender [" + name + "]",             e, ErrorCode.GENERIC_FAILURE);    }}

sendBuffer() 方法把緩沖區的內容作為IM消息來(lái)發(fā)送。此方法逐項遍歷保留在緩沖區中的事件,同時(shí)調用 layout 對象的 format() 方法來(lái)格式化每個(gè)事件。事件的字符串表示形式被附加到 StringBuffer 對象。最后,sendBuffer() 調用 chat 或者 groupchat 對象的 sendMessage() 方法,把消息發(fā)送出去。

請注意以下幾點(diǎn):

  • AppenderSkeleton.doAppend() 方法(它調用 append())是經(jīng)過(guò)同步的,因此 sendBuffer() 已經(jīng)擁有 appender 的監視器。這使得我們不必在 cb 上執行同步操作。

  • 異常提供了極其有用的信息。由于這個(gè)原因,如果指定的 layout 忽略了包含在 LoggingEvent 對象中的可拋出對象,自定義 appender 的開(kāi)發(fā)人員必須輸出包括在事件中的異常信息。如果 layout 忽略了可拋出的對象,那么 layout 的 ignoresThrowable() 方法應該返回 true,并且 sendBuffer() 可以使用 LoggingEvent.getThrowableStrRep() 方法來(lái)檢索包含在該事件中的可拋出信息的 String[] 表示形式。

下載源代碼
執行這個(gè)示例所必需的全部JAR文件(instantlogging.jar、smack-1.1.0.jar 和 log4j-1.2.8.jar)包括在本文的源代碼的 lib/ 目錄下。相應的 zip 檔案文件可從 參考資料 下載。

把全部?jì)热萁M合起來(lái)
下面將通過(guò)展示 IMAppender 的實(shí)際工作效果來(lái)結束本文的討論。我們將使用一個(gè)相當簡(jiǎn)單的名為 com.orangesoft.logging.example.EventCounter 的應用程序,如 清單8所示。這個(gè)示例應用程序在命令行接受兩個(gè)參數。第一個(gè)參數是一個(gè)整數,對應于要產(chǎn)生的日志記錄事件的數量。第二個(gè)參數必須是以屬性的格式提供的一個(gè) log4j 配置文件名。這個(gè)應用程序總是以 ERROR 事件結束,該事件將觸發(fā)一次 IM 消息傳送。

清單 8. EventCounter 示例應用程序
package com.orangesoft.logging.examples;import org.apache.log4j.Logger;import org.apache.log4j.PropertyConfigurator;/** * Generates the number of logging events indicated by the first  * argument value. The application ends with an ERROR level event  * to trigger the IMAppender action. */public class EventCounter {    private static Logger logger = Logger.getLogger(EventCounter.class);    public static void main(String args[]) {        int numEvents = Integer.parseInt(args[0]);            String log4jConfigFile = args[1];        PropertyConfigurator.configure(log4jConfigFile);        for (int i = 1; i <= numEvents; i++) {            logger.info("Event #" + i);        }                logger.error("This error event triggers the delivery",             new Exception("This is a mock exception"));    }    }

我們可以使用類(lèi)似清單9所示的配置文件:

清單 9. 示例 IMAppender 配置文件
log4j.rootLogger = ALL,imlog4j.appender.im = com.orangesoft.logging.IMAppenderlog4j.appender.im.host = JABBER_SERVER (e.g. jabber.org)log4j.appender.im.username = APP_JABBER_ACCOUNT_USERNAMElog4j.appender.im.password = APP_JABBER_ACCOUNT_PASSWORDlog4j.appender.im.recipient = YOUR_JABBER_ADDRESS (e.g. foobar@jabber.org)log4j.appender.im.layout=org.apache.log4j.PatternLayoutlog4j.appender.im.layout.ConversionPattern = %n%r [%-5p] %M:%L - %m

上面的配置文件腳本把 IMAppender 添加到根日志記錄器(root logger),這樣所接收到的每個(gè)日志記錄請求都將被分派到我們的 appender。

在試驗這個(gè)示例應用程序之前,請確保將 host、username、passwordrecipient 屬性設置為 您所在環(huán)境中的適當值。下面的命令將運行 EventCounter 應用程序:

java com.orangesoft.logging.examples.EventCounter 100 eventcounter.properties

當運行時(shí),EventCounter 將根據 eventcounter.properties 所設置的策略記錄 100 個(gè)事件。然后一個(gè) IM 消息將從接收方的屏幕上彈出來(lái)。圖4、5、6 顯示了不同平臺上的 Jabber 客戶(hù)機接收到的結果消息:

圖 4. Windows (Rhymbox)上的 Jabber 客戶(hù)機接收到的消息的屏幕快照

圖 5. Linux (PSI)上的 Jabber 客戶(hù)機接收到的消息的屏幕快照

圖 6. Pocket PC (imov)上的 Jabber 客戶(hù)機接收到的消息的屏幕快照

注意 EventCounter 產(chǎn)生了 100 個(gè)事件。然而,由于 IMAppender 緩沖區的默認大小為 16,接收方應該收到僅包含最后 16 個(gè)事件的 IM 消息??梢钥吹?,包含在最后一個(gè)事件(消息和堆棧跟蹤)中的異常信息已經(jīng)被正確地傳送了。

這個(gè)例子應用程序只展示了 IMAppender 的一個(gè)非常小的用途,因此繼續探索它吧,您會(huì )找到很多樂(lè )趣的!

結束語(yǔ)
log4j 網(wǎng)絡(luò ) appender,SocketAppender、 JMSAppenderSMTPAppender 已經(jīng)提供了監視 Java 分布式應用程序的機制。然而,多個(gè)因素使得 IM 成為用于實(shí)時(shí)遠程日志記錄的合適技術(shù)。在本文中,我們介紹了通過(guò)自定義 appender 來(lái)擴展 log4j 的基礎知識,并看到了一個(gè)基本 IMAppender 的逐步實(shí)現過(guò)程。許多開(kāi)發(fā)人員和系統管理員都可以從 appender 的使用中獲益。

參考資料

  • 下載 IMAppender 類(lèi)的 源代碼 、例子應用程序和必需的庫。 您可以根據需要隨便使用和擴展這些源代碼。

  • log4j項目首頁(yè) 獲得最新的 log4j 版本 ——包括完整的源代碼、類(lèi)文件和文檔。欲了解更多信息,請在 log4j官方文檔頁(yè) 查看文章和演示材料。

  • 如果您的開(kāi)發(fā)工作需要超出本文檔范圍的內容,可以參考 Ceki Gülcü 編著(zhù)的一本優(yōu)秀參考書(shū) log4j完全參考手冊(QOS.ch, 2003),該書(shū)詳細介紹了 log4j 的基本特性和高級特性。

  • developerWorks Web services 專(zhuān)區提供了 LogKit 作為“每周內容”(component of the week)” (2001年8月)。LogKit 是 Jakarta 的 Avalon項目 的日志記錄組件。

  • Sun 已經(jīng)完成了一個(gè)名為 JSR 47 的社區過(guò)程(community process),它定義了 Java 平臺的日志記錄 API。JSR 47 API和 log4j 在體系結構層次上相當類(lèi)似,不過(guò) log4j 具有許多 JSR 47 所沒(méi)有的特性。

  • 在“Merlin的魔力:異常和日志記錄”(developerWorks,2001年12月)中,John Zukowski展示了新的 JDK 1.4 日志記錄 API 是如何工作的。

  • Thomas E. Davis 撰寫(xiě)的 JavaWorld 文章 “Logging on to Internet Relay Chat (IRC)” 介紹了一種允許應用程序把輸出寫(xiě)到 IRC 的簡(jiǎn)單工具。

  • Gerhard Poul 的文章“Jabber” (developerWorks,2002年5月)說(shuō)明了 Jabber 如何適合于當今的電子商務(wù) 基礎設施。

  • Smack 是 Jive Software 公司提供的一個(gè)開(kāi)放源代碼庫,用于與 Jabber 服務(wù)器通信以執行即時(shí)消息傳送和聊天。


  • Iain Shigeoka 的文章 用 Java 實(shí)現即時(shí)消息傳送 (Manning, 2002) 深入分析了各種 Jabber 協(xié)議。

  • “模板方法(Template Method)設計模式”出自 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 所著(zhù)的 設計模式 一書(shū)(Addison-Wesley出版, 1995年),這四位作者也被稱(chēng)為“四人組(Gang of Four,GoF)。

  • 也可以在線(xiàn)閱讀 模板方法設計模式 的相關(guān)報道。

  • developerWorks Java技術(shù)專(zhuān)區 可以找到數百篇關(guān)于 Java 編程的各個(gè)方面的文章。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
log4j.properties
tomcat啟動(dòng)時(shí)啟動(dòng)日志不輸出問(wèn)題
Log4j的配置
日志Log4j使用
log4j的2.6.2版本properties配置文件的使用舉例
有效地記錄日志可以簡(jiǎn)化企業(yè)的開(kāi)發(fā)過(guò)程
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久