log4j 2.x 架構
主要元件
Log4j使用下圖中顯示的類。
使用Log4j 2 API的應用程式將向LogManager請求具有特定名稱的Logger。LogManager將找到相應的LoggerContext,然後從中獲取Logger。如果必須建立Logger,則它將與LoggerConfig相關聯,該LoggerConfig包含 a)與Logger相同的名稱,b)父包的名稱,或者c)根LoggerConfig。
LoggerConfig物件是從配置中的Logger宣告中建立的。LoggerConfig與實際傳遞LogEvent的Appender相關聯。
Logger層次結構
任何日誌API優於樸素的System.out.println
在Log4j 1.x中,記錄器層次結構是通過記錄器之間的關係來維護的。在Log4j 2中,這種關係不再存在。相反,這種層次結構通過LoggerConfig物件之間的關係來維持。
Loggers 和LoggerConfigs是已命名的實體。Logger名稱區分大小寫,它們遵循分層命名規則:
命名層次結構
如果一個LoggerConfig的名字+‘.’是後代名稱的字首, 則稱該LoggerConfig是另一個LoggerConfig 的祖先。
如果一個LoggerConfig和後代LoggerConfig之間沒有祖先,此LoggerConfig被稱為是子 LoggerConfig 的父級。
例如,名為"com.foo"
的LoggerConfig是名為"com.foo.Bar"
的LoggerConfig的父級。類似地,"java"
是 "java.util"
的父級和"java.util.Vector"
的祖先。這個命名方案應該是大多數開發人員都熟悉的。
根LoggerConfig位於LoggerConfig層次結構的頂部。作為唯一一個例外,它始終存在,並且是每個層次的一部分。直接連結到根LoggerConfig的Logger可以如下獲得:
Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
- 1
或者
Logger logger = LogManager.getRootLogger();
- 1
所有其他的Logger可以使用 LogManager.getLogger 靜態方法通過傳遞所需記錄器的名稱來檢索。有關Logging API的更多資訊可以在Log4j 2 API中找到。
LoggerContext
LoggerContext 在記錄系統裡充當錨點的作用。但根據具體情況,應用程式中可能會有多個活動的LoggerContext。LoggerContext的更多細節在Log Separtion部分。
配置
每個LoggerContext都有一個活動的 Configuration。該配置包含所有Appender,覆蓋上下文的Filter,LoggerConfig,幷包含對StrSubstitutor的引用。在重新配置期間,兩個配置物件將同時存在。一旦所有Logger重定向到新的配置,舊的配置將被停止並丟棄。
Logger
如上所述,Logger是通過呼叫LogManager.getLogger建立的 。Logger本身不執行直接操作。它只是一個名字,並與一個LoggerConfig相關聯。它擴充套件了 AbstractLogger 並實現了所需的方法。如果配置被修改,Logger可能會與不同的LoggerConfig關聯,從而導致其行為被修改。
檢索Logger
使用相同名稱去呼叫LogManager.getLogger方法將始終返回對完全相同的Logger物件的引用。如:
Logger x = LogManager.getLogger("wombat");
Logger y = LogManager.getLogger("wombat");
- 1
- 2
x
和y
指的是完全相同的Logger物件。
Log4j環境的配置通常在應用程式初始化時完成。首選的方法是讀取配置檔案。這在配置中討論。
Log4j可以很容易地通過軟體元件來命名Logger。這可以通過在每個類中例項化一個Logger來完成,Logger名稱等於該類的完全限定名稱。這是定義Logger的有用和直接的方法。由於日誌輸出帶有生成日誌記錄器的名稱,因此該命名策略可以輕鬆識別日誌訊息的來源。然而,這只是一種可能的,儘管是通用的命名記錄器的策略。Log4j不限制Logger命名規則。開發人員可以根據需要自由地命名Logger。
由於在擁有類之後命名“記錄器”是一種常見習慣用法,所以提供了便捷方法 LogManager.getLogger()來自動使用呼叫類的完全限定類名作為記錄器名稱。
儘管如此,以類的名稱來命名Logger似乎是目前已知的最好的策略。
LoggerConfig
LoggerConfig 物件是在日誌記錄配置中宣告Logger時建立的。LoggerConfig包含一組過濾器,任何LogEvent必須經過過濾後再傳遞給Appender。它還包含一組Appender(應用於處理事件)的引用。
日誌級別
LoggerConfig將被分配一個日誌級別。內建級別包括TRACE,DEBUG,INFO,WARN,ERROR和FATAL。Log4j 2還支援自定義日誌級別。獲得更多粒度的另一個機制是使用標記。
Log4j 1.x 和 Logback 都有“級別繼承”的概念。在Log4j 2中,Logger和LoggerConfig是兩個不同的物件,所以這個概念的實現方式有所不同。每個Logger引用相應的LoggerConfig,這個LoggerConfig又可以引用它的父代,從而達到相同的效果。
以下是五個具有各種指定級別值的表格以及與每個Logger關聯的結果級別。請注意,在所有這些情況下,如果未配置根LoggerConfig,則將為其分配預設級別。
Logger Name | Assigned LoggerConfig | LoggerCf Level | Logger Level |
---|---|---|---|
root | root | DEBUG | DEBUG |
X | root | DEBUG | DEBUG |
X.Y | root | DEBUG | DEBUG |
X.Y.Z | root | DEBUG | DEBUG |
在上述示例1中,只有根Logger被配置並且具有日誌級別。所有其他的Logger引用根LoggerConfig並使用它的Level。
Logger Name | Assigned LoggerConfig | LoggerCf Level | Logger Level |
---|---|---|---|
root | root | DEBUG | DEBUG |
X | X | ERROR | ERROR |
X.Y | X.Y | INFO | INFO |
X.Y.Z | X.Y.Z | WARN | WARN |
在上述示例2中,所有Logger都有一個已配置的LoggerConfig並從中獲取它們的Level。
Logger Name | Assigned LoggerConfig | LoggerCf Level | Logger Level |
---|---|---|---|
root | root | DEBUG | DEBUG |
X | X | ERROR | ERROR |
X.Y | X | ERROR | ERROR |
X.Y.Z | X.Y.Z | WARN | WARN |
在上述示例3中,Logger root、X 和 X.Y.Z 都有一個名稱相同的LoggerConfig。Logger X.Y 沒有配置的具有匹配名稱的LoggerConfig,因此使用LoggerConfig X的配置, 因為其名稱與Logger的字首名稱具有最長匹配。
Logger Name | Assigned LoggerConfig | LoggerCf Level | Logger Level |
---|---|---|---|
root | root | DEBUG | DEBUG |
X | X | ERROR | ERROR |
X.Y | X | ERROR | ERROR |
X.Y.Z | X | ERROR | ERROR |
在上述示例4中,Logger root和X 和都有一個名稱相同的LoggerConfig。Logger X.Y 和X.Y.Z沒有配置的具有匹配名稱的LoggerConfig,因此使用LoggerConfig X的配置, 因為其名稱與Logger的字首名稱具有最長匹配。
Logger Name | Assigned LoggerConfig | LoggerCf Level | Logger Level |
---|---|---|---|
root | root | DEBUG | DEBUG |
X | X | ERROR | ERROR |
X.Y | X.Y | INFO | INFO |
X.YZ | X | ERROR | ERROR |
在上述示例5中,Logger root、X 和 X.Y 都有一個名稱相同的LoggerConfig。Logger X.YZ 沒有配置的具有匹配名稱的LoggerConfig,因此使用LoggerConfig X的配置, 因為其名稱與Logger的字首名稱具有最長匹配。它不與LoggerConfig X.Y關聯, 因為令牌必須完全匹配
Logger Name | Assigned LoggerConfig | LoggerCf Level | Logger Level |
---|---|---|---|
root | root | DEBUG | DEBUG |
X | X | ERROR | ERROR |
X.Y | X.Y | ERROR | |
X.Y.Z | X.Y | ERROR |
在上述示例6中,LoggerConfig X.Y沒有配置級別,所以它從LoggerConfig X繼承它的級別。Logger X.Y.Z使用LoggerConfig X.Y,因為它沒有名稱完全匹配的LoggerConfig。它也從LoggerConfig X繼承它的日誌級別。
級別過濾原理
下表說明了級別過濾的工作原理。在表中,垂直標題顯示LogEvent的級別,而水平標題顯示與相應的LoggerConfig關聯的級別。交叉點標識是否允許LogEvent進行進一步處理(YES)或丟棄(NO)。
Event Level | LoggerConfig Level | ||||||
TRACE | DEBUG | INFO | WARN | ERROR | FATAL | OFF | |
ALL | YES | YES | YES | YES | YES | YES | NO |
TRACE | YES | NO | NO | NO | NO | NO | NO |
DEBUG | YES | YES | NO | NO | NO | NO | NO |
INFO | YES | YES | YES | NO | NO | NO | NO |
WARN | YES | YES | YES | YES | NO | NO | NO |
ERROR | YES | YES | YES | YES | YES | NO | NO |
FATAL | YES | YES | YES | YES | YES | YES | NO |
OFF | NO | NO | NO | NO | NO | NO | NO |
Filter
除了上述的自動日誌級別過濾之外,Log4j還提供過濾器,可以在控制權傳遞給任何LoggerConfig之前應用;或在控制權傳遞給LoggerConfig之後但在呼叫任何Appender之前應用;或在控制權傳遞給LoggerConfig之後,但在呼叫特定的Appender之前應用;以及給每個Appender新增過濾。以與防火牆過濾器非常相似的方式,每個過濾器可以返回三個結果之一:Accept
, Deny
或 Neutral
。Accept
的響應意味著不應該呼叫其他過濾器,並且事件將被處理。Deny
的迴應意味著事件應該立即被忽略,控制權應該返回給呼叫者。Neutral
的響應表示該事件應該傳遞給其他過濾器。如果沒有其他過濾器,事件將被處理。
注:一個事件可能被一個過濾器接受,但事件仍然可能不會被記錄。這種情況發生在事件被pre-LoggerConfig過濾器接受,但是被LoggerConfig過濾器拒絕,或被所有Appender拒絕。
Appender
根據logger選擇性地啟用或禁用記錄請求的能力只是Log4j的其中一個作用。Log4j允許記錄請求列印到多個目的地。在Log4j中,輸出目標被稱為 Appender。目前,控制檯,檔案,遠端套接字伺服器,Apache Flume,JMS,遠端UNIX Syslog守護程式以及各種資料庫API都有其對應的appender。更多詳細資訊,請參閱Appender部分 。一個Logger可以連線多個Appender。
可以通過呼叫當前配置的addLoggerAppender方法將Appender新增到Logger中 。如果與Logger名稱匹配的LoggerConfig不存在,則將建立一個LoggerConfig,將Appender附加到該LoggerConfig,然後所有Logger被通知去更新其LoggerConfig引用。
對於給定的logger,每個啟用的記錄請求將被轉發給Logger的LoggerConfig中的所有appender以及LoggerConfig父級的Appender。 換句話說,Appender是從LoggerConfig層次繼承的。例如,如果將控制檯appender新增到根日誌記錄器,則所有啟用的日誌記錄請求將至少在控制檯上列印。如果此時一個file appender新增到名為C的LoggerConfig,那啟用日誌請求時C和C的子級將在一個檔案和在控制檯上列印。可以重寫此預設行為,通過在配置檔案的Logger宣告中設定additivity = "false"
,可使Appender累積功能不再具有可加性。
以下總結了Appender可加性的規則。
Appender的可加性
Logger L的日誌語句的輸出將傳遞到LoggerConfig L 自身 和 祖先中關聯的所有Appender。這就是“appender additivity”的意思。
但是,如果與Logger L關聯的LoggerConfig祖先 P,將其可加性標誌設為false
,那麼L的輸出將被傳遞到LoggerConfig L和它的祖先直至P(包括P)中所有的appender,但不會傳遞至P的祖先中所關聯的Appenders 。
記錄器預設情況下將其可加性標誌設定為true
。
Logger Name | Added Appenders | Activity Flag | Output Targets | Comment |
---|---|---|---|---|
root | A1 | 不適用 | A1 | 根記錄器沒有父物件,所以可加性不適用於它。 |
x | A-x1, A-x2 | true | A1, A-x1, A-x2 | “x”和root的Appenders。 |
x.y | 無 | true | A1, A-x1, A-x2 | “x”和root的Appenders,沒有配置Appender的logger是不常見的。 |
x.y.z | A-xyz1 | true | A1, A-x1, A-x2, A-xyz1 | “x.y.z”、”x”和root的Appenders。 |
security | A-sec | false | A-sec | 由於可加性標誌設定為false ,所以沒有appender的積累。 |
security.access | 無 | true | A-sec | 只有”security”的appender,因為”security”中的可加性標誌被設定為false 。 |
Layout
多數情況下,使用者希望不僅自定義輸出目標,而且還要自定義輸出格式。這是通過將Layout與Appender關聯來實現的 。佈局負責根據使用者的意願格式化LogEvent,而appender負責將格式化的輸出傳送到目的地。所述的PatternLayout,是log4j分發標準的一部分,能讓使用者根據類似於C語言的printf
函式的轉換模式來指定輸出格式。
例如,具有轉換模式“%r [%t]%-5p%c - %m%n”的PatternLayout將輸出類似於:
176 [main] INFO org.foo.Bar - Located nearest gas station.
- 1
第一個欄位是程式啟動以來經過的毫秒數。第二個欄位是處理日誌請求的執行緒。第三個欄位是日誌語句的級別。第四個欄位是與日誌請求關聯的logger的名稱。“ - ”後面的文字是該陳述的訊息。
Log4j 為各種用例(如JSON,XML,HTML和Syslog(包括新的RFC 5424版本))提供了許多不同的佈局。其他appender(如資料庫聯結器)將填充指定的欄位而不是特定的文字佈局。
同樣重要的是,log4j將根據使用者指定的標準呈現日誌訊息的內容。例如,如果您經常需要記錄當前專案中使用的物件型別Oranges,則可以建立一個接受Orange例項的OrangeMessage類並將其傳遞給Log4j,以便在將Orange物件格式化為合適的位元組陣列時需要。
StrSubstitutor和StrLookup
該 StrSubstitutor 類和 StrLookup 介面是從Apache Commons Lang中借用的,然後加以修改來支援評估LOGEVENTS。另外 Interpolator 類是從Apache Commons Configuration借用來允許StrSubstitutor評估來自多個StrLookups的變數。它也被修改為支援評估LogEvents。上述程式碼提供了一種機制,允許配置引用來自系統屬性,配置檔案,LogEvent中的ThreadContext Map,StructuredData的變數。如果元件能夠處理它,則可以在處理配置時或處理每個事件時解析變數。請參閱 Lookups 瞭解更多資訊。
原文連結:Architecture
譯文連結:http://blog.csdn.net/why_still_confused/article/details/79097136
版權宣告:本文為博主原創翻譯文章,若要轉載請註明文章出處