非常完善的Log4net详细说明(转)
最可能來源:https://blog.csdn.net/ydm19891101/article/details/50561638
其它轉載者:http://www.cnblogs.com/zhangchenliang/p/4546352.html
1、概述
log4net是.Net下一個非常優秀的開源日志記錄組件。log4net記錄日志的功能非常強大。它可以將日志分不同的等級,以不同的格式,輸出到不同的媒介。本文主要是介紹如何在Visual Studio2008中使用log4net快速創建系統日志,如何擴展以輸出自定義字段。
?
2、一個簡單的使用實例
第一步:在項目中添加對log4net.dll的引用,這里引用版本是1.2.10.0。
第二步:程序啟動時讀取log4net的配置文件。
如果是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()]
也可以使用自定義的配置文件,具體請參見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附件。
3、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、配置文件詳解
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"));
?
5、如何記錄日志
Log4net使用很方便,先申明一個封裝類ILog?的對象,如下:
log4net.ILog?log = log4net.LogManager.GetLogger("ReflectionLayout");
其中"ReflectionLayout"便是我們自定義的日志對象<logger>的name的值。
對應5個日志輸出級別,log有5?個方法,每個方法都有兩個重載,使用如下:
try
????????????{
????????????????log.Debug("這是一個測試!");
????????????}
????????????catch(Exception?ec)
????????????{
????????????????log.Error("出現錯誤!", ec);
?????????}
如果我們需要輸出的消息是要區別開來,不按一個字符串全部輸出,就需要進行一些擴展了。
6、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.3、8.4、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
);
??????}
7、總結
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、附注:
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附件
使用log4net記錄日志
8.7參考
1、http://peibing211.blog.163.com/blog/static/37116360200992811595469/
2、http://www.cnblogs.com/qiangzi/archive/2009/09/10/1541023.html
3、http://blog.chinaunix.net/u/23701/showart_1414206.html
4、http://itrust.cnblogs.com/archive/2005/01/25/97225.html
5、http://www.cnitblog.com/seeyeah/archive/2009/09/20/61491.aspx
6、http://www.cnblogs.com/zhmore/archive/2009/03/19/1416707.html
7、http://blog.shinylife.net/blog/article.asp?id=948
8、http://www.cnblogs.com/manhoo/archive/2009/06/25/1511066.html
?轉載于:https://www.cnblogs.com/hao-1234-1234/p/9065332.html
總結
以上是生活随笔為你收集整理的非常完善的Log4net详细说明(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二次规划的对偶形式(CVX)
- 下一篇: 教程-上传应用公钥并获取支付宝公钥