690 字
3 分钟
C# Log4Net 学习笔记:将日志实时记录到数据库
在 C/S 架构的项目中,本地文件日志(.txt)虽然方便查看,但难以进行统计分析。通过 Log4Net 的 ADONetAppender,我们可以将异常信息和运行日志直接写入 SQL Server,便于后续通过 SQL 语句快速排查问题。
一、 数据准备:创建日志表
首先,我们需要在 SQL Server 中准备一张承载日志的表。由于日志数据增长极快,建议为 LogDate 字段建立索引。
CREATE TABLE [dbo].[LogDetail]( [LogID] [INT] IDENTITY(1,1) NOT NULL, [LogDate] [DATETIME] NOT NULL, -- 日志记录时间 [LogThread] [VARCHAR](50) NULL, -- 线程 ID [LogLevel] [VARCHAR](50) NULL, -- 日志级别 (INFO/ERROR等) [Logger] [VARCHAR](255) NULL, -- 记录器名称 [LogMessage] [NVARCHAR](MAX) NULL, -- 日志详细内容 CONSTRAINT [PK_LogDetail] PRIMARY KEY CLUSTERED ([LogID] ASC)) ON [PRIMARY];二、 Log4Net 核心配置解析
Log4Net 的强大之处在于其插件式架构。ADONetAppender 负责将 LoggingEvent 转化为数据库的一条记录。
2.1 配置文件 (ConfigFile/Log4NetToDB.config)
关键参数说明:
- bufferSize: 设置为
0表示即时写入。在生产高并发环境下,建议设为10-100以减轻数据库压力(利用批处理)。 - connectionType: 需指向对应的数据库驱动程序。
<?xml version="1.0" encoding="utf-8" ?><log4net> <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender"> <bufferSize value="0" /> <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <connectionString value="Data Source=.;Initial Catalog=TestDB;User ID=sa;Password=********;" />
<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="@LogMessage" /> <dbType value="String" /> <size value="4000" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%message" /> </layout> </parameter>
</appender>
<root> <level value="ALL" /> <appender-ref ref="ADONetAppender" /> </root></log4net>三、 高级进阶:自定义日志内容处理
有时我们需要记录的不止是一个简单的字符串,而是一个复杂的对象。通过重写 PatternLayoutConverter,我们可以动态地从对象属性中提取值。
3.1 核心逻辑实现
CustomLayoutConverter.cs 负责反射提取自定义对象中的属性:
protected override void Convert(TextWriter writer, LoggingEvent loggingEvent){ if (Option != null) { // 反射提取 LogContent.LogMessage var propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(Option); var value = propertyInfo?.GetValue(loggingEvent.MessageObject, null); WriteObject(writer, loggingEvent.Repository, value); }}四、 性能与避坑建议
- 异步写入:数据库写入是 IO 密集型操作。在高吞吐系统中,建议在外层嵌套一个
AsyncForwardingAppender(来自 log4net.Async 库),避免写日志阻塞业务线程。 - 数据库连接安全:不要在配置文件中明文存储密码。可以使用宝塔面板的加密功能或 .NET 自带的
configProtectionProvider。 - 表维护计划:日志表会迅速膨胀。建议建立 SQL 代理作业,定期清理(如仅保留 30 天)或归档旧日志:
DELETE FROM LogDetail WHERE LogDate < DATEADD(day, -30, GETDATE());总结
通过 Log4Net 记录日志到数据库,可以将离散的错误信息转化为有价值的资产。配合简单的 Grafana 或是自定义的后台界面,你就能实时监控系统的健康状况。
C# Log4Net 学习笔记:将日志实时记录到数据库
https://sw.rscclub.website/posts/csharplog4netsqlserver/