dwys0343

          技術整理

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            1 Posts :: 16 Stories :: 0 Comments :: 0 Trackbacks

          動態配置 log4j

          1?
          配置外部配置文件來配置的基本步驟
          1.1
           一個運用配置文件的實例
          Log4j
          之所以能成功的原因之一是它的靈活性。但如果只是簡單的調用 BasicConfigurator.configure() 來進行配置工作,那么所有的配置都是在函數中寫死的,以后修改配置就要修改原代碼,這就不能體現出 log4j 的靈活性了,所以基本上不會通過 BasicConfigurator.configure() 來進行配置工作的。
          為了增加軟件的靈活性,最常用的做法就是使用配置文件,如 web.xml 之于 J2EE , struts-config.xml 之于 struts 一樣, log4j 也提供了讓我們把配置信息從程序轉移到配置文件中的方法。 Log4j 提供了兩種方式的配置文件: XML 文件和 Java property 配置文件。通過把配置信息轉移到外部文件中,當我們要修改配置信息時,就可以直接修改配置文件而不用去修改代碼了,下面,我們就來完成一個通過配置文件來實現 log4j 的實例。
          2-a
          package?TestLog4j;
          import?org.apache.log4j.Logger;
          import?org.apache.log4j.BasicConfigurator;
          import?org.apache.log4j.PropertyConfigurator;
          import?org.apache.log4j.Priority;?public?class?TestLog4j?
          {
          static?Logger?logger?=?Logger.getLogger(TestLog4j.class.getName());
          public?TestLog4j(){}

          public?static?void?main(String[]?args)
          {
          //
          通過 BasicConfigurator 類來初始化
          //BasicConfigurator.configure();
          //
          1 )通過配置文件來初始化
          PropertyConfigurator.configure("F:\\nepalon\\log4j.properties");

          logger.debug("Start?of?the?main()?in?TestLog4j");
            // 代碼( 2
          logger.info("Just?testing?a?log?message?with?priority?set?to?INFO");
          logger.warn("Just?testing?a?log?message?with?priority?set?to?WARN");
          logger.error("Just?testing?a?log?message?with?priority?set?to?ERROR");
          logger.fatal("Just?testing?a?log?message?with?priority?set?to?FATAL");
          logger.log(Priority.WARN,?"Testing?a?log?message?use?a?alternate?form");
          logger.debug(TestLog4j.class.getName());
            // 代碼( 2
          }
          }
          在這個例子中,我們用 PropertyConfigurator.configure("F:\\nepalon\\log4j.properties") 代替 BasicConfigurator.configure() 進行配置。 PropertyConfigurator.configure() 函數的參數可以是一個 properties 文件所在路徑的 String 對象,可以是一個 properties 文件所在路徑的 URL 對象,也可以是一個 properties 對象。通過 PropertyConfigurator.configure() 可以通過指定的 properties 文件來配置信息。如果要用 XML 文件進行信息配置,可以在代碼中調用 DOMConfigurator() 函數來進行配置工作。在這里,我們只以 properties 文件來完成例子。接著,我們來看一下 log4j.properties 文件中都有些什么東西:
          2-b
          log4j.rootLogger?=?DEBUG,?A1
          log4j.appender.A1?=?org.apache.log4j.ConsoleAppender
          log4j.appender.A1.layout?=?org.apache.log4j.PatternLayout
          log4j.appender.A1.layout.ConversionPattern?=?%-4r?[%t]?%-5p?%c?%x?-?%m%n
          運行這個實例,運行結果為
          0?[main]?DEBUG?TestLog4j.TestLog4j?-?Start?of?the?main()?in?TestLog4j
          20?[main]?INFO?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?INFO

          20?[main]?WARN?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?WARN
          20?[main]?ERROR?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?ERROR
          20?[main]?FATAL?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?FATAL
          180?[main]?WARN?TestLog4j.TestLog4j?-?Testing?a?log?message?use?a?alternate?form
          180?[main]?DEBUG?TestLog4j.TestLog4j?-?TestLog4j.TestLog4j
          下面,我們分析一下這個配置文件。
          1)?
          由于每一個 Logger 對旬都有一個級別,文件的第一行就是定義了一個 Logger 及其級別。在這里定義了一個根記錄器( root?logger ),這涉及到記錄器的層次問題,在些暫時不深入討論,在后面的章節再進行討論。
          2)?
          第二行定義了一個名為 A1 的輸出流,這個流就是控制臺,所以通過 Logger 對象打印的信息會在控制臺輸出。
          3)?
          第三行定義了打印信息的布局。在這里我們用 PatternLayout 作為此記錄器的布局, PatternLayout 允許你以靈活的格式來打印信息。
          4)?
          第四行指定的打印信息的具體格式,從結果可知,這個實例的打印格式為:當前打印語句所使用的時間 ?[ 日志所在的線程 ]? 打印的級別 ? 當前日志所在的類的全名 ? 日志信息。
          現在我們來修改一下這個記錄器的級別,把第一行的 DEBUG 改為 INFO ,再運行程序,結果將變為:
          0?[main]?INFO?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?INFO
          10?[main]?WARN?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?WARN
          10?[main]?ERROR?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?ERROR
          10?[main]?FATAL?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?FATAL
          10?[main]?WARN?TestLog4j.TestLog4j?-?Testing?a?log?message?use?a?alternate?form
          由于這個 Logger 的級別變為 INFO ,而代碼( 2 )是調用 debug() 函數來輸出日志信息時只能當記錄器級別為 DEBUG 時才輸出信息,所以代碼( 2 )將不輸出信息。
          1.2
           實例原理
          1.2.1  初始化配置信息
          如果要通過 JAVA properties 文件來配置信息,那么在代碼中就要通過 PropertyConfigurator.configure() 函數從 properties 文件中加載配置信息,這個函數有三種參數形式:一個 properties 文件所在路徑的 String 對象,可以是一個 properties 文件所在路徑的 URL 對象,也可以是一個 properties 對象。如果要用 XML 文件來配置信息,則可用類型的
          DOMConfigurator()
          函數來從一個 XML 文件中加載配置信息。
          1.2.2
           輸出端 Appender
          在上面的例子中,我們都是簡單的把日志信息輸出到控制臺中。其實在 log4j 中還可以把日志信息輸出到其它的輸出端,對于同一個日志信息,我們還可以讓它同時輸出到多個輸出端中,如同時在控制臺和文件中進行打印。一個輸出端就是一個 appender 。要在配置文件中定義一個 appender 有三步:

          )? 在定義一個記錄器的同時定義出該記錄器的輸出端 appender 。在例 2 的配置文件的第一句 log4j.rootLogger?=?DEBUG,?A1 中,我們定義了一個根記錄器,它的級別為 DEBUG ,它有一個 appender 名為 A1 。定義根記錄器的格式為 log4j.rootLogger?=?[?level?],?appendName1,?appendName2,?…appendNameN 。同一個記錄器可有多個輸出端。
          2)?
          定義 appender 的輸出目的地。定義一個 appender 的輸出目的地的格式為 log4j.appender.appenderName?=?fully.qualified.name.of.appender.class 。 log4j 提供了以下幾種常用的輸出目的地:
          org.apache.log4j.ConsoleAppender ,將日志信息輸出到控制臺
          ?org.apache.log4j.FileAppender ,將日志信息輸出到一個文件
          org.apache.log4j.DailyRollingFileAppender ,將日志信息輸出到一個,并且每天輸出到一個新的日志文件
          org.apache.log4j.RollingFileAppender ,將日志信息輸出到一個文件,通過指定文件的的尺寸,當文件大小到達指定尺寸的時候會自動把文件改名,如名為 example.log 的文件會改名為 example.log.1 ,同時產生一個新的 example.log 文件。如果新的文件再次達到指定尺寸,又會自動把文件改名為 example.log.2 ,同時產生一個 example.log 文件。依此類推,直到 example.log.?MaxBackupIndex MaxBackupIndex 的值可在配置文件中定義。
          org.apache.log4j.WriterAppender ,將日志信息以流格式發送到任意指定的地方。
          ?org.apache.log4j.jdbc.JDBCAppender ,通過 JDBC 把日志信息輸出到 數據庫 中。
          在例 2 中, log4j.appender.A1?=?org.apache.log4j.ConsoleAppender 定義了名為 A1 appender 的輸出目的地為控制臺,所以日志信息將輸出到控制臺。
          3)?
          定義與所選的輸出目的地相關的參數,定義格式為:
          log4j.appender.appenderName.optionName1?=?value1
          ……
          log4j.appender.appenderName.optionNameN?=?valueN
          其中一個最常用的參數 layout 將在下面介紹。
          1.2.3  輸出格式(布局)layout
          通過 appender 可以控制輸出的目的地,而如果要控制輸出的格式,就可通過 log4j layout 組件來實現。通過配置文件定義一個 appender 的輸出格式,也通常需要兩個步驟:
          1)?
          定義 appender 的布局模式。定義一個 appender 的布局模式的格式為 log4j.appender.appenderName.layout?=?fully.qualified.name.of.layout.class Log4j 提供的布局模式有以下幾種:
          org.apache.log4j.HTMLLayout ,以 HTML 表格形式布局
          org.apache.log4j.PatternLayout ,可以靈活地指定布局模式
          org.apache.log4j.SimpleLayout ,包含日志信息的級別和信息字符串
          在例 2  中 log4j.appender.A1.layout?=?org.apache.log4j.PatternLayout 定義了名為 A1 appender 的布局模式為 PatternLayout 。
          2)?
          定義與所選的布局模式相關的設置信息,定義格式為:
          log4j.appender.appenderName.layout.optionName1?=?value1
          ……
          log4j.appender.appenderName.layout.optionNameN?=?valueN
          選擇了不同的布局模式可能會有不同的設置信息。實例 2 所選的布局模式 PatternLayout 的一個 PatternLayout ConversionPattern? ,通過定義這個 PatternLayout 的值,我們可以指定輸出信息的輸出格式。在例 2 的配置文件中的定義如下 log4j.appender.A1.layout.ConversionPattern?=?%-4r?[%t]?%-5p?%c?%x?-?%m%n 。在下面,我們將介紹布局模式 PatternLayout 的參數 ConversionPattern 的各個值代表的含義。
          1.2.4
            ConversionPattern 參數的格式含義
          格式名 ? 含義
          %c?
          輸出日志信息所屬的類的全名

          %d? 輸出日志時間點的日期或時間,默認格式為 ISO8601 ,也可以在其后指定格式,比如: %d{yyy-MM-dd?HH:mm:ss?} ,輸出類似: 2002-10-18 -?22 10 28
          %f?
          輸出日志信息所屬的類的類名
          %l?
          輸出日志事件的發生位置,即輸出日志信息的語句處于它所在的類的第幾行
          %m?
          輸出代碼中指定的信息,如 log(message) 中的 message
          %n?
          輸出一個回車換行符, Windows 平臺為 “\r\n” , Unix 平臺為 “\n”
          %p?
          輸出優先級,即 DEBUG , INFO , WARN ERROR , FATAL 。如果是調用 debug() 輸出的,則為 DEBUG ,依此類推
          %r?
          輸出自應用啟動到輸出該日志信息所耗費的毫秒數
          %t?
          輸出產生該日志事件的線程名
          1.3
           定義多個輸出目的地的實例
          從上面的實例原理中我們已經知道,同一個日志信息可以同時輸出到多個輸出目的地,在這個例子中,我們將實現一個把日志信息同時輸出到控制器、一個文件中的實例和 數據庫 中。這個實例的 Java 代碼我們沿用例 2 中的代碼,我們只需修改配置文件即可。這也體現了 log4j 的靈活性。
          3-a
          create?table?log4j(
          logID?int?primary?key?identity,
          message?varchar(1024),
          priority?varchar(10),
          milliseconds?int,
          category?varchar(256),
          thread?varchar(100),
          NDC?varchar(256),
          createDate?datetime,
          location?varchar(256),
          caller?varchar(100),
          method?varchar(100),
          filename?varchar(100),
          line?int
          )
          3-b
          #1?
          定義了兩個輸出端
          log4j.rootLogger?=?INFO,?A1,?A2,A3

          #2?
          定義 A1 輸出到控制器
          log4j.appender.A1?=?org.apache.log4j.ConsoleAppender
          #3?
          定義 A1 的布局模式為 PatternLayout
          log4j.appender.A1.layout?=?org.apache.log4j.PatternLayout
          #4?
          定義 A1 的輸出格式
          log4j.appender.A1.layout.ConversionPattern?=?%-4r?[%t]?%-5p?%c?-?%m%n

          #5?
          定義 A2 輸出到文件
          log4j.appender.A2?=?org.apache.log4j.RollingFileAppender
          #6?
          定義 A2 要輸出到哪一個文件
          log4j.appender.A2.File?=?F:\\nepalon\\classes\\example3.log
          #7?
          定義 A2 的輸出文件的最大長度
          log4j.appender.A2.MaxFileSize?=?1KB
          #8?
          定義 A2 的備份文件數
          log4j.appender.A2.MaxBackupIndex?=?3
          #9?
          定義 A2 的布局模式為 PatternLayout
          log4j.appender.A2.layout?=?org.apache.log4j.PatternLayout
          #10?
          定義 A2 的輸出格式
          log4j.appender.A2.layout.ConversionPattern?=?%d{yyyy-MM-dd?hh:mm:ss}:%p?%t?%c?-?%m%n

          #11
          ? 定義 A3 輸出到數據庫
          log4j.appender.A3?=?org.apache.log4j.jdbc.JDBCAppender
          log4j.appender.A3.BufferSize?=?40
          log4j.appender.A3.Driver?=?com.microsoft.jdbc.sqlserver.SQLServerDriver
          log4j.appender.A3.URL?=?jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=nepalon
          log4j.appender.A3.User?=?sa
          log4j.appender.A3.Password?=?
          log4j.appender.A3.layout?=?org.apache.log4j.PatternLayout
          log4j.appender.A3.layout.ConversionPattern?=?INSERT?INTO?log4j?(createDate,?thread,?priority,?category,?message)?values(getdate(),?'%t',?'%-5p',?'%c',?'%m')
          配置文件中的 6 、 7 、 8 行顯示了輸出端為 RollingFileAppender 的特有參數及其運用的方法。 11 區顯示了輸出端為 JDBCAppender 的特有參數及其運用方法。在這著重講解一下 6 、 7 、 8 行的作用。 6 行指定日志信息輸出到哪個文件, 7 行指定日志文件的最大長度,最后要詳細介紹 8 行。第 8 行的參數是設置備份文件的個數的參數,在這里我們設置為 3 ,表示最多有 3 個備份文件,具體作用為:

          1)? example3.log 文件的大小超過 K 時,就把文件改名為 example3.log.1 ,同時生成一個新的 example3.log 文件
          2)?
          example3.log 文件的大小再次超過 1K ,又把文件改名為 example3.log.1 。但由于此時 example3.log.1 已存在,則先把 example3.log.1 更名為 example3.log.2 ,再把 example3.log 文件改名為 example3.log.1
          3)?
          同理,當 example3.log 文件的大小再次超過 1K ,先把 example3.log.2 文件更名為 example3.log.3 ,把 example3.log.1 文件更名為 example3.log.2 ,再把 example3.log 文件改名為 example3.log.1
          4)?
          example3.log 文件的大小再次超過 1K ,先把 example3.log.2 文件更名為 example3.log.3 ,舊的 example3.log.3 文件將被覆蓋;把 example3.log.1 文件更名為 example3.log.2 ,舊的 example3.log.2 文件被覆蓋;最后把 example3.log 文件改名為 example3.log.1 并覆蓋掉舊的 example3.log.1 文件。
          運行結果將分為兩部分
          在控制器中:
          0?[main]?INFO?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?INFO
          11?[main]?WARN?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?WARN
          21?[main]?ERROR?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?ERROR?21?[main]?FATAL?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?FATAL
          21?[main]?WARN?TestLog4j.TestLog4j?-?Testing?a?log?message?use?a?alternate?form
          在文件 example3.log 中:
          2003-12-18?04:23:02:INFO?main?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?INFO
          2003-12-18?04:23:02:WARN?main?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?WARN
          2003-12-18?04:23:02:ERROR?main?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?ERROR
          2003-12-18?04:23:02:FATAL?main?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?FATAL
          2003-12-18?04:23:02:WARN?main?TestLog4j.TestLog4j?-?Testing?a?log?message?use?a?alternate?form
          1.4
           配置 log4j 的總結
          這個教程到這里,關于配置 log4j 的配置文件的基本原理已經講完了,而且通過例 3 我們已經可以完成基本的日志工作了?,F在,我們就做一個總結。配置一個配置文件的基本步驟如下:
          1)?
          定義一個 Logger 。在定義 Logger 時指定該 Logger 的級別級其輸出目的地。定義 Logger 的格式為
          log4j.rootLogger?=?[?level?],?appendName1,?appendName2,?…appendNameN
          。
          2)?
          定義 appender 的輸出目的地。定義一個 appender 的輸出目的地的格式為
          log4j.appender.appenderName?=?fully.qualified.name.of.appender.class
          。
          log4j
          提供的輸出端有 ConsoleAppender 、 FileAppender? DailyRollingFileAppender 、 RollingFileAppender WriterAppender 。

          3)? 定義 appender 的除布局模式外的其它相關參數,如例 3 中第 6 、 7 、 8 定義了 A2 的相關參數。定義格式為
          log4j.appender.appenderName.optionName1?=?value1
          ……
          log4j.appender.appenderName.optionNameN?=?valueN
          如果除了布局模式外不需要定義別的參數,可跳過這一步(如例 3 中的 A1 )。
          4)?
          定義 appender 的布局模式。定義一個 appender 的布局模式的格式為
          log4j.appender.appenderName.layout?=?fully.qualified.name.of.layout.class

          布局模式其實也是步驟 3 )中的一個部分,只是布局模式參數是每一個 appender 必須定義的參數。 Log4j 提供的布局模式有 HTMLLayout 、 PatternLayout SimpleLayout
          5)?
          定義與所選的布局模式相關的設置信息,定義格式為
          og4j.appender.appenderName.layout.optionName1?=?value1
          ……
          log4j.appender.appenderName.layout.optionNameN?=?valueN
          2
           記錄器的層次 Logger?hierarchy
          2.1
           何為記錄器的層次 hierarchy
          首先,我們先看一下何為層次,以我們最熟悉的繼承為例,下面是一張類圖

          在這個繼承體系中,類 B 是類 C 的父類,類 A 是類 C 的祖先類,類 D 是類 C 的子類。這些類之間就構成一種層次關系。在這些具有層次關系的類中,子類都可繼承它的父類的特征,如類 B 的對象能調用類 A 中的非 private 實例變量和函數;而類 C 由于繼承自類 B ,所以類 B 的對象可以同時調用類 A 和類 B 中的非 private 實例變量和函數。
          log4j 中,處于不同層次中的 Logger 也具有象類這樣的繼承關系。
          2.2
           記錄器的層次
          如果一個應用中包含了上千個類,那么也幾乎需要上千個 Logger 實例。如何對這上千個 Logger 實例進行方便地配置,就是一個很重要的問題。 Log4J 采用了一種樹狀的繼承層次巧妙地解決了這個問題。在 Log4J Logger 是具有層次關系的。它有一個共同的根,位于最上層,其它 Logger 遵循類似包的層次。下面我們將進行介紹。
          2.2.1  根記錄器root?logger
          就象一個 Java 中的 Object 類一樣, log4j 中的 logger 層次中有一個稱之為根記錄器的記錄器,其它所有的記錄器都繼承自這個根記錄器。根記錄器有兩個特征:
          1)?
          根記錄器總是存在。就像 Java 中的 Object 類一樣,因為用 log4j 輸出日志信息是通過記錄器來實現的,所以只要你應用了 log4j ,根記錄器就肯定存在的。
          2)?
          根記錄器沒有名稱,所以不能通過名稱來取得根記錄器。但在 Logger 類中提供了 getRootLogger() 的方法來取得根記錄器。
          2.2.2
           記錄器的層次
          Logger
          遵循類似包的層次。如
          static?Logger?rootLog?=?Logger.getRootLogger();
          static?Logger?log1?=?Logger.getLogger("test4j");
          static?Logger?log2?=?Logger.getLogger("test4j.test4j2");
          static?Logger?log3?=?Logger.getLogger("test4j.test4j2.test4j2");
          那么 rootLog log2 的祖先子記錄器, log1 log2 的父子記錄器, log3 log2 的子記錄器。記錄器象 Java 中的類繼承一樣,子記錄器可以繼承父記錄器的設置信息,也可以可以覆寫相應的信息。
          首先先看一下記錄器層次中的繼承有什么用處。假設程序中的每個包都具有一些基本的日志信息,而包中的不同包可能會有些額外的日志信息要輸出,這種情況就可以象處理 Java 中的類一樣,運用 Logger 中的層次關系來達到目的。假設有個名為 A 的包,我包下的所有類都要把日志信息輸出到控制臺中; A.B 包除了輸出到控制臺外還要輸出到文件中; A.C 包除了輸出到控制臺中還要輸出到 HTML 文檔中。這樣我們就可以通過定義一個父記錄器 A ,它負責把日志信息輸出到控制臺中;定義一個 A 的子記錄器 A.B ,它負責把日志信息輸出到文件中;定義一個 A 的子記錄器 A.C ,它負責把日志信息輸出到 HTML 文檔中。

          記錄器遵循的是類似包的層次,這樣做為我們帶來了大大的方便。 Logger 類中的 getLogger() 方法可以取得 Logger 對象,這個方法有三種參數形式 String 、 Class URL ,其實不論是用哪一種,最終都是通過記錄器的名字來取得記錄器對象的。如果要取得一個名為 A.B 的記錄器對象,我們可以 Logger.getLogger(“A.B”) 。但從上面的例子中,我們都是通過 Logger.getLogger(TestLog4j.class.getName()) 這種方法來取得記錄器對象。這是為什么呢?現在我們假設 A.B 的包下有一個類 BClass ,那么我們調用 BClass.class.getName() 得到的是這個類的全名 A.B.BClass 。所以當調用 Logger.getLogger(BClass.class.getName()) 時,最理想的情況是返回名為 A.B.BClass 的記錄器對象。但是如果不存在名為 A.B.BClass 的記錄器時它會怎樣呢?其實通過 Logger 類的 getLogger 方法取得記錄器時存在下面兩種情況:
          1)?
          如果存在與所要找的名字完全相同的記錄器,則返回相應的記錄器對象。
          當調用 Logger.getLogger(BClass.class.getName()) 時,如果定義了名為 A.B.BClass 的記錄器,它就返回該記錄器的對象。
          2)?
          但如果找不到,它會嘗試返回在記錄器層次中與所要找的記錄器最接近的記錄器對象。
          當調用 Logger.getLogger(BClass.class.getName()) 時,如果沒有定義了名為 A.B.BClass 的記錄器,那會嘗試返回名為 A.B 的記錄器的對象;如果又沒有定義名為 A.B 的記錄器,它會嘗試返回名為 A 的記錄器的對象;如果也沒定義名為 A 的記錄器,它就會返回根記錄器的對象,而根記錄器是必須存在的,所以你總能得到一個記錄器對象。
          好了,現在我們回到前面的問題,我們為什么總要通過 Logger.getLogger(BClass.class.getName()) 這種以類全名作為參數來取得記錄器對象呢?其實這是為了管理方便。因為我們在定義 設計 Logger 時也遵循類似包的規則,使設計器的名稱與程序中的類包對應。如上面的假設中我們的程序中有 A 包, A 包下有 B 包和 C 包, B 包下又有類 BClass ,那么我們就可使設計器的名為 A A.B 、 A.C A.B.BClass ,以此類推。那么當我們通過類命名來取得設計器對象時,總能取到與所要的設計器最接近的設計器對象。
          2.3
           如何應用記錄器的層次
          2.3.1  如果定義及獲取不同層次的記錄器
          任何一個記錄器的使用都有兩個步驟:
          1)?
          在配置文件中定義相應的記錄器。
          在配置文件中定義記錄器的格式有兩種
          ? 定義根記錄器的格式為
          log4j.rootLogger?=?[?level?],?appendName1,?appendName2,?…appendNameN
          ? 定義一個非根記錄器的格式為
          log4j.logger.loggerName1?=?[?level?],?appendName1,…appendNameN
          ……
          log4j.logger.loggerNameM?=?[?level?],?appendName1,?…appendNameN
          我們可以定義任意個非根記錄器。
          2)?
          在代碼中調用 Logger 類的取得記錄器方法取得相應的記錄器對象。
          要取得根記錄器對象可通過 Logger.getRootLogger() 函數,要取得非根記錄器可通過 Logger.getLogger() 函數。
          理論知道就講到這里,紙上得來終覺淺,下面,我們來小小演練一下。
          4-a
          package?TestLog4j;
          import?org.apache.log4j.Logger;
          import?org.apache.log4j.PropertyConfigurator;
          import?org.apache.log4j.Priority;
          import?TestLog4j.TestLog4j2.TestLog4j2;

          public?class?TestLog4j?
          {
          static?Logger?logger?=?Logger.getLogger(TestLog4j.class.getName());
            // 2
          public?TestLog4j(){}

          public?static?void?main(String[]?args)
          {
          //
          同時輸出到控制臺和一個文件的實例并實現了 Logger 的繼承
          PropertyConfigurator.configure("F:\\nepalon\\log4j2.properties");

          logger.debug("Start?of?the?main()?in?TestLog4j");
          logger.info("Just?testing?a?log?message?with?priority?set?to?INFO");
          logger.warn("Just?testing?a?log?message?with?priority?set?to?WARN");
          logger.error("Just?testing?a?log?message?with?priority?set?to?ERROR");
          logger.fatal("Just?testing?a?log?message?with?priority?set?to?FATAL");
          logger.log(Priority.WARN,?"Testing?a?log?message?use?a?alternate?form");
          logger.debug(TestLog4j.class.getName());
          TestLog4j2?testLog4j2?=?new?TestLog4j2();
            // 1
          testLog4j2.testLog();
          }
          }
          在類 TestLog4j 中我們調用了另一個類 TestLog4j2 ,下面看一下類 TestLog4j2 的代碼。
          4-b
          package?TestLog4j.TestLog4j2;
          import?org.apache.log4j.Logger;
          import?org.apache.log4j.PropertyConfigurator;
          import?org.apache.log4j.Priority;

          public?class?TestLog4j2?
          {
          static?Logger?logger?=?Logger.getLogger(TestLog4j2.class.getName());
            // 1
          public?TestLog4j2(){}

          public?void?testLog()
          {
          //
          同時輸出到控制臺和一個文件的實例
          PropertyConfigurator.configure("F:\\nepalon\\log4j2.properties");
          logger.debug("2Start?of?the?main()");
          logger.info("2Just?testing?a?log?message?with?priority?set?to?INFO");
          logger.warn("2Just?testing?a?log?message?with?priority?set?to?WARN");
          logger.error("2Just?testing?a?log?message?with?priority?set?to?ERROR");
          logger.fatal("2Just?testing?a?log?message?with?priority?set?to?FATAL");
          logger.log(Priority.DEBUG,?"Testing?a?log?message?use?a?alternate?form");
          logger.debug("2End?of?the?main()");
          }
          }
          最后我們來看一下配置文件。
          4-c
          log4j2.properties
          文件內容
          1
          ####?Use?two?appenders,?one?to?log?to?console,?another?to?log?to?a?file
          log4j.rootLogger?=?debug,?stdout

          #2

          #Print?only?messages?of?priority?WARN?or?higher?for?your?category
          log4j.logger.TestLog4j=?,?R
          log4j.logger.TestLog4j.TestLog4j2=WARN

          #3

          ####?First?appender?writes?to?console
          log4j.appender.stdout=org.apache.log4j.ConsoleAppender
          log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

          #?Pattern?to?output?the?caller's?file?name?and?line?number.
          log4j.appender.stdout.layout.ConversionPattern=%5p?[%t]?(%F:%L)?-?%m%n

          #4

          ####?Second?appender?writes?to?a?file
          log4j.appender.R=org.apache.log4j.RollingFileAppender
          log4j.appender.R.File=F:\\nepalon\\classes\\TestLog4j\\example.log

          #?Control?the?maximum?log?file?size

          log4j.appender.R.MaxFileSize=100KB
          #?Archive?log?files?(one?backup?file?here)
          log4j.appender.R.MaxBackupIndex=1

          log4j.appender.R.layout=org.apache.log4j.PatternLayout
          log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd?hh:mm:ss}:%p?%t?%c?-?%m%n
          先看一下運行結果。
          在控制臺中的結果為:
          DEBUG?[main]?(?:?)?-?Start?of?the?main()?in?TestLog4j
          INFO?[main]?(?:?)?-?Just?testing?a?log?message?with?priority?set?to?INFO
          WARN?[main]?(?:?)?-?Just?testing?a?log?message?with?priority?set?to?WARN
          ERROR?[main]?(?:?)?-?Just?testing?a?log?message?with?priority?set?to?ERROR
          FATAL?[main]?(?:?)?-?Just?testing?a?log?message?with?priority?set?to?FATAL
          WARN?[main]?(?:?)?-?Testing?a?log?message?use?a?alternate?form
          DEBUG?[main]?(?:?)?-?TestLog4j.TestLog4j
          WARN?[main]?(?:?)?-?2Just?testing?a?log?message?with?priority?set?to?WARN
          ERROR?[main]?(?:?)?-?2Just?testing?a?log?message?with?priority?set?to?ERROR
          FATAL?[main]?(?:?)?-?2Just?testing?a?log?message?with?priority?set?to?FATAL
          輸出文件的結果為:
          2003-12-19?04:19:44:DEBUG?main?TestLog4j.TestLog4j?-?Start?of?the?main()?in?TestLog4j
          2003-12-19?04:19:44:INFO?main?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?INFO
          2003-12-19?04:19:44:WARN?main?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?WARN
          2003-12-19?04:19:44:ERROR?main?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?ERROR
          2003-12-19?04:19:44:FATAL?main?TestLog4j.TestLog4j?-?Just?testing?a?log?message?with?priority?set?to?FATAL
          2003-12-19?04:19:44:WARN?main?TestLog4j.TestLog4j?-?Testing?a?log?message?use?a?alternate?form
          2003-12-19?04:19:44:DEBUG?main?TestLog4j.TestLog4j?-?TestLog4j.TestLog4j
          2003-12-19?04:19:44:WARN?main?TestLog4j.TestLog4j2.TestLog4j2?-?2Just?testing?a?log?message?with?priority?set?to?WARN
          2003-12-19?04:19:44:ERROR?main?TestLog4j.TestLog4j2.TestLog4j2?-?2Just?testing?a?log?message?with?priority?set?to?ERROR

          2003-12-19 ?04:19:44:FATAL?main?TestLog4j.TestLog4j2.TestLog4j2?-?2Just?testing?a?log?message?with?priority?set?to?FATAL

          首先,先來看一下配置文件都有些什么東西。
          1)?
          1 區中定義了一個根記錄器。這個根記錄器具有 DEBUG 級別并有一個名稱為 stdout 的輸出端 appender 。
          2)?2
          區中的內容是這一節的重點,也是應用到記錄器層次的地方,但其實也只有兩句,充分體現了 log4j 的簡單性。在這里,我們定義了兩個名稱分別為 TestLog4j TestLog4j.TestLog4j2設計 器。
          在定義 TestLog4j 記錄器時沒有指定級別,所以它的級別繼承自它的父記錄器,即要記錄器,所以它的級別也為 DEBUG 。在定義 TestLog4j 記錄器時又定義了一個名稱為 R 的輸出端,所以它的輸出端有兩個,一個從根記錄器繼承而來的名為 stdout 的輸出端,另一個為在此定義的名為 R 的輸出端。在此需要注意的是,在定義記錄器時必須先定義記錄器的級別,然后才是記錄器的輸出端。如果只想定義輸出端而不定義級別,則雖然級別可以為空,但逗號分隔符不能省略。如定義 TestLog4j 記錄器的做法。
          在定義 TestLog4j.TestLog4j2 記錄器時又指定了它的級別,由于一個記錄器的級別只能有一個,所以新指定的級別將覆寫掉它的父記錄器的級別(這就象 Java 中的多態)。我們沒有定義 TestLog4j.TestLog4j2 記錄器的輸出端,所以它的輸出端將從它的父記錄器中繼承而來。它的父記錄器為 estLog4j 記錄器,所以它和 estLog4j 記錄器一樣具有兩個名稱分別為 stdout R 的輸出端。
          3)?
          剩下的 3 區和 4 區分別設置了兩個輸出端的參數值。
          接下來,回到我們的代碼,看一下是如何取得記錄器,在取記錄器時又發生了什么。
          1)?
          4-a 中的代碼( 2 )中,語句 Logger.getLogger() 中的參數 TestLog4j.class.getName() 的值為 TestLog4j.?TestLog4j ,所以此語句的結果是取得一個名為 TestLog4j.?TestLog4j 的記錄器的對象。但在配置文件中并沒有定義這樣的記錄器,所以最終將返回與所需的名稱 TestLog4j.?TestLog4j 最接近的記錄器對象,即名為 TestLog4j 的記錄器的對象。
          2)?
          4-b 中的代碼( 1 )的原理與例 4-a 中的代碼( 2 )相似,期望取得的是名為 TestLog4j.TestLog4j2.?TestLog4j2 的記錄器對象,但最終返回的是 TestLog4j.TestLog4j2 記錄器的對象。

          log4j與J2EE的結合


          到目前為止,這篇文章講的都是如何在 application 中應用 log4j ,而 Java 現在的應用主流是 J2EE J2ME ?,F在,我們來看一下要如何在 J2EE 開發中應用 log4j 。其實在 Web?application 中應用 log4j 也很簡單,與在 application 中應用 log4j 不同之處就是要在所有應用 log4j 的代碼之前對 log4j 進行初始化。所以,我們在 web?application 中就要把 log4j 的初始化工作獨立出來,把它放在 Servlet 中。下面,我們看一個例子。
          5-a
          進行初始化的 Servlet
          import?org.apache.log4j.PropertyConfigurator;
          import?javax.servlet.http.HttpServlet;
          import?javax.servlet.http.HttpServletRequest;
          import?javax.servlet.http.HttpServletResponse;

          /**
          *?log4j.jar
          的初始化類,參考 web.xml
          */
          public?class?Log4jInit?extends?HttpServlet?
          {
          public?void?init()?
          {
          //
          通過 web.xml 來動態取得配置文件
          String?prefix?=?getServletContext().getRealPath("/");
          String?file?=?getInitParameter("log4j-init-file");

          //?
          如果沒有給出相應的配置文件,則不進行初始化
          if(file?!=?null)?
          {
          PropertyConfigurator.configure(prefix+file);
            // 1
          }
          }

          public?void?doGet(HttpServletRequest?req,?HttpServletResponse?res)?

          {}?
          }
          下面來看一下這個 Servlet web.xml 中的定義。
          5-b
          <servlet>
          <servlet-name>log4j-init</servlet-name>
          <servlet-class>TestLog4j.Log4jInit</servlet-class>
          <init-param>
          <param-name>log4j-init-file</param-name>
          <param-value>sort.properties</param-value>
          </init-param>
          <load-on-startup>1</load-on-startup>
          </servlet>
          因為 log4j 的初始化要在所有的 log4j 調用之前完成,所以在 web.xml 文件中,我們一定要把對應的 Servlet 定義的 load-on-startup 應設為 1 ,以便在 Web 容器啟動時即裝入該 Servlet 。
          完成了這兩個步驟這后,我們就可以象在 application 開發中一樣在 web?application 任何地方應用 log4j 了。下面是在 javabean 中的應用的一個例子。
          5-c
          import?org.apache.log4j.Logger;

          public?class?InfoForm?
          {
          static?Logger?logger?=?Logger.getLogger(InfoForm.class);

          protected?String?title;
          protected?String?content;

          public?InfoForm()?{}

          public?void?setTitle(Object?value)?
          {
          logger.debug("nepalon:title?=?"?+?title);
          title?=?value;
          }

          public?String?getTitle()?
          {
          logger.debug("nepalon:title?=?"?+?title);
          return?title;
          }

          public?void?setContent(String?value)?
          {
          content?=?value;
          logger.debug("nepalon:?content()?=?"?+?content);
          }

          public?String?getContent()?
          {
          logger.debug("nepalon:?content?=?\n"?+?content);
          return?content;
          }
          }

          posted on 2006-12-29 13:55 特蘭克斯 閱讀(315) 評論(0)  編輯  收藏 所屬分類: Log

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 西盟| 舞阳县| 鄂伦春自治旗| 陈巴尔虎旗| 丽江市| 崇明县| 榆社县| 平原县| 靖西县| 灵石县| 宜都市| 昆明市| 景谷| 玉树县| 湘西| 泰和县| 鄂州市| 平湖市| 阜宁县| 肃宁县| 辽中县| 大渡口区| 芦山县| 肥东县| 寻甸| 平武县| 天镇县| 荆州市| 于都县| 迭部县| 怀宁县| 石泉县| 辽阳县| 北流市| 土默特右旗| 阳泉市| 信阳市| 巧家县| 通海县| 哈巴河县| 常州市|