Enterprise Library 2.0 中的 Logging Application Block 在1.0版本中是Logging and Instrumentation Application Block,因為把重點放在了日志記錄上,所以改名為Logging Application Block。Logging Application Block提供了統一的日志記錄功能,它支持將日志寫入到多種目的地中,比如:1、數據庫;2、文本文件;3、Email;4、消息隊列;5、WMI event;6、事件日志;7、自定義區域(For Example:XML File)等等。
?? Logging Application Block 提供了統一的接口用于將日志寫入到任何指定的目的地,我們不需要在代碼中指定日志信息該寫到什么地方,而是在配置文件中設定我們什么情況
下寫日志以及將日志信息寫到什么地方,這也就意味著操作員可以和我們開發人員一樣不通過修改代碼來改變日志記錄行為。它對于我們程序開發有以下幾點好處:
1、可以使我們的應用程序中的日志記錄方法保持一致;
2、正是因為它提供一致的結構模型,很大程度上方便了我們開發人員對其的學習;
3、很好的解決了應用程序中的日志問題;
4、可擴展,我們可以自定義日志信息的過濾程序以及格式化日志信息的程序
... ...
?? 相對于上一個版本,Logging Application Block 2.0作出了下列改變:
1、LogEntry對象現在可以屬于一個或多個類別(category);
2、2.0版本中我們可以自定義過濾器,在Logging Application Block 將日志信息發送給監聽器(trace listeners)之前就將該信息過濾掉,過濾器支持我們根據事件的類別和(或)優先級來過濾事件,我們可以定制符合自己需要的標準的過濾器來過濾事件;
3、你可以在代碼中通過查詢過濾器來判斷當前事件是否需要被記錄日志,這樣就大大減少了我們日志記錄量,可以有效的提高應用程序的性能。
?? 下面我們就來說一下Logging Application Block的使用方法,首先需要添加對下面三個程序集的引用:
using?Microsoft.Practices.EnterpriseLibrary.Logging;
using?Microsoft.Practices.EnterpriseLibrary.Logging.ExtraInformation;
using?Microsoft.Practices.EnterpriseLibrary.Logging.Filters;

?????? 和前面幾個Block一樣,在使用之前還是先說一下配置方法,首先用配置工具代開我們程序的App.Config/Web.Config,然后選中Application右鍵,New-->Logging Application Block,如下圖:

這時你會發現,在新建的Logging Application Block節點下自動出現了Filters,Category Source,Special Source,Trace Listeners,Formatters這樣的幾個節點,如下:

????? 我下面按照我配置的順序來說一下每個節點的作用,首先是Formatters,它用于指定日志信息的格式,如下圖,我們在Formatters節點下創建一個Text Formatter,如下:

然后我們可以編輯它的模板,編輯我們要顯示的信息,如下:

我們還可以配置Binary Formatter和自定義的Formatter ,這里不在多說了。
?????? Formatter配置好了以后,我們就可以來配置Trace Listeners了,Enterprise Library 2.0 提供了七種Trace Listeners,分別用于將日志信息記錄到特定的目的地中,下面我們就來配置一個Flat File Trace Listener ,如下:

??????? 使用Flat File Trace Listener后,記錄的日志信息就輸出到指定的文本文件中,所以我們要指定輸出的文本文件的路徑,默認在Bin/Debug目錄下;同時我們需指定該Listener的Formatter,Name等屬性。如果我們配置的是一個DataBase Listener,我們則要在數據庫中建立相應的表,并創建一個用于插入日志信息的存儲過程。

Trace Listeners 配置好之后就可以開始配置Category Source,我們新建一個Category Source,命名為General,指定其SourceLevel為All,如下:

之后,我們可以對剛添加的Category Source添加一個或多個Trace Listener,本文中,我們將上面配置的SHY52O Formatter加進來,

???????? 如上圖,在RefrenceTraceListener中選擇SHY520 Listeners就可以了。
???????? 最后我們來看一下如何配置過濾器(Filters),Enterprise Library 2.0 中提供了三種默認的Filters,分別是:Category Filter ,Log Enable Filter和Priority Filter,我們以Category Filter為例來配置:

然后可以修改過濾器名稱和過濾規則:

這里面我們可以選擇過濾的模式,過濾模式有兩種:
1、Allow All Categories Except those explicitly denied below
2、Deny All Categories Except those explicitly allowed below
根據我們需要選擇好過濾模式,然后添加需要過濾的類別,點擊OK按鈕即可完成Category Filter的配置。
??????? 關于Logging Application Block 的介紹和配置部分就說到這里,下一篇我們在來介紹Logging Application Block的使用方法以及自定義Formatter和Listener的方法。
上一篇中我們介紹了如何去配置Logging Application Block,本文將主要介紹Logging Application Block 的基本操作以及Formatter和Trace Listeners 的自定義方法,首先我們來看如何將一個事件日志寫入到一個文本文件中。
??? 假設我們按照上一篇的操作配置了Logging Application Block,那么配置文件中的信息如下:
??<loggingConfiguration?name="Logging?Application?Block"?tracingEnabled="true"
????defaultCategory="General"?logWarningsWhenNoCategoriesMatch="true">
????<listeners>
??????<add?fileName="trace.log"?header="----------------------------------------"
????????footer="----------------------------------------"?formatter="SHY520?Formatter"
????????listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData,?

