天天看點

Log4j-設計原理

Log4j有三個主要的元件:Logger、Appender和Layout。這三個元件互相配合使得我們可以獲得非常強大的日志記錄的能力。

Logger

Logger的名稱是區分大小寫的,依據名稱可以确定其層次結構(即父子關系),規則如下:

  • 如果Logger A的名稱後跟一個點(.)是Logger B的名稱的字首就認為Logger A是LoggerB的祖先。
  • 如果在Logger A和Logger B之間,Logger B沒有任何其它的祖先就認為Logger A是LoggerB的父親。

在Logger的層次結構的最頂層是root logger,它會永遠存在,而且不能通過名字取到。

上面文字的描述可能不好的了解,為此我們給出了一張圖,Logger的層次結構圖,從中可以非常直覺的看出三種主要元件的關系和各自所起的作用。

圖示 1. Logger的層次結構圖

Log4j-設計原理

Loger x.y是Logger x.y.z的祖先,因為x.y.是x.y.z的字首,這符合規則的前一條。另外在Loggerx.y和Logger x.y.z之間,Logger x.y.z沒有其它的祖先,是以Logger x.y是Loggerx.y.z的父親,這符合規則的後一條。這樣我們依據上面的規則就可以構造出如圖1所示的Logger的層次結構。

從圖1中我們還可以看到每一個Logger都有一個Level,根據該Level的值Logger決定是否處理對應的日志請求。如果Level沒有被設定,就象圖1中的Loggerx.y一樣,又該怎麼辦呢?答案是可以從祖先那裡繼承。

如果Logger C沒有被設定Level,那麼它将沿着它的層次結構向上查找,如果找到就繼承并結束,否則會一直查找到rootlogger結束。因為log4j在設計時保證rootlogger會被設定一個預設的Level,是以任何logger都可以繼承到Level。

圖1中的Logger x.y沒有被設定Level,但是根據上面的繼承規則,Logger x.y繼承了rootlogger的Level。

我們在來看看Logger選擇日志記錄請求(log request)的規則:

假設Logger M具有q級的Level,這個Level可能是設定的也可能是繼承到的。

如果向LoggerM發出一個Level為p的日志記錄請求,那麼隻有滿足p>=q時這個日志記錄請求才會被處理。

org.apache.log4j.Logger中的不同方法發出不同Level的日志記錄請求,如下:

  • public void debug(Object message),發出Level為DEBUG的日志記錄請求
  • public void info(Object message),發出Level為INFO的日志記錄請求
  • public void warn(Object message),發出Level為WARN的日志記錄請求
  • public void error(Object message),發出Level為ERROR日志記錄請求
  • public void fatal(Object message),發出Level為FATAL的日志請求
  • public void log(Level l, Object message),發出指定Level的日志記錄請求

其中的靜态常量DEBUG、INFO、WARN、ERROR、FATAL是在org.apache.log4j.Level中定義的,除了使用這些預定義的Level之外,Log4j還支援自定義Level。

注:org.apache.log4j.Level中還預定義了一些其它的Level。

Appender

在Log4j中,Appender指的是日志記錄輸出的目的地。目前支援的Appender(目的地)有檔案(file)、控制台(console)、java.io.OutputStream、java.io.Writer、遠端伺服器、遠端UnixSyslog守護者、遠端JMS監聽者、NTEventLog或者發送e-mail。如果您在上面沒有找到适合的Appender,那就需要考慮實作自己的自定義Appender了。

每個Logger可以有多個Appender,但是相同的Appender隻會被添加一次。

Appender的附加性意味着Logger C會将日志記錄發給它的和它祖先的所有Appender。在圖1中Loggera會将日志記錄發給它自己的JDBCAppender和它的祖先rootlogger的ConsoleAppender和FileAppender。Loggerx.y.z自己沒有Appender,它将把日志記錄發給它的祖先rootlogger的ConsoleAppender和FileAppender,如果Loggerx.y也含有Appender,那麼它們也會包括在内。

Appender的附加性是可以被中斷的。假設Logger C的一個祖先為Logger P,如果LoggerP的附加性标志(additivity flag)設定為假,那麼Logger C會将日志記錄隻發給它的和在它和LoggerP之間的祖先(包括Logger P)的Appender,而不會發給LoggerP的祖先的Appender。Logger的附加性标志(additivity flag)預設值為ture。

在圖1中如果沒有設定Logger a的附加性标志(additivity flag),而是使用預設值true,那麼Loggera會将日志記錄發給它自己的JDBCAppender和它祖先rootlogger的ConsoleAppender和FileAppender,這和上面的描述相同。如果設定Loggera的附加性标志(additivity flag)的值false,那麼Loggera會将日志記錄發給它自己的JDBCAppender而不會在發給它祖先rootlogger的ConsoleAppender和FileAppender了。

Layout

Appender定制了輸出目的地,通常我們還需要定制日志記錄的輸出格式,在Log4j中是通過将Layout和Appender關聯到一起來實作的。Layout依據使用者的要求來格式化日志記錄。PatternLayout(标準Log4j元件)讓使用者依據類似于C語言printf函數的轉換模式來指定輸出格式。

例如,轉換模式(conversion pattern)為"%r [%t] %-5p %c -%m%n"的PatternLayout将生成類似于以下内容的輸出:

176 [main] INFO  org.foo.Bar - Located nearest gas station.   
      

在上面的輸出中:

  • 第一個字段表示自程式開始到發出日志記錄請求時所消耗的毫秒數
  • 第二個字段表示發出日志記錄請求的線程
  • 第三個字段表示日志記錄請求的Level
  • 第四個字段表示發出日志記錄請求的Logger的名稱
  • 第五個字段(-後的文本)表示日志記錄請求的消息

Log4j中還提到了一些其它的Layout,包括HTMLLayout、SimpleLayout、XMLLayout、TTCCLayout和DateLayout。如果這些不能滿足您的要求,還可以自定義自己的Layout。

繼續閱讀