天天看點

開源架構 - 日志記錄Log4Net(二)

序言

衆所周知,大多數情況下,業務需要記錄的并不是簡單的系統時間%date,級别%level,資訊%message等字段,而是需要自定義的業務字段。以便後續的資料挖掘和鑽取。

逐漸研究發現Log4Net記錄日志的info,error,debug等方法可以傳入object參數:log.info(object message)。

下面記錄一下,傳一個自定義的業務日志對象給info方法,它自動幫我得到該業務對象的字段的值,然後再寫入到資料庫背景。

解決方案

1、建立資料庫和資料表

  • 資料庫:Test,使用者名:sa,密碼:sa
  • 資料表:SysLogs
開源架構 - 日志記錄Log4Net(二)
開源架構 - 日志記錄Log4Net(二)
USE [Test]     GO     /****** Object:  Table [dbo].[SysLogs]    Script Date: 2020-05-02 22:07:49 ******/     SET ANSI_NULLS ON     GO     SET QUOTED_IDENTIFIER ON     GO     CREATE TABLE [dbo].[SysLogs](         [ID] [int] IDENTITY(1,1) NOT NULL,         [LogDate] [datetime] NULL,         [Msg] [nvarchar](max) NULL,         [UserName] [nvarchar](200) NULL,         [ThreadName] [nvarchar](200) NULL,         [Level] [nvarchar](200) NULL     ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]     GO      

SysLogs生成腳本

2、建立解決方案

  • 添加控制台應用程式 Log4NetDBDemo
  • 添加MyMsgPatternConverter類,啟用反射方式建立業務類屬性
  • 添加MyLayout類,在該類的構造方法中将自定義的Converter加進去,以便于處理property{}中的自定義字段)和一個PatternConverter
  • 封裝一個消息類LogContent,包含需要操作的業務屬性字段
  • 配置App.config檔案

3、核心代碼

開源架構 - 日志記錄Log4Net(二)
開源架構 - 日志記錄Log4Net(二)
using System;     using System.Collections.Generic;     using System.Linq;     using System.Text;     using System.Threading.Tasks;     namespace Log4NetDBDemo     {         class Program         {             static void Main(string[] args)             {                 log4net.Config.XmlConfigurator.Configure();                 log4net.ILog log = log4net.LogManager.GetLogger(typeof(Program));                 Console.WriteLine("開始寫日志_" + DateTime.Now.ToLongDateString());                 log.Info(new LogContent                 {                     Msg = "測試Log4Net日志存入資料庫",                     ThreadName = "控制台測試子產品",                     UserName = "sysman"                 });                 Console.WriteLine("日志寫入成功_" + DateTime.Now.ToLongDateString());                 Console.ReadKey();             }         }     }      

Program.cs

