日誌記錄往往是軟體開發周期中的重要組成部分。它具有以下幾個優點:它可以提供應用程式運行時的精確環境,可供開發人員儘快找到應用程式中的Bug;一旦在程式中加入了Log 輸出代碼,程式運行過程中就能生成並輸出日誌信息而無需人工干預。另外,日誌信息可以輸出到不同的地方(控制台,文件等)以備以後研究之用。 ...
日誌記錄往往是軟體開發周期中的重要組成部分。它具有以下幾個優點:它可以提供應用程式運行時的精確環境,可供開發人員儘快找到應用程式中的Bug;一旦在程式中加入了Log 輸出代碼,程式運行過程中就能生成並輸出日誌信息而無需人工干預。另外,日誌信息可以輸出到不同的地方(控制台,文件等)以備以後研究之用。
- 從http://logging.apache.org/log4net/下載log4net的源代碼。解壓軟體包後,在解壓的src目錄下將log4net.sln載入Visual Studio .NET,編譯後可以得到log4net.dll。
或直接使用NuGet
log4net 有四個主要的組件,分別是Logger(記錄器), Repository(庫), Appender(附著器)以及 Layout(佈局)
- 添加-新建配置文件Log4Net.config,併在文件屬性中“複製到輸出目錄”選中“始終複製”,文件內容如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!--Log日記配置, 申明一個名為“log4net“的自定義配置節-->
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<!--程式中只實例化一個logger,名字為LogHelper-->
<logger name ="LogHelper">
<!--輸出所有信息-->
<level value="ALL"/>
<!--介質名稱,對應錯誤,信息和控制台-->
<appender-ref ref="ErrorRollingFileAppender" />
<appender-ref ref="InfoRollingFileAppender" />
<appender-ref ref="ColoredConsoleAppender"/>
</logger>
<!--Info介質設置-->
<appender name="InfoRollingFileAppender" type="log4net.Appender.RollingFileAppender">
<!--定義文件存放位置,Info和Error保存在不同的文件夾,方便理解-->
<file value="Log\\Info\\"/> <!--日誌路徑-->
<appendToFile value="true"/>
<rollingStyle value="Date"/> <!--日誌根據日期滾動-->
<datePattern value="yyyyMMdd'.txt'"/> <!--日誌文件名格式為:20080831.txt-->
<staticLogFileName value="false"/> <!--日誌文件名是否是固定不變的-->
<param name="MaxSizeRollBackups" value="100"/> <!--log保留天數-->
<layout type="log4net.Layout.PatternLayout"> <!--輸出格式-->
<!--樣例:
記錄時間:2016-10-11 14:03:00,540
線程ID:[1]
日誌級別: INFO 錯誤內容-->
<conversionPattern value="記錄時間:%date %n線程ID:[%thread] %n
日誌級別: %level %message %newline "/>
</layout>
<!-- INFO輸出的等級-->
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="INFO" />
<param name="LevelMax" value="INFO" />
</filter>
</appender>
<!--Error介質設置-->
<appender name="ErrorRollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Log\\Error\\"/>
<appendToFile value="true"/>
<rollingStyle value="Date"/>
<datePattern value="yyyyMMdd'.txt'"/>
<staticLogFileName value="false"/>
<param name="MaxSizeRollBackups" value="100"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="記錄時間:%date %n線程ID:[%thread] %n
日誌級別: %level %message%newline "/>
</layout>
<!--設置輸出的等級 ERROR-->
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="ERROR" />
<param name="LevelMax" value="ERROR" />
</filter>
</appender>
<!-- 控制台前臺顯示日誌 -->
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
<mapping>
<level value="Info" />
<foreColor value="Green" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="Info" />
<param name="LevelMax" value="Fatal" />
</filter>
</appender>
</log4net>
</configuration>
3、在AssemblyInfo.cs中添加代碼,用於調用Log4Net.config:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Log4Net.config", Watch = true)]
或者在程式中添加
log4net.Config.XmlConfigurator.Configure();
4、實現LogHelper,代碼如下:
public class LogHelper
{
private static ILog log = log4net.LogManager.GetLogger("LogHelper");
/// <summary>
/// 整理異常信息
/// </summary>
/// <param name="error"></param>
/// <returns></returns>
private static string Msg(Exception error)
{
string str = "";
if (error != null)
{
str = string.Format("異常類型:{0}\r\n異常消息:{1}\r\n異常信息:{2}\r\n",
error.GetType().Name, error.Message, error.StackTrace);
}
return str;
}
/// <summary>
/// 輸出異常信息
/// </summary>
/// <param name="t"></param>
/// <param name="ex"></param>
public static void LogError(Exception ex)
{
log.Error(Msg(ex));
}
/// <summary>
/// 輸出日記信息
/// </summary>
/// <param name="str"></param>
public static void LogInfo(string str)
{
log.Info(str);
}
}
Log4net框架定義了一個叫做LogManager的類,用來管理所有的logger對象。它有一個GetLogger()靜態方法,用我們提供的名字參數來檢索已經存在的Logger對象。如果框架里不存在該Logger對象,它也會為我們創建一個Logger對象。LogManager.Exists(”name”)只獲取而不進行創建,不存在則返回null;
ILog log = log4net.LogManager.GetLogger("logger-name");
Repository
Repository主要用於負責日誌對象組織結構的維護。在log4net的以前版本中,框架僅支持分等級的組織結構(hierarchical organization)。這種等級結構本質上是庫的一個實現,並且定義在log4net.Repository.Hierarchy 名字空間中。要實現一個Repository,需要實現log4net.Repository.ILoggerRepository 介面。但是通常並不是直接實現該介面,而是以log4net.Repository.LoggerRepositorySkeleton為基類繼承。體系庫 (hierarchical repository )則由log4net.Repository.Hierarchy.Hierarchy類實現。
如果你是個log4net框架的使用者,而非擴展者,那麼你幾乎不會在你的代碼里用到Repository的類。相反的,你需要用到LogManager類來自動管理庫和日誌對象。
Appender
一個好的日誌框架應該能夠產生多目的地的輸出。比如說輸出到控制台或保存到一個日誌文件。log4net 能夠很好的滿足這些要求。它使用一個叫做Appender的組件來定義輸出介質。正如名字所示,這些組件把它們附加到Logger日誌組件上並將輸出傳遞到輸出流中。你可以把多個Appender組件附加到一個日誌對象上。 Log4net框架提供了幾個Appender組件。關於log4net提供的Appender組件的完整列表可以在log4net框架的幫助手冊中找到。有了這些現成的Appender組件,一般來說通過配置Filters和Layout來實現日誌的過濾和輸出格式。但是如果你願意,可以從log4net.Appender.AppenderSkeleton類繼承。
通過設置Type來配置輸出方式:
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 系統。
UdpAppende將日誌以無連接UDP數據報的形式送到遠程宿主或用UdpClient的形式廣播。
Appender Filters
一個Appender 對象預設地將所有的日誌事件傳遞到輸出流。Appender的過濾器(Appender Filters) 可以按照不同的標準過濾日誌事件。在log4net.Filter的名字空間下已經有幾個預定義的過濾器。使用這些過濾器,你可以按照日誌級別範圍過濾日誌事件,或者按照某個特殊的字元串進行過濾。你可以在API的幫助文件中發現更多關於過濾器的信息。
過濾器通常有以下幾種:
DenyAllFilter 阻止所有的日誌事件被記錄
LevelMatchFilter 只有指定等級的日誌事件才被記錄
LevelRangeFilter 日誌等級在指定範圍內的事件才被記錄
LoggerMatchFilter 與Logger名稱匹配,才記錄
PropertyFilter 消息匹配指定的屬性值時才被記錄
StringMathFilter 消息匹配指定的字元串才被記錄
Layout
Layout 組件用於向用戶顯示最後經過格式化的輸出信息。輸出信息可以以多種格式顯示,主要依賴於我們採用的Layout組件類型。可以是線性的或一個XML文件。Layout組件和一個Appender組件一起工作。API幫助手冊中有關於不同Layout組件的列表。一個Appender對象,只能對應一個Layout對象。要實現你自己的Layout類,你需要從log4net.Layout.LayoutSkeleton類繼承,它實現了ILayout介面。
Layout用於控制Appender的輸出格式,可以是線性的也可以是XML。
最常用的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。
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。
日誌的等級(level),它們由高到底分別為:
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。
Object Renders
它將告訴logger如何把一個對象轉化為一個字元串記錄到日誌里。(ILog中定義的介面接收的參數是Object,而不是String。)
例如你想把Orange對象記錄到日誌中,但此時logger只會調用Orange預設的ToString方法而已。所以要定義一個OrangeRender類實現log4net.ObjectRender.IObjectRender介面,然後註冊它(我們在本文中的擴展不使用這種方法,而是直接實現一個自定義的Layout)。這時logger就會知道如何把Orange記錄到日誌中了。
<log4net>
所有的配置都在<log4net>元素里定義。
支持的屬性:
debug |
可選,取值是true或false,預設是false。設置為true,開啟log4net的內部調試。 |
update |
可選,取值是Merge(合併)或Overwrite(覆蓋),預設值是Merge。設置為Overwrite,在提交配置的時候會重置已經配置過的庫。 |
threshold |
可選,取值是repository(庫)中註冊的level,預設值是ALL。 |
支持的子元素節點:
appender |
1或多個 |
logger |
0或多個 |
renderer |
0或多個 |
root |
最多一個 |
param |
0或多個 |
<root>
實際上就是一個根logger,所有其它logger都預設繼承它,如果配置文件里沒有顯式定義,則框架使用根日誌中定義的屬性。root元素沒有屬性。
支持的子元素:
appender-ref |
0個或多個,要引用的appender的名字。 |
level |
最多一個。 只有在這個級別或之上的事件才會被記錄。 |
param |
0個或多個, 設置一些參數。 |
<logger>
在框架的體系裡,所有的日誌對象<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>
支持的屬性:
name |
必須的,logger的名稱 |
additivity |
可選,取值是true或false,預設值是true。設置為false時將阻止父logger中的appender。 |
支持的子元素:
appender-ref |
0個或多個, 要引用的appender的名字。 |
level |
最多一個。 只有在這個級別或之上的事件才會被記錄。 |
param |
0個或多個, 設置一些參數。 |
<appender>
日誌輸出方式,只能作為log4net的子元素。name屬性必須唯一,type屬性必須指定。
支持的屬性:
name |
必須的, Appender對象的名稱 |
type |
必須的, Appender對象的輸出類型 |
支持的子元素:
appender-ref |
0個或多個 允許此appender引用其他appender,並不是所以appender類型都支持。 |
filter |
0個或多個 定義此app使用的過濾器。 |
layout |
最多一個 定義appender使用的輸出格式。 |
param |
0個或多個 設置Appender類中對應的屬性的值。 |
實際上<appender>所能包含的子元素遠不止上面4個。
配置設置參考官方網站:
http://logging.apache.org/log4net/release/config-examples.html
<layout>
佈局,只能作為<appender>的子元素。
支持的屬性:
type |
必須的,Layout的類型 |
支持的子元素:
conversionPattern |
0個或多個, 設置一些參數。 |
<filter>
過濾器,只能作為<appender>的子元素。
支持的屬性:
type |
必須的,Filter的類型 |
支持的子元素:
param |
0個或多個, 設置一些參數。 |
<param>
<param>元素可以是任何元素的子元素。
支持的屬性:
name |
必須的,取值是父對象的參數名。 |
value |
可選的,value和type中,必須有一個屬性被指定。value是一個能被轉化為參數值的字元串。 |
type |
可選的,value和type中,必須有一個屬性被指定。type是一個類型名,如果type不是在log4net程式集中定義的,就需要使用全名。 |
支持的子元素:
param |
0個或多個, 設置一些參數。 |
示例——寫入回滾文件:
<appender name="ReflectLayout" type="log4net.Appender.RollingFileAppender">
<!--日誌文件路徑,文件夾不存在則新建-->
<!--按文件大小方式輸出時,在這裡指定文件名,並且當天的日誌在下一天時在文件名後自動追加當天日期形成新文件。--> 如<file value="Log\log.txt"/>
<!—按照日期形式輸出時,直接連接元素DatePattern的value形成文件路徑。此處使用這種方式 -->
<param name="File" value=" Log\\Info\\"/> 等價<file value="Log\\Info\\"/>
<!--是否追加到文件-->
<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>
寫入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">
<!--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>
註意:
向表中輸出的欄位不能多於數據表本身欄位,而反之則可以,但這些多餘欄位一定使其可以為空,否則便寫不到資料庫;
輸出欄位的類型一定是對應數據表欄位數據類型可以隱式轉換的,而且長度也不能超過,否則也不能寫入;
數據表欄位設置儘量可以為空,這樣可以避免一條日誌記錄存在空數據導致後面的日誌都記錄不了。
關聯配置文件
log4net預設關聯的是應用程式的配置文件App.config(BS程式是Web.config),可以使用程式集自定義屬性來進行設置。下麵來介紹一下這個自定義屬性:
log4net.Config.XmlConifguratorAttribute。
XmlConfiguratorAttribute有3個屬性:
ConfigFile: 配置文件的名字,文件路徑相對於應用程式目錄
(AppDomain.CurrentDomain.BaseDirectory)。ConfigFile屬性不能和ConfigFileExtension屬性一起使用。
ConfigFileExtension: 配置文件的擴展名,文件路徑相對於應用程式的目錄。
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));
或直接使用絕對路徑:
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(@"c:/log4net.config"));
Log4net的簡單擴展
通過重寫佈局Layout輸出傳入的 message對象的屬性
1.1重寫Layout類
通過繼承log4net.Layout.PatternLayout類,使用log4net.Core.LoggingEvent類的方法得到了要輸出的message類的名稱,然後通過反射得到各個屬性的值,使用PatternLayout類AddConverter方法傳入得到的值。
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>
1.3程式中如何使用
和一般使用方法基本相同,只是傳入的參數是一個自定義的類,類的屬性和配置文件中<layout>所有的%property{屬性}是一致的,即%property{屬性}在輸出的時候就查找傳入message類中有無對應的屬性,如果有就輸出值,沒有則輸出null。例:
log4net.ILog log = log4net.LogManager.GetLogger("ReflectionLayout");
2通過重新實現ILog介面來增加輸入的參數
2.1重寫LogImpl,LogManager類及實現ILog介面
這種方式是通過構造一個名為IMyLog介面,是繼承Ilog介面而來,然後分別在MyLogImpl,MyLogManager重新實現IMyLog介面,增加了每種方法的參數。MyLogImpl,MyLogManager分別繼承LogImpl,LogManager而來。
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>
2.3程式中如何使用
先引用IMyLog ,MyLogManager所在的命名空間,創建一個IMyLog對象,myLog的5 個方法,每個方法都有四個重載,增加了多參數的重載。例:
IMyLog myLog = MyLogManager.GetLogger("ExpandILog");
PatterLayout格式化字元表
轉換字元 |
效果 |
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之間,少了在右邊補空格,多了截斷。 |
參考
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