1. 程式人生 > >log4net 詳解

log4net 詳解

log4net 詳解

作者:未知(搜了很久,未能找到原創者)
https://www.cnblogs.com/lzrabbit/archive/2012/03/23/2413180.html

1、概述

log4net 是 .Net 下一個非常優秀的開源日誌記錄元件。log4net 記錄日誌的功能非常強大。它可以將日誌分不同的等級,以不同的格式,輸出到不同的媒介。本文主要是介紹如何在 Visual Studio 2008 中使用 log4net 快速建立系統日誌,如何擴充套件以輸出自定義欄位。

官網:https://logging.apache.org/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 Layout

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,Info,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> 元素裡定義。

支援的屬性:

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>

元素可以是任何元素的子元素。

支援的屬性:

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.2 寫入 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>