开源框架 - 日志记录Log4Net(二)

2021-03-13 14:27

阅读:363

标签:you   object   word   代码   spl   dbf   OLE   done   alt   

序言

众所周知,大多数情况下,业务需要记录的并不是简单的系统时间%date,级别%level,信息%message等字段,而是需要自定义的业务字段。以便后续的数据挖掘和钻取。

逐步研究发现Log4Net记录日志的info,error,debug等方法可以传入object参数:log.info(object message)。

下面记录一下,传一个自定义的业务日志对象给info方法,它自动帮我得到该业务对象的字段的值,然后再写入到数据库后台。

解决方案

1、建立数据库和数据表

  • 数据库:Test,用户名:sa,密码:sa
  • 数据表:SysLogs
技术图片技术图片
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、核心代码

技术图片技术图片
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
技术图片技术图片
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());
            }
        }

        /// 
        /// 通过反射获取传入的日志对象的某个属性的值
        /// 
        /// 
        /// 
        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
技术图片技术图片
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
{
    /// 
    /// 自定义一个Layout,在该类的构造方法中将自定义的Converter加进去
    /// 以便于处理property{}中的自定义字段)和一个PatternConverter:
    /// 
    public class MyLayout : PatternLayout
    {
        public MyLayout()
        {
            this.AddConverter("property", typeof(MyMsgPatternConverter));
        }
    }  

}
MyLayout.cs
技术图片技术图片
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Log4NetDBDemo
{
    /// 
    /// 封装一个消息类,用来存放异常日志信息
    /// 
    public class LogContent
    {
        /// 
        /// 日志消息详情
        /// 
        public string Msg { get; set; }
        /// 
        /// 当前登录用户
        /// 
        public string UserName { get; set; }
        /// 
        /// 线程名称/模块名称/菜单名称/节点名称等
        /// 
        public string ThreadName { get; set; }
    }
}
LogContent.cs
技术图片技术图片
"1.0" encoding="utf-8" ?>
"log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
"All" /> ref ref="AdoNetAppender"/> "AdoNetAppender" type="log4net.Appender.AdoNetAppender"> "1" /> "System.Data.SqlClient.SqlConnection,System.Data, Version=1.0.3300.0, Culture=neutral,PublicKeyToken=b77a5c561934e089" /> "database=test;server=localhost;User ID=sa;Password=sa" /> "INSERT INTO SysLogs(LogDate,Msg,UserName,ThreadName,Level) VALUES (@LogDate,@Msg,@UserName,@ThreadName,@Level)" /> "@LogDate" /> "DateTime" /> "log4net.Layout.RawTimeStampLayout" /> "@Msg" /> "String" /> "2000" /> "Log4NetDBDemo.MyLayout, Log4NetDBDemo"> "ConversionPattern" value="%property{Msg}"/> "@UserName" /> "String" /> "200" /> "Log4NetDBDemo.MyLayout, Log4NetDBDemo" > "ConversionPattern" value="%property{UserName}"/> "@ThreadName" /> "String" /> "200" /> "Log4NetDBDemo.MyLayout, Log4NetDBDemo" > "ConversionPattern" value="%property{ThreadName}"/> "@Level" /> "String" /> "50" /> "log4net.Layout.PatternLayout" value="%level" />
App.config

运行结果

注意:我这里执行了三次。

技术图片

注意:

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

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

开源框架 - 日志记录Log4Net(二)

标签:you   object   word   代码   spl   dbf   OLE   done   alt   

原文地址:https://www.cnblogs.com/jeremywucnblog/p/12819964.html


评论


亲,登录后才可以留言!