(轉)非常完善的Log4net詳細說明

来源:http://www.cnblogs.com/yige/archive/2017/09/13/7513381.html
-Advertisement-
Play Games

1、概述 log4net是.Net下一個非常優秀的開源日誌記錄組件。log4net記錄日誌的功能非常強大。它可以將日誌分不同的等級,以不同的格式,輸出到不同的媒介。本文主要是介紹如何在Visual Studio2008中使用log4net快速創建系統日誌,如何擴展以輸出自定義欄位。 2、一個簡單的使 ...


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" />

 

      <!--按日期產生文件夾和文件名[在日期方式與混合方式下使用]-->

<!—此處按日期產生文件夾,文件名固定。註意&quot; 的位置-->

      <param name="DatePattern" value="yyyy-MM-dd/&quot;ReflectionLayout.log&quot;"  />

<!—這是按日期產生文件夾,併在文件名前也加上日期-->

      <param name="DatePattern" value="yyyyMMdd/yyyyMMdd&quot;-TimerServer.log&quot;"  />

<!—這是先按日期產生文件夾,再形成下一級固定的文件夾—>

      <param name="DatePattern" value="yyyyMMdd/&quot;TimerServer/TimerServer.log&quot;"  />

 

      <!--每個文件的大小。只在混合方式與文件大小方式下使用。

超出大小後在所有文件名後自動增加正整數重新命名,數字最大的最早寫入。

可用的單位: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"分別代表 Absol

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、Nginx(web伺服器) 二、LVS(調度) 1、LVS集群之原理及概述(1) 2、LVS集群之工作原理和調度演算法(2) 3、LVS集群之NAT模式實例(3) 4、LVS集群DR模式實例(4) 5、LVS集群TUN模式實例(5) 6、LVS集群ipvsadm命令和調度演算法(6) 7、記一次lv ...
  • 在代碼運行期間動態增加功能的方式,稱之為“裝飾器”(Decorator)。 由於函數也是一個對象,而且函數對象可以賦值給變數,所以通過變數也能調用該函數。 函數對象有一個__name__屬性,可以拿到函數的名字 ...
  • Python的functools模塊提供了很多有用的功能,其中一個就是偏函數(Partial function)。要註意,這裡的偏函數和數學意義上的偏函數不一樣。 在介紹函數參數的時候,我們講到,通過設定參數的預設值,可以降低函數調用的難度。而偏函數也可以做到這一點。舉例如下: int()函數可以把 ...
  • 關鍵字lambda表示匿名函數,冒號前面的x表示函數參數。 匿名函數有個限制,就是只能有一個表達式,不用寫return,返回值就是該表達式的結果。 ...
  • 一:函數作為返回值 二:閉包 ...
  • 我們都知道linux下所有設備都是以文件存在的,所以當我們需要用到這些設備的時候,首先就需要打開它們,下麵我們來詳細瞭解一下文件I/O操作。 用到的文件I/O有以下幾個操作:打開文件、讀文件、寫文件、關閉文件等,對應用到的函數有:open、read、write、close、lseek(文件指針偏移) ...
  • cd命令用來切換工作目錄至dirname。 其中dirName表示法可為絕對路徑或相對路徑。若目錄名稱省略,則變換至使用者的home directory(也就是剛login時所在的目錄)。 另外,~也表示為home directory的意思,.則是表示目前所在的目錄,..則表示目前目錄位置的上一層目 ...
  • 1.環境: /home/jello # uname -aLinux 3.10.0 #2 SMP Mon Mar 6 17:52:09 CST 2017 armv7l GNU/Linux 2.獲取mono源碼 wget download.mono-project.com/sources/mono/mo ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...