一、資料準備
在SQL Server中創建記錄日志的資料表LogDetail:
CREATE TABLE [dbo].[LogDetail]( [LogID] [INT] IDENTITY(1,1) NOT NULL, --自增ID [LogDate] [DATETIME] NULL, --日志時間 [LogLevel] [NVARCHAR](10) NULL, --日志級別 [LogThread] [NVARCHAR](10) NULL, --執行緒ID [Logger] [NVARCHAR](50) NULL, --日志名稱 [LogMessage] [NVARCHAR](3000) NULL, --日志內容 CONSTRAINT [PK_LogDetail] PRIMARY KEY CLUSTERED ( [LogID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
在此表中,日志時間、日志級別、執行緒ID、日志名稱都是可以通過組態檔從Log4Net庫中取值的,需要重點處理的是日志內容欄位,
二、記錄日志到資料庫
2.1、組態檔
添加一個ConfigFile檔案夾,然后在其下面新建一個Log4NetToDB.config的組態檔,接著在其屬性的復制到輸出目錄項下選擇始終復制,
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> </configSections> <log4net debug="false"> <!--type:表示用哪種型別記錄日志,log4net.Appender.ADONetAppender表示用資料庫記錄日志,--> <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender"> <!--日志快取寫入條數,設定為0時只要有一條就立刻寫到資料庫,--> <bufferSize value="0" /> <!--資料庫連接串--> <!--C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Config\machine.config--> <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <!--資料庫連接字串--> <connectionString value="Server=.;Database=Test;Uid=sa;Pwd=********;" /> <!--資料庫腳本--> <commandText value="INSERT INTO LogDetail (LogDate,LogLevel,LogThread,Logger,LogMessage) VALUES (@LogDate,@LogLevel,@LogThread,@Logger,@LogMessage)" /> <!--日志時間--> <parameter> <parameterName value="@LogDate" /> <dbType value="DateTime" /> <layout type="log4net.Layout.RawTimeStampLayout" /> </parameter> <!--日志級別--> <parameter> <parameterName value="@LogLevel" /> <dbType value="String" /> <size value="10" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%p" /> </layout> </parameter> <!--執行緒ID--> <parameter> <parameterName value="@LogThread" /> <dbType value="String" /> <size value="10" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%t" /> </layout> </parameter> <!--日志名稱--> <parameter> <parameterName value="@Logger" /> <dbType value="String" /> <size value="50" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%logger" /> </layout> </parameter> <!--日志內容--> <parameter> <parameterName value="@LogMessage" /> <dbType value="String" /> <size value="3000" /> <layout type="LinkTo.Test.ConsoleLog4Net.Utility.CustomLayout"> <conversionPattern value="%property{LogMessage}" /> </layout> </parameter> </appender> <root> <priority value="ALL" /> <level value="ALL" /> <appender-ref ref="ADONetAppender" /> </root> </log4net> </configuration>
2.2、日志內容處理程序
注:日志內容處理涉及的4個類(含幫助類)都是存放在Utility檔案夾下,
從配置的<layout type="LinkTo.Test.ConsoleLog4Net.Utility.CustomLayout">可以看出,日志內容的取值來源于一個自定義的Layout類CustomLayout:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using log4net.Layout; namespace LinkTo.Test.ConsoleLog4Net.Utility { public class CustomLayout : PatternLayout { /// <summary> /// 建構式:把需要寫入資料庫的屬性添加進來 /// </summary> public CustomLayout() { AddConverter("property", typeof(CustomLayoutConverter)); } } }
CustomLayout類添加屬性時,型別來源于CustomLayoutConverter類:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using log4net.Core; using log4net.Layout.Pattern; namespace LinkTo.Test.ConsoleLog4Net.Utility { public class CustomLayoutConverter : PatternLayoutConverter { protected override void Convert(TextWriter writer, LoggingEvent loggingEvent) { if (Option != null) { //寫入指定鍵的值 WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent)); } else { //Write all the key value pairs WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties()); } } /// <summary> /// 通過反射獲取傳入的日志物件的某個屬性的值 /// </summary> /// <param name="property"></param> /// <param name="loggingEvent"></param> /// <returns></returns> private object LookupProperty(string property, LoggingEvent loggingEvent) { object propertyValue = https://www.cnblogs.com/atomy/p/string.Empty; PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property); if (propertyInfo != null) propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null); return propertyValue; } } }
從配置的<conversionPattern value="https://www.cnblogs.com/atomy/p/%property{LogMessage}" />可以看出,日志內容的取值來源于屬性LogMessage,而這個LogMessage,統一來源于一個物體類LogContent:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LinkTo.Test.ConsoleLog4Net.Utility { public class LogContent { /// <summary> /// 日志內容 /// </summary> public string LogMessage { get; set; } public LogContent(string logMessage) { LogMessage = logMessage; } } }
2.3、幫助類
為了簡化寫日志的程序,封裝了一個簡單的幫助類LogHelper:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using log4net; namespace LinkTo.Test.ConsoleLog4Net.Utility { public class LogHelper { public static readonly ILog logger = LogManager.GetLogger("LinkTo.Test.ConsoleLog4Net"); //這里的引數不能使用Type型別 public static void Fatal(LogContent content) { logger.Fatal(content); } public static void Error(LogContent content) { logger.Error(content); } public static void Warn(LogContent content) { logger.Warn(content); } public static void Info(LogContent content) { logger.Info(content); } public static void Debug(LogContent content) { logger.Debug(content); } } }
2.4、測驗代碼
class Program { static void Main(string[] args) { XmlConfigurator.Configure(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "ConfigFile\\Log4NetToDB.config"))); LogHelper.Fatal(new LogContent("This is fatal message.")); LogHelper.Error(new LogContent("This is error message.")); LogHelper.Warn(new LogContent("This is warn message.")); LogHelper.Info(new LogContent("This is info message.")); LogHelper.Debug(new LogContent("This is debug message.")); Console.Read(); } }
2.5、運行結果

2.6、一點優化
每次寫日志時,都需要進行Log4Net檔案配置的話,肯定是沒有必要的:
XmlConfigurator.Configure(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "ConfigFile\\Log4NetToDB.config")));
可以在專案的Properties\AssemblyInfo.cs最下面加上下面這一句,進行全域的統一配置:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "ConfigFile\\Log4NetToDB.config")]
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/40651.html
標籤:C#
