002 使用Appender扩展logger框架
這個地方,在看公司的源代碼的時候,寫的知識點;
現在再看,竟然不是太懂,重新寫一份新的文檔,外加示例說明。
一:說明
1.log4j 環境的三個主要組件:
logger(日志記錄器):控制要啟用或禁用哪些日志記錄語句。可以對日志記錄器指定如下級別:ALL、DEBUG、INFO、WARN、ERROR,FATA或OFF。
layout(布局):根據用戶的愿望格式化日志記錄請求。
appender:向目的地發送格式化的輸出。
2.理解 appender
log4j 框架允許向任何日志記錄器附加多個 appender。
可以在任何時候對某個日子記錄器添加(或刪除)appender。附隨 log4j 分發的 appender 有多個,包括:
ConsoleAppender
FileAppender
SMTPAppender
JDBCAppender
JMSAppender
NTEventLogAppender
SyslogAppender
也可以創建自己的自定義appender。
3.工作原理
所有的 appender 都必須擴展 org.apache.log4j.AppenderSkeleton 類。
這是一個抽象類,它實現了 org.apache.log4j.Appender 和 org.apache.log4j.spi.OptionHandler 接口。
這是AppenderSkeleton的UML類圖。
二:Appender接口
1.Appender接口:
1 import org.apache.log4j.spi.ErrorHandler;
2 import org.apache.log4j.spi.Filter;
3 import org.apache.log4j.spi.LoggingEvent;
4
5 public interface Appender {
6 void addFilter(Filter var1);
7
8 Filter getFilter();
9
10 void clearFilters();
11
12 void close();
13
14 void doAppend(LoggingEvent var1);
15
16 String getName();
17
18 void setErrorHandler(ErrorHandler var1);
19
20 ErrorHandler getErrorHandler();
21
22 void setLayout(Layout var1);
23
24 Layout getLayout();
25
26 void setName(String var1);
27
28 boolean requiresLayout();
29 }
2.對上文的注解說明
這些方法處理 appender 的如下屬性:
name: Appender 是命名的實體,因此有一個針對其名稱的 setter/getter。
layout: Appender 可以具有關聯的 Layout,因此還有另一個針對 layout 的setter/getter 方法。
注意我們說的是“可以”而不是“必須”。這是因為有些 appender 不需要 layout。
lauout 管理格式輸出――也就是說,它返回LoggingEvent 的 String 表示形式。
另一方面, JMSAppender 發送的事件是 串行化的,因此您不需要對它附加 layout。如果自定義的 appender 不需要 layout,那么 requiresLayout() 方法必須返回 false ,以避免 log4j 抱怨說丟失了 layout 信息。
errorHandler : 另一個 setter/getter 方法是為 ErrorHandler 而存在的。
appender 可能把它們的錯誤處理委托給一個 ErrorHandler 對象――即 org.apache.log4j.spi 包中的一個接口。
實現類有兩個: OnlyOnceErrorHandler 和 FallbackErrorHandler 。
OnlyOnceErrorHandle 實現 log4j 的默認錯誤處理策略,它發送出第一個錯誤的消息并忽略其余的所有錯誤。錯誤消息將輸出到 System.err 。
FallbackErrorHandler 實現 ErrorHandler 接口,以便能夠指定一個輔助的 appender。如果主 appender 失敗,輔助 appender 將接管工作。錯誤消息將輸出到 System.err ,然后登錄到新的輔助 appender。
還有管理過濾器的其他方法(比如 ddFilter() 、 clearFilters() 和 getFilter() 方法 )。盡管 log4j 具有過濾日志請求的多種內置方法(比如知識庫范圍級、日志記錄器級和 appender 閾值級),但它使用自定義過濾器方法的能力也是非常強大的。
一個 appender 可以包含多個過濾器。
自定義過濾器必須擴展 org.apache.log4j.spi.Filter 抽象類。這個抽象類要求把過濾器組織為線性鏈。
對每個過濾器的 decide(LoggingEvent) 方法的調用要按照過濾器被添加到鏈中的順序來進行。
自定義過濾器基于三元邏輯。 decide() 方法必須返回 DENY 、 NEUTRAL 或者 ACCEPT 這三個整型常量值之一。
除了 setter/getter 方法以及和過濾器相關的方法外,還有另外兩個方法: close() 和 doAppend() 。 close() 方法釋放 appender 中分配的任何資源,比如文件句柄、網絡連接,等等。
在編寫自定義 appender 代碼時,務必要實現這個方法,以便當您的 appender 關閉時,它的 closed 字段將被設置為 true 。
3.doAppend方法的源代碼
1 public synchronized void doAppend (LoggingEvent event) {
2 if (closed) {
3 // step 1
4 LogLog.error("Attempted to append to closed appender [" + name + "].");
5 return;
6 } if ( !isAsSevereAsThreshold (event.level) ) {
7 // step 2
8 return;
9 }
10 Filter f = this.headFilter;
11 // step 3
12 FILTER_LOOP:
13 while ( f != null) {
14 switch ( f .decide(event) ) {
15 case Filter.DENY: return;
16 case Filter.ACCEPT: break FILTER_LOOP;
17 case Filter.NEUTRAL: f = f.next;
18 }
19 }
20 this.append(event);
21 // step 4
22 }
doAppend()方法之前就提到了append()方法。
它是自定義 appender 必須實現的一個抽象方法,因為框架在doAppend()方法內調用append()方法。append()方法是框架的鉤子(hook)之一。
4.doAppender算法框架
檢查 appender 是否關閉。附加關閉的 appender 是一個編程錯誤。
檢查正在記錄日志的事件是否處于 appender 的閾值之下。
檢查是否有過濾器附加到 appender,如果有,則拒絕請求。
調用 appender 的append()方法。這個步驟被委托給每個子類。
三:OptionHandler
1.OptionHandler接口說明
OptionHandler僅包含一個方法:activateOptions()。
這個方法在對屬性調用 setter 方法之后由一個配置器類調用。
有些屬性彼此依賴,因此它們在全部加載完成之前是無法激活的,比如在activateOptions()方法中就是這樣。
這個方法是開發人員在 appender 變為激活和就緒之前用來執行任何必要任務的機制。
2.OptionHandler接口
1 package org.apache.log4j.spi;
2
3 public interface OptionHandler {
4 void activateOptions();
5 }
3.對上文的注解說明
OptionHandler僅包含一個方法:activateOptions()。
這個方法在對屬性調用 setter 方法之后由一個配置器類調用。
有些屬性彼此依賴,因此它們在全部加載完成之前是無法激活的,比如在activateOptions()方法中就是這樣。
這個方法是開發人員在 appender 變為激活和就緒之前用來執行任何必要任務的機制。
四:理論總結
1.Appender生命周期
appender 實例不存在。或許框架還沒有配置好。
框架實例化了一個新的 appender。這發生在配置器類分析配置腳本中的一個 appender聲明的時候。配置器類調用Class.newInstance(YourCustomAppender.class),這等價于動態調用new YourCustomAppender()。框架這樣做是為了避免被硬編碼為任何特定的 appender 名稱;框架是通用的,適用于任何 appender。
框架判斷 appender 是否需要 layout。如果該 appender 不需要 layout,配置器就不會嘗試從配置腳本中加載 layout 信息。
Log4j 配置器調用 setter 方法。在所有屬性都已設置好之后,框架就會調用這個方法。程序員可以在這里激活必須同時激活的屬性。
配置器調用 activateOptions() 方法。在所有屬性都已設置好之后,框架就會調用這個方法。程序員可以在這里激活必須同時激活的屬性。
Appender 準備就緒。此刻,框架可以調用 append() 方法來處理日志記錄請求。這個方法由 AppenderSkeleton.doAppend() 方法調用。
最后,關閉appender。當框架即將要刪除您的自定義 appender 實例時,它會調用您的 appender 的close()方法。close()是一個清理方法,意味著 您需要釋放已分配的所有資源。它是一個必需的方法,并且不接受任何參數。它必須把closed字段設置為true,并在有人嘗試使用關閉的 appender 時向框架發出警報。
2.生命周期圖
3.書寫Appender的步驟
擴展AppenderSkeleton抽象類。
指定您的 appender 是否需要 layout。
如果某些屬性必須同時激活,則應該在activateOptions()方法內完成。
實現close()方法。它必須把 closed 字段的值設置為true。記得釋放所有資源。
可選地指定要使用的默認ErrorHandler對象。
編寫append()方法的代碼。這個方法負責附加日志記錄事件,并在錯誤發生時負責調用錯誤處理程序。
4.log4j執行順序
五:小示例
1.程序結構
感覺使用maven管理jar比較方便,這里就使用maven項目
2.pom
一直在加包,導致現在也不清楚需要多少包,以后這里再研究。
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 2 <modelVersion>4.0.0</modelVersion> 3 <groupId>appender</groupId> 4 <artifactId>jun.it</artifactId> 5 <version>0.0.1-SNAPSHOT</version> 6 <name>AppenderDemo</name> 7 <dependencies> 8 <!-- https://mvnrepository.com/artifact/log4j/log4j --> 9 <dependency> 10 <groupId>log4j</groupId> 11 <artifactId>log4j</artifactId> 12 <version>1.2.17</version> 13 </dependency> 14 <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> 15 <dependency> 16 <groupId>org.apache.logging.log4j</groupId> 17 <artifactId>log4j-core</artifactId> 18 <version>2.10.0</version> 19 </dependency> 20 <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api --> 21 <dependency> 22 <groupId>org.apache.logging.log4j</groupId> 23 <artifactId>log4j-api</artifactId> 24 <version>2.10.0</version> 25 </dependency> 26 <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl --> 27 <dependency> 28 <groupId>org.apache.logging.log4j</groupId> 29 <artifactId>log4j-slf4j-impl</artifactId> 30 <version>2.10.0</version> 31 </dependency> 32 <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --> 33 <dependency> 34 <groupId>commons-logging</groupId> 35 <artifactId>commons-logging</artifactId> 36 <version>1.2</version> 37 </dependency> 38 39 40 41 42 43 </dependencies> 44 </project>
3.HelloAppender
1 package com.jun.it;
2
3 import org.apache.log4j.AppenderSkeleton;
4 import org.apache.log4j.spi.LoggingEvent;
5
6 public class HelloAppender extends AppenderSkeleton {
7 // ==============參數==============
8 private String account;
9
10 public String getAccount() {
11 return account;
12 }
13
14 public void setAccount(String account) {
15 this.account = account;
16 }
17 // ================================
18
19 public void close() {
20
21 }
22
23 public boolean requiresLayout() {
24 return false;
25 }
26
27 @Override
28 protected void append(LoggingEvent event) {
29 System.out.println("Hello, " + account + " : " + event.getMessage());
30 }
31
32 }
4.測試類
1 package com.jun.it;
2
3 import org.apache.commons.logging.Log;
4 import org.apache.commons.logging.LogFactory;
5
6 public class TestAppenderDemo {
7
8 public static void main(String[] args) {
9 Log log = LogFactory.getLog("hello");
10 log.info("I am ready.");
11
12 }
13
14 }
5.log4j.properties
1 log4j.rootLogger=INFO,hello 2 log4j.appender.hello=com.jun.it.HelloAppender 3 log4j.appender.hello.account=world 4 log4j.appender.hello.Encoding=UTF-8 5 log4j.appender.hello.Threshold=DEBUG 6 log4j.appender.hello.DatePattern=yyyy-MM-dd'.log'
6.效果
總結
以上是生活随笔為你收集整理的002 使用Appender扩展logger框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: activemenu怎么拼 vue_vu
- 下一篇: popstate_HTML onpops