開源架構 - 日志記錄Log4Net(二)
開源架構 - 日志記錄Log4Net(二)
using log4net.Layout.Pattern;     using System;     using System.Collections.Generic;     using System.Linq;     using System.Reflection;     using System.Text;     using System.Threading.Tasks;     namespace Log4NetDBDemo     {         public class MyMsgPatternConverter : PatternLayoutConverter         {             protected override void Convert(System.IO.TextWriter writer, log4net.Core.LoggingEvent loggingEvent)             {                 if (Option != null)                 {                     // Write the value for the specified key                     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>             /// <returns></returns>             private object LookupProperty(string property, log4net.Core.LoggingEvent loggingEvent)             {                 object propertyValue = string.Empty;                 PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property);                 if (propertyInfo != null)                     propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null);                 return propertyValue;             }         }     }      

MyMsgPatternConverter.cs

開源架構 - 日志記錄Log4Net(二)
開源架構 - 日志記錄Log4Net(二)
using log4net.Layout;     using log4net.Layout.Pattern;     using System;     using System.Collections.Generic;     using System.Linq;     using System.Reflection;     using System.Text;     using System.Threading.Tasks;     namespace Log4NetDBDemo     {         /// <summary>         /// 自定義一個Layout,在該類的構造方法中将自定義的Converter加進去         /// 以便于處理property{}中的自定義字段)和一個PatternConverter:         /// </summary>         public class MyLayout : PatternLayout         {             public MyLayout()             {                 this.AddConverter("property", typeof(MyMsgPatternConverter));             }         }       }      

MyLayout.cs

開源架構 - 日志記錄Log4Net(二)
開源架構 - 日志記錄Log4Net(二)
using System;     using System.Collections.Generic;     using System.Linq;     using System.Text;     using System.Threading.Tasks;     namespace Log4NetDBDemo     {         /// <summary>         /// 封裝一個消息類,用來存放異常日志資訊         /// </summary>         public class LogContent         {             /// <summary>             /// 日志消息詳情             /// </summary>             public string Msg { get; set; }             /// <summary>             /// 目前登入使用者             /// </summary>             public string UserName { get; set; }             /// <summary>             /// 線程名稱/子產品名稱/菜單名稱/節點名稱等             /// </summary>             public string ThreadName { get; set; }         }     }      

LogContent.cs

開源架構 - 日志記錄Log4Net(二)
開源架構 - 日志記錄Log4Net(二)
<?xml version="1.0" encoding="utf-8" ?>     <configuration>       <configSections>         <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>       </configSections>       <log4net>         <root>           <level value="All" />           <!--媒體類型:資料庫-->           <appender-ref ref="AdoNetAppender"/>         </root>         <!--媒體類型配置:資料庫相關配置-->         <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">           <bufferSize value="1" />           <!--連接配接字元串-->           <connectionType value="System.Data.SqlClient.SqlConnection,System.Data, Version=1.0.3300.0, Culture=neutral,PublicKeyToken=b77a5c561934e089" />           <!--連接配接字元串value-->           <connectionString value="database=test;server=localhost;User ID=sa;Password=sa" />           <!--sql語句-->           <commandText value="INSERT INTO SysLogs(LogDate,Msg,UserName,ThreadName,Level) VALUES (@LogDate,@Msg,@UserName,@ThreadName,@Level)" />           <!--定義一些業務邏輯對象的屬性,以便寫入到資料庫背景-->           <!--日志寫入時間-->           <parameter>             <parameterName value="@LogDate" />             <dbType value="DateTime" />             <layout type="log4net.Layout.RawTimeStampLayout" />           </parameter>           <!--日志内容-->           <parameter>             <parameterName value="@Msg" />             <dbType value="String" />             <size value="2000" />             <layout type="Log4NetDBDemo.MyLayout, Log4NetDBDemo">               <param name="ConversionPattern" value="%property{Msg}"/>             </layout>           </parameter>           <!--使用者名-->           <parameter>             <parameterName value="@UserName" />             <dbType value="String" />             <size value="200" />             <layout type="Log4NetDBDemo.MyLayout, Log4NetDBDemo" >               <param name="ConversionPattern" value="%property{UserName}"/>             </layout>           </parameter>           <!--程序、子產品名稱-->           <parameter>             <parameterName value="@ThreadName" />             <dbType value="String" />             <size value="200" />             <layout type="Log4NetDBDemo.MyLayout, Log4NetDBDemo" >               <param name="ConversionPattern" value="%property{ThreadName}"/>             </layout>           </parameter>           <!--Log4Net Level-->           <parameter>             <parameterName value="@Level" />             <dbType value="String" />             <size value="50" />             <layout type="log4net.Layout.PatternLayout" value="%level" />           </parameter>           <!--定義一些業務邏輯對象的屬性,以便寫入到資料庫背景 結束-->         </appender>       </log4net>     </configuration>      

App.config

運作結果

注意:我這裡執行了三次。

開源架構 - 日志記錄Log4Net(二)

注意:

項目除了添加Log4Net.dll引用外還需要添加System.Data.dll引用。

參考資料:https://www.cnblogs.com/Arlen/archive/2008/11/22/1338908.html

繼續閱讀