一、概述
log4net是.Net下一個很是優秀的開源日誌記錄組件。log4net記錄日誌的功能很是強大。它能夠將日誌分不一樣的等級,以不一樣的格式,輸出到不一樣的媒介。本文主要是介紹如何在Visual Studio2008中使用log4net快速建立系統日誌,如何擴展以輸出自定義字段。數據庫
二、一個簡單的使用實例
第一步:在項目中添加對log4net.dll的引用,這裏引用版本是1.2.10.0。express
第二步:程序啓動時讀取log4net的配置文件。apache
若是是CS程序,在根目錄的Program.cs中的Main方法中添加:瀏覽器
log4net.Config.XmlConfigurator.Configure();緩存
若是是BS程序,在根目錄的Global.asax.cs(沒有新建一個)中的Application_Start方法中添加:安全
log4net.Config.XmlConfigurator.Configure();網絡
不管BS仍是CS程序均可直接在項目的AssemblyInfo.cs文件裏添加如下的語句:多線程
[assembly: log4net.Config .XmlConfigurator()]app
也可使用自定義的配置文件,具體請參見4.4 關聯配置文件。
第三步:修改配置文件。若是是CS程序,則在默認的App.config文件(沒有新建一個)中添加內容;若是是BS程序,則添加到Web.config文件中,添加內容同樣,這裏再也不列出。
App.config文件添加內容以下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</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] "/>
<param name="Footer" value="[Footer] "/>
<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.ILog log = log4net.LogManager.GetLogger("testApp.Logging");//獲取一個日誌記錄器
log.Info(DateTime.Now.ToString() + ": login success");//寫入一條新log
這樣就將信息同時輸出到控制檯和寫入到文件名爲「log-file.txt」的文件中,其中「log-file.txt」文件的路徑是當前程序運行所在目錄;也能夠定義爲絕對路徑,配置如:
<param name="File" value="C:/log-file.txt" />就寫入C盤根目錄下log-file.txt文件中,具體使用技巧參見4.2.1。
本例的實現請參見8.6附件。
三、Log4net的主要組成部分
3.1 Appenders
Appenders用來定義日誌的輸出方式,即日誌要寫到那種介質上去。較經常使用的Log4net已經實現好了,直接在配置文件中調用便可,可參見上面配置文件例子;固然也能夠本身寫一個,須要從log4net.Appender.AppenderSkeleton類繼承。它還能夠經過配置Filters和Layout來實現日誌的過濾和輸出格式。
已經實現的輸出方式有:
AdoNetAppender 將日誌記錄到數據庫中。能夠採用SQL和存儲過程兩種方式。
AnsiColorTerminalAppender 將日誌高亮輸出到ANSI終端。
AspNetTraceAppender 能用asp.net中Trace的方式查看記錄的日誌。
BufferingForwardingAppender 在輸出到子Appenders以前先緩存日誌事件。
ConsoleAppender 將日誌輸出到應用程序控制臺。
EventLogAppender 將日誌寫到Windows Event Log。
FileAppender 將日誌輸出到文件。
ForwardingAppender 發送日誌事件到子Appenders。
LocalSyslogAppender 將日誌寫到local syslog service (僅用於UNIX環境下)。
MemoryAppender 將日誌存到內存緩衝區。
NetSendAppender 將日誌輸出到Windows Messenger service.這些日誌信息將在用戶終端的對話框中顯示。
OutputDebugStringAppender 將日誌輸出到Debuger,若是程序沒有Debuger,就輸出到系統Debuger。若是系統Debuger也不可用,將忽略消息。
RemoteSyslogAppender 經過UDP網絡協議將日誌寫到Remote syslog service。
RemotingAppender 經過.NET Remoting將日誌寫到遠程接收端。
RollingFileAppender 將日誌以回滾文件的形式寫到文件中。
SmtpAppender 將日誌寫到郵件中。
SmtpPickupDirAppender 將消息以文件的方式放入一個目錄中,像IIS SMTP agent這樣的SMTP代理就能夠閱讀或發送它們。
TelnetAppender 客戶端經過Telnet來接受日誌事件。
TraceAppender 將日誌寫到.NET trace 系統。
UdpAppender 將日誌以無鏈接UDP數據報的形式送到遠程宿主或用UdpClient的形式廣播。
3.2 Filters
使用過濾器能夠過濾掉Appender輸出的內容。過濾器一般有如下幾種:
DenyAllFilter 阻止全部的日誌事件被記錄
LevelMatchFilter 只有指定等級的日誌事件才被記錄
LevelRangeFilter 日誌等級在指定範圍內的事件才被記錄
LoggerMatchFilter 與Logger名稱匹配,才記錄
PropertyFilter 消息匹配指定的屬性值時才被記錄
StringMathFilter 消息匹配指定的字符串才被記錄
3.3 Layouts
Layout用於控制Appender的輸出格式,能夠是線性的也能夠是XML。
一個Appender只能有一個Layout。
最經常使用的Layout應該是經典格式的PatternLayout,其次是SimpleLayout,RawTimeStampLayout和ExceptionLayout。而後還有IRawLayout,XMLLayout等幾個,使用較少。Layout能夠本身實現,須要從log4net.Layout.LayoutSkeleton類繼承,來輸出一些特殊須要的格式,在後面擴展時就從新實現了一個Layout。
SimpleLayout簡單輸出格式,只輸出日誌級別與消息內容。
RawTimeStampLayout 用來格式化時間,在向數據庫輸出時會用到。
樣式如「yyyy-MM-dd HH:mm:ss「
ExceptionLayout須要給Logger的方法傳入Exception對象做爲參數才起做用,不然就什麼也不輸出。輸出的時候會包含Message和Trace。
PatterLayout使用最多的一個Layout,能輸出的信息不少,使用方式可參見上面例子中的配置文件。PatterLayout的格式化字符串見文後附註8.1。
3.4 Loggers
Logger是直接和應用程序交互的組件。Logger只是產生日誌,而後由它引用的Appender記錄到指定的媒介,並由Layout控制輸出格式。
Logger提供了多種方式來記錄一個日誌消息,也能夠有多個Logger同時存在。每一個實例化的Logger對象對被log4net做爲命名實體(Named Entity)來維護。log4net使用繼承體系,也就是說假如存在兩個Logger,名字分別爲a.b.c和a.b。那麼a.b就是a.b.c的祖先。每一個Logger都繼承了它祖先的屬性。全部的Logger都從Root繼承,Root自己也是一個Logger。
日誌的等級,它們由高到底分別爲:
OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL
高於等級設定值方法(如何設置參見「配置文件詳解」)都能寫入日誌, Off全部的寫入方法都不寫到日誌裏,ALL則相反。例如當咱們設成Info時,logger.Debug就會被忽略而不寫入文件,可是FATAL,ERROR,WARN,INFO會被寫入,由於他們等級高於INFO。
在具體寫日誌時,通常能夠這樣理解日誌等級:
FATAL(致命錯誤):記錄系統中出現的能使用系統徹底失去功能,服務中止,系統崩潰等使系統沒法繼續運行下去的錯誤。例如,數據庫沒法鏈接,系統出現死循環。
ERROR(通常錯誤):記錄系統中出現的致使系統不穩定,部分功能出現混亂或部分功能失效一類的錯誤。例如,數據字段爲空,數據操做不可完成,操做出現異常等。
WARN(警告):記錄系統中不影響系統繼續運行,但不符合系統運行正常條件,有可能引發系統錯誤的信息。例如,記錄內容爲空,數據內容不正確等。
INFO(通常信息):記錄系統運行中應該讓用戶知道的基本信息。例如,服務開始運行,功能已經開戶等。
DEBUG (調試信息):記錄系統用於調試的一切信息,內容或者是一些關鍵數據內容的輸出。
Logger實現的ILog接口,ILog定義了5個方法(Debug,Inof,Warn,Error,Fatal)分別對不一樣的日誌等級記錄日誌。這5個方法還有5個重載。以Debug爲例說明一下,其它的和它差很少。
ILog中對Debug方法的定義以下:
void Debug(object message);
void Debug(object message, Exception ex);
還有一個布爾屬性:
bool IsDebugEnabled { get; }
若是使用Debug(object message, Exception ex),則不管Layout中是否認義了%exception,默認配置下日誌都會輸出Exception。包括Exception的Message和Trace。若是使用Debug(object message),則日誌是不會輸出Exception。
最後還要說一個LogManager類,它用來管理全部的Logger。它的GetLogger靜態方法,能夠得到配置文件中相應的Logger:
log4net.ILog log = log4net.LogManager.GetLogger("logger-name");
3.5 Object Renders
它將告訴logger如何把一個對象轉化爲一個字符串記錄到日誌裏。(ILog中定義的接口接收的參數是Object,而不是String。)
例如你想把Orange對象記錄到日誌中,但此時logger只會調用Orange默認的ToString方法而已。因此要定義一個OrangeRender類實現log4net.ObjectRender.IObjectRender接口,而後註冊它(咱們在本文中的擴展不使用這種方法,而是直接實現一個自定義的Layout)。這時logger就會知道如何把Orange記錄到日誌中了。
3.6 Repository
Repository主要用於日誌對象組織結構的維護。
四、配置文件詳解
4.1 配置文件構成
主要有兩大部分,一是申明一個名爲「log4net「的自定義配置節,以下所示:
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
二是<log4net>節的具體配置,這是下面要重點說明的。
4.1.1<log4net>
全部的配置都要在<log4net>元素裏定義。
支持的屬性:
debug |
可選,取值是true或false,默認是false。設置爲true,開啓log4net的內部調試。 |
update |
可選,取值是Merge(合併)或Overwrite(覆蓋),默認值是Merge。設置爲Overwrite,在提交配置的時候會重置已經配置過的庫。 |
threshold |
可選,取值是repository(庫)中註冊的level,默認值是ALL。 |
支持的子元素:
appender |
0或多個 |
logger |
0或多個 |
renderer |
0或多個 |
root |
最多一個 |
param |
0或多個 |
4.1.2 <root>
實際上就是一個根logger,全部其它logger都默認繼承它,若是配置文件裏沒有顯式定義,則框架使用根日誌中定義的屬性。root元素沒有屬性。
支持的子元素:
appender-ref |
0個或多個,要引用的appender的名字。 |
level |
最多一個。 只有在這個級別或之上的事件纔會被記錄。 |
param |
0個或多個, 設置一些參數。 |
4.1.3 <logger>
支持的屬性:
name |
必須的,logger的名稱 |
additivity |
可選,取值是true或false,默認值是true。設置爲false時將阻止父logger中的appender。 |
支持的子元素:
appender-ref |
0個或多個,要引用的appender的名字。 |
level |
最多一個。 只有在這個級別或之上的事件纔會被記錄。 |
param |
0個或多個, 設置一些參數。 |
4.1.4 <appender>
定義日誌的輸出方式,只能做爲 log4net 的子元素。name屬性必須惟一,type屬性必須指定。
支持的屬性:
name |
必須的,Appender對象的名稱 |
type |
必須的,Appender對象的輸出類型 |
支持的子元素:
appender-ref |
0個或多個,容許此appender引用其餘appender,並非因此appender類型都支持。 |
filter |
0個或多個,定義此app使用的過濾器。 |
layout |
最多一個。定義appender使用的輸出格式。 |
param |
0個或多個, 設置Appender類中對應的屬性的值。 |
實際上<appender>所能包含的子元素遠不止上面4個。
4.1.5 <layout>
佈局,只能做爲<appender>的子元素。
支持的屬性:
type |
必須的,Layout的類型 |
支持的子元素:
param |
0個或多個, 設置一些參數。 |
4.1.6 <filter>
過濾器,只能做爲<appender>的子元素。
支持的屬性:
type |
必須的,Filter的類型 |
支持的子元素:
param |
0個或多個, 設置一些參數。 |
4.1.7 <param>
<param>元素能夠是任何元素的子元素。
支持的屬性:
name |
必須的,取值是父對象的參數名。 |
value |
可選的,value和type中,必須有一個屬性被指定。value是一個能被轉化爲參數值的字符串。 |
type |
可選的,value和type中,必須有一個屬性被指定。type是一個類型名,若是type不是在log4net程序集中定義的,就須要使用全名。 |
支持的子元素:
param |
0個或多個, 設置一些參數。 |
4.2 <appender>配置
<appender>在配置文件中至少有一個,也能夠有多個,有些<appender>類型還能夠引用其餘<appender>類型,具體參數可參見上表。
下面只對寫入回滾文件與輸出到數據庫(這裏使用SQL數據庫)配置體會說一下,其餘配置可參考官方網站:http://logging.apache.org/log4net/release/config-examples.html
4.2.1寫入回滾文件
<appender name="ReflectionLayout" type="log4net.Appender.RollingFileAppender,log4net">
<!--日誌文件路徑,「/」與「/」做用相同,到達的目錄相同,文件夾不存在則新建 -->
<!--按文件大小方式輸出時在這裏指定文件名,而且當天的日誌在下一天時在文件名後自動追加當天日期造成新文件。-->
<!—按照日期形式輸出時,直接鏈接元素DatePattern的value造成文件路徑。此處使用這種方式 -->
<!--param的名稱,能夠直接查對應的appender類的屬性名便可,這裏要查的就是RollingFileAppender類的屬性 -->
<param name="File" value="D:/Log/" />
<!--是否追加到文件-->
<param name="AppendToFile" value="true" />
<!--記錄日誌寫入文件時,不鎖定文本文件,防止多線程時不能寫Log,官方說線程非安全-->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<!—使用Unicode編碼-->
<Encoding value="UTF-8" />
<!--最多產生的日誌文件數,超過則只保留最新的n個。設定值value="-1"爲不限文件數-->
<param name="MaxSizeRollBackups" value="10" />
<!--是否只寫到一個文件中-->
<param name="StaticLogFileName" value="false" />
<!--按照何種方式產生多個日誌文件(日期[Date],文件大小[Size],混合[Composite])-->
<param name="RollingStyle" value="Composite" />
<!--按日期產生文件夾和文件名[在日期方式與混合方式下使用]-->
<!—此處按日期產生文件夾,文件名固定。注意" 的位置-->
<param name="DatePattern" value="yyyy-MM-dd/"ReflectionLayout.log"" />
<!—這是按日期產生文件夾,並在文件名前也加上日期-->
<param name="DatePattern" value="yyyyMMdd/yyyyMMdd"-TimerServer.log"" />
<!—這是先按日期產生文件夾,再造成下一級固定的文件夾—>
<param name="DatePattern" value="yyyyMMdd/"TimerServer/TimerServer.log"" />
<!--每一個文件的大小。只在混合方式與文件大小方式下使用。
超出大小後在全部文件名後自動增長正整數從新命名,數字最大的最先寫入。
可用的單位:KB|MB|GB。不要使用小數,不然會一直寫入當前日誌-->
<param name="maximumFileSize" value="500KB" />
<!--計數類型爲1,2,3…-->
<param name="CountDirection" value="1"/>
<!—過濾設置,LevelRangeFilter爲使用的過濾器。 -->
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="DEBUG" />
<param name="LevelMax" value="WARN" />
</filter>
<!--記錄的格式。通常用log4net.Layout.PatternLayout佈局-->
<!—此處用繼承了log4net.Layout.PatternLayout的自定義佈局,TGLog.ExpandLayout2
爲命名空間。%property{Operator}、%property{Action}是自定義的輸出-->
<layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
<param name="ConversionPattern"
value="記錄時間:%date 線程ID:[%thread] 日誌級別:%-5level 記錄類:%logger 操做者ID:%property{Operator} 操做類型:%property{Action}%n 當前機器名:%property%n當前機器名及登陸用戶:%username %n 記錄位置:%location%n 消息描述:%property{Message}%n 異常:%exception%n 消息:%message%newline%n%n" />
</layout>
</appender>
注意這些配置屬性有些是可選的,若是須要,必定要寫正確,不然要麼輸出的不是本身想要的結果,要麼乾脆不輸出任何信息。
4.2.1寫入SQL數據庫
須要在相應的數據庫中準備好一張表,建立語句以下:
CREATE TABLE [Log] (
[ID] [int] IDENTITY (1, 1) NOT NULL ,
[Date] [datetime] NOT NULL ,
[Thread] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
[Level] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
[Logger] [varchar] (200) COLLATE Chinese_PRC_CI_AS NULL ,
[Operator] [int] NULL ,
[Message] [text] COLLATE Chinese_PRC_CI_AS NULL ,
[ActionType] [int] NULL ,
[Operand] [varchar] (300) COLLATE Chinese_PRC_CI_AS NULL ,
[IP] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
[MachineName] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,
[Browser] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[Location] [text] COLLATE Chinese_PRC_CI_AS NULL ,
[Exception] [text] COLLATE Chinese_PRC_CI_AS NULL
)
<appender name="ADONetAppender" type="log4net.Appender.ADONetAppender,log4net">
<!--BufferSize爲緩衝區大小,只有日誌記錄超設定值纔會一塊寫入到數據庫-->
<bufferSize value="10" /><!—或寫爲<param name="BufferSize" value="10" />-->
<!--引用-->
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<!--鏈接數據庫字符串-->
<connectionString value="data source=.;initial catalog=Test;integrated security=false;persist security info=True;User ID=sa;Password=;" />
<!--插入到表Log-->
<commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Operator],[Message],[ActionType],[Operand],[IP],[MachineName],[Browser],[Location],[Exception]) VALUES (@log_date, @thread, @log_level, @logger,@operator, @message,@action_type,@operand,@ip,@machineName,@browser,@location,@exception)" />
<!—日誌記錄時間,RawTimeStampLayout爲默認的時間輸出格式 -->
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<!--線程號-->
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<!—長度不能夠省略,不然不會輸出-->
<size value="100" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread" />
</layout>
</parameter>
<!--日誌等級-->
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="100" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<!--日誌記錄類名稱-->
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="200" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<!--操做者。這個是自定義的輸出字段,使用從新實現的佈局器ReflectionLayout -->
<parameter>
<parameterName value="@operator" />
<!—設置爲Int32時只有bufferSize的 value<="1"才正確輸出,沒有找出緣由。-->
<dbType value="Int16" />
<layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
<conversionPattern value="%property{Operator}" />
</layout>
</parameter>
<!--操做對象-->
<parameter>
<parameterName value="@operand" />
<dbType value="String" />
<size value="300" />
<layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
<conversionPattern value="%property{Operand}" />
</layout>
</parameter>
<!—IP地址-->
<parameter>
<parameterName value="@ip" />
<dbType value="String" />
<size value="20" />
<layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
<conversionPattern value="%property{IP}" />
</layout>
</parameter>
<!--機器名-->
<parameter>
<parameterName value="@machineName" />
<dbType value="String" />
<size value="100" />
<layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
<conversionPattern value="%property{MachineName}" />
</layout>
</parameter>
<!--瀏覽器-->
<parameter>
<parameterName value="@browser" />
<dbType value="String" />
<size value="50" />
<layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
<conversionPattern value="%property{Browser}" />
</layout>
</parameter>
<!—日誌消息-->
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="3000" />
<layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
<conversionPattern value="%property{Message}" />
</layout>
</parameter>
<!--動做類型-->
<parameter>
<parameterName value="@action_type" />
<dbType value="Int16" />
<layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
<conversionPattern value="%property{ActionType}" />
</layout>
</parameter>
<!—記錄日誌的位置-->
<parameter>
<parameterName value="@location" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%location" />
</layout>
</parameter>
<!—異常信息。ExceptionLayout 爲異常輸出的默認格式-->
<parameter>
<parameterName value="@exception" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
注意:
向表中輸出的字段不能多於數據表自己字段,而反之則能夠,但這些多餘字段必定使其能夠爲空,不然便寫不到數據庫;
輸出字段的類型必定是對應數據表字段數據類型能夠隱式轉換的,並且長度也不能超過,不然也不能寫入;
數據表字段設置儘可能能夠爲空,這樣能夠避免一條日誌記錄存在空數據致使後面的日誌都記錄不了。
4.3<logger>的配置
在配置文件<appender>中的配置好了輸出的介質,格式,過濾方式,還要定義日誌對象<logger>。
在框架的體系裏,全部的日誌對象都是根日誌(root logger)的後代。 所以若是一個日誌對象沒有在配置文件裏顯式定義,則框架使用根日誌中定義的屬性。在<root>標籤裏,能夠定義level級別值和Appender的列表。若是沒有定義LEVEL的值,則缺省爲DEBUG。能夠經過<appender-ref>標籤訂義日誌對象使用的Appender對象。<appender-ref>聲明瞭在其餘地方定義的Appender對象的一個引用。在一個logger對象中的設置會覆蓋根日誌的設置。而對Appender屬性來講,子日誌對象則會繼承父日誌對象的Appender列表。這種缺省的行爲方式也能夠經過顯式地設定<logger>標籤的additivity屬性爲false而改變。
<root>不顯式申明時使用默認的配置。我以爲在使用時不定義<root>,自定義多個<logger>,在程序中記錄日誌時直接使用<logger>的name來查找相應的<logger>,這樣更靈活一些。例如:
<!--同時寫兩個文件和數據庫-->
<logger name="ReflectionLayout">
<level value="DEBUG"/>
<appender-ref ref="HashtableLayout"/>
<appender-ref ref="ReflectionLayout"/>
<appender-ref ref="ADONetAppender"/>
</logger>
4.4關聯配置文件
log4net默認關聯的是應用程序的配置文件App.config(BS程序是Web.config),可使用程序集自定義屬性來進行設置。下面來介紹一下這個自定義屬性:
log4net.Config.XmlConifguratorAttribute。
XmlConfiguratorAttribute有3個屬性:
ConfigFile: 配置文件的名字,文件路徑相對於應用程序目錄
(AppDomain.CurrentDomain.BaseDirectory)。ConfigFile屬性不能和ConfigFileExtension屬性一塊兒使用。
ConfigFileExtension: 配置文件的擴展名,文件路徑相對於應用程序的目錄。ConfigFileExtension屬性不能和ConfigFile屬性一塊兒使用。
Watch: 若是將Watch屬性設置爲true,就會監視配置文件。當配置文件發生變化的時候,就會從新加載。
若是ConfigFile和ConfigFileExtension都沒有設置,則使用應用程序的配置文件App.config(Web.config)。
能夠在項目的AssemblyInfo.cs文件裏添加如下的語句:
//監視默認的配置文件,App.exe.config
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
//監視配置文件,App.exe.log4net。
[assembly: log4net. Config.XmlConfigurator(ConfigFileExtension = "log4net", Watch = true)]
//使用配置文件log4net.config,不監視改變。注意log4net.config文件的目錄,BS程序在站點目錄//下,CS則在應用程序啓動目錄下,如調試時在/bin/Debug下,通常將文件屬性的文件輸出目錄調爲//始終複製便可
[assembly: log4net. Config.XmlConfigurator(ConfigFile = "log4net.config")]
//使用配置文件log4net.config,不監視改變
[assembly: log4net. Config.XmlConfigurator()]
也能夠在Global.asax的Application_Start裏或者是Program.cs中的Main方法中添加,注意這裏必定是絕對路徑,以下所示:
//這是在BS程序下,使用自定義的配置文件log4net.xml,使用Server.MapPath("~") + //@"/log4net.xml」來取得路徑。/log4net.xml爲相對於站點的路徑
// ConfigureAndWatch()至關於Configure(Watch = true)
log4net.Config.XmlConfigurator.ConfigureAndWatch(
new System.IO.FileInfo(Server.MapPath("~") + @"/log4net.xml"));
//這是在CS程序下,能夠用如下方法得到:
string assemblyFilePath = Assembly.GetExecutingAssembly().Location;
string assemblyDirPath = Path.GetDirectoryName(assemblyFilePath);
string configFilePath = assemblyDirPath + " //log4net.xml";
log4net.Config.XmlConfigurator.ConfigureAndWatch(
new FileInfo(configFilePath));
或直接使用絕對路徑:
//使用自定義的配置文件,直接絕對路徑爲:c:/log4net.config
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(@"c:/log4net.config"));
五、如何記錄日誌
Log4net使用很方便,先申明一個封裝類ILog 的對象,以下:
log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout");
其中"ReflectionLayout"即是咱們自定義的日誌對象<logger>的name的值。
對應5個日誌輸出級別,log有5 個方法,每一個方法都有兩個重載,使用以下:
try
{
log.Debug("這是一個測試!");
}
catch(Exception ec)
{
log.Error("出現錯誤!", ec);
}
若是咱們須要輸出的消息是要區別開來,不按一個字符串所有輸出,就須要進行一些擴展了。
六、Log4net的簡單擴展
6.1經過重寫佈局Layout輸出傳入的 message對象的屬性
6.1.1重寫Layout類
經過繼承log4net.Layout.PatternLayout類,使用log4net.Core.LoggingEvent類的方法獲得了要輸出的message類的名稱,而後經過反射獲得各個屬性的值,使用PatternLayout類AddConverter方法傳入獲得的值。這裏注意要引用用到的類的命名空間。
代碼見附註8.2。
6.1.2配置相應的配置文件
配置文件其餘地方不用改動,只是須要改動<appender>中的<layout>。例如:
<layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
<param name="ConversionPattern"
value="記錄時間:%date 操做者ID:%property{Operator}
操做類型:%property{Action}%n 消息描述:%property{Message}%n 異常:%exception%n " />
</layout>
其中<layout>的type由原來的log4net.Layout.PatternLayout換爲自定義的TGLog.ExpandLayout2.ReflectionLayout(TGLog.ExpandLayout2爲命名空間)。%property{Operator}輸出的即爲message類對象的屬性Operator的值。數據庫配置一樣,相應的字段若是是自定義的,則輸出選用自定義的<layout>。例:
<!--動做類型-->
<parameter>
<parameterName value="@action_type" />
<dbType value="Int16" />
<layout type="TGLog.ExpandLayout2.ReflectionLayout,TGLog">
<conversionPattern value="%property{ActionType}" />
</layout>
</parameter>
6.1.3程序中如何使用
和通常使用方法基本相同,只是傳入的參數是一個自定義的類,類的屬性和配置文件中<layout>全部的%property{屬性}是一致的,即%property{屬性}在輸出的時候就查找傳入message類中有無對應的屬性,若是有就輸出值,沒有則輸出null。例:
log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout");
try
{
log.Debug(new LogMessage(
1,
"操做對象:0",
(int)TGLog.ActionType.Other,
"這是四個參數測試")
);
}
catch(Exception ec)
{
log.Error(new LogMessage(
1,
"操做對象:0",
(int)TGLog.ActionType.Other,
"這是所有參數測試",
"192.168.1.1",
"MyComputer",
"Maxthon(MyIE2)Fans"),
ec
);
}
LogMessage的所有屬性的構造方法以下:
public LogMessage(
int operatorID,
string operand,
int ActionType,
string message,
string ip,
string machineName,
string browser
)
{
this.ActionType = ActionType;
this.Operator = operatorID;
this.Message = message;
this.Operand = operand;
this.IP = ip;
this.Browser = browser;
this.MachineName = machineName;
}
6.2經過從新實現ILog接口來增長輸入的參數
6.2.1重寫LogImpl,LogManager類及實現ILog接口
這種方式是經過構造一個名爲IMyLog接口,是繼承Ilog接口而來,而後分別在MyLogImpl,MyLogManager從新實現IMyLog接口,增長了每種方法的參數。MyLogImpl,MyLogManager分別繼承LogImpl,LogManager而來。
代碼分別見8.三、8.四、8.5:
6.2.2配置相應的配置文件
配置文件其餘地方不用改動,只是須要改動<appender>中的<layout>元素name爲ConversionPattern的value中輸出格式。例如:
<layout type=" log4net.Layout.PatternLayout ">
<param name="ConversionPattern"
value="記錄時間:%date 操做者ID:%property{Operator}
操做類型:%property{Action}%n 消息描述:%property{Message}%n 異常:%exception%n " />
</layout>
%property{參數}中的參數在MyLogImpl類中定義,如語句:
loggingEvent.Properties["Operator"] = operatorID;
就定義了Operator輸出參數,即%property{Operator}輸出的即爲IMyLog中的參數operatorID的值。
數據庫配置一樣。例:
<!--動做類型-->
<parameter>
<parameterName value="@action_type" />
<dbType value="Int16" />
<layout type=" log4net.Layout.PatternLayout ">
<conversionPattern value="%property{ActionType}" />
</layout>
</parameter>
6.2.3程序中如何使用
先引用IMyLog ,MyLogManager所在的命名空間,建立一個IMyLog對象,myLog的5 個方法,每一個方法都有四個重載,增長了多參數的重載。例:
IMyLog myLog = MyLogManager.GetLogger("ExpandILog");
try
{
myLog.Debug("這是一個參數重載測試!");
}
catch(Exception ec)
{
log.Error(
1,
"操做對象:0",
(int)TGLog.ActionType.Other,
"這是所有參數測試",
"192.168.1.1",
"MyComputer",
"Maxthon(MyIE2)Fans",
ec
);
}
七、總結
Log4net 功能不少,這裏只是對已經嘗試用過的功能總結一下,普通寫日誌已經足夠。須要注意的是:
1. Log4net自己也有一些缺陷,好比一個記錄引發了log4net自己的異常,就會使後面的日誌沒法記錄下來,尤爲是在寫入數據庫時。例如使用6.1擴展後,int型的屬性在<appender >的元素<bufferSize>設置不爲1時,<dbType value="Int32" />時,就不能輸出到數據庫,而<dbType value="Int16" />則沒任何問題。
2. Log4net自己出現了異常,好比配置文件出現錯誤,有些日誌輸出方式會記錄下這些異常,例如應用程序控制臺;有些則不會輸出這些錯誤,如數據庫與文件。
3. 擴展時也會留下一些問題。例如在使用6.1擴展輸出字段時就會出現,在log.debug(object message)中,若是message是一個自定義的類,屬性與配置文件中輸出設置也一致,構造函數時也只構造一個參數的實例,寫文件與寫數據庫都成功,而將message按沒有擴展的方式直接傳入一個字符串,即log.debug(「信息內容」)使用則只能寫入文件,而數據庫則沒寫入。自定義的Layout 就是繼承默認的PatternLayout,原本不該該出錯,但出現了問題。緣由分析是自定義的message類有類型爲int的屬性,做爲一個對象傳入時在默認值0,而直接使用字符串則int型的字段得不到默認值,引起異常。因此建議在有擴展存在時,最好多設幾個<logger>,區分清楚,按照統一的形式記錄日誌,不要混合使用。
4. 配置文件的設置必定要準確,在一點不正確就會致使日誌不能正常輸出,因此在配置時先從最簡單的開始,同時輸出方式選擇一種能輸出log4net自己異常的方式,成功後一點一點加在新配置,這樣出錯了也容易找到那個地方配置有問題。
5. log4net擴展性很強,幾乎全部的組件均可以重寫,在配置文件中配置好就可使用。
八、附註:
8.1PatterLayout格式化字符表
轉換字符 |
效果 |
a |
等價於appdomain |
appdomain |
引起日誌事件的應用程序域的友好名稱。(使用中通常是可執行文件的名字。) |
c |
等價於 logger |
C |
等價於 type |
class |
等價於 type |
d |
等價於 date |
date |
發生日誌事件的本地時間。 使用 DE>%utcdate 輸出UTC時間。date後面還能夠跟一個日期格式,用大括號括起來。DE>例如:%date{HH:mm:ss,fff}或者%date{dd MMM yyyy HH:mm:ss,fff}。若是date後面什麼也不跟,將使用ISO8601 格式 。 日期格式和.Net中DateTime類的ToString方法中使用的格式是同樣。 另外log4net還有3個本身的格式Formatter。 它們是 "ABSOLUTE", "DATE"和"ISO8601"分別表明 AbsoluteTimeDateFormatter, DateTimeDateFormatter和Iso8601DateFormatter。例如:%date{ISO8601}或%date{ABSOLUTE}。 它們的性能要好於ToString。 |
exception |
異常信息 日誌事件中必須存了一個異常對象,若是日誌事件不包含沒有異常對象,將什麼也不輸出。異常輸出完畢後會跟一個換行。通常會在輸出異常前加一個換行,並將異常放在最後。 |
F |
等價於 file |
file |
發生日誌請求的源代碼文件的名字。 警告:只在調試的時候有效。調用本地信息會影響性能。 |
identity |
當前活動用戶的名字(Principal.Identity.Name). 警告:會影響性能。(我測試的時候%identity返回都是空的。) |
l |
等價於 location |
L |
等價於 line |
location |
引起日誌事件的方法(包括命名空間和類名),以及所在的源文件和行號。 警告:會影響性能。沒有pdb文件的話,只有方法名,沒有源文件名和行號。 |
level |
日誌事件等級 |
line |
引起日誌事件的行號 警告:會影響性能。 |
logger |
記錄日誌事件的Logger對象的名字。 可使用精度說明符控制Logger的名字的輸出層級,默認輸出全名。 注意,精度符的控制是從右開始的。例如:logger 名爲 "a.b.c", 輸出模型爲%logger{2} ,將輸出"b.c"。 |
m |
等價於 message |
M |
等價於 method |
message |
由應用程序提供給日誌事件的消息。 |
mdc |
MDC (舊爲:ThreadContext.Properties) 如今是事件屬性的一部分。 保留它是爲了兼容性,它等價於 property。 |
method |
發生日誌請求的方法名(只有方法名而已)。 警告:會影響性能。 |
n |
等價於 newline |
newline |
換行符 |
ndc |
NDC (nested diagnostic context) |
p |
等價於 level |
P |
等價於 property |
properties |
等價於 property |
property |
輸出事件的特殊屬性。例如: %property{user} 輸出user屬性。屬性是由loggers或appenders添加到時間中的。 有一個默認的屬性"DE>log4net:HostName"老是會有。DE> %property將輸出全部的屬性 。 (擴展後可使用)
|
r |
等價於 timestamp |
t |
等價於 thread |
timestamp |
從程序啓動到事件發生所通過的毫秒數。 |
thread |
引起日誌事件的線程,若是沒有線程名就使用線程號。 |
type |
引起日誌請求的類的全名。. 可使用精度控制符。例如: 類名是 "log4net.Layout.PatternLayout", 格式模型是%type{1} 將輸出"PatternLayout"。(也是從右開始的。) 警告:會影響性能。 |
u |
等價於 identity |
username |
當前用戶的WindowsIdentity。(相似:HostName/Username) 警告:會影響性能。 |
utcdate |
發生日誌事件的UTC時間。DE>後面還能夠跟一個日期格式,用大括號括起來。DE>例如:%utcdate{HH:mm:ss,fff}或者%utcdate{dd MMM yyyy HH:mm:ss,fff}。若是utcdate後面什麼也不跟,將使用ISO8601 格式 。 日期格式和.Net中DateTime類的ToString方法中使用的格式是同樣。 另外log4net還有3個本身的格式Formatter。 它們是 "ABSOLUTE", "DATE"和"ISO8601"分別表明 AbsoluteTimeDateFormatter, DateTimeDateFormatter和Iso8601DateFormatter。例如:%date{ISO8601}或%date{ABSOLUTE}。 它們的性能要好於ToString。 |
w |
等價於 username |
x |
等價於 ndc |
X |
等價於 mdc |
% |
%%輸出一個百分號 |
關於調用本地信息(caller location information)的說明:
%type %file %line %method %location %class %C %F %L %l %M 都會調用本地信息。這樣作會影響性能。本地信息使用System.Diagnostics.StackTrace獲得。.Net 1.0 不支持System.Diagnostics.StackTrace 類。
本地信息在調試模式下能夠正常獲取,在非調試模式下可能獲取不到,或只能獲取一部分。(根據個人測試,實際上是須要有一個程序數據庫(.pdb)文件。)
%property屬性要用代碼來設置才能使用(也就是擴展一下),
默認屬性log4net:HostName不用設置。
轉義字符的修飾符:
Format modifier |
left justify |
minimum width |
maximum width |
comment |
%20logger |
false |
20 |
none |
若是logger名不足20個字符,就在左邊補空格。 |
%-20logger |
true |
20 |
none |
若是logger名不足20個字符,就在右邊補空格。 |
%.30logger |
NA |
none |
30 |
超過30個字符將截斷。 |
%20.30logger |
false |
20 |
30 |
logger名要在20到30之間,少了在左邊補空格,多了截斷。 |
%-20.30logger |
true |
20 |
30 |
logger名要在20到30之間,少了在右邊補空格,多了截斷。 |
8.2Layout類代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net.Layout;
using log4net.Layout.Pattern;
using System.Reflection;
using System.Collections;
using FastReflectionLib;
namespace TGLog.ExpandLayout2
{
public class ReflectionLayout : PatternLayout
{
public ReflectionLayout()
{
this.AddConverter("property", typeof(ReflectionPatternConverter));
}
}
public class ReflectionPatternConverter : PatternLayoutConverter
{
protected override void Convert(
System.IO.TextWriter writer,
log4net.Core.LoggingEvent loggingEvent
)
{
if (Option != null)
{
// 寫入指定鍵的值
WriteObject(
writer,
loggingEvent.Repository,
LookupProperty(Option,
loggingEvent)
);
}
else
{
// 寫入全部關鍵值對
WriteDictionary(
writer,
loggingEvent.Repository,
loggingEvent.GetProperties()
);
}
}
/// <summary>
/// 經過反射獲取傳入的日誌對象的某個屬性的值
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private object LookupProperty(
string property,
log4net.Core.LoggingEvent loggingEvent)
{
object propertyValue = string.Empty;
PropertyInfo propertyInfo =
loggingEvent.MessageObject.GetType().GetProperty(property);
if (propertyInfo != null)
{
propertyValue =
propertyInfo.GetValue(loggingEvent.MessageObject, null);
}
return propertyValue;
}
}
}
8.3 MyLogImpl類代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net.Core;
namespace TGLog.ExpandILog
{
public class MyLogImpl : LogImpl, IMyLog
{
/// <summary>
/// The fully qualified name of this declaring type not the type of any subclass.
/// </summary>
private readonly static Type ThisDeclaringType = typeof(MyLogImpl);
public MyLogImpl(ILogger logger)
: base(logger)
{
}
#region Implementation of IMyLog
public void Debug(int operatorID, string operand, int actionType,object message,
string ip, string browser, string machineName)
{
Debug(operatorID, operand, actionType, message,
ip, browser, machineName, null);
}
public void Debug(int operatorID, string operand, int actionType,object message,
string ip, string browser, string machineName, System.Exception t)
{
if (this.IsDebugEnabled)
{
LoggingEvent loggingEvent =
new LoggingEvent(ThisDeclaringType, Logger.Repository,
Logger.Name, Level.Info, message, t);
loggingEvent.Properties["Operator"] = operatorID;
loggingEvent.Properties["Operand"] = operand;
loggingEvent.Properties["ActionType"] = actionType;
loggingEvent.Properties["IP"] = ip;
loggingEvent.Properties["Browser"] = browser;
loggingEvent.Properties["MachineName"] = machineName;
Logger.Log(loggingEvent);
}
}
public void Info(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName)
{
Info(operatorID, operand, actionType, message, ip, browser, machineName, null);
}
public void Info(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, System.Exception t)
{
if (this.IsInfoEnabled)
{
LoggingEvent loggingEvent =
new LoggingEvent(ThisDeclaringType, Logger.Repository,
Logger.Name, Level.Info, message, t);
loggingEvent.Properties["Operator"] = operatorID;
loggingEvent.Properties["Operand"] = operand;
loggingEvent.Properties["ActionType"] = actionType;
loggingEvent.Properties["IP"] = ip;
loggingEvent.Properties["Browser"] = browser;
loggingEvent.Properties["MachineName"] = machineName;
Logger.Log(loggingEvent);
}
}
public void Warn(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName)
{
Warn(operatorID, operand, actionType, message, ip, browser, machineName, null);
}
public void Warn(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, System.Exception t)
{
if (this.IsWarnEnabled)
{
LoggingEvent loggingEvent =
new LoggingEvent(ThisDeclaringType, Logger.Repository,
Logger.Name, Level.Info, message, t);
loggingEvent.Properties["Operator"] = operatorID;
loggingEvent.Properties["Operand"] = operand;
loggingEvent.Properties["ActionType"] = actionType;
loggingEvent.Properties["IP"] = ip;
loggingEvent.Properties["Browser"] = browser;
loggingEvent.Properties["MachineName"] = machineName;
Logger.Log(loggingEvent);
}
}
public void Error(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName)
{
Error(operatorID, operand, actionType, message, ip, browser, machineName, null);
}
public void Error(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, System.Exception t)
{
if (this.IsErrorEnabled)
{
LoggingEvent loggingEvent =
new LoggingEvent(ThisDeclaringType, Logger.Repository,
Logger.Name, Level.Info, message, t);
loggingEvent.Properties["Operator"] = operatorID;
loggingEvent.Properties["Operand"] = operand;
loggingEvent.Properties["ActionType"] = actionType;
loggingEvent.Properties["IP"] = ip;
loggingEvent.Properties["Browser"] = browser;
loggingEvent.Properties["MachineName"] = machineName;
Logger.Log(loggingEvent);
}
}
public void Fatal(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName)
{
Fatal(operatorID, operand, actionType, message, ip, browser, machineName, null);
}
public void Fatal(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, System.Exception t)
{
if (this.IsFatalEnabled)
{
LoggingEvent loggingEvent =
new LoggingEvent(ThisDeclaringType, Logger.Repository,
Logger.Name, Level.Info, message, t);
loggingEvent.Properties["Operator"] = operatorID;
loggingEvent.Properties["Operand"] = operand;
loggingEvent.Properties["ActionType"] = actionType;
loggingEvent.Properties["IP"] = ip;
loggingEvent.Properties["Browser"] = browser;
loggingEvent.Properties["MachineName"] = machineName;
Logger.Log(loggingEvent);
}
}
#endregion Implementation of IMyLog
}
}
8.4 MyLogManager類代碼
#region Copyright & License
//
// Copyright 2001-2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#endregion
using System;
using System.Reflection;
using System.Collections;
using log4net;
using log4net.Core;
using log4net.Repository;
using log4net.Repository.Hierarchy;
namespace TGLog.ExpandILog
{
public class MyLogManager
{
#region Static Member Variables
/// <summary>
/// The wrapper map to use to hold the <see cref="EventIDLogImpl"/> objects
/// </summary>
private static readonly WrapperMap s_wrapperMap = new WrapperMap(newWrapperCreationHandler(WrapperCreationHandler));
#endregion
#region Constructor
/// <summary>
/// Private constructor to prevent object creation
/// </summary>
private MyLogManager() { }
#endregion
#region Type Specific Manager Methods
/// <summary>
/// Returns the named logger if it exists
/// </summary>
/// <remarks>
/// <para>If the named logger exists (in the default hierarchy) then it
/// returns a reference to the logger, otherwise it returns
/// <c>null</c>.</para>
/// </remarks>
/// <param name="name">The fully qualified logger name to look for</param>
/// <returns>The logger found, or null</returns>
public static IMyLog Exists(string name)
{
return Exists(Assembly.GetCallingAssembly(), name);
}
/// <summary>
/// Returns the named logger if it exists
/// </summary>
/// <remarks>
/// <para>If the named logger exists (in the specified domain) then it
/// returns a reference to the logger, otherwise it returns
/// <c>null</c>.</para>
/// </remarks>
/// <param name="domain">the domain to lookup in</param>
/// <param name="name">The fully qualified logger name to look for</param>
/// <returns>The logger found, or null</returns>
public static IMyLog Exists(string domain, string name)
{
return WrapLogger(LoggerManager.Exists(domain, name));
}
/// <summary>
/// Returns the named logger if it exists
/// </summary>
/// <remarks>
/// <para>If the named logger exists (in the specified assembly's domain) then it
/// returns a reference to the logger, otherwise it returns
/// <c>null</c>.</para>
/// </remarks>
/// <param name="assembly">the assembly to use to lookup the domain</param>
/// <param name="name">The fully qualified logger name to look for</param>
/// <returns>The logger found, or null</returns>
public static IMyLog Exists(Assembly assembly, string name)
{
return WrapLogger(LoggerManager.Exists(assembly, name));
}
/// <summary>
/// Returns all the currently defined loggers in the default domain.
/// </summary>
/// <remarks>
/// <para>The root logger is <b>not</b> included in the returned array.</para>
/// </remarks>
/// <returns>All the defined loggers</returns>
public static IMyLog[] GetCurrentLoggers()
{
return GetCurrentLoggers(Assembly.GetCallingAssembly());
}
/// <summary>
/// Returns all the currently defined loggers in the specified domain.
/// </summary>
/// <param name="domain">the domain to lookup in</param>
/// <remarks>
/// The root logger is <b>not</b> included in the returned array.
/// </remarks>
/// <returns>All the defined loggers</returns>
public static IMyLog[] GetCurrentLoggers(string domain)
{
return WrapLoggers(LoggerManager.GetCurrentLoggers(domain));
}
/// <summary>
/// Returns all the currently defined loggers in the specified assembly's domain.
/// </summary>
/// <param name="assembly">the assembly to use to lookup the domain</param>
/// <remarks>
/// The root logger is <b>not</b> included in the returned array.
/// </remarks>
/// <returns>All the defined loggers</returns>
public static IMyLog[] GetCurrentLoggers(Assembly assembly)
{
return WrapLoggers(LoggerManager.GetCurrentLoggers(assembly));
}
/// <summary>
/// Retrieve or create a named logger.
/// </summary>
/// <remarks>
/// <para>Retrieve a logger named as the <paramref name="name"/>
/// parameter. If the named logger already exists, then the
/// existing instance will be returned. Otherwise, a new instance is
/// created.</para>
///
/// <para>By default, loggers do not have a set level but inherit
/// it from the hierarchy. This is one of the central features of
/// log4net.</para>
/// </remarks>
/// <param name="name">The name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(string name)
{
return GetLogger(Assembly.GetCallingAssembly(), name);
}
/// <summary>
/// Retrieve or create a named logger.
/// </summary>
/// <remarks>
/// <para>Retrieve a logger named as the <paramref name="name"/>
/// parameter. If the named logger already exists, then the
/// existing instance will be returned. Otherwise, a new instance is
/// created.</para>
///
/// <para>By default, loggers do not have a set level but inherit
/// it from the hierarchy. This is one of the central features of
/// log4net.</para>
/// </remarks>
/// <param name="domain">the domain to lookup in</param>
/// <param name="name">The name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(string domain, string name)
{
return WrapLogger(LoggerManager.GetLogger(domain, name));
}
/// <summary>
/// Retrieve or create a named logger.
/// </summary>
/// <remarks>
/// <para>Retrieve a logger named as the <paramref name="name"/>
/// parameter. If the named logger already exists, then the
/// existing instance will be returned. Otherwise, a new instance is
/// created.</para>
///
/// <para>By default, loggers do not have a set level but inherit
/// it from the hierarchy. This is one of the central features of
/// log4net.</para>
/// </remarks>
/// <param name="assembly">the assembly to use to lookup the domain</param>
/// <param name="name">The name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(Assembly assembly, string name)
{
return WrapLogger(LoggerManager.GetLogger(assembly, name));
}
/// <summary>
/// Shorthand for <see cref="LogManager.GetLogger(string)"/>.
/// </summary>
/// <remarks>
/// Get the logger for the fully qualified name of the type specified.
/// </remarks>
/// <param name="type">The full name of <paramref name="type"/> will
/// be used as the name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(Type type)
{
return GetLogger(Assembly.GetCallingAssembly(), type.FullName);
}
/// <summary>
/// Shorthand for <see cref="LogManager.GetLogger(string)"/>.
/// </summary>
/// <remarks>
/// Get the logger for the fully qualified name of the type specified.
/// </remarks>
/// <param name="domain">the domain to lookup in</param>
/// <param name="type">The full name of <paramref name="type"/> will
/// be used as the name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(string domain, Type type)
{
return WrapLogger(LoggerManager.GetLogger(domain, type));
}
/// <summary>
/// Shorthand for <see cref="LogManager.GetLogger(string)"/>.
/// </summary>
/// <remarks>
/// Get the logger for the fully qualified name of the type specified.
/// </remarks>
/// <param name="assembly">the assembly to use to lookup the domain</param>
/// <param name="type">The full name of <paramref name="type"/> will
/// be used as the name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(Assembly assembly, Type type)
{
return WrapLogger(LoggerManager.GetLogger(assembly, type));
}
#endregion
#region Extension Handlers
/// <summary>
/// Lookup the wrapper object for the logger specified
/// </summary>
/// <param name="logger">the logger to get the wrapper for</param>
/// <returns>the wrapper for the logger specified</returns>
private static IMyLog WrapLogger(ILogger logger)
{
return (IMyLog)s_wrapperMap.GetWrapper(logger);
}
/// <summary>
/// Lookup the wrapper objects for the loggers specified
/// </summary>
/// <param name="loggers">the loggers to get the wrappers for</param>
/// <returns>Lookup the wrapper objects for the loggers specified</returns>
private static IMyLog[] WrapLoggers(ILogger[] loggers)
{
IMyLog[] results = new IMyLog[loggers.Length];
for (int i = 0; i < loggers.Length; i++)
{
results[i] = WrapLogger(loggers[i]);
}
return results;
}
/// <summary>
/// Method to create the <see cref="ILoggerWrapper"/> objects used by
/// this manager.
/// </summary>
/// <param name="logger">The logger to wrap</param>
/// <returns>The wrapper for the logger specified</returns>
private static ILoggerWrapper WrapperCreationHandler(ILogger logger)
{
return new MyLogImpl(logger);
}
#endregion
}
}
8.5 IMyLog類代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
namespace TGLog.ExpandILog
{
public interface IMyLog : ILog
{
void Debug(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName);
void Debug(int operatorID, string operand, int actionType,object message,
string ip, string browser, string machineName, Exception t);
void Info(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName);
void Info(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, Exception t);
void Warn(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName);
void Warn(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, Exception t);
void Error(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName);
void Error(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, Exception t);
void Fatal(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName);
void Fatal(int operatorID, string operand, int actionType, object message,
string ip, string browser, string machineName, Exception t);
}
}
8.6附件
8.7參考
一、http://peibing211.blog.163.com/blog/static/37116360200992811595469/
二、http://www.cnblogs.com/qiangzi/archive/2009/09/10/1541023.html
三、http://blog.chinaunix.net/u/23701/showart_1414206.html
四、http://itrust.cnblogs.com/archive/2005/01/25/97225.html
五、http://www.cnitblog.com/seeyeah/archive/2009/09/20/61491.aspx
六、http://www.cnblogs.com/zhmore/archive/2009/03/19/1416707.html
七、http://blog.shinylife.net/blog/article.asp?id=948
八、http://www.cnblogs.com/manhoo/archive/2009/06/25/1511066.html