泰仔在線

          java學習,心情日記,繽紛時刻
          posts - 100, comments - 34, trackbacks - 0, articles - 0

          Log4Net使用指南

          Posted on 2008-02-19 20:16 泰仔在線 閱讀(313) 評論(0)  編輯  收藏 所屬分類: .NET相關

          Log4Net使用指南

          1           簡介

          1.1          Log4net的優(yōu)點:

          幾乎所有的大型應用都會有自己的用于跟蹤調(diào)試的API。因為一旦程序被部署以后,就不太可能再利用專門的調(diào)試工具了。然而一個管理員可能需要有一套強大的日志系統(tǒng)來診斷和修復配置上的問題。

          經(jīng)驗表明,日志記錄往往是軟件開發(fā)周期中的重要組成部分。它具有以下幾個優(yōu)點:它可以提供應用程序運行時的精確環(huán)境,可供開發(fā)人員盡快找到應用程序中的Bug;一旦在程序中加入了Log 輸出代碼,程序運行過程中就能生成并輸出日志信息而無需人工干預。另外,日志信息可以輸出到不同的地方(控制臺,文件等)以備以后研究之用。

          Log4net就是為這樣一個目的設計的,用于.NET開發(fā)環(huán)境的日志記錄包。

          1.2          Log4net的安裝:

          用戶可以從http://logging.apache.org/log4net/下載log4net的源代碼。解壓軟件包后,在解壓的src目錄下將log4net.sln載入Visual Studio .NET,編譯后可以得到log4net.dll。用戶要在自己的程序里加入日志功能,只需將log4net.dll引入工程即可。  

          2           Log4net的結構

          log4net 有四種主要的組件,分別是Logger(記錄器), Repository(庫), Appender(附著器)以及 Layout(布局).

          2.1          Logger

          2.1.1     Logger接口

          Logger是應用程序需要交互的主要組件,它用來產(chǎn)生日志消息。產(chǎn)生的日志消息并不直接顯示,還要預先經(jīng)過Layout的格式化處理后才會輸出。

          Logger提供了多種方式來記錄一個日志消息,你可以在你的應用程序里創(chuàng)建多個Logger,每個實例化的Logger對象都被log4net框架作為命名實體(named entity)來維護。這意味著為了重用Logger對象,你不必將它在不同的類或?qū)ο箝g傳遞,只需要用它的名字為參數(shù)調(diào)用就可以了。log4net框架使用繼承體系,繼承體系類似于.NET中的名字空間。也就是說,如果有兩個logger,分別被定義為a.b.c和a.b,那么我們說a.b是a.b.c的祖先。每一個logger都繼承了祖先的屬性

          Log4net框架定義了一個ILog接口,所有的logger類都必須實現(xiàn)這個接口。如果你想實現(xiàn)一個自定義的logger,你必須首先實現(xiàn)這個接口。你可以參考在/extension目錄下的幾個例子。

          ILog接口的定義如下:

          public interface ILog

          {

            void Debug(object message);

            void Info(object message);

            void Warn(object message);

            void Error(object message);

            void Fatal(object message);

           

          //以上的每一個方法都有一個重載的方法,用來支持異常處理。

          //每一個重載方法都如下所示,有一個異常類型的附加參數(shù)。

            void Debug(object message, Exception ex);

            // ...

           

          //Boolean 屬性用來檢查Logger的日志級別

          //(我們馬上會在后面看到日志級別)

            bool isDebugEnabled;

            bool isInfoEnabled;

            //… 其他方法對應的Boolean屬性

          }

          Log4net框架定義了一個叫做LogManager的類,用來管理所有的logger對象。它有一個GetLogger()靜態(tài)方法,用我們提供的名字參數(shù)來檢索已經(jīng)存在的Logger對象。如果框架里不存在該Logger對象,它也會為我們創(chuàng)建一個Logger對象。代碼如下所示:

          log4net.ILog log = log4net.LogManager.GetLogger("logger-name");

          通常來說,我們會以類(class)的類型(type)為參數(shù)來調(diào)用GetLogger(),以便跟蹤我們正在進行日志記錄的類。傳遞的類(class)的類型(type)可以用typeof(Classname)方法來獲得,或者可以用如下的反射方法來獲得:

          System.Reflection.MethodBase.GetCurrentMethod().DeclaringType

          盡管符號長了一些,但是后者可以用于一些場合,比如獲取調(diào)用方法的類(class)的類型(type)。

          2.1.2     日志的級別

          正如你在ILog的接口中看到的一樣,有五種不同的方法可以跟蹤一個應用程序。事實上,這五種方法是運作在Logger對象設置的不同日志優(yōu)先級別上。這幾種不同的級別是作為常量定義在log4net.spi.Level類中。你可以在程序中使用任何一種方法。但是在最后的發(fā)布中你也許不想讓所有的代碼來浪費你的CPU周期,因此,框架提供了7種級別和相應的Boolean屬性來控制日志記錄的類型。

           

           

          Level有以下幾種取值

          級別
           允許的方法
           Boolean屬性
           優(yōu)先級別
           
          OFF
            
            
           Highest
           
          FATAL
           void Fatal(...);
           bool IsFatalEnabled;
            
           
          RROR
           void Error(...);
           bool IsErrorEnabled;
            
           
          WARN
           void Warn(...);
           bool IsWarnEnabled;
            
           
          INFO
           void Info(...);
           bool IsInfoEnabled;
            
           
          DEBUG
           void Debug(...);
           bool IsDebugEnabled;
            
           
          ALL
            
            
           Lowest
           

          表1  Logger的日志級別

          在log4net框架里,通過設置配置文件,每個日志對象都被分配了一個日志優(yōu)先級別。如果沒有給一個日志對象顯式地分配一個級別,那么該對象會試圖從他的祖先繼承一個級別值。

          ILog接口的每個方法都有一個預先定義好了的級別值。正如你在表1看到的,ILog的Inof()方法具有INFO級別。同樣的,以此類推,Error()方法具有ERROR級別。當我們使用以上的任何一種方法時,log4net框架會檢查日志對象logger的級別和方法的級別。只有當方法的級別高于日志級別時,日志請求才會被接受并執(zhí)行。

          舉例說明,當你創(chuàng)建了一個日志對象,并且把他的級別設置為INFO。于是框架會設置日志的每個Boolean屬性。當你調(diào)用相應的日志方法時,框架會檢查相應的Boolean屬性,以決定該方法能不能執(zhí)行。如下的代碼:

           

          Logger.Info("message");

          Logger.Debug("message");

          Logger.Warn("message");

          對于第一種方法,Info()的級別等與日志的級別(INFO),因此日志請求會被傳遞,我們可以得到輸出結果”message”。

          對于第二種方法,Debug()的級別低于日志對象logger的日志級別(INFO),因此,日志請求被拒絕了,我們得不到任何輸出。同樣的,針對第三行語句,我們可以很容易得出結論。

          在表1中有兩個特殊的級別:ALL和OFF。ALL表示允許所有的日志請求。OFF是拒絕所有的請求。

          你也可以顯式地檢查Logger對象的Boolean屬性,如下所示:

          if (logger.IsDebugEnabled)

          {

            Logger.Debug("message");

          }

           

          2.2          Repository

          Repository主要用于負責日志對象組織結構的維護。在log4net的以前版本中,框架僅支持分等級的組織結構(hierarchical organization)。這種等級結構本質(zhì)上是庫的一個實現(xiàn),并且定義在log4net.Repository.Hierarchy 名字空間中。要實現(xiàn)一個Repository,需要實現(xiàn)log4net.Repository.ILoggerRepository 接口。但是通常并不是直接實現(xiàn)該接口,而是以log4net.Repository.LoggerRepositorySkeleton為基類繼承。體系庫 (hierarchical repository )則由log4net.Repository.Hierarchy.Hierarchy類實現(xiàn)。

          如果你是個log4net框架的使用者,而非擴展者,那么你幾乎不會在你的代碼里用到Repository的類。相反的,你需要用到LogManager類來自動管理庫和日志對象。

          2.3          Appender

          一個好的日志框架應該能夠產(chǎn)生多目的地的輸出。比如說輸出到控制臺或保存到一個日志文件。log4net 能夠很好的滿足這些要求。它使用一個叫做Appender的組件來定義輸出介質(zhì)。正如名字所示,這些組件把它們附加到Logger日志組件上并將輸出傳遞到輸出流中。你可以把多個Appender組件附加到一個日志對象上。 Log4net框架提供了幾個Appender組件。關于log4net提供的Appender組件的完整列表可以在log4net框架的幫助手冊中找到。有了這些現(xiàn)成的Appender組件,一般來說你沒有必要再自己編寫了。但是如果你愿意,可以從log4net.Appender.AppenderSkeleton類繼承。

          2.4          Appender Filters

          一個Appender 對象缺省地將所有的日志事件傳遞到輸出流。Appender的過濾器(Appender Filters) 可以按照不同的標準過濾日志事件。在log4net.Filter的名字空間下已經(jīng)有幾個預定義的過濾器。使用這些過濾器,你可以按照日志級別范圍過濾日志事件,或者按照某個特殊的字符串進行過濾。你可以在API的幫助文件中發(fā)現(xiàn)更多關于過濾器的信息。

          2.5          Layout

          Layout 組件用于向用戶顯示最后經(jīng)過格式化的輸出信息。輸出信息可以以多種格式顯示,主要依賴于我們采用的Layout組件類型。可以是線性的或一個XML文件。Layout組件和一個Appender組件一起工作。API幫助手冊中有關于不同Layout組件的列表。一個Appender對象,只能對應一個Layout對象。要實現(xiàn)你自己的Layout類,你需要從log4net.Layout.LayoutSkeleton類繼承,它實現(xiàn)了ILayout接口。

           

           

          3           在程序中使用log4net

          在開始對你的程序進行日志記錄前,需要先啟動log4net引擎。這意味著你需要先配置前面提到的三種組件。你可以用兩種方法來設定配置:在單獨的文件中設定配置或在代碼中定義配置。

          因為下面幾種原因,推薦在一個單獨的文件中定義配置:

          l         你不需要重新編譯源代碼就能改變配置;

          l         你可以在程序正運行的時候就改變配置。這一點在一些WEB程序和遠程過程調(diào)用的程序中有時很重要;

          考慮到第一種方法的重要性,我們先看看怎樣在文件中設定配置信息。

          3.1          定義配置文件

          配置信息可以放在如下幾種形式文件的一種中。

          在程序的配置文件里,如AssemblyName.config 或web.config.

          在你自己的文件里。文件名可以是任何你想要的名字,如AppName.exe.xyz等.

          log4net框架會在相對于AppDomain.CurrentDomain.BaseDirectory 屬性定義的目錄路徑下查找配置文件。框架在配置文件里要查找的唯一標識是<log4net>標簽。一個完整的配置文件的例子如下:

           

          <?xml version="1.0" encoding="utf-8" ?>

          <configuration>

            <configSections>

              <section name="log4net"

                type="log4net.Config.Log4NetConfigurationSectionHandler,

                      log4net-net-1.0"

              />

            </configSections>

           

            <log4net>

           

              <root>

                <level value="WARN" />

                <appender-ref ref="LogFileAppender" />

                <appender-ref ref="ConsoleAppender" />

              </root>

           

              <logger name="testApp.Logging">

                <level value="DEBUG"/>

              </logger>

             

              <appender name="LogFileAppender"

                       type="log4net.Appender.FileAppender" >

                <param name="File" value="log-file.txt" />

                <param name="AppendToFile" value="true" />

           

                <layout type="log4net.Layout.PatternLayout">

                  <param name="Header" value="[Header]\r\n"/>

                  <param name="Footer" value="[Footer]\r\n"/>

                  <param name="ConversionPattern"

                     value="%d [%t] %-5p %c [%x]  - %m%n"

                   />

                </layout>

           

                <filter type="log4net.Filter.LevelRangeFilter">

                  <param name="LevelMin" value="DEBUG" />

                  <param name="LevelMax" value="WARN" />

                </filter>

              </appender>

             

              <appender name="ConsoleAppender"

                        type="log4net.Appender.ConsoleAppender" >

                <layout type="log4net.Layout.PatternLayout">

                  <param name="ConversionPattern"  value="%d [%t] %-5p %c [%x] - %m%n"

                  />

                </layout>

              </appender>

             

            </log4net>

          </configuration>

          你可以直接將上面的文本拷貝到任何程序中使用,但是最好還是能夠理解配置文件是怎樣構成的。 只有當你需要在應用程序配置文件中使用log4net配置時,才需要在<configSection>標簽中加入<section>配置節(jié)點入口。對于其他的單獨文件,只有<log4net>標簽內(nèi)的文本才是必需的,這些標簽的順序并不是固定的。下面我們依次講解各個標簽內(nèi)文本的含義:

          3.1.1     <root>

          <root>

            <level value="WARN" />

            <appender-ref ref="LogFileAppender" />

            <appender-ref ref="ConsoleAppender" />

          </root>

           

          在框架的體系里,所有的日志對象都是根日志(root logger)的后代。 因此如果一個日志對象沒有在配置文件里顯式定義,則框架使用根日志中定義的屬性。在<root>標簽里,可以定義level級別值和Appender的列表。如果沒有定義LEVEL的值,則缺省為DEBUG。可以通過<appender-ref>標簽定義日志對象使用的Appender對象。<appender-ref>聲明了在其他地方定義的Appender對象的一個引用。在一個logger對象中的設置會覆蓋根日志的設置。而對Appender屬性來說,子日志對象則會繼承父日志對象的Appender列表。這種缺省的行為方式也可以通過顯式地設定<logger>標簽的additivity屬性為false而改變。

          <logger name="testApp.Logging" additivity="false">

          </logger>

          Additivity的值缺省是true.

           

           

          3.1.2     <Logger>

          <logger name="testApp.Logging">

            <level value="DEBUG"/>

          </logger>

           

          <logger> 元素預定義了一個具體日志對象的設置。然后通過調(diào)用LogManager.GetLogger(“testAPP.Logging”)函數(shù),你可以檢索具有該名字的日志。如果LogManager.GetLogger(…)打開的不是預定義的日志對象,則該日志對象會繼承根日志對象的屬性。知道了這一點,我們可以說,其實<logger>標簽并不是必須的。

           

           

          3.1.3     <appender>

           

          <appender name="LogFileAppender"

                    type="log4net.Appender.FileAppender" >

            <param name="File" value="log-file.txt" />

            <param name="AppendToFile" value="true" />

            <layout type="log4net.Layout.PatternLayout">

              <param name="Header" value="[Header]\r\n" />

              <param name="Footer" value="[Footer]\r\n"/>

              <param name="ConversionPattern"

                value="%d [%t] %-5p %c - %m%n"

              />

            </layout>

            <filter type="log4net.Filter.LevelRangeFilter">

              <param name="LevelMin" value="DEBUG" />

              <param name="LevelMax" value="WARN" />

            </filter>

          </appender>

           

          在<root>標簽或單個的<logger>標簽里的Appender對象可以用<appender>標簽定義。<appender>標簽的基本形式如上面所示。它定義了appender的名字和類型。 另外比較重要的是<appender>標簽內(nèi)部的其他標簽。不同的appender有不同的<param>標簽。在這里,為了使用FileAppender,你需要一個文件名作為參數(shù)。另外還需要一個在<appender>標簽內(nèi)部定義一個Layout對象。Layout對象定義在它自己的<layout>標簽內(nèi)。<layout>標簽的type屬性定義了Layout的類型(在本例里是PatternLayout),同時也確定了需要提供的參數(shù)值。Header和Footer標簽提供了一個日志會話(logging session)開始和結束時輸出的文字。有關每種appender的具體配置的例子,可以在log4net\doc\manual\example-config-appender.html中得到。

           

          3.1.4     log4net.Layout.PatternLayout中的轉換模式(ConversionPattern)

          %m(message):輸出的日志消息,如ILog.Debug(…)輸出的一條消息

          %n(new line):換行

          %d(datetime):輸出當前語句運行的時刻

          %r(run time):輸出程序從運行到執(zhí)行到當前語句時消耗的毫秒數(shù)

          %t(thread id):當前語句所在的線程ID

          %p(priority): 日志的當前優(yōu)先級別,即DEBUG、INFO、WARN…等

          %c(class):當前日志對象的名稱,例如:

                 模式字符串為:%-10c -%m%n

                 代碼為:

          ILog log=LogManager.GetLogger(“Exam.Log”);

          log.Debug(“Hello”);

              則輸出為下面的形式:

          Exam.Log       - Hello

          %L:輸出語句所在的行號

          %F:輸出語句所在的文件名

          %-數(shù)字:表示該項的最小長度,如果不夠,則用空格填充

          例如,轉換模式為%r [%t]%-5p %c - %m%n 的 PatternLayout 將生成類似于以下內(nèi)容的輸出:

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

           

          3.1.5     <filter>

          最后,讓我們看看在Appender元素里的<filter>標簽。它定義了應用到Appender對象的過濾器。本例中,我們使用了LevelRangeFilter過濾器,它可以只記錄LevelMin和LevelMax參數(shù)指定的日志級別之間的日志事件。可以在一個Appender上定義多個過濾器(Filter),這些過濾器將會按照它們定義的順序?qū)θ罩臼录M行過濾。其他過濾器的有關信息可以在log4net的SDK文檔中找到。

           

          3.2          使用配置文件

          3.2.1     關聯(lián)配置文件

          當我們創(chuàng)建了上面的配置文件后,我們接下來需要把它和我們的應用聯(lián)系起來。缺省的,每個獨立的可執(zhí)行程序集都會定義它自己的配置。log4net框架使用 log4net.Config.DOMConfiguratorAttribute在程序集的級別上定義配置文件。


          例如:可以在項目的AssemblyInfo.cs文件里添加以下的語句

          [assembly:log4net.Config.DOMConfigurator(ConfigFile="filename",

            ConfigFileExtension="ext",Watch=true/false)]

          l         ConfigFile:指出了我們的配置文件的路徑及文件名,包括擴展名。

          l         ConfigFileExtension:如果我們對被編譯程序的程序集使用了不同的文件擴展名,那么我們需要定義這個屬性,缺省的,程序集的配置文件擴展名為”config”。

          l         Watch (Boolean屬性): log4net框架用這個屬性來確定是否需要在運行時監(jiān)視文件的改變。如果這個屬性為true,那么FileSystemWatcher將會被用來監(jiān)視文件的改變,重命名,刪除等事件。

          其中:ConfigFile和ConfigFileExtension屬性不能同時使用,ConfigFile指出了配置文件的名字,例如,ConfigFile=”Config.txt”

          ConfigFileExtension則是指明了和可執(zhí)行程序集同名的配置文件的擴展名,例如,應用程序的名稱是”test.exe”,ConfigFileExtension=”txt”,則配置文件就應該是”test.exe.txt” ;

          也可以不帶參數(shù)應用DOMConfiguratio():

           [assembly: log4net.Config.DOMConfigurator()]

          也可以在程序代碼中用DOMConfigurator類打開配置文件。類的構造函數(shù)需要一個FileInfo對象作參數(shù),以指出要打開的配置文件名。 這個方法和前面在程序集里設置屬性打開一個配置文件的效果是一樣的。

          log4net.Config.DOMConfigurator.Configure(

            new FileInfo("TestLogger.Exe.Config"));

          DOMConfigurator 類還有一個方法ConfigureAndWatch(..), 用來配置框架并檢測文件的變化。

          以上的步驟總結了和配置相關的各個方面,下面我們將分兩步來使用logger對象。

          3.2.2     創(chuàng)建或獲取日志對象

          日志對象會使用在配置文件里定義的屬性。如果某個日志對象沒有事先在配置文件里定義,那么框架會根據(jù)繼承結構獲取祖先節(jié)點的屬性,最終的,會從根日志獲取屬性。如下所示:

          Log4net.ILog log = Log4net.LogManager.GetLogger("MyLogger");

          3.2.3     輸出日志信息

          可以使用ILog的幾種方法輸出日志信息。你也可以在調(diào)用某方法前先檢查IsXXXEnabled布爾變量,再決定是否調(diào)用輸出日志信息的函數(shù),這樣可以提高程序的性能。因為框架在調(diào)用如ILog.Debug(…)這樣的函數(shù)時,也會先判斷是否滿足Level日志級別條件。

          if (log.IsDebugEnabled) log.Debug("message");

          if (log.IsInfoEnabled) log.Info("message);

           

          3.3          在程序中配置log4net

          除了前面講的用一個配置文件來配置log4net以外,還可以在程序中用代碼來配置log4net框架。如下面的例子:

           

          // 和PatternLayout一起使用FileAppender

          log4net.Config.BasicConfigurator.Configure(

            new log4net.Appender.FileAppender(

               new log4net.Layout.PatternLayout("%d

                 [%t]%-5p %c [%x] - %m%n"),"testfile.log"));

           

          // using a FileAppender with an XMLLayout

          log4net.Config.BasicConfigurator.Configure(

            new log4net.Appender.FileAppender(

              new log4net.Layout.XMLLayout(),"testfile.xml"));

           

          // using a ConsoleAppender with a PatternLayout

          log4net.Config.BasicConfigurator.Configure(

            new log4net.Appender.ConsoleAppender(

              new log4net.Layout.PatternLayout("%d

                [%t] %-5p %c - %m%n")));

           

          // using a ConsoleAppender with a SimpleLayout

          log4net.Config.BasicConfigurator.Configure(

            new log4net.Appender.ConsoleAppender(new

              log4net.Layout.SimpleLayout()));

          盡管這里用代碼配置log4net也很方便,但是你卻不能分別配置每個日志對象。所有的這些配置都是被應用到根日志上的。

          log4net.Config.BasicConfigurator 類使用靜態(tài)方法Configure 設置一個Appender 對象。而Appender的構造函數(shù)又會相應的要求Layout對象。你也可以不帶參數(shù)直接調(diào)用BasicConfigurator.Configure(),它會使用一個缺省的PatternLayout對象,在一個ConsoleAppender中輸出信息。如下所示:

           

          log4net.Config.BasicConfigurator.Configure();

          在輸出時會顯示如下格式的信息:

           

          0 [1688] DEBUG log1 A B C - Test

          20 [1688] INFO log1 A B C - Test

          當log4net框架被配置好以后,就可以如前所述使用日志功能了。

          主站蜘蛛池模板: 郴州市| 镇安县| 封丘县| 和硕县| 宿松县| 五家渠市| 成都市| 大埔县| 望都县| 上虞市| 泸溪县| 延安市| 通化县| 错那县| 东安县| 华阴市| 昌平区| 琼结县| 东阿县| 福清市| 故城县| 沙湾县| 金堂县| 滁州市| 疏勒县| 扶绥县| 涪陵区| 新平| 康马县| 朝阳县| 永胜县| 元朗区| 龙游县| 清镇市| 富裕县| 梅河口市| 沅陵县| 龙州县| 马尔康县| 策勒县| 宁陕县|