Microsoft.Practices.EnterpriseLibrary.Logging,?Version=2.0.0.0,?Culture=neutral,?PublicKeyToken=null"
????????traceOutputOptions="None"?type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener,?

Microsoft.Practices.EnterpriseLibrary.Logging,?Version=2.0.0.0,?Culture=neutral,?PublicKeyToken=null"
????????name="SHY520?Listeners"?/>
??????<add?source="Enterprise?Library?Logging"?formatter="Text?Formatter"
????????log="Application"?machineName=""?listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData,?

Microsoft.Practices.EnterpriseLibrary.Logging,?Version=2.0.0.0,?Culture=neutral,?PublicKeyToken=null"
????????traceOutputOptions="None"?type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener,?

Microsoft.Practices.EnterpriseLibrary.Logging,?Version=2.0.0.0,?Culture=neutral,?PublicKeyToken=null"
????????name="Formatted?EventLog?TraceListener"?/>
????</listeners>
????<formatters>
??????<add?template="Timestamp:?{timestamp} Message:?{message} Category:?{category} Priority:?{priority} EventId:?

{eventid} Severity:?{severity} Title:{title} Machine:?{machine} Application?Domain:?{appDomain} Process?Id:?

{processId} Process?Name:?{processName} Win32?Thread?Id:?{win32ThreadId} Thread?Name:?{threadName} Extended?Properties:?

{dictionary({key}?-?{value} )}"
????????type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter,?Microsoft.Practices.EnterpriseLibrary.Logging,?Version=2.0.0.0,?

Culture=neutral,?PublicKeyToken=null"
????????name="Text?Formatter"?/>
??????<add?template="Timestamp:?{timestamp} Message:?{message} Category:?{category} Priority:?{priority} EventId:?

{eventid} Severity:?{severity} Title:{title} Machine:?{machine} Application?Domain:?{appDomain} Process?Id:?

{processId} Process?Name:?{processName} Win32?Thread?Id:?{win32ThreadId} Thread?Name:?{threadName} Extended?Properties:?

{dictionary({key}?-?{value} )}"
????????type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter,?Microsoft.Practices.EnterpriseLibrary.Logging,?Version=2.0.0.0,?

Culture=neutral,?PublicKeyToken=null"
????????name="SHY520?Formatter"?/>
????</formatters>
????<logFilters>
??????<add?categoryFilterMode="AllowAllExceptDenied"?type="Microsoft.Practices.EnterpriseLibrary.Logging.Filters.CategoryFilter,?

Microsoft.Practices.EnterpriseLibrary.Logging,?Version=2.0.0.0,?Culture=neutral,?PublicKeyToken=null"
????????name="Category?Filter"?/>
????</logFilters>
????<categorySources>
??????<add?switchValue="All"?name="General">
????????<listeners>
??????????<add?name="SHY520?Listeners"?/>
????????</listeners>
??????</add>
????</categorySources>
????<specialSources>
??????<allEvents?switchValue="All"?name="All?Events"?/>
??????<notProcessed?switchValue="All"?name="Unprocessed?Category"?/>
??????<errors?switchValue="All"?name="Logging?Errors?&?Warnings">
????????<listeners>
??????????<add?name="Formatted?EventLog?TraceListener"?/>
????????</listeners>
??????</errors>
????</specialSources>
??</loggingConfiguration>
下面我們來看如何將日志寫入到文本文件:
????????[TestMethod]
????????public?void?DoLog()

????????
{
????????????//創建一個日志條目
????????????LogEntry?log?=?new?LogEntry();
????????????//指定該日志所屬類別
????????????log.Categories.Add("General");
????????????//日志標題
????????????log.Title?=?"SHY520's?Tests";
????????????log.Message?=?"there?is?log?information";
????????????//優先級
????????????log.Priority?=?0;

????????????Logger.Write(log);
????????}
????? 上面的代碼中,我們為該日志指定所屬類別為General,在配置文件中我們可以看到General這個類別使用的Trace Listener是SHY520 Listeners,SHY520 Listeners是一個Flat File Trace Listener,它指定了我們的日志信息輸出的地方(trace.log),我用的測試項目,運行測試后,該文件在TestResult/out目錄中,如果是一般的Web項目或Consle項目,該文件則在Bin/Debug目錄下,下面我們來看一下輸出的日志信息:

上圖中,我們可以看到我們在程序中記錄的一些日志信息,我們還可以記錄一些額外的信息,這些信息是鍵值對應的,在1.0版本中我們用Hashtable,這里我們用的是一個泛型的Dictionary類型,代碼如下:
????????[TestMethod]
????????public?void?LoggEntry()

