zoukankan      html  css  js  c++  java
  • 开源框架

    序言

    众所周知,大多数情况下,业务需要记录的并不是简单的系统时间%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());
                }
            }
    
            /// <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
    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
    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
    <?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.dll引用外还需要添加System.Data.dll引用。

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

  • 相关阅读:
    Git 基础
    SharePoint 2013 对象模型操作"网站设置"菜单
    SharePoint 2013 隐藏部分Ribbon菜单
    SharePoint 2013 Designer系列之数据视图筛选
    SharePoint 2013 Designer系列之数据视图
    SharePoint 2013 Designer系列之自定义列表表单
    SharePoint 2013 设置自定义布局页
    SharePoint 2013 "通知我"功能简介
    SharePoint 2013 创建web应用程序报错"This page can’t be displayed"
    SharePoint 禁用本地回环的两个方法
  • 原文地址:https://www.cnblogs.com/jeremywucnblog/p/12819964.html
Copyright © 2011-2022 走看看