当前位置:
首页 > temp > 简明python教程 >
-
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:\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 = 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")));
可以在项目的Properties\AssemblyInfo.cs最下面加上下面这一句,进行全局的统一配置:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "ConfigFile\\Log4NetToDB.config")]
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
关于JS定时器的整理
JS中使用Promise.all控制所有的异步请求都完
js中字符串的方法
import-local执行流程与node模块路径解析流程
检测数据类型的四种方法
js中数组的方法,32种方法
前端操作方法
数据类型
window.localStorage.setItem 和 localStorage.setIte
如何完美解决前端数字计算精度丢失与数