????????
{
????????????LogEntry?log?=?new?LogEntry();
????????????//事件ID
????????????log.EventId?=?2000;
????????????//日志優先級
????????????log.Priority?=?2;
????????????log.Message?=?"Test?LogEntry?2";

????????????//日志類別
????????????ICollection<string>?coll?=?new?List<string>();
????????????coll.Add("General");
????????????log.Categories?=?coll;

????????????//添加額外信息
????????????Dictionary<string,?object>?dic?=?new?Dictionary<string,?object>();
????????????dic.Add("name",?"SHY520");
????????????dic.Add("sex","男");
????????????dic.Add("age",?"22");

????????????log.ExtendedProperties?=?dic;
????????????//寫入日志
????????????Logger.Write(log);
????????}
然后運行測試,在TestResult/Out目錄下的trace.log文件中就能看到我們在程序中添加的額外信息了。

下面我們來介紹一下過濾器的用法:
實現方法很簡單,這里我們假設我們已經按照上一篇文章中的方法配置好了一個Category Filter,在Category Filter中我們可以設置要過濾掉哪種類別的事件日志,具體實現方式有兩種,如下:
方法一:
????????[TestMethod]
????????public?void?TestFilter1()

????????
{
????????????LogEntry?logEntry?=?new?LogEntry();
????????????logEntry.Priority?=?2;
????????????logEntry.Categories.Add("General");

????????????//ShouldLog()方法根據Filter配置返回是否需要記錄日志
????????????if?(Logger.GetFilter<CategoryFilter>().ShouldLog(logEntry.Categories))

????????????
{
????????????????//TODO:記錄日志
????????????????Logger.Write(logEntry);
????????????}
????????}
方法二:
????????[TestMethod]
????????public?void?TestFilter2()

????????
{
????????????LogEntry?logEntry?=?new?LogEntry();
????????????logEntry.Priority?=?2;
????????????logEntry.Categories.Add("General");

????????????if?(Logger.ShouldLog(logEntry))

????????????
{
????????????????Logger.Write(logEntry);
????????????}
????????}
??????? 關于事件日志的過濾就說到這里,下面我們來看看如何創建一個自定義的Trace Listener,首先我們新建一個類(MyListener),并且繼承與CustomTraceListener,同時不要忘了在為這個新建的類加上[ConfigurationElementType(typeof(CustomTraceListenerData))]的Attribute,最后重寫基類的三個方法,在每個方法中加入自己需要的邏輯既可。完整的類的代碼如下:
using?System;
using?System.Collections.Generic;
using?System.Text;
using?Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using?Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
using?Microsoft.Practices.EnterpriseLibrary.Logging;
using?Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;

namespace?Enterprise_Library_2


{
????[ConfigurationElementType(typeof(CustomTraceListenerData))]
????public?class?MyListener?:?CustomTraceListener

????
{
????????public?override?void??TraceData(System.Diagnostics.TraceEventCache?eventCache,?string?source,?System.Diagnostics.TraceEventType?eventType,?int?id,?

object?data)

????????
{
????????????if?(data?is?LogEntry?&&?this.Formatter?!=?null)

????????????
{
????????????????this.WriteLine(this.Formatter.Format(data?as?LogEntry));
????????????}
????????????else

????????????
{
????????????????this.WriteLine(data.ToString());
????????????}
????????}


????????public?override?void?Write(string?message)

????????
{
????????????//TODO:添加自己所需的邏輯
????????}

????????public?override?void?WriteLine(string?message)

????????
{
????????????//TODO:添加自己所需的邏輯
????????}
????}
}
然后我們在配置Trace Listener的時候選擇Custom Trace Listener就可以了。
接下來我們來看看如何自定義Formatter,實現的方法和上面類似,首先新建一個類MyFormatter,繼承ILogFormatter接口,同時加上[ConfigurationElementType(typeof(CustomFormatterData))]的Attribute,完整的代碼如下:
using?System;
using?System.Collections.Generic;
using?System.Text;
using?System.Collections.Specialized;
using?Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using?Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
using?Microsoft.Practices.EnterpriseLibrary.Logging;
using?Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;

namespace?Enterprise_Library_2


{
????[ConfigurationElementType(typeof(CustomFormatterData))]
????public?class?MyFormatter?:?ILogFormatter????

????
{
????????public?MyFormatter(NameValueCollection?nv)

????????
{
????????????//注意:構造函數的參數必須是NameValueCollection類型的
????????}

????????public?string?Format(LogEntry?log)

????????
{
????????????string?result?=?string.Empty;

????????????//TODO:此處添加我們個性化的Formatter邏輯

????????????return?result;
????????}
????}
}
到這里,關于Logging Application Block的有關問題已經都簡單的介紹了一下,有遺漏錯誤的地方,請指正,謝謝!
希望對初學者有所幫助,同時也歡迎Enterprise Library學習者一起共同交流經驗。
凡是有該標志的文章,都是該blog博主Caoer(草兒)原創,凡是索引、收藏
、轉載請注明來處和原文作者。非常感謝。