zoukankan      html  css  js  c++  java
  • C# Log4Net学习笔记:记录日志到数据库

        一、数据准备

        在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:WINDOWSMicrosoft.NETFrameworkv4.0.30319Configmachine.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 = string.Empty;
                PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property);
                if (propertyInfo != null)
                    propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null);
                return propertyValue;
            }
    
    
        }
    }

        从配置的<conversionPattern value="%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")));

        可以在项目的PropertiesAssemblyInfo.cs最下面加上下面这一句,进行全局的统一配置:

    [assembly: log4net.Config.XmlConfigurator(ConfigFile = "ConfigFile\Log4NetToDB.config")]
  • 相关阅读:
    android listview去掉分割线
    svn 上传 过滤
    PPPOE 模拟环境搭建
    Android笔记之网络-基本了解
    ios多线程操作(五)—— GCD串行队列与并发队列
    UVa 679
    android中更改spinner、AutoCompleteTextView切割线的颜色
    Cocos2d-x中触摸事件
    全然符合package.json在CommonJS中的规范
    Hibernate实体对象继承策略
  • 原文地址:https://www.cnblogs.com/atomy/p/12873389.html
Copyright © 2011-2022 走看看