一. Log4Net簡介html
Log4net是從Java中的Log4j遷移過來的一個.Net版的開源日誌框架,它的功能很強大,能夠將日誌分爲不一樣的等級,以不一樣的格式輸出到不一樣的存儲介質中,好比:數據庫、txt文件、內存緩衝區、郵件、控制檯、ANSI終端、遠程接收端等等,咱們這裏主要介紹最經常使用的兩種:txt文件和數據庫。web
(PS:其它的存儲介質詳見 http://logging.apache.org/log4net/release/config-examples.html)數據庫
Log4net將日誌分爲五個級別,分別是: FATAL(致命錯誤) > ERROR(通常錯誤) > WARN(警告) > INFO(通常信息) > DEBUG(調試信息),每一個級別都對應着一組重載方法進行調用。apache
官網地址:http://logging.apache.org/log4net/index.htmlapp
Nuget地址:https://www.nuget.org/packages/log4net/框架
Nuget安裝:Install-Package log4netide
最新版本:2.0.8 (2018-08-09)工具
本節主要圍繞兩個主要的存儲介質:【txt文件】和【SQLServer數據庫】展開,涵蓋的知識點有:佈局
①. 基本的使用步驟。測試
②. 初始化關聯配置文件的幾種形式。
③. 代碼調用詳解。
④. 配置文件詳解。
⑤. 簡單的封裝和在MVC框架中的調用。
二. 基本使用步驟
咱們先以控制檯程序爲例,簡單介紹Log4net存儲日誌到txt文本文檔中,後面在作代碼的詳解。
1. 新建01-SimpleDemo控制檯程序,經過指令 【Install-Package log4net】安裝相應程序集。
2. 在默認配置文件中App.config(B/S程序則爲web.config)中進行配置,主要分兩塊:
A. 在<configuration></configuration>節點下新增節點下新增(要在其最頂部):
<configSections>
<section name = "log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
B. 在<configuration></configuration>根節點下,配置log4net的核心配置代碼, 主要節點以下:
<log4net> <appender> </appender> <root></root> </log4net>
詳細代碼以下:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <!-- 1. 添加log4net的節點聲明配置代碼--> 4 <configSections> 5 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> 6 </configSections> 7 <!--2. log4net的核心配置代碼--> 8 <log4net> 9 <!--把日誌信息輸出到以日期命名的文件裏--> 10 <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> 11 <!--文件夾的位置--> 12 <file value="D:\MyLog1\" /> 13 <appendToFile value="true" /> 14 <!--動態生成文件名--> 15 <param name="StaticLogFileName" value="false" /> 16 <!--以日期命名--> 17 <param name="DatePattern" value="yyyyMMdd".log"" /> 18 <rollingStyle value="Date" /> 19 <!--日誌在日誌文件中的佈局方式--> 20 <layout type="log4net.Layout.PatternLayout"> 21 <conversionPattern value="%newline %n記錄時間:%date %n線程ID:[%thread] %n日誌級別: %-5level %n出錯類:%logger property: [%property{NDC}] - %n錯誤描述:%message%newline %n"/> 22 </layout> 23 <!--使用最小鎖定模型(minimal locking model),以容許多個進程能夠寫入同一個文件 --> 24 <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> 25 </appender> 26 <root> 27 <level value="ALL"></level> 28 <appender-ref ref="RollingFileAppender"></appender-ref> 29 </root> 30 </log4net> 31 <startup> 32 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" /> 33 </startup> 34 </configuration>
3. 代碼調用
1 log4net.Config.XmlConfigurator.Configure(); 2 ILog log = LogManager.GetLogger("test"); 3 log.Debug("調試信息");
4. 運行結果
截止此處,日誌保存成功。
三. 初始化配置文件
前面提到在默認配置文件中App.config(B/S程序則爲web.config)中進行配置,能夠經過代碼 log4net.Config.XmlConfigurator.Configure(); 來初始化配置,或者還能夠經過 [assembly: log4net.Config.XmlConfigurator()] 反射的形式進行初始化配置,兩者能夠達到一樣的效果,表明了兩種初始化配置文件的形式。
PS: [assembly: log4net.Config.XmlConfigurator()] 能夠加在 當前使用文件的 namespace上做用於當前文件,或者加在Properties/AssemblyInfo.cs中,則該項目全局都無須再初始化了。
狀況一: 使用默認配置文件的狀況
1. 代碼配置:log4net.Config.XmlConfigurator.Configure();
2. 反射配置:[assembly: log4net.Config.XmlConfigurator()]
狀況二:修改默認配置文件的名稱爲:App1.config (這裏只是舉例,不多有修改默認配置文件名稱的)
1. 代碼配置: 首先將App1.config文件的屬性中的「生成操做」改成「 嵌入的資源」,而後經過如下代碼進行配置。
1 Assembly assembly = Assembly.GetExecutingAssembly(); 2 var xml = assembly.GetManifestResourceStream("_01_SimpleDemo.App1.config"); 3 log4net.Config.XmlConfigurator.Configure(xml);
注:代碼中的 _01_SimpleDemo 爲命名空間名。
2. 反射配置:[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.xml")]
注:用這種方式屬性中的:複製到輸出目錄須要改成:始終複製,生成操做不須要配置,使用默認:無 便可
狀況三:新建單獨xml文件,進行log4net的配置 (推薦採用這種方式,和原配置文件區分開,單獨配置方便,處理方式和狀況二是一致的)
1. 代碼配置:首先將log4net.xml文件的屬性中的「生成操做」改成「 嵌入的資源」,而後經過如下代碼進行配置。
1 Assembly assembly = Assembly.GetExecutingAssembly(); 2 var xml = assembly.GetManifestResourceStream("_01_SimpleDemo.log4net.xml"); 3 log4net.Config.XmlConfigurator.Configure(xml);
注:代碼中的 _01_SimpleDemo 爲命名空間名。
狀況四:不管是修改默認配置文件的名稱爲 或者 新建單獨的xml做爲配置文件 → 能夠經過絕對路徑的方式進行處理 【不推薦這種方式】
1. 直接寫絕對路徑 (注意這種方式【不須要】配置文件屬性爲 「嵌入的資源」)
1 log4net.Config.XmlConfigurator.Configure(new FileInfo(@"D:\06-個人開發之路\DotNet體系\05-DotNet框架篇\03-Log4net詳解\Code\01-SimpleDemo\log4net.xml"));
2 經過代碼獲取絕對路徑 (注意這種方式【不須要】配置文件屬性的「生成操做」改成 「嵌入的資源」,但須要改成「始終複製」,確保輸出到bin文件下)
1 string assemblyFilePath = Assembly.GetExecutingAssembly().Location; 2 string assemblyDirPath = Path.GetDirectoryName(assemblyFilePath); 3 string configFilePath = assemblyDirPath + " //log4net.xml"; 4 log4net.Config.XmlConfigurator.Configure(new FileInfo(configFilePath));
PS:B/S程序下經過 log4net.Config.XmlConfigurator.Configure(new FileInfo(Server.MapPath("~") + @"/log4net.xml")); 來配置。
四. 代碼調用詳解
Log4net容許多個ILog對象同時存在,經過代碼:ILog log = LogManager.GetLogger("xxx"); 來建立。
A: 日誌級別由高到低分別爲:FATAL(致命錯誤) > ERROR(通常錯誤) > WARN(警告) > INFO(通常信息) > DEBUG(調試信息),另外還有 OFF和 ALL 。
幾點說明:OFF表示全部信息都不寫入,ALL表示全部信息都寫入,咱們也能夠經過:<root><level value = "WARN" ></ level ></root>這樣配置,表示WARN級別以及高於WARN以上的級別纔會被寫入日誌。
B: 寫入日誌的方法有:Debug、Error、Fatal、Info、Warn五個方法,每一個方法都有兩個重載,以下圖:
分享在使用配置文件爲log4net.xml的狀況下的調用代碼:
1 Assembly assembly = Assembly.GetExecutingAssembly(); 2 var xml = assembly.GetManifestResourceStream("_01_SimpleDemo.log4net.xml"); 3 log4net.Config.XmlConfigurator.Configure(xml); 4 ILog log = LogManager.GetLogger("test"); 5 log.Debug("調試信息"); 6 log.Info("通常信息"); 7 log.Warn("警告"); 8 try 9 { 10 int.Parse("ddd"); 11 } 12 catch (Exception ex) 13 { 14 log.Error("通常錯誤", ex); 15 } 16 log.Fatal("致命錯誤");
五. 配置文件詳解
Log4net的配置文件主要分爲兩大部分:分別是 【自定義配置節點】和 【核心代碼配置】,自定義配置節點代碼固定,以下圖,核心代碼配置主要位於:<log4net></log4net>節點中,裏面包括<appender></appender>節點配置日日誌輸出途徑 和 <root></root>節點,用於設置記錄日誌的級別和啓用哪些輸出途徑。
幾點說明:
1. 自定義配置節點 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> 代碼固定,直接複製便可。
2. <root></root> 節點主要用來: 配置日誌的的輸出級別和加載日誌的輸出途徑。
A: level中的value值表示該值及其以上的日誌級別纔會輸出,日誌級別包括:OFF > FATAL(致命錯誤) > ERROR(通常錯誤) > WARN(警告) > INFO(通常信息) > DEBUG(調試信息) > ALL ,好比:
<level value="INFO"></level> 表示只有INFO及其以上的日誌級別纔會被保存。
PS:OFF表示全部信息都不寫入,ALL表示全部信息都寫入。
B: <appender-ref></appender-ref>標籤用於加載日誌的輸出途徑代碼,經過ref和appender標籤的中name屬性相關聯,好比:
<appender-ref ref="RollingFileAppender"></appender-ref> 表示開啓txt文檔保存日誌的方式。
3. <appender></appender>節點,用來配置日誌的輸出途徑的,本節主要介紹了輸出到 【txt文本文檔】中 和 【數據庫】。
A:分享一下數據庫的表結構,詳細配置見下面的代碼分享,須要注意字段類型相匹配,而且要顯式指定其長度。
B:關於txt文本文檔的命名,能夠存放到一個文件夾裏,也能夠按照時間來區分文件夾,而且命名能夠 動態+指定命名的方式。
C:關於日誌文件大小的說明和文件個數的說明,主要須要三個節點配合使用(實際開發中,若是一個txt特別大,打開的時候會很是的慢,卡頓,因此該步驟有必要配置一下)。
PS:首先要配置 RollingStyle 節點爲Size模式或者Composite模式,而後配置 maximumFileSize 節點設置每一個文件的大小,最後配置 MaxSizeRollBackups 節點,設置日誌文件的個數。超出大小後在全部文件名後自動增長正整數從新命名,數字最大的最先寫入。
用下面的代碼簡單測試一下:
1 <param name="RollingStyle" value="Composite" /> 2 <param name="maximumFileSize" value="10KB" /> 3 <param name="MaxSizeRollBackups" value="5" />
詳細代碼以下:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <!-- 一. 添加log4net的自定義配置節點--> 4 <configSections> 5 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> 6 </configSections> 7 <!--二. log4net的核心配置代碼--> 8 <log4net> 9 <!--(一) 配置日誌的輸出途徑--> 10 <!--1. 輸出途徑(一) 將日誌以回滾文件的形式寫到文件中--> 11 <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> 12 <!--1.1 文件夾的位置(也能夠寫相對路徑)--> 13 <param name="File" value="D:\MyLog1\" /> 14 <!--相對路徑 C/S程序生成在Debug目錄下--> 15 <!--<param name="File" value="/Logs/" />--> 16 <!--1.2 是否追加到文件--> 17 <param name="AppendToFile" value="true" /> 18 <!--1.3 使用最小鎖定模型(minimal locking model),以容許多個進程能夠寫入同一個文件 --> 19 <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> 20 <!--1.4 配置Unicode編碼--> 21 <Encoding value="UTF-8" /> 22 <!--1.5 是否只寫到一個文件裏--> 23 <param name="StaticLogFileName" value="false" /> 24 <!--1.6 配置按照何種方式產生多個日誌文件 (Date:日期、Size:文件大小、Composite:日期和文件大小的混合方式)--> 25 <param name="RollingStyle" value="Composite" /> 26 <!--1.7 介紹多種日誌的的命名和存放在磁盤的形式--> 27 <!--1.7.1 在根目錄下直接以日期命名txt文件 注意"的位置,去空格 --> 28 <param name="DatePattern" value="yyyy-MM-dd".log"" /> 29 <!--1.7.2 在根目錄下按日期產生文件夾,文件名固定 test.log --> 30 <!--<param name="DatePattern" value="yyyy-MM-dd/"test.log"" />--> 31 <!--1.7.3 在根目錄下按日期產生文件夾,這是按日期產生文件夾,並在文件名前也加上日期 --> 32 <!--<param name="DatePattern" value="yyyyMMdd/yyyyMMdd"-test.log"" />--> 33 <!--1.7.4 在根目錄下按日期產生文件夾,這再造成下一級固定的文件夾 --> 34 <!--<param name="DatePattern" value="yyyyMMdd/"OrderInfor/test.log"" />--> 35 <!--1.8 配置每一個日誌的大小。【只在1.6 RollingStyle 選擇混合方式與文件大小方式下才起做用!!!】可用的單位:KB|MB|GB。不要使用小數,不然會一直寫入當前日誌, 36 超出大小後在全部文件名後自動增長正整數從新命名,數字最大的最先寫入。--> 37 <param name="maximumFileSize" value="10MB" /> 38 <!--1.9 最多產生的日誌文件個數,超過則保留最新的n個 將value的值設置-1,則不限文件個數 【只在1.6 RollingStyle 選擇混合方式與文件大小方式下才起做用!!!】 39 與1.8中maximumFileSize文件大小是配合使用的--> 40 <param name="MaxSizeRollBackups" value="5" /> 41 <!--1.10 配置文件文件的佈局格式,使用PatternLayout,自定義佈局--> 42 <layout type="log4net.Layout.PatternLayout"> 43 <conversionPattern value="記錄時間:%date %n線程ID:[%thread] %n日誌級別:%-5level %n出錯類:%logger property: [%property{NDC}] - %n錯誤描述:%message%newline %n%newline"/> 44 </layout> 45 </appender> 46 47 <!--2. 輸出途徑(二) 記錄日誌到數據庫--> 48 <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender"> 49 <!--2.1 設置緩衝區大小,只有日誌記錄超設定值纔會一塊寫入到數據庫--> 50 <param name="BufferSize" value="1" /> 51 <!--2.2 引用--> 52 <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> 53 <!--2.3 數據庫鏈接字符串--> 54 <connectionString value="data source=localhost;initial catalog=LogDB;integrated security=false;persist security info=True;User ID=sa;Password=123456" /> 55 <!--2.4 SQL語句插入到指定表--> 56 <commandText value="INSERT INTO LogInfor ([threadId],[log_level],[log_name],[log_msg],[log_exception],[log_time]) VALUES (@threadId, @log_level, @log_name, @log_msg, @log_exception,@log_time)" /> 57 <!--2.5 數據庫字段匹配--> 58 <!-- 線程號--> 59 <parameter> 60 <parameterName value="@threadId" /> 61 <dbType value="String" /> 62 <size value="100" /> 63 <layout type="log4net.Layout.PatternLayout"> 64 <conversionPattern value="%thread" /> 65 </layout> 66 </parameter> 67 <!--日誌級別--> 68 <parameter> 69 <parameterName value="@log_level" /> 70 <dbType value="String" /> 71 <size value="100" /> 72 <layout type="log4net.Layout.PatternLayout"> 73 <conversionPattern value="%level" /> 74 </layout> 75 </parameter> 76 <!--日誌記錄類名稱--> 77 <parameter> 78 <parameterName value="@log_name" /> 79 <dbType value="String" /> 80 <size value="100" /> 81 <layout type="log4net.Layout.PatternLayout"> 82 <conversionPattern value="%logger" /> 83 </layout> 84 </parameter> 85 <!--日誌信息--> 86 <parameter> 87 <parameterName value="@log_msg" /> 88 <dbType value="String" /> 89 <size value="5000" /> 90 <layout type="log4net.Layout.PatternLayout"> 91 <conversionPattern value="%message" /> 92 </layout> 93 </parameter> 94 <!--異常信息 指的是如Infor 方法的第二個參數的值--> 95 <parameter> 96 <parameterName value="@log_exception" /> 97 <dbType value="String" /> 98 <size value="2000" /> 99 <layout type="log4net.Layout.ExceptionLayout" /> 100 </parameter> 101 <!-- 日誌記錄時間--> 102 <parameter> 103 <parameterName value="@log_time" /> 104 <dbType value="DateTime" /> 105 <layout type="log4net.Layout.RawTimeStampLayout" /> 106 </parameter> 107 </appender> 108 <!--(二). 配置日誌的的輸出級別和加載日誌的輸出途徑--> 109 <root> 110 <!--1. level中的value值表示該值及其以上的日誌級別纔會輸出--> 111 <!--OFF > FATAL(致命錯誤) > ERROR(通常錯誤) > WARN(警告) > INFO(通常信息) > DEBUG(調試信息) > ALL --> 112 <!--OFF表示全部信息都不寫入,ALL表示全部信息都寫入--> 113 <level value="ALL"></level> 114 <!--2. append-ref標籤表示要加載前面的日誌輸出途徑代碼 經過ref和appender標籤的中name屬性相關聯--> 115 <appender-ref ref="RollingFileAppender"></appender-ref> 116 <appender-ref ref="AdoNetAppender"></appender-ref> 117 </root> 118 </log4net> 119 120 </configuration>
六. 簡單的封裝及完整代碼分享
這裏模擬在系統框架中對Log4net進行簡單的封裝,而後在MVC框架中調用,並分享所有代碼。
步驟一:新建Ypf.Utils類庫,做爲工具類庫,引入log4net程序集,並將前面用到的log4net.xml 複製進來,改屬性爲嵌入資源,而後新建LogUtils類(不要起名爲LogHelp),對Log4net的方法進行簡單的封裝,主要包括:初始化代碼、ILog實例建立、五類日誌級別的封裝。
特別注意:這種封裝會帶來一個問題,會致使輸出的文件中出錯類永遠顯示的爲LogUtils這個封裝類,這裏採用StackTrace類進行迂迴處理一下,就能夠定位到具體的出錯位置了,以下圖:
log4net.xml文件代碼以下:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <!-- 一. 添加log4net的自定義配置節點--> 4 <configSections> 5 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> 6 </configSections> 7 <!--二. log4net的核心配置代碼--> 8 <log4net> 9 <!--(一) 配置日誌的輸出途徑--> 10 <!--1. 輸出途徑(一) 將日誌以回滾文件的形式寫到文件中--> 11 <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> 12 <!--1.1 文件夾的位置(也能夠寫相對路徑)--> 13 <param name="File" value="D:\MyLog1\" /> 14 <!--相對路徑--> 15 <!--<param name="File" value="Logs/" />--> 16 <!--1.2 是否追加到文件--> 17 <param name="AppendToFile" value="true" /> 18 <!--1.3 使用最小鎖定模型(minimal locking model),以容許多個進程能夠寫入同一個文件 --> 19 <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> 20 <!--1.4 配置Unicode編碼--> 21 <Encoding value="UTF-8" /> 22 <!--1.5 是否只寫到一個文件裏--> 23 <param name="StaticLogFileName" value="false" /> 24 <!--1.6 配置按照何種方式產生多個日誌文件 (Date:日期、Size:文件大小、Composite:日期和文件大小的混合方式)--> 25 <param name="RollingStyle" value="Composite" /> 26 <!--1.7 介紹多種日誌的的命名和存放在磁盤的形式--> 27 <!--1.7.1 在根目錄下直接以日期命名txt文件 注意"的位置,去空格 --> 28 <param name="DatePattern" value="yyyy-MM-dd".log"" /> 29 <!--1.7.2 在根目錄下按日期產生文件夾,文件名固定 test.log --> 30 <!--<param name="DatePattern" value="yyyy-MM-dd/"test.log"" />--> 31 <!--1.7.3 在根目錄下按日期產生文件夾,這是按日期產生文件夾,並在文件名前也加上日期 --> 32 <!--<param name="DatePattern" value="yyyyMMdd/yyyyMMdd"-test.log"" />--> 33 <!--1.7.4 在根目錄下按日期產生文件夾,這再造成下一級固定的文件夾 --> 34 <!--<param name="DatePattern" value="yyyyMMdd/"OrderInfor/test.log"" />--> 35 <!--1.8 配置每一個日誌的大小。【只在1.6 RollingStyle 選擇混合方式與文件大小方式下才起做用!!!】可用的單位:KB|MB|GB。不要使用小數,不然會一直寫入當前日誌, 36 超出大小後在全部文件名後自動增長正整數從新命名,數字最大的最先寫入。--> 37 <param name="maximumFileSize" value="10MB" /> 38 <!--1.9 最多產生的日誌文件個數,超過則保留最新的n個 將value的值設置-1,則不限文件個數 【只在1.6 RollingStyle 選擇混合方式與文件大小方式下才起做用!!!】 39 與1.8中maximumFileSize文件大小是配合使用的--> 40 <param name="MaxSizeRollBackups" value="5" /> 41 <!--1.10 配置文件文件的佈局格式,使用PatternLayout,自定義佈局--> 42 <layout type="log4net.Layout.PatternLayout"> 43 <conversionPattern value="記錄時間:%date %n線程ID:[%thread] %n日誌級別:%-5level %n出錯類:%logger property: [%property{NDC}] - %n錯誤描述:%message%newline %n%newline"/> 44 </layout> 45 </appender> 46 47 <!--2. 輸出途徑(二) 記錄日誌到數據庫--> 48 <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender"> 49 <!--2.1 設置緩衝區大小,只有日誌記錄超設定值纔會一塊寫入到數據庫--> 50 <param name="BufferSize" value="1" /> 51 <!--2.2 引用--> 52 <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> 53 <!--2.3 數據庫鏈接字符串--> 54 <connectionString value="data source=localhost;initial catalog=LogDB;integrated security=false;persist security info=True;User ID=sa;Password=123456" /> 55 <!--2.4 SQL語句插入到指定表--> 56 <commandText value="INSERT INTO LogInfor ([threadId],[log_level],[log_name],[log_msg],[log_exception],[log_time]) VALUES (@threadId, @log_level, @log_name, @log_msg, @log_exception,@log_time)" /> 57 <!--2.5 數據庫字段匹配--> 58 <!-- 線程號--> 59 <parameter> 60 <parameterName value="@threadId" /> 61 <dbType value="String" /> 62 <size value="100" /> 63 <layout type="log4net.Layout.PatternLayout"> 64 <conversionPattern value="%thread" /> 65 </layout> 66 </parameter> 67 <!--日誌級別--> 68 <parameter> 69 <parameterName value="@log_level" /> 70 <dbType value="String" /> 71 <size value="100" /> 72 <layout type="log4net.Layout.PatternLayout"> 73 <conversionPattern value="%level" /> 74 </layout> 75 </parameter> 76 <!--日誌記錄類名稱--> 77 <parameter> 78 <parameterName value="@log_name" /> 79 <dbType value="String" /> 80 <size value="100" /> 81 <layout type="log4net.Layout.PatternLayout"> 82 <conversionPattern value="%logger" /> 83 </layout> 84 </parameter> 85 <!--日誌信息--> 86 <parameter> 87 <parameterName value="@log_msg" /> 88 <dbType value="String" /> 89 <size value="5000" /> 90 <layout type="log4net.Layout.PatternLayout"> 91 <conversionPattern value="%message" /> 92 </layout> 93 </parameter> 94 <!--異常信息 指的是如Infor 方法的第二個參數的值--> 95 <parameter> 96 <parameterName value="@log_exception" /> 97 <dbType value="String" /> 98 <size value="2000" /> 99 <layout type="log4net.Layout.ExceptionLayout" /> 100 </parameter> 101 <!-- 日誌記錄時間--> 102 <parameter> 103 <parameterName value="@log_time" /> 104 <dbType value="DateTime" /> 105 <layout type="log4net.Layout.RawTimeStampLayout" /> 106 </parameter> 107 </appender> 108 <!--(二). 配置日誌的的輸出級別和加載日誌的輸出途徑--> 109 <root> 110 <!--1. level中的value值表示該值及其以上的日誌級別纔會輸出--> 111 <!--OFF > FATAL(致命錯誤) > ERROR(通常錯誤) > WARN(警告) > INFO(通常信息) > DEBUG(調試信息) > ALL --> 112 <!--OFF表示全部信息都不寫入,ALL表示全部信息都寫入--> 113 <level value="ALL"></level> 114 <!--2. append-ref標籤表示要加載前面的日誌輸出途徑代碼 經過ref和appender標籤的中name屬性相關聯--> 115 <appender-ref ref="RollingFileAppender"></appender-ref> 116 <appender-ref ref="AdoNetAppender"></appender-ref> 117 </root> 118 </log4net> 119 120 </configuration>
LogUtils類代碼以下
1 using log4net; 2 using System; 3 using System.Collections.Generic; 4 using System.Diagnostics; 5 using System.Linq; 6 using System.Reflection; 7 using System.Text; 8 using System.Threading.Tasks; 9 10 namespace Ypf.Utils 11 { 12 public class LogUtils 13 { 14 //能夠聲明多個日誌對象 15 public static ILog log = LogManager.GetLogger(typeof(LogUtils)); 16 17 #region 01-初始化Log4net的配置 18 /// <summary> 19 /// 初始化Log4net的配置 20 /// xml文件必定要改成嵌入的資源 21 /// </summary> 22 public static void InitLog4Net() 23 { 24 Assembly assembly = Assembly.GetExecutingAssembly(); 25 var xml = assembly.GetManifestResourceStream("Ypf.Utils.log4net.xml"); 26 log4net.Config.XmlConfigurator.Configure(xml); 27 } 28 #endregion 29 30 31 32 33 /************************* 五種不一樣日誌級別 *******************************/ 34 //FATAL(致命錯誤) > ERROR(通常錯誤) > WARN(警告) > INFO(通常信息) > DEBUG(調試信息) 35 36 /// <summary> 37 /// 將調試的信息輸出,能夠定位到具體的位置(解決高層封裝帶來的問題) 38 /// </summary> 39 /// <returns></returns> 40 private static string getDebugInfo() 41 { 42 StackTrace trace = new StackTrace(true); 43 return trace.ToString(); 44 } 45 46 #region 01-DEBUG(調試信息) 47 /// <summary> 48 /// Debug 49 /// </summary> 50 /// <param name="msg">日誌信息</param> 51 public static void Debug(string msg) 52 { 53 log.Debug(getDebugInfo() + msg); 54 } 55 /// <summary> 56 /// Debug 57 /// </summary> 58 /// <param name="msg">日誌信息</param> 59 /// <param name="exception">錯誤信息</param> 60 public static void Debug(string msg, Exception exception) 61 { 62 log.Debug(getDebugInfo() + msg, exception); 63 } 64 65 #endregion 66 67 #region 02-INFO(通常信息) 68 /// <summary> 69 /// Info 70 /// </summary> 71 /// <param name="msg">日誌信息</param> 72 public static void Info(string msg) 73 { 74 log.Info(getDebugInfo() + msg); 75 } 76 /// <summary> 77 /// Info 78 /// </summary> 79 /// <param name="msg">日誌信息</param> 80 /// <param name="exception">錯誤信息</param> 81 public static void Info(string msg, Exception exception) 82 { 83 log.Info(getDebugInfo() + msg, exception); 84 } 85 #endregion 86 87 #region 03-WARN(警告) 88 /// <summary> 89 /// Warn 90 /// </summary> 91 /// <param name="msg">日誌信息</param> 92 public static void Warn(string msg) 93 { 94 log.Warn(getDebugInfo() + msg); 95 } 96 /// <summary> 97 /// Warn 98 /// </summary> 99 /// <param name="msg">日誌信息</param> 100 /// <param name="exception">錯誤信息</param> 101 public static void Warn(string msg, Exception exception) 102 { 103 log.Warn(getDebugInfo() + msg, exception); 104 } 105 #endregion 106 107 #region 04-ERROR(通常錯誤) 108 /// <summary> 109 /// Error 110 /// </summary> 111 /// <param name="msg">日誌信息</param> 112 public static void Error(string msg) 113 { 114 log.Error(getDebugInfo() + msg); 115 } 116 /// <summary> 117 /// Error 118 /// </summary> 119 /// <param name="msg">日誌信息</param> 120 /// <param name="exception">錯誤信息</param> 121 public static void Error(string msg, Exception exception) 122 { 123 log.Error(getDebugInfo() + msg, exception); 124 } 125 #endregion 126 127 #region 05-FATAL(致命錯誤) 128 /// <summary> 129 /// Fatal 130 /// </summary> 131 /// <param name="msg">日誌信息</param> 132 public static void Fatal(string msg) 133 { 134 log.Fatal(getDebugInfo() + msg); 135 } 136 /// <summary> 137 /// Fatal 138 /// </summary> 139 /// <param name="msg">日誌信息</param> 140 /// <param name="exception">錯誤信息</param> 141 public static void Fatal(string msg, Exception exception) 142 { 143 log.Fatal(getDebugInfo() + msg, exception); 144 } 145 146 #endregion 147 148 149 150 } 151 }
步驟二:新建名Ypf.MVC的MVC5框架,添加對Ypf.Utils類庫的引用,在Global.asax全局文件中添加對 對Log4net進行初始化。
而後就能夠愉快的進行調用測試了哦。
1 /// <summary> 2 /// 測試log4net 3 /// 首先須要再Global中初始化log4net 4 /// </summary> 5 /// <returns></returns> 6 public ActionResult Index() 7 { 8 //FATAL(致命錯誤) > ERROR(通常錯誤) > WARN(警告) > INFO(通常信息) > DEBUG(調試信息) 9 LogUtils.Debug("出錯了"); 10 try 11 { 12 int.Parse("ddf"); 13 } 14 catch (Exception ex) 15 { 16 LogUtils.Debug("出錯了",ex); 17 } 18 19 LogUtils.Info("出錯了"); 20 try 21 { 22 int.Parse("ddf"); 23 } 24 catch (Exception ex) 25 { 26 LogUtils.Info("出錯了", ex); 27 } 28 29 LogUtils.Warn("出錯了"); 30 try 31 { 32 int.Parse("ddf"); 33 } 34 catch (Exception ex) 35 { 36 LogUtils.Warn("出錯了", ex); 37 } 38 39 LogUtils.Error("出錯了"); 40 try 41 { 42 int.Parse("ddf"); 43 } 44 catch (Exception ex) 45 { 46 LogUtils.Error("出錯了", ex); 47 } 48 49 LogUtils.Fatal("出錯了"); 50 try 51 { 52 int.Parse("ddf"); 53 } 54 catch (Exception ex) 55 { 56 LogUtils.Fatal("出錯了", ex); 57 } 58 59 return View(); 60 }
七. 補充:分文件存放
在前面的介紹中,忽略了一種狀況,各類類型的日誌(操做日誌也好,錯誤日誌也好)都存放在一個txt文檔裏,在實際開發中很不方便,在這裏介紹一種利用Log4net過濾器實現不一樣日誌分文件夾存放的功能。
幾種過濾器,能夠用來過濾掉Appender中的內容:
DenyAllFilter: 阻止全部的日誌事件被記錄
LevelMatchFilter: 只有指定等級的日誌事件才被記錄
LevelRangeFilter :日誌等級在指定範圍內的事件才被記錄
LoggerMatchFilter: 與Logger名稱匹配,才記錄
PropertyFilter: 消息匹配指定的屬性值時才被記錄
StringMathFilter: 消息匹配指定的字符串才被記錄
分文件夾存放的核心所在:
①. 配置文件的調整:利用LoggerMatchFilter和DenyAllFilter過濾器實現分文件存放。
②:聲明ILog對象的時候,須要與LoggerMatchFilter過濾器中的Value值相對應,才能保證該ILog對象記錄的日誌存放到該Appender節點對應的路徑下。
③. 高層調用:
分享一下log4net的配置文件和LogUtils的封裝文件。
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <!-- 一. 添加log4net的自定義配置節點--> 4 <configSections> 5 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> 6 </configSections> 7 <!--二. log4net的核心配置代碼--> 8 <log4net> 9 <!--1. 輸出途徑(一) 將日誌以回滾文件的形式寫到文件中--> 10 11 <!--模式一:所有存放到一個文件夾裏--> 12 <appender name="log0" type="log4net.Appender.RollingFileAppender"> 13 <!--1.1 文件夾的位置(也能夠寫相對路徑)--> 14 <param name="File" value="D:\MyLog\" /> 15 <!--相對路徑--> 16 <!--<param name="File" value="Logs/" />--> 17 <!--1.2 是否追加到文件--> 18 <param name="AppendToFile" value="true" /> 19 <!--1.3 使用最小鎖定模型(minimal locking model),以容許多個進程能夠寫入同一個文件 --> 20 <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> 21 <!--1.4 配置Unicode編碼--> 22 <Encoding value="UTF-8" /> 23 <!--1.5 是否只寫到一個文件裏--> 24 <param name="StaticLogFileName" value="false" /> 25 <!--1.6 配置按照何種方式產生多個日誌文件 (Date:日期、Size:文件大小、Composite:日期和文件大小的混合方式)--> 26 <param name="RollingStyle" value="Composite" /> 27 <!--1.7 介紹多種日誌的的命名和存放在磁盤的形式--> 28 <!--1.7.1 在根目錄下直接以日期命名txt文件 注意"的位置,去空格 --> 29 <param name="DatePattern" value="yyyy-MM-dd".log"" /> 30 <!--1.7.2 在根目錄下按日期產生文件夾,文件名固定 test.log --> 31 <!--<param name="DatePattern" value="yyyy-MM-dd/"test.log"" />--> 32 <!--1.7.3 在根目錄下按日期產生文件夾,這是按日期產生文件夾,並在文件名前也加上日期 --> 33 <!--<param name="DatePattern" value="yyyyMMdd/yyyyMMdd"-test.log"" />--> 34 <!--1.7.4 在根目錄下按日期產生文件夾,這再造成下一級固定的文件夾 --> 35 <!--<param name="DatePattern" value="yyyyMMdd/"OrderInfor/test.log"" />--> 36 <!--1.8 配置每一個日誌的大小。【只在1.6 RollingStyle 選擇混合方式與文件大小方式下才起做用!!!】可用的單位:KB|MB|GB。不要使用小數,不然會一直寫入當前日誌, 37 超出大小後在全部文件名後自動增長正整數從新命名,數字最大的最先寫入。--> 38 <param name="maximumFileSize" value="10MB" /> 39 <!--1.9 最多產生的日誌文件個數,超過則保留最新的n個 將value的值設置-1,則不限文件個數 【只在1.6 RollingStyle 選擇混合方式與文件大小方式下才起做用!!!】 40 與1.8中maximumFileSize文件大小是配合使用的--> 41 <param name="MaxSizeRollBackups" value="5" /> 42 <!--1.10 配置文件文件的佈局格式,使用PatternLayout,自定義佈局--> 43 <layout type="log4net.Layout.PatternLayout"> 44 <conversionPattern value="記錄時間:%date %n線程ID:[%thread] %n日誌級別:%-5level %n出錯類:%logger property: [%property{NDC}] - %n錯誤描述:%message%newline %n%newline"/> 45 </layout> 46 </appender> 47 48 <!--模式二:分文件夾存放--> 49 <!--文件夾1--> 50 <appender name="log1" type="log4net.Appender.RollingFileAppender"> 51 <param name="File" value="D:\MyLog\OneLog\" /> 52 <param name="AppendToFile" value="true" /> 53 <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> 54 <Encoding value="UTF-8" /> 55 <param name="StaticLogFileName" value="false" /> 56 <param name="RollingStyle" value="Composite" /> 57 <param name="DatePattern" value="yyyy-MM-dd".log"" /> 58 <param name="maximumFileSize" value="10MB" /> 59 <param name="MaxSizeRollBackups" value="5" /> 60 <layout type="log4net.Layout.PatternLayout"> 61 <conversionPattern value="%message%newline" /> 62 </layout> 63 <!--下面是利用過濾器進行分文件夾存放,兩種過濾器進行配合--> 64 <!--與Logger名稱(OneLog)匹配,才記錄,--> 65 <filter type="log4net.Filter.LoggerMatchFilter"> 66 <loggerToMatch value="OneLog" /> 67 </filter> 68 <!--阻止全部的日誌事件被記錄--> 69 <filter type="log4net.Filter.DenyAllFilter" /> 70 </appender> 71 <!--文件夾2--> 72 <appender name="log2" type="log4net.Appender.RollingFileAppender"> 73 <param name="File" value="D:\MyLog\TwoLog\" /> 74 <param name="AppendToFile" value="true" /> 75 <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> 76 <Encoding value="UTF-8" /> 77 <param name="StaticLogFileName" value="false" /> 78 <param name="RollingStyle" value="Composite" /> 79 <param name="DatePattern" value="yyyy-MM-dd".log"" /> 80 <param name="maximumFileSize" value="10MB" /> 81 <param name="MaxSizeRollBackups" value="5" /> 82 <layout type="log4net.Layout.PatternLayout"> 83 <conversionPattern value="%message%newline" /> 84 </layout> 85 <!--下面是利用過濾器進行分文件夾存放,兩種過濾器進行配合--> 86 <!--與Logger名稱(TwoLog)匹配,才記錄,--> 87 <filter type="log4net.Filter.LoggerMatchFilter"> 88 <loggerToMatch value="TwoLog" /> 89 </filter> 90 <!--阻止全部的日誌事件被記錄--> 91 <filter type="log4net.Filter.DenyAllFilter" /> 92 </appender> 93 94 95 <!--2. 輸出途徑(二) 記錄日誌到數據庫--> 96 <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender"> 97 <!--2.1 設置緩衝區大小,只有日誌記錄超設定值纔會一塊寫入到數據庫--> 98 <param name="BufferSize" value="1" /> 99 <!--2.2 引用--> 100 <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> 101 <!--2.3 數據庫鏈接字符串--> 102 <connectionString value="data source=localhost;initial catalog=LogDB;integrated security=false;persist security info=True;User ID=sa;Password=123456" /> 103 <!--2.4 SQL語句插入到指定表--> 104 <commandText value="INSERT INTO LogInfor ([threadId],[log_level],[log_name],[log_msg],[log_exception],[log_time]) VALUES (@threadId, @log_level, @log_name, @log_msg, @log_exception,@log_time)" /> 105 <!--2.5 數據庫字段匹配--> 106 <!-- 線程號--> 107 <parameter> 108 <parameterName value="@threadId" /> 109 <dbType value="String" /> 110 <size value="100" /> 111 <layout type="log4net.Layout.PatternLayout"> 112 <conversionPattern value="%thread" /> 113 </layout> 114 </parameter> 115 <!--日誌級別--> 116 <parameter> 117 <parameterName value="@log_level" /> 118 <dbType value="String" /> 119 <size value="100" /> 120 <layout type="log4net.Layout.PatternLayout"> 121 <conversionPattern value="%level" /> 122 </layout> 123 </parameter> 124 <!--日誌記錄類名稱--> 125 <parameter> 126 <parameterName value="@log_name" /> 127 <dbType value="String" /> 128 <size value="100" /> 129 <layout type="log4net.Layout.PatternLayout"> 130 <conversionPattern value="%logger" /> 131 </layout> 132 </parameter> 133 <!--日誌信息--> 134 <parameter> 135 <parameterName value="@log_msg" /> 136 <dbType value="String" /> 137 <size value="5000" /> 138 <layout type="log4net.Layout.PatternLayout"> 139 <conversionPattern value="%message" /> 140 </layout> 141 </parameter> 142 <!--異常信息 指的是如Infor 方法的第二個參數的值--> 143 <parameter> 144 <parameterName value="@log_exception" /> 145 <dbType value="String" /> 146 <size value="2000" /> 147 <layout type="log4net.Layout.ExceptionLayout" /> 148 </parameter> 149 <!-- 日誌記錄時間--> 150 <parameter> 151 <parameterName value="@log_time" /> 152 <dbType value="DateTime" /> 153 <layout type="log4net.Layout.RawTimeStampLayout" /> 154 </parameter> 155 </appender> 156 157 158 <!--(二). 配置日誌的的輸出級別和加載日誌的輸出途徑--> 159 <root> 160 <!--1. level中的value值表示該值及其以上的日誌級別纔會輸出--> 161 <!--OFF > FATAL(致命錯誤) > ERROR(通常錯誤) > WARN(警告) > INFO(通常信息) > DEBUG(調試信息) > ALL --> 162 <!--OFF表示全部信息都不寫入,ALL表示全部信息都寫入--> 163 <level value="ALL"></level> 164 <!--2. append-ref標籤表示要加載前面的日誌輸出途徑代碼 經過ref和appender標籤的中name屬性相關聯--> 165 166 <!--<appender-ref ref="AdoNetAppender"></appender-ref>--> 167 <appender-ref ref="log0"></appender-ref> 168 <appender-ref ref="log1"></appender-ref> 169 <appender-ref ref="log2"></appender-ref> 170 </root> 171 </log4net> 172 173 </configuration>
1 using log4net; 2 using System; 3 using System.Collections.Generic; 4 using System.Diagnostics; 5 using System.Linq; 6 using System.Reflection; 7 using System.Text; 8 using System.Threading.Tasks; 9 10 namespace Ypf.Utils 11 { 12 public class LogUtils 13 { 14 //聲明文件夾名稱(這裏分兩個文件夾) 15 static string log1Name = "OneLog"; 16 static string log2Name = "TwoLog"; 17 18 //能夠聲明多個日誌對象 19 //模式一:不分文件夾 20 public static ILog log = LogManager.GetLogger(typeof(LogUtils)); 21 22 //模式二:分文件夾 23 //若是是要分文件夾存儲,這裏的名稱須要和配置文件中loggerToMatch節點中的value相配合 24 //1. OneLog文件夾 25 public static ILog log1 = LogManager.GetLogger(log1Name); 26 //2. TwoLog文件夾 27 public static ILog log2 = LogManager.GetLogger(log2Name); 28 29 #region 01-初始化Log4net的配置 30 /// <summary> 31 /// 初始化Log4net的配置 32 /// xml文件必定要改成嵌入的資源 33 /// </summary> 34 public static void InitLog4Net() 35 { 36 Assembly assembly = Assembly.GetExecutingAssembly(); 37 var xml = assembly.GetManifestResourceStream("Ypf.Utils.log4net.xml"); 38 log4net.Config.XmlConfigurator.Configure(xml); 39 } 40 #endregion 41 42 /************************* 五種不一樣日誌級別 *******************************/ 43 //FATAL(致命錯誤) > ERROR(通常錯誤) > WARN(警告) > INFO(通常信息) > DEBUG(調試信息) 44 45 #region 00-將調試的信息輸出,能夠定位到具體的位置(解決高層封裝帶來的問題) 46 /// <summary> 47 /// 將調試的信息輸出,能夠定位到具體的位置(解決高層封裝帶來的問題) 48 /// </summary> 49 /// <returns></returns> 50 private static string getDebugInfo() 51 { 52 StackTrace trace = new StackTrace(true); 53 return trace.ToString(); 54 } 55 #endregion 56 57 #region 01-DEBUG(調試信息) 58 /// <summary> 59 /// DEBUG(調試信息) 60 /// </summary> 61 /// <param name="msg">日誌信息</param> 62 /// <param name="logName">文件夾名稱</param> 63 public static void Debug(string msg, string logName = "") 64 { 65 if (logName == "") 66 { 67 log.Debug(getDebugInfo() + msg); 68 } 69 else if (logName == log1Name) 70 { 71 log1.Debug(msg); 72 } 73 else if (logName == log2Name) 74 { 75 log2.Debug(msg); 76 } 77 } 78 /// <summary> 79 /// Debug 80 /// </summary> 81 /// <param name="msg">日誌信息</param> 82 /// <param name="exception">錯誤信息</param> 83 public static void Debug(string msg, Exception exception) 84 { 85 log.Debug(getDebugInfo() + msg, exception); 86 } 87 88 #endregion 89 90 #region 02-INFO(通常信息) 91 /// <summary> 92 /// INFO(通常信息) 93 /// </summary> 94 /// <param name="msg">日誌信息</param> 95 /// <param name="logName">文件夾名稱</param> 96 public static void Info(string msg, string logName = "") 97 { 98 if (logName == "") 99 { 100 log.Info(getDebugInfo() + msg); 101 } 102 else if (logName == log1Name) 103 { 104 log1.Info(msg); 105 } 106 else if (logName == log2Name) 107 { 108 log2.Info(msg); 109 } 110 } 111 /// <summary> 112 /// Info 113 /// </summary> 114 /// <param name="msg">日誌信息</param> 115 /// <param name="exception">錯誤信息</param> 116 public static void Info(string msg, Exception exception) 117 { 118 log.Info(getDebugInfo() + msg, exception); 119 } 120 #endregion 121 122 #region 03-WARN(警告) 123 /// <summary> 124 ///WARN(警告) 125 /// </summary> 126 /// <param name="msg">日誌信息</param> 127 /// <param name="logName">文件夾名稱</param> 128 public static void Warn(string msg, string logName = "") 129 { 130 if (logName == "") 131 { 132 log.Warn(getDebugInfo() + msg); 133 } 134 else if (logName == log1Name) 135 { 136 log1.Warn(msg); 137 } 138 else if (logName == log2Name) 139 { 140 log2.Warn(msg); 141 } 142 } 143 /// <summary> 144 /// Warn 145 /// </summary> 146 /// <param name="msg">日誌信息</param> 147 /// <param name="exception">錯誤信息</param> 148 public static void Warn(string msg, Exception exception) 149 { 150 log.Warn(getDebugInfo() + msg, exception); 151 } 152 #endregion 153 154 #region 04-ERROR(通常錯誤) 155 /// <summary> 156 /// ERROR(通常錯誤) 157 /// </summary> 158 /// <param name="msg">日誌信息</param> 159 /// <param name="logName">文件夾名稱</param> 160 public static void Error(string msg, string logName = "") 161 { 162 if (logName == "") 163 { 164 log.Error(getDebugInfo() + msg); 165 } 166 else if (logName == log1Name) 167 { 168 log1.Error(msg); 169 } 170 else if (logName == log2Name) 171 { 172 log2.Error(msg); 173 } 174 } 175 /// <summary> 176 /// Error 177 /// </summary> 178 /// <param name="msg">日誌信息</param> 179 /// <param name="exception">錯誤信息</param> 180 public static void Error(string msg, Exception exception) 181 { 182 log.Error(getDebugInfo() + msg, exception); 183 } 184 #endregion 185 186 #region 05-FATAL(致命錯誤) 187 /// <summary> 188 /// FATAL(致命錯誤) 189 /// </summary> 190 /// <param name="msg">日誌信息</param> 191 /// <param name="logName">文件夾名稱</param> 192 public static void Fatal(string msg, string logName = "") 193 { 194 if (logName == "") 195 { 196 log.Fatal(getDebugInfo() + msg); 197 } 198 else if (logName == log1Name) 199 { 200 log1.Fatal(msg); 201 } 202 else if (logName == log2Name) 203 { 204 log2.Fatal(msg); 205 } 206 } 207 /// <summary> 208 /// Fatal 209 /// </summary> 210 /// <param name="msg">日誌信息</param> 211 /// <param name="exception">錯誤信息</param> 212 public static void Fatal(string msg, Exception exception) 213 { 214 log.Fatal(getDebugInfo() + msg, exception); 215 } 216 217 #endregion 218 219 220 221 } 222 }
!